<gchristensen>
builds that don't bit-by-bit reproduce, are they idempotent?
drakonis has quit [Quit: WeeChat 2.3]
drakonis has joined #nixos-dev
drakonis has quit [Quit: WeeChat 2.3]
drakonis has joined #nixos-dev
lezed1 has joined #nixos-dev
drakonis has quit [Quit: WeeChat 2.3]
lassulus_ has joined #nixos-dev
lassulus has quit [Ping timeout: 250 seconds]
lassulus_ is now known as lassulus
pie___ has joined #nixos-dev
pie__ has quit [Ping timeout: 245 seconds]
lezed1 has quit [Quit: Connection closed for inactivity]
<simpson>
Does anybody else happen to care about pypyPackages? pypyPackages.mock has been unhappy for a while due to a failing test, and I'm wondering whether `doCheck = false;` is appropriate on such a central library.
<simpson>
The irony of tests failing on a testing library *is* pretty delicious.
<simpson>
infinisil: I will explain more in my commit, likely, but the short version is that the test is known broken and that upstream has it patched out on their master branch.
<simpson>
Given that this package tracks a 3-to-2 stdlib backport, it is *very* unlikely that we'll get upstream to release a new version just for this. So I'll leave a comment explaining that we shouldn't do the checks on PyPy for this version.
<shlevy>
clever: gchristensen reached out about #2665... How do you expect to reuse the value object exactly? Once created Values are pure from the perspective of the language (thunk forcing is unobservable as long as it's not bottom), but you'd need to force the thunk in a different context for different calls to the fn right?
<clever>
{ args1 }: { args2 }: let expr = 5*5; in body
<clever>
{ args1 }: let expr = 5*5; { args2 }: body
<shlevy>
Sure
<clever>
shlevy: in the 1st case, when the ExptLet is being evaled, it will maybeThunk() the 5*5, creating a thunk for that ExprApp
<clever>
and if you run the 2nd lambda 200 times, that creates 200 thunks
<clever>
which each have to re-compute 5*5
<shlevy>
Yes
<Synthetica>
clever: There is a check for that in nix-linter
<clever>
in the 2nd example, it can reuse the result, when calling the 2nd lambda repeatedly
<shlevy>
But unless we're doing static analysis for references to arg2 (which is feasible but not trivial) we can't reuse it
<shlevy>
I get the difference. I'm just not clear on what you're proposing we do
<clever>
add a std::map to Expr, that will map from Env* to Value*
<shlevy>
By pointer equality?
<clever>
so, when maybeThunk is creating a thunk for a given Env, it can possibly return an old Value for the same thunk
<clever>
yeah, pointer equality seems simplest for a first try
<shlevy>
How do you want to identify "equivalent" Env*s?
<clever>
oh, hmmm, i can see an issue there now
<clever>
the Env* will include the args2 key
<shlevy>
I'd expect the Env to be different at each call
<shlevy>
Right
<clever>
and will be different for each eval
<shlevy>
And even if you called it with the exact same value it'd be different
<shlevy>
qua pointer
<clever>
yeah, it would be a new (but identical) Env
<clever>
you would need to analyze what the Expr is accessing, and what parts of the Env it cares about
<shlevy>
builtins.memoise (on an experimental branch) could cover the same-args case, static analysis could identify opportunities for lifting
<clever>
Synthetica: where is that linter?
<shlevy>
But if nix-linter is already doing that analysis then let's see if there's even a big win possible first :) FWIW I already manually do this transformation when I write expressions, I'm not sure how many others do though
<clever>
shlevy: oh, but let lifting wouldnt actually have found this, in its original form
<clever>
i initially put it into a let block one step up, but it didnt solve it, moving it another scope further up (and fixing the import of this file to do the same), is what shaved 2gig off the heap usage
<clever>
Synthetica: could the linter have found this?
<shlevy>
clever: If [ ... ] is constant, it should be able to find it yeah
<shlevy>
You can lift that to the very top of the file before you even define the top-level function
<shlevy>
Then Nix's import caching will cover you
<clever>
the constant part, was the `map (arg: "--hsc2hs-option=" + arg) ["--cross-compile" "--via-asm"]
<clever>
shlevy: why does one branch use lambda.body->eval, and the other fun.lambda.fun->body->eval ?
<clever>
ExprLambda & lambda(*fun.lambda.fun);
<clever>
when lambda is a reference to fun.lambda.fun, and so they should be identical?
<shlevy>
Yeah looks like lambda was added later as a convenience
<shlevy>
Patch would be nice
<shlevy>
It *might* somehow impact tail-recursion but I don't think it should
<clever>
ah, i can see how it might
<clever>
lambda is on the stack, and has to still be on the stack, to de-reference it
<shlevy>
It's a reference so it shouldn't impact lifetimes
<shlevy>
Once you've de-referenced there's no destructor or anything to worry about
<clever>
but, for tail-recursion to work, it would be clearing the stack up before the call, and then doing jmp rather then call
<shlevy>
Right
<clever>
but it still has to remove that reference from the local stack
<shlevy>
But you've already dereferenced by then
<shlevy>
The key is that you can (and indeed must) dereference beforethe call
<shlevy>
And once you have you don't need it around
<clever>
depends on if the compiler can save it into a register while clearing the stack for tail-call or not
<shlevy>
It has to save it into a register :P
<shlevy>
It's the call target
<shlevy>
or the jump target
<clever>
but, will the compiler be smart enough to do know it can tail-recurse, and save it to a reg before cleaning the stack? or will it not re-arrange things, and then fail to tail-recurse?
<clever>
would need to try it, and then disassemble
<shlevy>
clever: It's definitely going to separate the deref from the call and do tail-call analysis after
<shlevy>
There's no way gcc and clang devs are leaving this $100 bill on the ground :P
<clever>
lol
hedning has quit [Quit: hedning]
<clever>
the only way i can see nix optimizing this let thing at runtime, is if an Expr propagates all ExprVar's up the tree
<shlevy>
Yeah
<clever>
i think ExprVar is the only one that deals with the Env an Expr is ran within?
<shlevy>
And constant subexpression lifting isn't always even what you want
<shlevy>
The only direct one
<shlevy>
But anything containing ExprVars would have the same issue if not also lifted
<clever>
let me check the latest profile run...
<clever>
"/home/clever/iohk/cardano-nsis/haskell.nix/builder/comp-builder.nix:41:24 null ran 1214672",