From cbf07e717847d6b2c6c4fe6b31773daac9504f82 Mon Sep 17 00:00:00 2001 From: Philip Taron Date: Fri, 22 Dec 2023 12:33:09 -0800 Subject: [PATCH 01/12] flake.nix: rewrite 1. Split into separate files per output. 2. Added overlays, so that this flake can be integrated into others. The names in the overlay are `llama-cpp`, `llama-cpp-opencl`, `llama-cpp-cuda`, and `llama-cpp-rocm` so that they fit into the broader set of Nix packages from [nixpkgs](https://github.com/nixos/nixpkgs). 3. Use [callPackage](https://summer.nixos.org/blog/callpackage-a-tool-for-the-lazy/) rather than `with pkgs;` so that there's dependency injection rather than dependency lookup. 4. Add a description and meta information for each package. The description includes a bit about what's trying to accelerate each one. 5. Use specific CUDA packages instead of cudatoolkit on the advice of @SomeoneSerge. 6. Format with `serokell/nixfmt` for a consistent style. 7. Update `flake.lock` with the latest goods. --- .devops/nix/apps.nix | 14 +++ .devops/nix/devshells.nix | 10 ++ .devops/nix/overlay.nix | 17 +++ .devops/nix/package.nix | 189 ++++++++++++++++++++++++++++++++ flake.lock | 40 +------ flake.nix | 220 +++++++++++++++----------------------- 6 files changed, 320 insertions(+), 170 deletions(-) create mode 100644 .devops/nix/apps.nix create mode 100644 .devops/nix/devshells.nix create mode 100644 .devops/nix/overlay.nix create mode 100644 .devops/nix/package.nix diff --git a/.devops/nix/apps.nix b/.devops/nix/apps.nix new file mode 100644 index 0000000000000..d9b6a1e000628 --- /dev/null +++ b/.devops/nix/apps.nix @@ -0,0 +1,14 @@ +{ package, binaries }: + +let + default = builtins.elemAt binaries 0; + mkApp = name: { + ${name} = { + type = "app"; + program = "${package}/bin/${name}"; + }; + }; + result = builtins.foldl' (acc: name: (mkApp name) // acc) { } binaries; +in + +result // { default = result.${default}; } diff --git a/.devops/nix/devshells.nix b/.devops/nix/devshells.nix new file mode 100644 index 0000000000000..f8d541f3068a5 --- /dev/null +++ b/.devops/nix/devshells.nix @@ -0,0 +1,10 @@ +{ concatMapAttrs, packages }: + +concatMapAttrs + (name: package: { + ${name} = package.passthru.shell.overrideAttrs (prevAttrs: { inputsFrom = [ package ]; }); + ${name + "-extra"} = package.passthru.shell-extra.overrideAttrs ( + prevAttrs: { inputsFrom = [ package ]; } + ); + }) + packages diff --git a/.devops/nix/overlay.nix b/.devops/nix/overlay.nix new file mode 100644 index 0000000000000..e5fede7740641 --- /dev/null +++ b/.devops/nix/overlay.nix @@ -0,0 +1,17 @@ +final: prev: + +let + inherit (final.stdenv) isAarch64 isDarwin; + + darwinSpecific = + if isAarch64 then + { inherit (final.darwin.apple_sdk_11_0.frameworks) Accelerate MetalKit; } + else + { inherit (final.darwin.apple_sdk.frameworks) Accelerate CoreGraphics CoreVideo; }; + + osSpecific = if isDarwin then darwinSpecific else { }; +in + +{ + llama-cpp = final.callPackage ./package.nix osSpecific; +} diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix new file mode 100644 index 0000000000000..42349d0bac581 --- /dev/null +++ b/.devops/nix/package.nix @@ -0,0 +1,189 @@ +{ + lib, + config, + stdenv, + mkShell, + cmake, + ninja, + pkg-config, + git, + python3, + mpi, + openblas, # This could be `blas` to enable easy swapping out with `lapack` + cudaPackages, + rocmPackages, + clblast, + Accelerate ? null, + MetalKit ? null, + CoreVideo ? null, + CoreGraphics ? null, + useOpenCL ? false, + useCuda ? config.cudaSupport, + useRocm ? config.rocmSupport, +}@inputs: + +let + inherit (lib) + cmakeBool + cmakeFeature + optionals + versionOlder + ; + isDefault = !useOpenCL && !useCuda && !useRocm; + + # It's necessary to consistently use backendStdenv when building with CUDA support, + # otherwise we get libstdc++ errors downstream. + stdenv = throw "Use effectiveStdenv instead"; + effectiveStdenv = if useCuda then cudaPackages.backendStdenv else inputs.stdenv; + + # Give a little description difference between the flavors. + descriptionSuffix = + if useOpenCL then + " (OpenCL accelerated)" + else if useCuda then + " (CUDA accelerated)" + else if useRocm then + " (ROCm accelerated)" + else if (MetalKit != null) then + " (MetalKit accelerated)" + else + ""; + + # TODO: package the Python in this repository in a Nix-like way. + # It'd be nice to migrate to buildPythonPackage, as well as ensure this repo + # is PEP 517-compatible, and ensure the correct .dist-info is generated. + # https://peps.python.org/pep-0517/ + llama-python = python3.withPackages ( + ps: [ + ps.numpy + ps.sentencepiece + ] + ); + + # TODO(Green-Sky): find a better way to opt-into the heavy ml python runtime + llama-python-extra = python3.withPackages ( + ps: [ + ps.numpy + ps.sentencepiece + ps.torchWithoutCuda + ps.transformers + ] + ); + + # See ./overlay.nix for where these dependencies are passed in. + defaultBuildInputs = builtins.filter (p: p != null) [ + Accelerate + MetalKit + CoreVideo + CoreGraphics + ]; + + cudaBuildInputs = with cudaPackages; [ + cuda_cccl.dev # + cuda_cudart + libcublas + ]; + + rocmBuildInputs = with rocmPackages; [ + clr + hipblas + rocblas + ]; +in + +effectiveStdenv.mkDerivation { + name = "llama.cpp"; + src = ../../.; + meta = { + description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; + mainProgram = "llama"; + }; + + postPatch = '' + substituteInPlace ./ggml-metal.m \ + --replace '[bundle pathForResource:@"ggml-metal" ofType:@"metal"];' "@\"$out/bin/ggml-metal.metal\";" + + # TODO: Package up each Python script or service appropriately. + # If we were to migrate to buildPythonPackage and prepare the `pyproject.toml`, + # we could make those *.py into setuptools' entrypoints + substituteInPlace ./*.py --replace "/usr/bin/env python" "${llama-python}/bin/python" + ''; + + nativeBuildInputs = [ + cmake + ninja + pkg-config + git + ] ++ optionals useCuda [ cudaPackages.cuda_nvcc ]; + + buildInputs = + [ mpi ] + ++ optionals useOpenCL [ clblast ] + ++ optionals useCuda cudaBuildInputs + ++ optionals useRocm rocmBuildInputs + ++ optionals isDefault defaultBuildInputs; + + cmakeFlags = + [ + (cmakeBool "LLAMA_NATIVE" true) + (cmakeBool "LLAMA_BUILD_SERVER" true) + (cmakeBool "BUILD_SHARED_LIBS" true) + (cmakeBool "CMAKE_SKIP_BUILD_RPATH" true) + ] + ++ optionals useOpenCL [ (cmakeBool "LLAMA_CLBLAST" true) ] + ++ optionals useCuda [ (cmakeBool "LLAMA_CUBLAS" true) ] + ++ optionals useRocm [ + (cmakeBool "LLAMA_HIPBLAS" true) + (cmakeFeature "CMAKE_C_COMPILER" "hipcc") + (cmakeFeature "CMAKE_CXX_COMPILER" "hipcc") + + # Build all targets supported by rocBLAS. When updating search for TARGET_LIST_ROCM + # in https://github.com/ROCmSoftwarePlatform/rocBLAS/blob/develop/CMakeLists.txt + # and select the line that matches the current nixpkgs version of rocBLAS. + # Should likely use `rocmPackages.clr.gpuTargets`. + "-DAMDGPU_TARGETS=gfx803;gfx900;gfx906:xnack-;gfx908:xnack-;gfx90a:xnack+;gfx90a:xnack-;gfx940;gfx941;gfx942;gfx1010;gfx1012;gfx1030;gfx1100;gfx1101;gfx1102" + ] + ++ optionals isDefault ( + if (MetalKit != null) then + [ + "-DCMAKE_C_FLAGS=-D__ARM_FEATURE_DOTPROD=1" + "-DLLAMA_METAL=ON" + ] + else + [ + "-DLLAMA_BLAS=ON" + "-DLLAMA_BLAS_VENDOR=OpenBLAS" + ] + ); + + # TODO(SomeoneSerge): It's better to add proper install targets at the CMake level, + # if they haven't been added yet. + # + # For example: + # + # 1. Avoid GLOBs + # 2. Add whatever COMPONENTs are missing + # 3. Fix whatever issues remain with override-ability. + # + postInstall = '' + mv $out/bin/main $out/bin/llama + mv $out/bin/server $out/bin/llama-server + mkdir -p $out/include + cp $src/llama.h $out/include/ + ''; + + # Define the shells here, but don't add in the inputsFrom to avoid recursion. + passthru = { + shell = mkShell { + name = "default${descriptionSuffix}"; + description = "contains numpy and sentencepiece"; + buildInputs = [ llama-python ]; + }; + + shell-extra = mkShell { + name = "extra${descriptionSuffix}"; + description = "contains numpy, sentencepiece, torchWithoutCuda, and transformers"; + buildInputs = [ llama-python-extra ]; + }; + }; +} diff --git a/flake.lock b/flake.lock index 0455f65617a2d..fdcd6d411b324 100644 --- a/flake.lock +++ b/flake.lock @@ -1,30 +1,12 @@ { "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1698318101, - "narHash": "sha256-gUihHt3yPD7bVqg+k/UVHgngyaJ3DMEBchbymBMvK1E=", + "lastModified": 1703013332, + "narHash": "sha256-+tFNwMvlXLbJZXiMHqYq77z/RfmpfpiI3yjL6o/Zo9M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "63678e9f3d3afecfeafa0acead6239cdb447574c", + "rev": "54aac082a4d9bb5bbc5c4e899603abfb76a3f6d6", "type": "github" }, "original": { @@ -36,24 +18,8 @@ }, "root": { "inputs": { - "flake-utils": "flake-utils", "nixpkgs": "nixpkgs" } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 4cf28d5c11c0f..dcf8e1d9defa0 100644 --- a/flake.nix +++ b/flake.nix @@ -1,139 +1,93 @@ { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - name = "llama.cpp"; - src = ./.; - meta.mainProgram = "llama"; - inherit (pkgs.stdenv) isAarch32 isAarch64 isDarwin; - buildInputs = with pkgs; [ openmpi ]; - osSpecific = with pkgs; buildInputs ++ ( - if isAarch64 && isDarwin then - with pkgs.darwin.apple_sdk_11_0.frameworks; [ - Accelerate - MetalKit - ] - else if isAarch32 && isDarwin then - with pkgs.darwin.apple_sdk.frameworks; [ - Accelerate - CoreGraphics - CoreVideo - ] - else if isDarwin then - with pkgs.darwin.apple_sdk.frameworks; [ - Accelerate - CoreGraphics - CoreVideo - ] - else - with pkgs; [ openblas ] - ); - pkgs = import nixpkgs { inherit system; }; - nativeBuildInputs = with pkgs; [ cmake ninja pkg-config ]; - cudatoolkit_joined = with pkgs; symlinkJoin { - # HACK(Green-Sky): nix currently has issues with cmake findcudatoolkit - # see https://github.com/NixOS/nixpkgs/issues/224291 - # copied from jaxlib - name = "${cudaPackages.cudatoolkit.name}-merged"; - paths = [ - cudaPackages.cudatoolkit.lib - cudaPackages.cudatoolkit.out - ] ++ lib.optionals (lib.versionOlder cudaPackages.cudatoolkit.version "11") [ - # for some reason some of the required libs are in the targets/x86_64-linux - # directory; not sure why but this works around it - "${cudaPackages.cudatoolkit}/targets/${system}" + + outputs = + { self, nixpkgs }: + + let + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" # x86_64-darwin isn't tested (and likely isn't relevant) + "x86_64-linux" + ]; + eachSystem = f: nixpkgs.lib.genAttrs systems (system: f system); + in + + { + # These define the various ways to build the llama.cpp project. + # Integrate them into your flake.nix configuration by adding this overlay to nixpkgs.overlays. + overlays.default = import ./.devops/nix/overlay.nix; + + # These use the package definition from `./.devops/nix/package.nix`. + # There's one per backend that llama-cpp uses. Add more as needed! + packages = eachSystem ( + system: + let + defaultConfig = { + inherit system; + overlays = [ self.overlays.default ]; + }; + pkgs = import nixpkgs defaultConfig; + + # Let's not make a big deal about getting the CUDA bits. + cudaConfig = defaultConfig // { + config.cudaSupport = true; + config.allowUnfreePredicate = + p: + builtins.all + ( + license: + license.free + || builtins.elem license.shortName [ + "CUDA EULA" + "cuDNN EULA" + ] + ) + (p.meta.licenses or [ p.meta.license ]); + }; + pkgsCuda = import nixpkgs cudaConfig; + + # Let's make sure to turn on ROCm support across the whole package ecosystem. + rocmConfig = defaultConfig // { + config.rocmSupport = true; + }; + pkgsRocm = import nixpkgs rocmConfig; + in + { + default = pkgs.llama-cpp; + opencl = pkgs.llama-cpp.override { useOpenCL = true; }; + cuda = pkgsCuda.llama-cpp; + rocm = pkgsRocm.llama-cpp; + } + ); + + # These use the definition of llama-cpp from `./.devops/nix/package.nix` + # and expose various binaries as apps with `nix run .#app-name`. + # Note that none of these apps use anything other than the default backend. + apps = eachSystem ( + system: + import ./.devops/nix/apps.nix { + package = self.packages.${system}.default; + binaries = [ + "llama" + "llama-embedding" + "llama-server" + "quantize" + "train-text-from-scratch" ]; - }; - llama-python = - pkgs.python3.withPackages (ps: with ps; [ numpy sentencepiece ]); - # TODO(Green-Sky): find a better way to opt-into the heavy ml python runtime - llama-python-extra = - pkgs.python3.withPackages (ps: with ps; [ numpy sentencepiece torchWithoutCuda transformers ]); - postPatch = '' - substituteInPlace ./ggml-metal.m \ - --replace '[bundle pathForResource:@"ggml-metal" ofType:@"metal"];' "@\"$out/bin/ggml-metal.metal\";" - substituteInPlace ./*.py --replace '/usr/bin/env python' '${llama-python}/bin/python' - ''; - postInstall = '' - mv $out/bin/main $out/bin/llama - mv $out/bin/server $out/bin/llama-server - mkdir -p $out/include - cp ${src}/llama.h $out/include/ - ''; - cmakeFlags = [ "-DLLAMA_NATIVE=OFF" "-DLLAMA_BUILD_SERVER=ON" "-DBUILD_SHARED_LIBS=ON" "-DCMAKE_SKIP_BUILD_RPATH=ON" ]; - in - { - packages.default = pkgs.stdenv.mkDerivation { - inherit name src meta postPatch nativeBuildInputs postInstall; - buildInputs = osSpecific; - cmakeFlags = cmakeFlags - ++ (if isAarch64 && isDarwin then [ - "-DCMAKE_C_FLAGS=-D__ARM_FEATURE_DOTPROD=1" - "-DLLAMA_METAL=ON" - ] else [ - "-DLLAMA_BLAS=ON" - "-DLLAMA_BLAS_VENDOR=OpenBLAS" - ]); - }; - packages.opencl = pkgs.stdenv.mkDerivation { - inherit name src meta postPatch nativeBuildInputs postInstall; - buildInputs = with pkgs; buildInputs ++ [ clblast ]; - cmakeFlags = cmakeFlags ++ [ - "-DLLAMA_CLBLAST=ON" - ]; - }; - packages.cuda = pkgs.stdenv.mkDerivation { - inherit name src meta postPatch nativeBuildInputs postInstall; - buildInputs = with pkgs; buildInputs ++ [ cudatoolkit_joined ]; - cmakeFlags = cmakeFlags ++ [ - "-DLLAMA_CUBLAS=ON" - ]; - }; - packages.rocm = pkgs.stdenv.mkDerivation { - inherit name src meta postPatch nativeBuildInputs postInstall; - buildInputs = with pkgs.rocmPackages; buildInputs ++ [ clr hipblas rocblas ]; - cmakeFlags = cmakeFlags ++ [ - "-DLLAMA_HIPBLAS=1" - "-DCMAKE_C_COMPILER=hipcc" - "-DCMAKE_CXX_COMPILER=hipcc" - # Build all targets supported by rocBLAS. When updating search for TARGET_LIST_ROCM - # in github.com/ROCmSoftwarePlatform/rocBLAS/blob/develop/CMakeLists.txt - # and select the line that matches the current nixpkgs version of rocBLAS. - "-DAMDGPU_TARGETS=gfx803;gfx900;gfx906:xnack-;gfx908:xnack-;gfx90a:xnack+;gfx90a:xnack-;gfx940;gfx941;gfx942;gfx1010;gfx1012;gfx1030;gfx1100;gfx1101;gfx1102" - ]; - }; - apps.llama-server = { - type = "app"; - program = "${self.packages.${system}.default}/bin/llama-server"; - }; - apps.llama-embedding = { - type = "app"; - program = "${self.packages.${system}.default}/bin/embedding"; - }; - apps.llama = { - type = "app"; - program = "${self.packages.${system}.default}/bin/llama"; - }; - apps.quantize = { - type = "app"; - program = "${self.packages.${system}.default}/bin/quantize"; - }; - apps.train-text-from-scratch = { - type = "app"; - program = "${self.packages.${system}.default}/bin/train-text-from-scratch"; - }; - apps.default = self.apps.${system}.llama; - devShells.default = pkgs.mkShell { - buildInputs = [ llama-python ]; - packages = nativeBuildInputs ++ osSpecific; - }; - devShells.extra = pkgs.mkShell { - buildInputs = [ llama-python-extra ]; - packages = nativeBuildInputs ++ osSpecific; - }; - }); + } + ); + + # These expose a build environment for either a "default" or an "extra" set of dependencies. + devShells = eachSystem ( + system: + import ./.devops/nix/devshells.nix { + concatMapAttrs = nixpkgs.lib.concatMapAttrs; + packages = self.packages.${system}; + } + ); + }; } From 76f348aabb88c003741d44a22dd0ca83da5563e6 Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Sun, 24 Dec 2023 18:15:25 +0000 Subject: [PATCH 02/12] flake.nix: use finalPackage instead of passing it manually --- .devops/nix/devshells.nix | 6 ++---- .devops/nix/package.nix | 6 ++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.devops/nix/devshells.nix b/.devops/nix/devshells.nix index f8d541f3068a5..afaaa2644059b 100644 --- a/.devops/nix/devshells.nix +++ b/.devops/nix/devshells.nix @@ -2,9 +2,7 @@ concatMapAttrs (name: package: { - ${name} = package.passthru.shell.overrideAttrs (prevAttrs: { inputsFrom = [ package ]; }); - ${name + "-extra"} = package.passthru.shell-extra.overrideAttrs ( - prevAttrs: { inputsFrom = [ package ]; } - ); + ${name} = package.passthru.shell; + ${name + "-extra"} = package.passthru.shell-extra; }) packages diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index 42349d0bac581..ccce3e5e6b8aa 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -91,7 +91,7 @@ let ]; in -effectiveStdenv.mkDerivation { +effectiveStdenv.mkDerivation (finalAttrs: { name = "llama.cpp"; src = ../../.; meta = { @@ -178,12 +178,14 @@ effectiveStdenv.mkDerivation { name = "default${descriptionSuffix}"; description = "contains numpy and sentencepiece"; buildInputs = [ llama-python ]; + inputsFrom = [ finalAttrs.finalPackage ]; }; shell-extra = mkShell { name = "extra${descriptionSuffix}"; description = "contains numpy, sentencepiece, torchWithoutCuda, and transformers"; buildInputs = [ llama-python-extra ]; + inputsFrom = [ finalAttrs.finalPackage ]; }; }; -} +}) From b28426a9526ce19e2917979c92915e723250d66d Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Sun, 24 Dec 2023 18:24:28 +0000 Subject: [PATCH 03/12] fixup! flake.nix: rewrite --- .devops/nix/package.nix | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index ccce3e5e6b8aa..bd2dbf4b2c4bd 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -9,7 +9,7 @@ git, python3, mpi, - openblas, # This could be `blas` to enable easy swapping out with `lapack` + openblas, # TODO: Use the generic `blas` so users could switch betwen alternative implementations cudaPackages, rocmPackages, clblast, @@ -158,13 +158,6 @@ effectiveStdenv.mkDerivation (finalAttrs: { # TODO(SomeoneSerge): It's better to add proper install targets at the CMake level, # if they haven't been added yet. - # - # For example: - # - # 1. Avoid GLOBs - # 2. Add whatever COMPONENTs are missing - # 3. Fix whatever issues remain with override-ability. - # postInstall = '' mv $out/bin/main $out/bin/llama mv $out/bin/server $out/bin/llama-server From d73272f18bd5abfcde9a226f7079111f86c75485 Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Sun, 24 Dec 2023 19:35:32 +0000 Subject: [PATCH 04/12] flake.nix: unclutter darwin support --- .devops/nix/overlay.nix | 14 +---------- .devops/nix/package.nix | 52 ++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 40 deletions(-) diff --git a/.devops/nix/overlay.nix b/.devops/nix/overlay.nix index e5fede7740641..c7baec8434fa4 100644 --- a/.devops/nix/overlay.nix +++ b/.devops/nix/overlay.nix @@ -1,17 +1,5 @@ final: prev: -let - inherit (final.stdenv) isAarch64 isDarwin; - - darwinSpecific = - if isAarch64 then - { inherit (final.darwin.apple_sdk_11_0.frameworks) Accelerate MetalKit; } - else - { inherit (final.darwin.apple_sdk.frameworks) Accelerate CoreGraphics CoreVideo; }; - - osSpecific = if isDarwin then darwinSpecific else { }; -in - { - llama-cpp = final.callPackage ./package.nix osSpecific; + llama-cpp = final.callPackage ./package.nix { }; } diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index bd2dbf4b2c4bd..e286fda191b66 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -11,14 +11,18 @@ mpi, openblas, # TODO: Use the generic `blas` so users could switch betwen alternative implementations cudaPackages, + darwin, rocmPackages, clblast, - Accelerate ? null, - MetalKit ? null, - CoreVideo ? null, - CoreGraphics ? null, - useOpenCL ? false, + useBlas ? builtins.all (x: !x) [ + useCuda + useMetalKit + useOpenCL + useRocm + ], useCuda ? config.cudaSupport, + useMetalKit ? stdenv.isAarch64 && stdenv.isDarwin && !useOpenCL, + useOpenCL ? false, useRocm ? config.rocmSupport, }@inputs: @@ -29,7 +33,6 @@ let optionals versionOlder ; - isDefault = !useOpenCL && !useCuda && !useRocm; # It's necessary to consistently use backendStdenv when building with CUDA support, # otherwise we get libstdc++ errors downstream. @@ -44,7 +47,7 @@ let " (CUDA accelerated)" else if useRocm then " (ROCm accelerated)" - else if (MetalKit != null) then + else if useMetalKit then " (MetalKit accelerated)" else ""; @@ -70,13 +73,16 @@ let ] ); - # See ./overlay.nix for where these dependencies are passed in. - defaultBuildInputs = builtins.filter (p: p != null) [ - Accelerate - MetalKit - CoreVideo - CoreGraphics - ]; + # apple_sdk is supposed to choose sane defaults, no need to handle isAarch64 + # separately + darwinBuildInputs = + with darwin.apple_sdk.frameworks; + [ Accelerate ] + ++ optionals useMetalKit [ MetalKit ] + ++ optionals (!useMetalKit) [ + CoreVideo + CoreGraphics + ]; cudaBuildInputs = with cudaPackages; [ cuda_cccl.dev # @@ -121,7 +127,7 @@ effectiveStdenv.mkDerivation (finalAttrs: { ++ optionals useOpenCL [ clblast ] ++ optionals useCuda cudaBuildInputs ++ optionals useRocm rocmBuildInputs - ++ optionals isDefault defaultBuildInputs; + ++ optionals effectiveStdenv.isDarwin darwinBuildInputs; cmakeFlags = [ @@ -129,6 +135,8 @@ effectiveStdenv.mkDerivation (finalAttrs: { (cmakeBool "LLAMA_BUILD_SERVER" true) (cmakeBool "BUILD_SHARED_LIBS" true) (cmakeBool "CMAKE_SKIP_BUILD_RPATH" true) + (cmakeBool "LLAMA_METAL" useMetalKit) + (cmakeBool "LLAMA_BLAS" useBlas) ] ++ optionals useOpenCL [ (cmakeBool "LLAMA_CLBLAST" true) ] ++ optionals useCuda [ (cmakeBool "LLAMA_CUBLAS" true) ] @@ -143,18 +151,8 @@ effectiveStdenv.mkDerivation (finalAttrs: { # Should likely use `rocmPackages.clr.gpuTargets`. "-DAMDGPU_TARGETS=gfx803;gfx900;gfx906:xnack-;gfx908:xnack-;gfx90a:xnack+;gfx90a:xnack-;gfx940;gfx941;gfx942;gfx1010;gfx1012;gfx1030;gfx1100;gfx1101;gfx1102" ] - ++ optionals isDefault ( - if (MetalKit != null) then - [ - "-DCMAKE_C_FLAGS=-D__ARM_FEATURE_DOTPROD=1" - "-DLLAMA_METAL=ON" - ] - else - [ - "-DLLAMA_BLAS=ON" - "-DLLAMA_BLAS_VENDOR=OpenBLAS" - ] - ); + ++ optionals useMetalKit [ (lib.cmakeFeature "CMAKE_C_FLAGS" "-D__ARM_FEATURE_DOTPROD=1") ] + ++ optionals useBlas [ (lib.cmakeFeature "LLAMA_BLAS_VENDOR" "OpenBLAS") ]; # TODO(SomeoneSerge): It's better to add proper install targets at the CMake level, # if they haven't been added yet. From fea0239e24bf47909040b5996e6149aca71e58cb Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Sun, 24 Dec 2023 19:36:30 +0000 Subject: [PATCH 05/12] flake.nix: pass most darwin frameworks unconditionally ...for simplicity --- .devops/nix/package.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index e286fda191b66..1d401a9ee4ce9 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -77,12 +77,12 @@ let # separately darwinBuildInputs = with darwin.apple_sdk.frameworks; - [ Accelerate ] - ++ optionals useMetalKit [ MetalKit ] - ++ optionals (!useMetalKit) [ + [ + Accelerate CoreVideo CoreGraphics - ]; + ] + ++ optionals useMetalKit [ MetalKit ]; cudaBuildInputs = with cudaPackages; [ cuda_cccl.dev # From 34f2477854bbbb9ab0e101946943223083e21950 Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Mon, 25 Dec 2023 16:23:56 +0000 Subject: [PATCH 06/12] *.nix: nixfmt nix shell github:piegamesde/nixfmt/rfc101-style --command \ nixfmt flake.nix .devops/nix/*.nix --- .devops/nix/package.nix | 162 ++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index 1d401a9ee4ce9..5b88cf079f605 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -97,86 +97,88 @@ let ]; in -effectiveStdenv.mkDerivation (finalAttrs: { - name = "llama.cpp"; - src = ../../.; - meta = { - description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; - mainProgram = "llama"; - }; - - postPatch = '' - substituteInPlace ./ggml-metal.m \ - --replace '[bundle pathForResource:@"ggml-metal" ofType:@"metal"];' "@\"$out/bin/ggml-metal.metal\";" - - # TODO: Package up each Python script or service appropriately. - # If we were to migrate to buildPythonPackage and prepare the `pyproject.toml`, - # we could make those *.py into setuptools' entrypoints - substituteInPlace ./*.py --replace "/usr/bin/env python" "${llama-python}/bin/python" - ''; - - nativeBuildInputs = [ - cmake - ninja - pkg-config - git - ] ++ optionals useCuda [ cudaPackages.cuda_nvcc ]; - - buildInputs = - [ mpi ] - ++ optionals useOpenCL [ clblast ] - ++ optionals useCuda cudaBuildInputs - ++ optionals useRocm rocmBuildInputs - ++ optionals effectiveStdenv.isDarwin darwinBuildInputs; - - cmakeFlags = - [ - (cmakeBool "LLAMA_NATIVE" true) - (cmakeBool "LLAMA_BUILD_SERVER" true) - (cmakeBool "BUILD_SHARED_LIBS" true) - (cmakeBool "CMAKE_SKIP_BUILD_RPATH" true) - (cmakeBool "LLAMA_METAL" useMetalKit) - (cmakeBool "LLAMA_BLAS" useBlas) - ] - ++ optionals useOpenCL [ (cmakeBool "LLAMA_CLBLAST" true) ] - ++ optionals useCuda [ (cmakeBool "LLAMA_CUBLAS" true) ] - ++ optionals useRocm [ - (cmakeBool "LLAMA_HIPBLAS" true) - (cmakeFeature "CMAKE_C_COMPILER" "hipcc") - (cmakeFeature "CMAKE_CXX_COMPILER" "hipcc") - - # Build all targets supported by rocBLAS. When updating search for TARGET_LIST_ROCM - # in https://github.com/ROCmSoftwarePlatform/rocBLAS/blob/develop/CMakeLists.txt - # and select the line that matches the current nixpkgs version of rocBLAS. - # Should likely use `rocmPackages.clr.gpuTargets`. - "-DAMDGPU_TARGETS=gfx803;gfx900;gfx906:xnack-;gfx908:xnack-;gfx90a:xnack+;gfx90a:xnack-;gfx940;gfx941;gfx942;gfx1010;gfx1012;gfx1030;gfx1100;gfx1101;gfx1102" - ] - ++ optionals useMetalKit [ (lib.cmakeFeature "CMAKE_C_FLAGS" "-D__ARM_FEATURE_DOTPROD=1") ] - ++ optionals useBlas [ (lib.cmakeFeature "LLAMA_BLAS_VENDOR" "OpenBLAS") ]; - - # TODO(SomeoneSerge): It's better to add proper install targets at the CMake level, - # if they haven't been added yet. - postInstall = '' - mv $out/bin/main $out/bin/llama - mv $out/bin/server $out/bin/llama-server - mkdir -p $out/include - cp $src/llama.h $out/include/ - ''; - - # Define the shells here, but don't add in the inputsFrom to avoid recursion. - passthru = { - shell = mkShell { - name = "default${descriptionSuffix}"; - description = "contains numpy and sentencepiece"; - buildInputs = [ llama-python ]; - inputsFrom = [ finalAttrs.finalPackage ]; +effectiveStdenv.mkDerivation ( + finalAttrs: { + name = "llama.cpp"; + src = ../../.; + meta = { + description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; + mainProgram = "llama"; }; - shell-extra = mkShell { - name = "extra${descriptionSuffix}"; - description = "contains numpy, sentencepiece, torchWithoutCuda, and transformers"; - buildInputs = [ llama-python-extra ]; - inputsFrom = [ finalAttrs.finalPackage ]; + postPatch = '' + substituteInPlace ./ggml-metal.m \ + --replace '[bundle pathForResource:@"ggml-metal" ofType:@"metal"];' "@\"$out/bin/ggml-metal.metal\";" + + # TODO: Package up each Python script or service appropriately. + # If we were to migrate to buildPythonPackage and prepare the `pyproject.toml`, + # we could make those *.py into setuptools' entrypoints + substituteInPlace ./*.py --replace "/usr/bin/env python" "${llama-python}/bin/python" + ''; + + nativeBuildInputs = [ + cmake + ninja + pkg-config + git + ] ++ optionals useCuda [ cudaPackages.cuda_nvcc ]; + + buildInputs = + [ mpi ] + ++ optionals useOpenCL [ clblast ] + ++ optionals useCuda cudaBuildInputs + ++ optionals useRocm rocmBuildInputs + ++ optionals effectiveStdenv.isDarwin darwinBuildInputs; + + cmakeFlags = + [ + (cmakeBool "LLAMA_NATIVE" true) + (cmakeBool "LLAMA_BUILD_SERVER" true) + (cmakeBool "BUILD_SHARED_LIBS" true) + (cmakeBool "CMAKE_SKIP_BUILD_RPATH" true) + (cmakeBool "LLAMA_METAL" useMetalKit) + (cmakeBool "LLAMA_BLAS" useBlas) + ] + ++ optionals useOpenCL [ (cmakeBool "LLAMA_CLBLAST" true) ] + ++ optionals useCuda [ (cmakeBool "LLAMA_CUBLAS" true) ] + ++ optionals useRocm [ + (cmakeBool "LLAMA_HIPBLAS" true) + (cmakeFeature "CMAKE_C_COMPILER" "hipcc") + (cmakeFeature "CMAKE_CXX_COMPILER" "hipcc") + + # Build all targets supported by rocBLAS. When updating search for TARGET_LIST_ROCM + # in https://github.com/ROCmSoftwarePlatform/rocBLAS/blob/develop/CMakeLists.txt + # and select the line that matches the current nixpkgs version of rocBLAS. + # Should likely use `rocmPackages.clr.gpuTargets`. + "-DAMDGPU_TARGETS=gfx803;gfx900;gfx906:xnack-;gfx908:xnack-;gfx90a:xnack+;gfx90a:xnack-;gfx940;gfx941;gfx942;gfx1010;gfx1012;gfx1030;gfx1100;gfx1101;gfx1102" + ] + ++ optionals useMetalKit [ (lib.cmakeFeature "CMAKE_C_FLAGS" "-D__ARM_FEATURE_DOTPROD=1") ] + ++ optionals useBlas [ (lib.cmakeFeature "LLAMA_BLAS_VENDOR" "OpenBLAS") ]; + + # TODO(SomeoneSerge): It's better to add proper install targets at the CMake level, + # if they haven't been added yet. + postInstall = '' + mv $out/bin/main $out/bin/llama + mv $out/bin/server $out/bin/llama-server + mkdir -p $out/include + cp $src/llama.h $out/include/ + ''; + + # Define the shells here, but don't add in the inputsFrom to avoid recursion. + passthru = { + shell = mkShell { + name = "default${descriptionSuffix}"; + description = "contains numpy and sentencepiece"; + buildInputs = [ llama-python ]; + inputsFrom = [ finalAttrs.finalPackage ]; + }; + + shell-extra = mkShell { + name = "extra${descriptionSuffix}"; + description = "contains numpy, sentencepiece, torchWithoutCuda, and transformers"; + buildInputs = [ llama-python-extra ]; + inputsFrom = [ finalAttrs.finalPackage ]; + }; }; - }; -}) + } +) From 0925e7ee7cc7b9aa62590279fcf15866936a12bd Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Mon, 25 Dec 2023 17:29:02 +0000 Subject: [PATCH 07/12] flake.nix: add maintainers --- .devops/nix/package.nix | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index 5b88cf079f605..12b8f66451f47 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -104,6 +104,16 @@ effectiveStdenv.mkDerivation ( meta = { description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; mainProgram = "llama"; + + + # These people might respond if you ping them in case of Nix-specific + # regressions or for reviewing Nix-specific PRs. + + # Note that lib.maintainers is defined in Nixpkgs. + maintainers = with lib.maintainers; [ + philiptaron + SomeoneSerge + ]; }; postPatch = '' From 0e614077c32a85ed5e0cc4e7c41ac54772243d05 Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Mon, 25 Dec 2023 17:29:50 +0000 Subject: [PATCH 08/12] nix: move meta down to follow Nixpkgs style more closely --- .devops/nix/package.nix | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index 12b8f66451f47..471c46b2a7235 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -101,20 +101,6 @@ effectiveStdenv.mkDerivation ( finalAttrs: { name = "llama.cpp"; src = ../../.; - meta = { - description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; - mainProgram = "llama"; - - - # These people might respond if you ping them in case of Nix-specific - # regressions or for reviewing Nix-specific PRs. - - # Note that lib.maintainers is defined in Nixpkgs. - maintainers = with lib.maintainers; [ - philiptaron - SomeoneSerge - ]; - }; postPatch = '' substituteInPlace ./ggml-metal.m \ @@ -190,5 +176,20 @@ effectiveStdenv.mkDerivation ( inputsFrom = [ finalAttrs.finalPackage ]; }; }; + + meta = { + description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; + mainProgram = "llama"; + + + # These people might respond if you ping them in case of Nix-specific + # regressions or for reviewing Nix-specific PRs. + + # Note that lib.maintainers is defined in Nixpkgs. + maintainers = with lib.maintainers; [ + philiptaron + SomeoneSerge + ]; + }; } ) From 5dfe9ba4b698623fc3baf98b89fd80a7db14004e Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Mon, 25 Dec 2023 17:32:44 +0000 Subject: [PATCH 09/12] nix: add missing meta attributes --- .devops/nix/package.nix | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index 471c46b2a7235..a9d5453de058b 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -178,18 +178,24 @@ effectiveStdenv.mkDerivation ( }; meta = { + broken = (useCuda && effectiveStdenv.isDarwin) || (useMetalKit && !effectiveStdenv.isDarwin); description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; - mainProgram = "llama"; + homepage = "https://github.com/ggerganov/llama.cpp/"; + license = lib.licenses.mit; + # Accommodates `nix run` and `lib.getExe` + mainProgram = "llama"; # These people might respond if you ping them in case of Nix-specific # regressions or for reviewing Nix-specific PRs. # Note that lib.maintainers is defined in Nixpkgs. maintainers = with lib.maintainers; [ - philiptaron - SomeoneSerge + philiptaron + SomeoneSerge ]; + + platforms = lib.platforms.unix; }; } ) From 12115d62dae66bc057e916e365805629bedf3523 Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Mon, 25 Dec 2023 17:45:19 +0000 Subject: [PATCH 10/12] nix: clarify the interpretation of meta.maintainers --- .devops/nix/package.nix | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index a9d5453de058b..0f1cab916470d 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -186,10 +186,16 @@ effectiveStdenv.mkDerivation ( # Accommodates `nix run` and `lib.getExe` mainProgram = "llama"; - # These people might respond if you ping them in case of Nix-specific - # regressions or for reviewing Nix-specific PRs. - - # Note that lib.maintainers is defined in Nixpkgs. + # These people might respond, on the best effort basis, if you ping them + # in case of Nix-specific regressions or for reviewing Nix-specific PRs. + # Consider adding yourself to this list if you want to ensure this flake + # stays maintained and you're willing to invest your time. Do not add + # other people without their consent. Consider removing people after + # they've been unreachable for long periods of time. + + # Note that lib.maintainers is defined in Nixpkgs, but you may just add + # an attrset following the same format as in + # https://github.com/NixOS/nixpkgs/blob/f36a80e54da29775c78d7eff0e628c2b4e34d1d7/maintainers/maintainer-list.nix maintainers = with lib.maintainers; [ philiptaron SomeoneSerge From 42c7bbed76990fc70a410e4e76bd3dccfdf8a29f Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Mon, 25 Dec 2023 17:59:16 +0000 Subject: [PATCH 11/12] nix: clarify the meaning of "broken" and "badPlatforms" --- .devops/nix/package.nix | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index 0f1cab916470d..59c5e4c53713a 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -178,7 +178,15 @@ effectiveStdenv.mkDerivation ( }; meta = { - broken = (useCuda && effectiveStdenv.isDarwin) || (useMetalKit && !effectiveStdenv.isDarwin); + # Configurations we don't want even the CI to evaluate. Results in the + # "unsupported platform" messages. This is mostly a no-op, because + # cudaPackages would've refused to evaluate anyway. + badPlatforms = optionals (useCuda || useOpenCL) lib.platforms.darwin; + + # Configurations that are known to result in build failures. Can be + # overridden by importing Nixpkgs with `allowBroken = true`. + broken = (useMetalKit && !effectiveStdenv.isDarwin); + description = "Inference of LLaMA model in pure C/C++${descriptionSuffix}"; homepage = "https://github.com/ggerganov/llama.cpp/"; license = lib.licenses.mit; @@ -201,7 +209,8 @@ effectiveStdenv.mkDerivation ( SomeoneSerge ]; - platforms = lib.platforms.unix; + # Extend `badPlatforms` instead + platforms = lib.platforms.all; }; } ) From d98f4ab00eb068c71f3109c609c3ba42769765f7 Mon Sep 17 00:00:00 2001 From: Someone Serge Date: Mon, 25 Dec 2023 18:09:28 +0000 Subject: [PATCH 12/12] nix: passthru: expose the use* flags for inspection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit E.g.: ``` ❯ nix eval .#cuda.useCuda true ``` --- .devops/nix/package.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.devops/nix/package.nix b/.devops/nix/package.nix index 59c5e4c53713a..c6d03b4a480e7 100644 --- a/.devops/nix/package.nix +++ b/.devops/nix/package.nix @@ -162,6 +162,14 @@ effectiveStdenv.mkDerivation ( # Define the shells here, but don't add in the inputsFrom to avoid recursion. passthru = { + inherit + useBlas + useCuda + useMetalKit + useOpenCL + useRocm + ; + shell = mkShell { name = "default${descriptionSuffix}"; description = "contains numpy and sentencepiece";