Stack: Profiling build defaults

Created on 19 May 2018  路  17Comments  路  Source: commercialhaskell/stack

@bitemyapp's Makefiles are a treasure trove of build tips. Here's a trick for profiling builds:

stack build --profile --work-dir .stack-work-profiling

This tremendously improves build caching, at the expense of disk space.

Can this be a default behavior, or at least, enabled via a global config flag or similar? It is soul crushing to have to rebuild all of the deps for a large project for profiling, and rebuild them again for normal mode.

Most helpful comment

Only downside I can see is screwing up gitignore files, but that seems a small price to pay. What about doing it as a subdir of .stack-work? I don't even know if that will work.

All 17 comments

I do this all the time, Do you know if it is also required to have a --stack-root as well to make sure the snapshot dependencies are also profiled?

Only downside I can see is screwing up gitignore files, but that seems a small price to pay. What about doing it as a subdir of .stack-work? I don't even know if that will work.

@snoyberg could be a good idea in part because of we always suffix the profiling version of a build then anyone making custom use of workdirs like I was would benefit from this behavior across the board.

Not sure if this is the ideal approach or not, though.

Working on this from the hackathon: haskell-hackathon/#5.

Hey @gavwhela, just bumping this. Any questions on the codebase?

I just experienced this pain and agree --profile should, at the very least, be a sticky flag. I agree there needs to be a way to customize stack at some level. Has there been any thought into adding custom synonyms i.e. profile=build --profile --work-dir .stack-work-profiling.

@snoyberg

Only downside I can see is screwing up gitignore files, but that seems a small price to pay. What about doing it as a subdir of .stack-work? I don't even know if that will work

I think using a subdir of .stack-work for the new profiling builds default is a great idea. It's not just .gitignore files that are affected by adding another top-level Stack related scratch dir, because various tools have hardcoded special treatment of standard Haskell build dirs (.stack-work, dist, dist-newstyle). For example, haskell-mode and projectile in Emacs ignore these build dirs by default when generating TAGS. Making the profiling cache a subdir of .stack-work would allow all of the existing special treatment to keep working unchanged.

However, using a subdir of .stack-work fails for me. For example, on one of my local projects:

stack --work-dir .stack-work/.stack-work-profile build --profile                    
flexdis86-0.1.2: configure (lib + exe)
flexdis86-0.1.2: build (lib + exe)                                                                     
macaw-base-0.3: configure (lib)                            
macaw-base-0.3: build (lib)                                
what4-0.4.0: configure (lib)                               
what4-0.4.0: build (lib)                                   
flexdis86-0.1.2: copy/register                             
macaw-base-0.3: copy/register                              
what4-0.4.0: copy/register                
Progress 8/27             
No directory could be located matching the supplied path: /tmp/stack13129/regex-1.0.0.0/.stack-work
No directory could be located matching the supplied path: /tmp/stack13129/s-cargot-0.1.4.0/.stack-work
No directory could be located matching the supplied path: /tmp/stack13129/located-base-0.1.1.1/.stack-work
No directory could be located matching the supplied path: /tmp/stack13129/monadLib-3.7.3/.stack-work
No directory could be located matching the supplied path: /tmp/stack13129/limp-0.3.2.2/.stack-work

A little experimentation makes me suspect the problem is that Stack doesn't do the equivalent mkdir --parents when creating the work dir. For example,

stack --work-dir no-such-parent-dir/.stack-work build

fails with

No directory could be located matching the supplied path: /home/conathan/brittle/sfe.git/no-such-parent-dir

Should be trivial to fix that.

I'm a bit worried that choosing a new working directory will duplicate more than the absolute necessary. It's already the case that after stack clean or just delete the .stack-work directory and then rebuilding leaves a smaller .stack-work directory. So some dirty artifacts remain which are not needed for the rebuild. I hope this doesn't increase the amount of unneeded files. Also see https://github.com/commercialhaskell/stack/issues/2244

Any update on this issue? This would be a lovely feature to have, and think that @ntc2 makes some good points regarding the implementation.

Afaict, this issue is ready for someone to work on now. It seems like no one has volunteered to do it yet

Ahh, so do you think it's safe to assume @gavwhela has stopped working on it?

Totally forgot that he'd been working on it and didn't see it when reviewing this issue :)

Yeah, I think it's safe to assume that at this point.

As #4412 and #4582 (with some tests, see https://github.com/commercialhaskell/stack/issues/4308#issuecomment-468304497) were merged I think this one was implemented by resolving #3922
@snoyberg are we OK with closing it?

It's probably still worthwhile to have a separate .stack-work for profiling builds for all mutable packages. You're right that the implicit snapshots work will drastically improve the situation already.

Oh, right, that's about .stack-work which is a bit different thing, missed that

I have a general question about Stack's ability to reuse work when changing flags like --profile. Since this seems to be the main issue tracking this at the moment I'll leave it here.

I was reading this blog post about the current state of the cabal/stack divide, and it has this paragraph:

Although stack began its life with the best-of-class caching, cabal has now caught up and overtaken. stack struggles to support changing compiler flags (e.g. swapping between --fast builds and regular builds) whereas cabal can swap between -O0 / -O1 / -O2 without missing a beat. stack is unable to share the caches of extra-deps or git sources, whereas cabal treats everything equally and can share builds between projects .

I'm a longtime stack user but this one aspect of cabal seems really nice. I think it would be worth viewing this problem in the more general setting of keeping/reusing build artifacts compiled with different flags. The cabal behavior described above sounds like the ideal. Would it be possible for stack to solve the problem in the same general way?

I have an SO answer on how to use --profile with Stack and someone just pointed out that Stack 2.X now requires --profile to also be passed to stack exec, in addition to stack build. I can't find this documented anywhere, but a little testing indicates that Stack is now keeping the profiling and non profiling builds separate automatically (the paths are different):

$ stack path --local-install-root
/tmp/prof-test/.stack-work/install/x86_64-linux/645ca5b89c41f1c9c1d95cd056827eb0ff49366e41dc71baafee7e8750f3202f/8.6.5
$ stack path --profile --local-install-root 
/tmp/prof-test/.stack-work/install/x86_64-linux/56dac42cad4cb0f4eed3c37ccc75047b71308bac53fbd2316970727a0981353f/8.6.5

Is this due to "implicit snapshots"?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

symbiont-joseph-kachmar picture symbiont-joseph-kachmar  路  3Comments

jwaldmann picture jwaldmann  路  4Comments

tinkyholloway picture tinkyholloway  路  4Comments

domenkozar picture domenkozar  路  3Comments

Cosmius picture Cosmius  路  3Comments