Blame tune/speed-ext.c

Packit 5c3484
/* An example of extending the speed program to measure routines not in GMP.
Packit 5c3484
Packit 5c3484
Copyright 1999, 2000, 2002, 2003, 2005 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* The extension here is three versions of an mpn arithmetic mean.  These
Packit 5c3484
   aren't meant to be particularly useful, just examples.
Packit 5c3484
Packit 5c3484
   You can run something like the following to compare their speeds.
Packit 5c3484
Packit 5c3484
           ./speed-ext -s 1-20 -c mean_calls mean_open mean_open2
Packit 5c3484
Packit 5c3484
   On RISC chips, mean_open() might be fastest if the compiler is doing a
Packit 5c3484
   good job.  On the register starved x86s, mean_calls will be fastest.
Packit 5c3484
Packit 5c3484
Packit 5c3484
   Notes:
Packit 5c3484
Packit 5c3484
   SPEED_EXTRA_PROTOS and SPEED_EXTRA_ROUTINES are macros that get expanded
Packit 5c3484
   by speed.c in useful places.  SPEED_EXTRA_PROTOS goes after the header
Packit 5c3484
   files, and SPEED_EXTRA_ROUTINES goes in the array of available routines.
Packit 5c3484
Packit 5c3484
   The advantage of this #include "speed.c" scheme is that there's no
Packit 5c3484
   editing of a copy of that file, and new features in new versions of it
Packit 5c3484
   will be immediately available.
Packit 5c3484
Packit 5c3484
   In a real program the routines mean_calls() etc would probably be in
Packit 5c3484
   separate C or assembler source files, and just the measuring
Packit 5c3484
   speed_mean_calls() etc would be here.  Linking against other libraries
Packit 5c3484
   for things to measure is perfectly possible too.
Packit 5c3484
Packit 5c3484
   When attempting to compare two versions of the same named routine, say
Packit 5c3484
   like the generic and assembler versions of mpn_add_n(), creative use of
Packit 5c3484
   cc -D or #define is suggested, so one or both can be renamed and linked
Packit 5c3484
   into the same program.  It'll be much easier to compare them side by side
Packit 5c3484
   than with separate programs for each.
Packit 5c3484
Packit 5c3484
   common.c has notes on writing speed measuring routines.
Packit 5c3484
Packit 5c3484
   Remember to link against tune/libspeed.la (or tune/.libs/libspeed.a if
Packit 5c3484
   not using libtool) to get common.o and other objects needed by speed.c.  */
Packit 5c3484
Packit 5c3484
Packit 5c3484
#define SPEED_EXTRA_PROTOS                                              \
Packit 5c3484
  double speed_mean_calls (struct speed_params *s);			\
Packit 5c3484
  double speed_mean_open  (struct speed_params *s);			\
Packit 5c3484
  double speed_mean_open2 (struct speed_params *s);
Packit 5c3484
Packit 5c3484
#define SPEED_EXTRA_ROUTINES            \
Packit 5c3484
  { "mean_calls",  speed_mean_calls  }, \
Packit 5c3484
  { "mean_open",   speed_mean_open   }, \
Packit 5c3484
  { "mean_open2",  speed_mean_open2  },
Packit 5c3484
Packit 5c3484
#include "speed.c"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* A straightforward implementation calling mpn subroutines.
Packit 5c3484
Packit 5c3484
   wp,size is set to (xp,size + yp,size) / 2.  The return value is the
Packit 5c3484
   remainder from the division.  The other versions are the same.  */
