[GHC] #8647: Reduce allocations in `integer-gmp`

GHC ghc-devs at haskell.org
Fri Jan 3 12:55:33 UTC 2014


#8647: Reduce allocations in `integer-gmp`
------------------------------+--------------------------------------------
       Reporter:  hvr         |             Owner:
           Type:  task        |            Status:  new
       Priority:  normal      |         Milestone:  7.8.1
      Component:  libraries   |           Version:  7.6.3
  (other)                     |  Operating System:  Unknown/Multiple
       Keywords:              |   Type of failure:  Runtime performance bug
   Architecture:  x86_64      |         Test Case:
  (amd64)                     |          Blocking:
     Difficulty:  Unknown     |
     Blocked By:              |
Related Tickets:  #8638       |
------------------------------+--------------------------------------------
 I've added `printf(3)`s to `integer-gmp`s GMP allocation/reallocation
 functions, and noticed there to a significant amount of allocations going
 on.

 This is due to the fact that the CMM wrappers call `gmpz_init()` to
 initialize the result, and this already allocates a 1-limb `StgArray`. But
 the actual GMP operations perform a reallocate-call  (which by contract
 also needs `memcpy` the untouched limb over to the newly allocated
 structure) based on the type of operation and the involved operands,
 causing the optimistically allocated 1-limb structure to become garbage
 right away w/o even being written to.

 I've been able to get rid of most such superfluous allocations by
 replacing

 {{{#!c
 ccall __gmpz_init(mp_result1 "ptr");
 }}}

 by

 {{{#!c
 MP_INT__mp_alloc(mp_result1) = 0;
 MP_INT__mp_size(mp_result1)  = 0;
 MP_INT__mp_d(mp_result1)     = 0; // (1)
 }}}

 which is handled properly by all GMP operations we make use of currently.
 This elegantly lets the very first allocation be performed within the GMP
 operation (which has better knowledge with respect to how many limbs the
 result will require)

 I've got working proof-of-concept code, which reduces the allocations the
 big-num heavy `nofib` programs (I've omitted the benchmarks which had a 0%
 allocation change):

 {{{
 --------------------------------------------------------------------------------
         Program           Size    Allocs   Runtime   Elapsed  TotalMem
 --------------------------------------------------------------------------------
 ...
      bernouilli          -0.1%     -5.2%      0.12      0.12     +0.0%
           kahan          -0.1%    -10.5%      0.17      0.17     +0.0%
       primetest          -0.1%    -12.8%      0.07      0.07     +0.0%
             rsa          -0.1%    -13.8%      0.02      0.02     +0.0%
          symalg          -0.1%     -2.3%      0.01      0.01     +0.0%
 ...
 --------------------------------------------------------------------------------
             Min          -0.1%    -13.8%     -3.1%     -3.1%     -6.5%
             Max          -0.0%     +0.4%     +4.0%     +4.0%     +1.5%
  Geometric Mean          -0.1%     -0.5%     +0.5%     +0.4%     -0.1%
 }}}

 `(1)` This should actually point to a proper static closure I didn't need
 this for the proof-of-concept

 ----

 Another place which helps avoiding temporarily allocating 1-limb
 `StgArrays` which live only for the duration of GMP FFI calls are those
 caused by the `toBig`-casts, which I'm also experimenting by making use of
 GMP's big-int/small-int add/sub/mul primitives (the deltas shown above are
 actually measured on top of this optimization), here's what to expect from
 such an optimization by itself (i.e. w/o the realloc-optimization from
 above):

 {{{
      bernouilli          +0.1%     -4.2%      0.12      0.12     +0.0%
           kahan          +0.1%    -12.6%      0.17      0.17     +0.0%
           power          +0.1%     -2.7%     +2.2%     +2.2%     +0.0%
             rsa          +0.1%     -4.1%      0.02      0.02     +0.0%
             scs          +0.1%     -2.6%     -1.6%     -1.6%     +0.0%
 }}}

 Thus, the `kahan` benchmark benefits from this optimization by -12.6%, and
 on top of that another -10.5% by also avoiding the GMP-reallocations.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8647>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list