Contributing
Thanks for caring about Déjà Fu!
Ways to contribute
Déjà Fu is a project under active development, there's always something to do. Here's a list of ideas to get you started:
- Submit bug reports.
- Submit feature requests.
- Got a particularly slow test case which you think should be faster? Open an issue for that too.
- Blog about how and why you use Déjà Fu.
- Check if any bugs which have been open for a while are still bugs.
If you want to contribute code, you could:
- Tackle one of the issues tagged "good first issue".
- Tackle a bigger issue, perhaps one of the roadmap issues!
- Run code coverage and try to fix a gap in the tests.
- Profile the test suite and try to improve a slow function.
Roadmap issues are priority issues (in my opinion), so help with those is especially appreciated.
If you have a support question, you can talk to me on IRC (#haskell on freenode) or send an email (mike@barrucadu.co.uk) rather than opening an issue. But maybe your question is a bug report about poor documentation in disguise!
Making the change
-
Talk to me!
I don't bite, and chances are I can quickly tell you where you should start. It's better to ask what seems like a stupid question than to waste a lot of time on the wrong approach.
-
Make the change.
Figure out what needs to be changed, how to change it, and do it. If you're fixing a bug, make sure to add a minimal reproduction to Cases.Regressions in dejafu-tests.
-
Document the change.
All top-level definitions should have a Haddock comment explaining what it does. If you've added or changed a top-level function, consider commenting its arguments too.
If you've added a top-level definition, or changed one in a backwards-incompatible way, add an
@since unreleased
Haddock comment to it. This is to help prevent me from missing things when I update the changelog ahead of a release. -
Submit a PR.
GitHub Actions will run some checks, which might prompt further action. You should expect a response from me in a day or two.
Don't worry about your PR being perfect the first time. We'll work through any issues together, to ensure that Déjà Fu gets the best code it can.
Coding style
There isn't really a prescribed style. It's not quite the wild west though; keep these three rules in mind:
- Be consistent.
- Run stylish-haskell to format import lists.
- Use hlint and weeder and fix lints unless you have a good reason not to.
GitHub Actions runs stylish-haskell and hlint on all PRs.
Coverage
hpc can generate a coverage report from the execution of dejafu-tests:
$ stack build --coverage
$ stack exec dejafu-tests
$ stack hpc report --all dejafu-tests.tix
This will print some stats and generate an HTML coverage report:
Generating combined report
52% expressions used (4052/7693)
48% boolean coverage (63/129)
43% guards (46/106), 31 always True, 9 always False, 20 unevaluated
68% 'if' conditions (11/16), 2 always True, 3 unevaluated
85% qualifiers (6/7), 1 unevaluated
61% alternatives used (392/635)
80% local declarations used (210/261)
26% top-level declarations used (280/1063)
The combined report is available at /home/barrucadu/projects/dejafu/.stack-work/install/x86_64-linux/nightly-2016-06-20/8.0.1/hpc/combined/custom/hpc_index.html
The highlighted code in the HTML report emphasises branch coverage:
- Red means a branch was evaluated as always false.
- Green means a branch was evaluated as always true.
- Yellow means an expression was never evaluated.
See also the stack coverage documentation.
Performance
GHC can generate performance statistics from the execution of dejafu-tests:
$ stack build --profile
$ stack exec -- dejafu-tests +RTS -p
$ less dejafu-tests.prof
This prints a detailed breakdown of where memory and time are being spent:
Mon Mar 20 19:26 2017 Time and Allocation Profiling Report (Final)
dejafu-tests +RTS -p -RTS
total time = 105.94 secs (105938 ticks @ 1000 us, 1 processor)
total alloc = 46,641,766,952 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
findBacktrackSteps.doBacktrack.idxs' Test.DejaFu.SCT.Internal 21.9 12.0
== Test.DejaFu.Common 12.4 0.0
yieldCount.go Test.DejaFu.SCT 12.1 0.0
dependent' Test.DejaFu.SCT 5.1 0.0
runThreads.go Test.DejaFu.Conc.Internal 2.7 4.1
[...]
Be careful, however! Compiling with profiling can significantly affect the behaviour of a program! Use profiling to get an idea of where the hot spots are, but make sure to confirm with a non-profiled build that things are actually getting faster.
If you compile with -rtsopts
you can get some basic stats from a non-profiled
build:
$ stack exec -- dejafu-tests +RTS -s
[...]
86,659,658,504 bytes allocated in the heap
13,057,037,448 bytes copied during GC
13,346,952 bytes maximum residency (4743 sample(s))
127,824 bytes maximum slop
37 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 78860 colls, 0 par 32.659s 32.970s 0.0004s 0.0669s
Gen 1 4743 colls, 0 par 3.043s 3.052s 0.0006s 0.0086s
TASKS: 174069 (174065 bound, 4 peak workers (4 total), using -N1)
SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
INIT time 0.001s ( 0.001s elapsed)
MUT time 98.685s (101.611s elapsed)
GC time 35.702s ( 36.022s elapsed)
EXIT time 0.001s ( 0.007s elapsed)
Total time 134.388s (137.640s elapsed)
Alloc rate 878,145,635 bytes per MUT second
Productivity 73.4% of total user, 73.8% of total elapsed
Heap profiling
GHC can tell you where the memory is going:
$ stack build --profile
$ stack exec -- dejafu-tests +RTS -hc
$ hp2ps -c dejafu-tests.hp
This will produce a graph of memory usage over time, as a postscript file, broken down by cost-centre which produced the data. There are a few different views:
-hm
breaks down the graph by module-hd
breaks down the graph by closure description-hy
breaks down the graph by type
I typically find -hd
and -hy
most useful. If you're feeling particularly
brave, you can try -hr
, which is intended to help track down memory leaks
caused by unevaluated thunks.