Skip to content
  • kristenk's avatar
    Don't add flag to conflict set when true and false introduce the same conflict. · 6900c9f4
    kristenk authored
    A DependencyReason contains flags paired with values FlagTrue, FlagFalse, or
    FlagBoth, where FlagBoth means that the dependency was introduced by either
    value of the flag and was lifted out of a conditional.  In the previous commit,
    when a dependency led to a conflict, all flags in the DependencyReason were
    added to the error message and conflict set.  This commit avoids adding flags
    with value FlagBoth to the conflict set, because they can have a negative effect
    on goal order: After the solver encounters a conflict involving such a flag, it
    starts to prefer the flag when choosing goals, due to the solver's conflict
    counting feature.  The solver shouldn't prefer the flag goal because it didn't
    actually need to choose the flag to see the dependency.  Flags with value
    FlagBoth are still useful for error messages, though.
    
    I measured the performance of the last two commits by comparing commit
    fc3ef2a7 (master) with this commit.  I did all
    testing with GHC 8.0.1 and
    'index-state(hackage.haskell.org) = 2017-06-11T02:16:39Z'.  I ran each version
    of cabal (cabal install --dry-run) on each package on Hackage and looked for
    packages with a difference in run time of at least 10%.  Then I reran cabal on
    those packages to narrow down the list further (The results were noisy).  Here
    are the average run times from five runs with the remaining packages:
    
    package                        master result   master time (seconds)   branch result   branch time (seconds)   speedup
    concraft                       backjump limit   5.67                   backjump limit   4.89                    1.16
    forml                          backjump limit  10.26                   backjump limit   8.85                    1.16
    hack-handler-simpleserver      backjump limit   6.28                   no solution      1.96                    3.21
    hack-middleware-clientsession  backjump limit  17.86                   no solution      1.95                    9.14
    haskore                        backjump limit   5.21                   no solution      1.67                    3.12
    haskore-synthesizer            no solution     23.14                   no solution      2.21                   10.49
    language-gcl                   no solution      3.06                   no solution      2.31                    1.33
    ms                             backjump limit  61.68                   no solution      7.95                    7.76
    nerf                           solution         4.1                    backjump limit   5.87                    0.7
    puzzle-draw                    solution        56.28                   solution         5.31                   10.6
    react-haskell                  backjump limit  44.23                   backjump limit  14.46                    3.06
    reflex-transformers            no solution      2.18                   no solution      1.9                     1.15
    shpider                        backjump limit   7.44                   solution         1.88                    3.95
    thorn                          backjump limit  11.11                   backjump limit   4.44                    2.5
    
    Both versions of cabal hit the backjump limit in four of the cases, so they
    don't really tell us which version performed better.  All but one of the others
    are improvements.  I looked at a few of the logs, and, as far as I can tell,
    most of the improvements are due to flags being used in conflict counting.  This
    behavior is similar to #4147, which was reverted.  The log for 'nerf', the one
    package that had worse performance, showed that the solver chose some flags
    earlier, but I didn't see any other reason for the slowdown.  The solver found a
    solution when I used '--max-backjumps -1'.
    
    These differences in run time are caused by differences in goal order and/or
    backjumping, but I also wanted to compare performance when the solver went
    through similar steps on master and the branch.  I found two commands that led
    to very similar -v3 output between the cabal versions.  Presumably, package
    flags didn't cause many conflicts in these runs.
    
    cabal install --dry-run --max-backjumps -1 gi-glib happstack
    cabal install --dry-run yesod
    
    I took the average of three runs.  There wasn't a big difference between master
    and the branch.
    
    packages             result        master time (seconds)   branch time (seconds)   master memory (MB)   branch memory (MB)
    gi-glib, happstack   no solution   30.02                   30.70                   245                  245
    yesod                solution       3.53                    3.55                   239                  239.3
    6900c9f4