Packit 5c3484
Packit 5c3484
mp_limb_t
Packit 5c3484
mean_calls (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
Packit 5c3484
{
Packit 5c3484
  mp_limb_t  c, ret;
Packit 5c3484
Packit 5c3484
  ASSERT (size >= 1);
Packit 5c3484
Packit 5c3484
  c = mpn_add_n (wp, xp, yp, size);
Packit 5c3484
  ret = mpn_rshift (wp, wp, size, 1) >> (GMP_LIMB_BITS-1);
Packit 5c3484
  wp[size-1] |= (c << (GMP_LIMB_BITS-1));
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* An open-coded version, making one pass over the data.  The right shift is
Packit 5c3484
   done as the added limbs are produced.  The addition code follows
Packit 5c3484
   mpn/generic/add_n.c. */
Packit 5c3484
Packit 5c3484
mp_limb_t
Packit 5c3484
mean_open (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
Packit 5c3484
{
Packit 5c3484
  mp_limb_t  w, wprev, x, y, c, ret;
Packit 5c3484
  mp_size_t  i;
Packit 5c3484
Packit 5c3484
  ASSERT (size >= 1);
Packit 5c3484
Packit 5c3484
  x = xp[0];
Packit 5c3484
  y = yp[0];
Packit 5c3484
Packit 5c3484
  wprev = x + y;
Packit 5c3484
  c = (wprev < x);
Packit 5c3484
  ret = (wprev & 1);
Packit 5c3484
Packit 5c3484
#define RSHIFT(hi,lo)   (((lo) >> 1) | ((hi) << (GMP_LIMB_BITS-1)))
Packit 5c3484
Packit 5c3484
  for (i = 1; i < size; i++)
Packit 5c3484
    {
Packit 5c3484
      x = xp[i];
Packit 5c3484
      y = yp[i];
Packit 5c3484
Packit 5c3484
      w = x + c;
Packit 5c3484
      c = (w < x);
Packit 5c3484
      w += y;
Packit 5c3484
      c += (w < y);
Packit 5c3484
Packit 5c3484
      wp[i-1] = RSHIFT (w, wprev);
Packit 5c3484
      wprev = w;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  wp[i-1] = RSHIFT (c, wprev);
Packit 5c3484
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Another one-pass version, but right shifting the source limbs rather than
Packit 5c3484
   the result limbs.  There's not much chance of this being better than the
Packit 5c3484
   above, but it's an alternative at least. */
Packit 5c3484
Packit 5c3484
mp_limb_t
Packit 5c3484
mean_open2 (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
Packit 5c3484
{
Packit 5c3484
  mp_limb_t  w, x, y, xnext, ynext, c, ret;
Packit 5c3484
  mp_size_t  i;
Packit 5c3484
Packit 5c3484
  ASSERT (size >= 1);
Packit 5c3484
Packit 5c3484
  x = xp[0];
Packit 5c3484
  y = yp[0];
Packit 5c3484
Packit 5c3484
  /* ret is the low bit of x+y, c is the carry out of that low bit add */
Packit 5c3484
  ret = (x ^ y) & 1;
Packit 5c3484
  c   = (x & y) & 1;
Packit 5c3484
Packit 5c3484
  for (i = 0; i < size-1; i++)
Packit 5c3484
    {
Packit 5c3484
      xnext = xp[i+1];
Packit 5c3484
      ynext = yp[i+1];
Packit 5c3484
      x = RSHIFT (xnext, x);
Packit 5c3484
      y = RSHIFT (ynext, y);
Packit 5c3484
Packit 5c3484
      w = x + c;
Packit 5c3484
      c = (w < x);
Packit 5c3484
      w += y;
Packit 5c3484
      c += (w < y);
Packit 5c3484
      wp[i] = w;
Packit 5c3484
Packit 5c3484
      x = xnext;
Packit 5c3484
      y = ynext;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  wp[i] = (x >> 1) + (y >> 1) + c;
Packit 5c3484
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* The speed measuring routines are the same apart from which function they
Packit 5c3484
   run, so a macro is used.  Actually this macro is the same as
Packit 5c3484
   SPEED_ROUTINE_MPN_BINARY_N.  */
Packit 5c3484
Packit 5c3484
#define SPEED_ROUTINE_MEAN(mean_fun)                    \
Packit 5c3484
  {                                                     \
Packit 5c3484
    unsigned  i;                                        \
Packit 5c3484
    mp_ptr    wp;                                       \
Packit 5c3484
    double    t;                                        \
Packit 5c3484
    TMP_DECL;                                  \
Packit 5c3484
                                                        \
Packit 5c3484
    SPEED_RESTRICT_COND (s->size >= 1);                 \
Packit 5c3484
                                                        \
Packit 5c3484
    TMP_MARK;                                  \
Packit 5c3484
    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);   \
Packit 5c3484
                                                        \
Packit 5c3484
    speed_operand_src (s, s->xp, s->size);              \
Packit 5c3484
    speed_operand_src (s, s->yp, s->size);              \
Packit 5c3484
    speed_operand_dst (s, wp, s->size);                 \
Packit 5c3484
    speed_cache_fill (s);                               \
Packit 5c3484
                                                        \
Packit 5c3484
    speed_starttime ();                                 \
Packit 5c3484
    i = s->reps;                                        \
Packit 5c3484
    do                                                  \
Packit 5c3484
      mean_fun (wp, s->xp, s->yp, s->size);             \
Packit 5c3484
    while (--i != 0);                                   \
Packit 5c3484
    t = speed_endtime ();                               \
Packit 5c3484
                                                        \
Packit 5c3484
    TMP_FREE;                                  \
Packit 5c3484
    return t;                                           \
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
double
Packit 5c3484
speed_mean_calls (struct speed_params *s)
Packit 5c3484
{
Packit 5c3484
  SPEED_ROUTINE_MEAN (mean_calls);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
double
Packit 5c3484
speed_mean_open (struct speed_params *s)
Packit 5c3484
{
Packit 5c3484
  SPEED_ROUTINE_MEAN (mean_open);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
double
Packit 5c3484
speed_mean_open2 (struct speed_params *s)
Packit 5c3484
{
Packit 5c3484
  SPEED_ROUTINE_MEAN (mean_open2);
Packit 5c3484
}