simon-git: spigot (master): Simon Tatham

Commits to Tartarus CVS repository. tartarus-commits at lists.tartarus.org
Sat Apr 16 15:28:49 BST 2016


TL;DR:
  9db94bf Fix O(N^2) memory management in internal bigint add/sub.
  1aa8cbb Avoid pointless mpz_init_set in GMP bigint operations.

Repository:     git://git.tartarus.org/simon/spigot.git
On the web:     http://tartarus.org/~simon-git/gitweb/?p=spigot.git
Branch updated: master
Committer:      Simon Tatham <anakin at pobox.com>
Date:           2016-04-16 15:28:49

commit 9db94bf8f48a373e267bd110f7531a2bd9f5bbe3
web diff http://tartarus.org/~simon-git/gitweb/?p=spigot.git;a=commitdiff;h=9db94bf8f48a373e267bd110f7531a2bd9f5bbe3;hp=689a6b6988d5ba4b95305de542772a1a9d562fe5
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Apr 16 14:55:51 2016 +0100

    Fix O(N^2) memory management in internal bigint add/sub.
    
    I ran across Brendan Gregg's 'flame graph' visualisation of profiling
    data recently, and spigot seemed like an easy thing to try it out on.
    Running with the internal bigints, I promptly found that an absurd
    amount of time was spent in std::vector resize operations called from
    bigint::add_word_at_pos(), because I was absentmindedly resizing the
    vector one word bigger for each word of the addition, due to the
    relevant code being split between two functions so it hadn't jumped
    out at me.
    
    Easily fixed by resizing it once before the main addition loop, and
    normalising it again afterwards. 'spigot -d5000 pi' with internal
    bigints now runs in 13.1 seconds of CPU time (on my machine) compared
    to 24.8 before. (Which is still quite bad compared to under half a
    second with gmp! But it is just an emergency fallback...)

 bi_internal.h |   25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

commit 1aa8cbb73f8fcbfd569bb1132054c52f61aeb625
web diff http://tartarus.org/~simon-git/gitweb/?p=spigot.git;a=commitdiff;h=1aa8cbb73f8fcbfd569bb1132054c52f61aeb625;hp=9db94bf8f48a373e267bd110f7531a2bd9f5bbe3
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Apr 16 15:19:26 2016 +0100

    Avoid pointless mpz_init_set in GMP bigint operations.
    
    This is another low-hanging-fruit optimisation pointed out by a flame
    graph. All bi_gmp.h's non-assigning arithmetic operators (like
    operator+) were implemented in terms of the assigning versions like
    operator+=, by the idiom 'bigint ret = a; return ret += b;'.
    Unfortunately, the construction of ret unpacks to an mpz_init_set that
    copies a, followed by an addition of b, and it turns out that the copy
    takes about as long as the addition, so it's faster to just initialise
    the output bigint as empty and overwrite it directly with the sum of a
    and b.
    
    Fixed by abstracting the actual gmp calls out into subroutines, so
    that now instead of operator+ being based on operator+=, both are
    based on overwrite_add(), and similarly for all the other operations
    I'd implemented this way. (The exception is reversed subtraction of
    the form 'ordinary int minus bigint', because there's no gmp call that
    does that in one go for a signed integer, so you do need a separate
    mpz_neg.)
    
    Now my 5000-digits pi test *with* gmp has gone down from 0.444s to
    0.299s, which is nice.

 bi_gmp.h |   73 +++++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 44 insertions(+), 29 deletions(-)



More information about the tartarus-commits mailing list