Skip to content

stdenv: Move all stdenv lookups out of mkDerivation#431756

Merged
philiptaron merged 1 commit intoNixOS:masterfrom
tweag:mkderivation-stdenv-lookup-optimisation
Aug 27, 2025
Merged

stdenv: Move all stdenv lookups out of mkDerivation#431756
philiptaron merged 1 commit intoNixOS:masterfrom
tweag:mkderivation-stdenv-lookup-optimisation

Conversation

@YorikSar
Copy link
Contributor

@YorikSar YorikSar commented Aug 7, 2025

All lookups and expressions that don't depend on derivation attrs are moved to the outer let block. Saves over 10% lookups for eval on x86_64-linux, along with 53MiB memory (over 1%).
For some reason lists concats go 14% up, but defaultConfigurePlatformsFlags optimisation removes ~7% of them.

Overall time is down ~3%.

Things done


Add a 👍 reaction to pull requests you find important.

@nixpkgs-ci nixpkgs-ci bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 0 This PR does not cause any packages to rebuild on Linux. 6.topic: stdenv Standard environment labels Aug 7, 2025
@philiptaron
Copy link
Contributor

philiptaron commented Aug 11, 2025

I still have this on my list to review, but I won't be able to be at a computer until a little later this week. These sorts of PRs need careful attention…Although I have a strong belief that you have not introduced any regressions with this change.

Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes only for the defaultConfigurePlatformsFlags searching and the system hoisting. Everything else is me puzzling over how this whole thing came to be.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't true anymore, based on the usage of ++ below. That would cause an eval failure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't know where it came from. Maybe this was the case in the days of yore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to remove it in this PR, since we're mutating configureFlags so much. I leave that preference in your hands.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry, I wasn't fast enough here. I guess, such trivial change can be done any time later :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can avoid this list concatenation in the common case by testing the following booleans.

  1. attrs ? configureFlags: the derivation specified configureFlags
  2. attrs ? configurePlatforms: the derivation specified configurePlatforms

The common case is !attrs ? configureFlags and !attrs ? configurePlatforms, which ought to just be defaultConfigurePlatformsFlags.

Here's the truth table that I'm thinking of.

attrs ? configureFlags attrs ? configurePlatforms Meaning Result
false false Defaults in every case defaultConfigurePlatformsFlags
false true Non-default platforms, need to test for target Do elem "target" logic on the platforms
true false Some flags are set, default platforms (other common case) configureFlags ++ defaultConfigurePlatformsFlags
true true Rare case configureFlags plus the elem target logic.

What do you think?

Copy link
Contributor Author

@YorikSar YorikSar Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do elem "target" logic on the platforms

Note that we'll need to do this logic for all variants, not just for "target".
I also wonder if this elem logic could be replaced with one concatMap instead. It might change the order of arguments in some cases not present in Nixpkgs.
Overall I'd prefer to do this optimisation separately to see its effect in isolation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, because the logic is so mutated in this PR, and there was this line in the headmatter:

For some reason lists concats go 14% up, but defaultConfigurePlatformsFlags optimisation removes ~7% of them.

I suspect all of these list concats are here, in this logic, and most could be removed through judicious refactors of logic.

That's why I was nudging for something like this truth table be extracted into a set of Nix expressions and used in this PR, to make it be even more a Pareto improvement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect all of these list concats are here, in this logic, and most could be removed through judicious refactors of logic.

But I strictly reduced the overall number of concats here: it was 3 for all derivations, and even before defaultConfigurePlatformsFlags it remained 3, with this optimisation, it's only 3 for ~100 or so packages that set configurePlatforms. All this means that I missed some list concats somewhere, but not here...

@github-project-automation github-project-automation bot moved this to In Progress in Stdenv Aug 12, 2025
All lookups and expressions that don't depend on derivation attrs are
moved to the outer let block. Saves over 10% lookups for eval on
x86_64-linux, along with 53MiB memory (over 1%).

For some reason lists concats go 14% up, but
defaultConfigurePlatformsFlags optimisation removes ~7% of them.

