This thread is early exploration of how to employ heavily optimized binaries that require multi-step workflows while using Nix.
Goal
Support enabling use of such binaries with a single configuration option on NixOS or one of two (profile versus optimize) attirbutes on many derivations in nixpkgs. When enabled on NixOS, the user’s machine would automatically use the profiling builds first and switch the derivation to an optimized build once available.
Implementation Sketch
The high level problem is that profiling requires two unique derivations to be used. However, while the user would opt into the workflow, they would still only declare one thing installed. I believe the correct high-level model for NixOS is binary substitution. The derivation the users specifies does not change. The binary used to satisfy that specification changes.
Runtime questions created:
- How do we decide if we have the profiling data necessary to do substitution?
- How do programs know where to output their profiling data?
- How does the user know the current states?
- How does substitution occur?
On NixOS
First, each profiling binary needs an environment variable to decide where to output the profile data. I do not think wrapping is the right approach, but I don’t think I have considered enough either. With Clang, it seems a pattern can be used so that one environment variable automatically covers all profiling binaries.
Second we have to get the profile data available for building substitutes and making them active. On NixOS, I believe a daemon is the right approach. The daemon would merge and place this data into the nix store.
When enough profile data is available, as a threshold of configurable megabytes, it should build the target binary and either notify the user or perform some enabling operation automatically.
In Nix
So, how do these nuts and bolts become expressions?
Specifying Use of Binaries
The user likely only wants key binaries to be optimized. Each derivation should have a convenient way to be expressed as one that will be optimized. The optimization-capable derivation should further support being built in its profile and optimize variants.
Deriving Profile vs Optimize Builds
Since extra compiler flags are sufficient to convert many vanilla derivations to profile-capable derivations, I believe overriding them with a modified stdenv and exposing that override as an attribute is acceptable. Use of a stdenv adaptor would enable specific creation of both variants of a derivation manually for testing and development.
Selecting Optimized Builds
This should be done by simply supplying an extra argument to the nix CLI or manually to the derviation so that the optimized variant of the profile-capable derivation is built.
Driving the Work Forward
It is of obvious commercial significance, both for enthusiasts and “warehouse” applications. Given that, I believe that instead of waiting for myself or volunteers to write what is necessary, it may be both viable and significantly faster to collect interested parties to coordinate paying sizeable tips to developers who make progress either on the design or implementation so as to accelerate both.
As the viability grows, the chance to obtain the a well-implemented result may attract other users to support the collective effort. This is a new model of commercial open source I’m presenting via https://prizeforge.com, where I am developing the means of coordinating the tips. In any case I will be opening a stream for NixOS soon while I seek to start attracting users.
I’m currently doing FDO/PLO on Emacs binaries to work out the basics of how the variant derivations actually differ and how to provide the data to the derivation source.