[Ecls-list] computing results into preallocated bignums

Nils Bruin nbruin at cecm.sfu.ca
Tue Sep 8 23:27:37 UTC 2009


When the recent changes to ECL's use of GMP were made, one thing came up:

If we could preallocate limb space for bignums in such a way that GMP 
doesn't need to resize it, one could avoid the use of registers 
altogether. Jason Moxham responded to the suggestion by making available 
macros that would guarantee space needs (it's pretty clear how much space 
an answer is going to need, but MPIR development wants to reserve the 
right to use a little more, should that ever be beneficial for speed)

I decided to run a little experiment with addition to see if avoiding 
extra memcpy's is going to make a difference:

In the file "num_arith.d" I tried out the following:

OLD CODE in ecl_plus:
------------------------------------------------------------------------------
 		case t_bignum:
                         z = _ecl_big_register0();
                         _ecl_big_add(z,x,y);
 			return _ecl_big_register_normalize(z);
------------------------------------------------------------------------------
NEW CODE in ecl_plus:
------------------------------------------------------------------------------
 		case t_bignum:
                         i = x->big.big_size;
                         if (i < 0) i = -i;
                         j = y->big.big_size;
                         if (j < 0) j = -j;
                         if (i > j ) dim = (i+1); else dim = (j+1);
                         z = ecl_alloc_compact_object(t_bignum, (cl_index) (dim*sizeof(mp_limb_t)));
                         z->big.big_limbs = ECL_COMPACT_OBJECT_EXTRA(z);
                         z->big.big_size = 0;
                         z->big.big_dim = dim;
                         _ecl_big_add(z, x, y);
------------------------------------------------------------------------------
(so this only affects bignum+bignum). I tried out the following program:

-------------------------------------------------------------------------
(defun fibo (n)
    (let ((a 1)(b 1)(c 0))
    (loop for i from 1 to n do
      (setq c a)
      (setq a (+ a b))
      (setq b c))
    b))

(defun test (n m)
     (let ((t0 (get-internal-run-time)))
     (loop for i from 1 to m do
       (fibo n))
     (- (get-internal-run-time) t0)))

-------------------------------------------------------

On a 2391.454 MHz AMD Opteron(tm) Processor 250 I tried getting some 
timings from

(test 4000 4000)

It was hard to get stable results, so the following figures are indicative 
only:

OLD: 15665, 16050, 16032
NEW: 15217, 15233, 15210

after

(compile 'fibo)
(compile 'test)

OLD: 9182, 9189, 9181 [but also some much lower values at the start]
NEW: 8156, 8144, 8144

so, I think the conclusion is: Yes, in some situations, the extra 
allocations/deallocations and memcpy involved in bignum arithmetic do have 
an influence on computation times. With macro's becoming available to 
guarantee allocation sizes, it may be worthwhile to rewrite bignum 
arithmetic to avoid extra register use as much as possible.

(incidentally, the "ECL" executable is still dynamically linked to libecl, 
so renaming "ecl" to "ecl_old" and then recompiling ecl does NOT lead to a 
situation where one can compare two versions of ecl!)

Kind regards,

Nils




More information about the ecl-devel mailing list