1/*
2Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007, 2008
3Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19
20#include <stdlib.h>
21#include <string.h>
22#include <stdio.h>
23#include "gmp.h"
24#include "gmp-impl.h"
25#include "longlong.h"
26#include "tests.h"
27
28#ifdef OPERATION_mul_1
29#define func __gmpn_mul_1
30#define reffunc refmpn_mul_1
31#define funcname "mpn_mul_1"
32#endif
33
34#ifdef OPERATION_addmul_1
35#define func __gmpn_addmul_1
36#define reffunc refmpn_addmul_1
37#define funcname "mpn_addmul_1"
38#endif
39
40#ifdef OPERATION_submul_1
41#define func __gmpn_submul_1
42#define reffunc refmpn_submul_1
43#define funcname "mpn_submul_1"
44#endif
45
46#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
47#include <time.h>
48
49int
50cputime ()
51{
52  if (CLOCKS_PER_SEC < 100000)
53    return clock () * 1000 / CLOCKS_PER_SEC;
54  return clock () / (CLOCKS_PER_SEC / 1000);
55}
56#else
57#include <sys/types.h>
58#include <sys/time.h>
59#include <sys/resource.h>
60
61int
62cputime ()
63{
64  struct rusage rus;
65
66  getrusage (0, &rus);
67  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
68}
69#endif
70
71static void print_posneg (mp_limb_t);
72static void mpn_print (mp_ptr, mp_size_t);
73
74#define LXW ((int) (2 * sizeof (mp_limb_t)))
75#define M * 1000000
76
77#ifndef CLOCK
78#error "Don't know CLOCK of your machine"
79#endif
80
81#ifndef OPS
82#define OPS (CLOCK/5)
83#endif
84#ifndef SIZE
85#define SIZE 496
86#endif
87#ifndef TIMES
88#define TIMES OPS/(SIZE+1)
89#endif
90
91int
92main (int argc, char **argv)
93{
94  mp_ptr s1, ref, rp;
95  mp_limb_t cy_ref, cy_try;
96  int i;
97  long t0, t;
98  unsigned int test;
99  mp_limb_t xlimb;
100  mp_size_t size;
101  double cyc;
102  unsigned int ntests;
103
104  s1 = malloc (SIZE * sizeof (mp_limb_t));
105  ref = malloc (SIZE * sizeof (mp_limb_t));
106  rp = malloc ((SIZE + 2) * sizeof (mp_limb_t));
107  rp++;
108
109  ntests = ~(unsigned) 0;
110  if (argc == 2)
111    ntests = strtol (argv[1], 0, 0);
112
113  for (test = 1; test <= ntests; test++)
114    {
115#if TIMES == 1 && ! defined (PRINT)
116      if (test % (1 + 0x80000 / (SIZE + 20)) == 0)
117	{
118	  printf ("\r%u", test);
119	  fflush (stdout);
120	}
121#endif
122
123#ifdef RANDOM
124      size = random () % SIZE + 1;
125#else
126      size = SIZE;
127#endif
128
129      rp[-1] = 0x87654321;
130      rp[size] = 0x12345678;
131
132#ifdef FIXED_XLIMB
133      xlimb = FIXED_XLIMB;
134#else
135      mpn_random2 (&xlimb, 1);
136#endif
137
138#if TIMES != 1
139      mpn_random (s1, size);
140      mpn_random (rp, size);
141
142      MPN_COPY (ref, rp, size);
143      t0 = cputime();
144      for (i = 0; i < TIMES; i++)
145	func (ref, s1, size, xlimb);
146      t = cputime() - t0;
147      cyc = ((double) t * CLOCK) / (TIMES * size * 1000.0);
148      printf (funcname ":    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
149	      t, cyc,
150	      CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
151#endif
152
153#ifndef NOCHECK
154      mpn_random2 (s1, size);
155#ifdef ZERO
156      memset (rp, 0, size * sizeof *rp);
157#else
158      mpn_random2 (rp, size);
159#endif
160#if defined (PRINT) || defined (XPRINT)
161      printf ("xlimb=");
162      mpn_print (&xlimb, 1);
163#endif
164#ifdef PRINT
165#ifndef OPERATION_mul_1
166      printf ("%*s ", (int) (2 * sizeof(mp_limb_t)), "");
167      mpn_print (rp, size);
168#endif
169      printf ("%*s ", (int) (2 * sizeof(mp_limb_t)), "");
170      mpn_print (s1, size);
171#endif
172
173      MPN_COPY (ref, rp, size);
174      cy_ref = reffunc (ref, s1, size, xlimb);
175      cy_try = func (rp, s1, size, xlimb);
176
177#ifdef PRINT
178      mpn_print (&cy_ref, 1);
179      mpn_print (ref, size);
180      mpn_print (&cy_try, 1);
181      mpn_print (rp, size);
182#endif
183
184      if (cy_ref != cy_try || mpn_cmp (ref, rp, size) != 0
185	  || rp[-1] != 0x87654321 || rp[size] != 0x12345678)
186	{
187	  printf ("\n        ref%*s try%*s diff\n", LXW - 3, "", 2 * LXW - 6, "");
188	  for (i = 0; i < size; i++)
189	    {
190	      printf ("%6d: ", i);
191	      printf ("%0*llX ", LXW, (unsigned long long) ref[i]);
192	      printf ("%0*llX ", LXW, (unsigned long long) rp[i]);
193	      print_posneg (rp[i] - ref[i]);
194	      printf ("\n");
195	    }
196	  printf ("retval: ");
197	  printf ("%0*llX ", LXW, (unsigned long long) cy_ref);
198	  printf ("%0*llX ", LXW, (unsigned long long) cy_try);
199	  print_posneg (cy_try - cy_ref);
200	  printf ("\n");
201	  if (rp[-1] != 0x87654321)
202	    printf ("clobbered at low end\n");
203	  if (rp[size] != 0x12345678)
204	    printf ("clobbered at high end\n");
205	  printf ("TEST NUMBER %u\n", test);
206	  abort();
207	}
208#endif
209    }
210  exit (0);
211}
212
213static void
214print_posneg (mp_limb_t d)
215{
216  char buf[LXW + 2];
217  if (d == 0)
218    printf (" %*X", LXW, 0);
219  else if (-d < d)
220    {
221      sprintf (buf, "%llX", (unsigned long long) -d);
222      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
223    }
224  else
225    {
226      sprintf (buf, "%llX", (unsigned long long) d);
227      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
228    }
229}
230
231static void
232mpn_print (mp_ptr p, mp_size_t size)
233{
234  mp_size_t i;
235
236  for (i = size - 1; i >= 0; i--)
237    {
238#ifdef _LONG_LONG_LIMB
239      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
240	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
241              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
242#else
243      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
244#endif
245#ifdef SPACE
246      if (i != 0)
247	printf (" ");
248#endif
249    }
250  puts ("");
251}
252