Overall time is down ~3%.
@YorikSar YorikSar force-pushed the mkderivation-stdenv-lookup-optimisation branch from a29daaa to 7151ae1 Compare August 22, 2025 13:31
Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still want the system thing changed the way I outline in this review, but I won't block the PR on that preference.

Strongly suspect that the change to use if ... then ... else ... instead of optional* will be net positive in this file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to remove it in this PR, since we're mutating configureFlags so much. I leave that preference in your hands.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, because the logic is so mutated in this PR, and there was this line in the headmatter:

For some reason lists concats go 14% up, but defaultConfigurePlatformsFlags optimisation removes ~7% of them.

I suspect all of these list concats are here, in this logic, and most could be removed through judicious refactors of logic.

That's why I was nudging for something like this truth table be extracted into a set of Nix expressions and used in this PR, to make it be even more a Pareto improvement.

stdenvHasCC = stdenv.hasCC;
stdenvShell = stdenv.shell;

buildPlatformSystem = buildPlatform.system;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
buildPlatformSystem = buildPlatform.system;

# attribute of `buildPlatform` matches Nix's degree of specificity.
# exactly.
inherit (stdenv.buildPlatform) system;
system = buildPlatformSystem;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
system = buildPlatformSystem;
inherit (buildPlatform) system;

My mental model of how Nix holds references says that this inherit both matches the comment and is at least as good as the extraction into the let block, possibly better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, it would be interesting to see the effect of such change. I thought that inherit (x) y; is strictly equivalent to y = x.y, and Nix doesn't try to optimise x.y at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, here: https://github.com/NixOS/nix/blob/218cd6c16c0981cc32a45e3a15be1d3c1a68eb85/src/libexpr/parser.y#L419-L422 the parser essentially replaces inherit (x) y; with x = x.y; and then in https://github.com/NixOS/nix/blob/218cd6c16c0981cc32a45e3a15be1d3c1a68eb85/src/libexpr/eval.cc#L1237-L1242 we allocate additional env (I don't quite understand, why) if there is any inherit (x) y attrs and then we do necessary binding at eval time. It means that my removing all "inherit from" attrs from this attrset we save one env allocation per call.

@nixpkgs-ci nixpkgs-ci bot added the 12.approvals: 1 This PR was reviewed and approved by one person. label Aug 22, 2025
@philiptaron philiptaron merged commit 78256f5 into NixOS:master Aug 27, 2025
26 of 28 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Stdenv Aug 27, 2025
@YorikSar YorikSar deleted the mkderivation-stdenv-lookup-optimisation branch August 28, 2025 12:01
Copy link
Contributor Author

@YorikSar YorikSar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@philiptaron I'm sorry for taking too long to respond and thanks a lot for a quick merge. I hope I'll be able to find some time for deeper optimisations in this area in the future, this was fun.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect all of these list concats are here, in this logic, and most could be removed through judicious refactors of logic.

But I strictly reduced the overall number of concats here: it was 3 for all derivations, and even before defaultConfigurePlatformsFlags it remained 3, with this optimisation, it's only 3 for ~100 or so packages that set configurePlatforms. All this means that I missed some list concats somewhere, but not here...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry, I wasn't fast enough here. I guess, such trivial change can be done any time later :)

# attribute of `buildPlatform` matches Nix's degree of specificity.
# exactly.
inherit (stdenv.buildPlatform) system;
system = buildPlatformSystem;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, it would be interesting to see the effect of such change. I thought that inherit (x) y; is strictly equivalent to y = x.y, and Nix doesn't try to optimise x.y at all.

@philiptaron
Copy link
Contributor

philiptaron commented Sep 6, 2025

@YorikSar are you at NixCon 2025?

@YorikSar
Copy link
Contributor Author

YorikSar commented Sep 6, 2025

@philiptaron no, I’m not. I’ll also be barely available in the coming month.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.topic: stdenv Standard environment 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 10.rebuild-linux: 0 This PR does not cause any packages to rebuild on Linux. 12.approvals: 1 This PR was reviewed and approved by one person.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants