Optimise `Ord Version` instance
commitaabee7c3633eb276cf417459e31a5162a5b7bfae
authorHerbert Valerio Riedel <hvr@gnu.org>
Sat, 1 Oct 2016 14:10:48 +0000 (1 16:10 +0200)
committerHerbert Valerio Riedel <hvr@gnu.org>
Sun, 2 Oct 2016 07:02:39 +0000 (2 09:02 +0200)
tree00a051f60ec87ee3d3dcddf57c5d1ea9dc09fce3
parentcbddd8cbb8321d767d42f048d0b4e9e836e06331
Optimise `Ord Version` instance

Profiling showed that there are quite a few 'Ord' calls (~70k calls)
which result in 'versionNumbers' being evaluated because the need to
compare with Versions not fitting in a Word64 becomes necessary, mostly
when inserting into a `Map`. So I've optimised this a bit more.  After
some experimentation, the new `compare` implemetation results in faster
comparisions (`cmpOpt` is the new optimised impl, `compare` is the
previous naive one):

comparing two PV1 constructors:

    benchmarking compare 1.2.3.4.5 1.2.3.4.5
    time                 42.33 ns   (42.17 ns .. 42.47 ns)
                         1.000 R²   (1.000 R² .. 1.000 R²)
    mean                 42.17 ns   (42.13 ns .. 42.28 ns)
    std dev              205.1 ps   (128.7 ps .. 325.7 ps)

    benchmarking cmpOpt  1.2.3.4.5 1.2.3.4.5
    time                 33.31 ns   (33.23 ns .. 33.40 ns)
                         1.000 R²   (1.000 R² .. 1.000 R²)
    mean                 33.37 ns   (33.29 ns .. 33.46 ns)
    std dev              288.6 ps   (242.9 ps .. 315.8 ps)

    benchmarking compare [1.2.3.4.5] [1.2.3.4.5]
    time                 31.92 ns   (31.89 ns .. 31.94 ns)
                         1.000 R²   (1.000 R² .. 1.000 R²)
    mean                 31.89 ns   (31.88 ns .. 31.91 ns)
    std dev              37.09 ps   (24.38 ps .. 54.82 ps)

comparing a PV0 constructor with a PV1 constructor when the first digit
decides the outcome:

    benchmarking compare 2.3.4 1.2.3.4.5
    time                 24.96 ns   (24.78 ns .. 25.25 ns)
                         0.996 R²   (0.989 R² .. 1.000 R²)
    mean                 25.50 ns   (24.95 ns .. 26.95 ns)
    std dev              2.802 ns   (1.275 ns .. 5.163 ns)
    variance introduced by outliers: 93% (severely inflated)

    benchmarking cmpOpt  2.3.4 1.2.3.4.5
    time                 11.29 ns   (11.27 ns .. 11.30 ns)
                         1.000 R²   (1.000 R² .. 1.000 R²)
    mean                 11.28 ns   (11.27 ns .. 11.29 ns)
    std dev              24.69 ps   (12.02 ps .. 46.86 ps)

    benchmarking compare [2.3.4] [1.2.3.4.5]
    time                 11.05 ns   (11.04 ns .. 11.06 ns)
                         1.000 R²   (1.000 R² .. 1.000 R²)
    mean                 11.05 ns   (11.04 ns .. 11.06 ns)
    std dev              32.82 ps   (15.89 ps .. 61.64 ps)

These timings are now very close to the 'Ord [Int]' timings.

With this optimisation, the total number of 'versionNumbers' calls
reported by `+RTS -p` for `cabal new-build --dry`'ing haskell-ide-engine
went down from originally 73501 calls to 6789 calls.
Cabal/Distribution/Version.hs