I was trying like this initially:
nix-shell -p "haskell.packages.ghc821.ghcWithPackages (p: with p; [text hspec lens])" -j4 --run 'ghc Main.hs -prof
Then GHC told me
Main.hs:4:1: error:
Could not find module ‘Control.Lens’
Perhaps you haven't installed the profiling libraries for package ‘lens-4.15.4’?
Use -v to see a list of the files searched for.
Searching around the web I found this: https://github.com/NixOS/nixpkgs/issues/22340
So it seems I won't be able to download from the cache. But that's okay, if at least I can build the profiled variants locally.
Can I do that somehow simply by modifying the nix expression given to -p
slightly?
Then at this point in writing this question, I remembered this resource: https://github.com/NixOS/nixpkgs/blob/bd6ba7/pkgs/development/haskell-modules/lib.nix
Where I found enableLibraryProfiling
. So I tried:
nix-shell -p "haskell.packages.ghc821.ghcWithPackages (p: with p; [text hspec (haskell.lib.enableLibraryProfiling lens)])" -j4 --run 'ghc Main.hs -prof'
Which got me to a new error:
src/Control/Lens/Internal/Getter.hs:26:1: error:
Could not find module ‘Data.Functor.Contravariant’
Perhaps you haven't installed the profiling libraries for package ‘contravariant-1.4’?
Use -v to see a list of the files searched for.
|
26 | import Data.Functor.Contravariant
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
So if I could map over all packages to enableLibraryProfiling
on them, then I guess this could work. But my nix knowledge doesn't quite extend that far at the moment. How could I do that? And is this even the correct path to pursue?
nix developed by IOHK to build Haskell programs for Nix.
nix is infrastructure for building Haskell packages with Nix. haskell. nix can automatically translate your Cabal or Stack project and its dependencies into Nix code.
Basic project usageIn your repo, run nix flake init to generate the flake. nix file. Then run git add flake. nix to add it to the git staging area, otherwise nix will not recognize that the file exists.
The Nix Expression Language is a dynamic, functional and lazy domain-specific language used to instruct Nix how to build packages. Benefits of Nix programming language are reproducibility, binary caching, multiple versions, distributed and non-privileged builds.
With further snooping around in nix-repl
and some helpful pointers from ElvishJerricco on #reflex-frp at FreeNode, I was able to construct this, which seems to work:
$ nix-shell -p "(haskell.packages.ghc821.extend (self: super: {mkDerivation = expr: super.mkDerivation (expr // { enableLibraryProfiling = true; });})).ghcWithPackages (p: with p; [text hspec lens])" -j4 --run 'ghc Main.hs -prof'
I figured out a simple approach that I'm working into a largest blog post on Haskell development using Nix. For now, here's the text of just the profiling section:
Nix makes this fairly easy. First, we add the following to a ~/.config/nixpkgs/config.nix
:
{
packageOverrides = super: let self = super.pkgs; in
{
profiledHaskellPackages = self.haskellPackages.override {
overrides = self: super: {
mkDerivation = args: super.mkDerivation (args // {
enableLibraryProfiling = true;
});
};
};
};
}
Now in the project we want to profile, we create a new profiling-shell.nix
:
let nixpkgs = import <nixpkgs> {};
orig = nixpkgs.pkgs.profiledHaskellPackages.callPackage ./default.nix {};
in (nixpkgs.pkgs.haskell.lib.doBenchmark orig).env
Almost identical to our normal shell.nix
, except for the usage of profiledHaskellPackages
, which we just defined globally. Now, an invocation of nix-shell profiling-shell.nix
will rebuild every dependency in our project with profiling enabled. The first time this is done it will take quite a long time. Luckily this doesn't corrupt our Nix store - a vanilla nix-shell
does seem to present us with our regular dependencies again, without redownloading or rebuilding.
WARNING: A nix-collect-garbage -d
will wipe away all the custom-built libs from our Nix Store, and we'd have to build them again if they're needed.
If we're writing a library, the closest executable on hand that we could profile would be our benchmark suite. To do that:
-prof
and -fprof-auto
to our benchmark's GHC optionsdefault.nix
nix-shell profiling-shell.nix
cabal configure --enable-library-profiling --enable-benchmarks
cabal build
dist/build/projname/projname-bench +RTS -p
projname-bench.prof
fileBased on the results, we can make code changes, remove the profiling options, regenerate default.nix
, and benchmark as usual in our normal Nix Shell.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With