blob: 3b5a4a8a3689fada680d77fbaf940017763ff503 [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* tune-gcd-p
2
3 Tune the choice for splitting p in divide-and-conquer gcd.
4
5Copyright 2008, 2010, 2011 Free Software Foundation, Inc.
6
7This file is part of the GNU MP Library.
8
9The GNU MP Library is free software; you can redistribute it and/or modify
10it under the terms of either:
11
12 * the GNU Lesser General Public License as published by the Free
13 Software Foundation; either version 3 of the License, or (at your
14 option) any later version.
15
16or
17
18 * the GNU General Public License as published by the Free Software
19 Foundation; either version 2 of the License, or (at your option) any
20 later version.
21
22or both in parallel, as here.
23
24The GNU MP Library is distributed in the hope that it will be useful, but
25WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27for more details.
28
29You should have received copies of the GNU General Public License and the
30GNU Lesser General Public License along with the GNU MP Library. If not,
31see https://www.gnu.org/licenses/. */
32
33#define TUNE_GCD_P 1
34
35#include "../mpn/gcd.c"
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <time.h>
41
42#include "speed.h"
43
44/* Search for minimum over a range. FIXME: Implement golden-section /
45 fibonacci search*/
46static int
47search (double *minp, double (*f)(void *, int), void *ctx, int start, int end)
48{
49 int x[4];
50 double y[4];
51
52 int best_i;
53
54 x[0] = start;
55 x[3] = end;
56
57 y[0] = f(ctx, x[0]);
58 y[3] = f(ctx, x[3]);
59
60 for (;;)
61 {
62 int i;
63 int length = x[3] - x[0];
64
65 x[1] = x[0] + length/3;
66 x[2] = x[0] + 2*length/3;
67
68 y[1] = f(ctx, x[1]);
69 y[2] = f(ctx, x[2]);
70
71#if 0
72 printf("%d: %f, %d: %f, %d:, %f %d: %f\n",
73 x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3]);
74#endif
75 for (best_i = 0, i = 1; i < 4; i++)
76 if (y[i] < y[best_i])
77 best_i = i;
78
79 if (length <= 4)
80 break;
81
82 if (best_i >= 2)
83 {
84 x[0] = x[1];
85 y[0] = y[1];
86 }
87 else
88 {
89 x[3] = x[2];
90 y[3] = y[2];
91 }
92 }
93 *minp = y[best_i];
94 return x[best_i];
95}
96
97static int
98compare_double(const void *ap, const void *bp)
99{
100 double a = * (const double *) ap;
101 double b = * (const double *) bp;
102
103 if (a < b)
104 return -1;
105 else if (a > b)
106 return 1;
107 else
108 return 0;
109}
110
111static double
112median (double *v, size_t n)
113{
114 qsort(v, n, sizeof(*v), compare_double);
115
116 return v[n/2];
117}
118
119#define TIME(res, code) do { \
120 double time_measurement[5]; \
121 unsigned time_i; \
122 \
123 for (time_i = 0; time_i < 5; time_i++) \
124 { \
125 speed_starttime(); \
126 code; \
127 time_measurement[time_i] = speed_endtime(); \
128 } \
129 res = median(time_measurement, 5); \
130} while (0)
131
132struct bench_data
133{
134 mp_size_t n;
135 mp_ptr ap;
136 mp_ptr bp;
137 mp_ptr up;
138 mp_ptr vp;
139 mp_ptr gp;
140};
141
142static double
143bench_gcd (void *ctx, int p)
144{
145 struct bench_data *data = (struct bench_data *) ctx;
146 double t;
147
148 p_table[data->n] = p;
149 TIME(t, {
150 MPN_COPY (data->up, data->ap, data->n);
151 MPN_COPY (data->vp, data->bp, data->n);
152 mpn_gcd (data->gp, data->up, data->n, data->vp, data->n);
153 });
154
155 return t;
156}
157
158int
159main(int argc, char **argv)
160{
161 gmp_randstate_t rands; struct bench_data data;
162 mp_size_t n;
163
164 TMP_DECL;
165
166 /* Unbuffered so if output is redirected to a file it isn't lost if the
167 program is killed part way through. */
168 setbuf (stdout, NULL);
169 setbuf (stderr, NULL);
170
171 gmp_randinit_default (rands);
172
173 TMP_MARK;
174
175 data.ap = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
176 data.bp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
177 data.up = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
178 data.vp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
179 data.gp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
180
181 mpn_random (data.ap, P_TABLE_SIZE);
182 mpn_random (data.bp, P_TABLE_SIZE);
183
184 memset (p_table, 0, sizeof(p_table));
185
186 for (n = 100; n < P_TABLE_SIZE; n++)
187 {
188 mp_size_t p;
189 mp_size_t best_p;
190 double best_time;
191 double lehmer_time;
192
193 if (data.ap[n-1] == 0)
194 data.ap[n-1] = 1;
195
196 if (data.bp[n-1] == 0)
197 data.bp[n-1] = 1;
198
199 data.n = n;
200
201 lehmer_time = bench_gcd (&data, 0);
202
203 best_p = search (&best_time, bench_gcd, &data, n/5, 4*n/5);
204 if (best_time > lehmer_time)
205 best_p = 0;
206
207 printf("%6zu %6zu %5.3g", n, best_p, (double) best_p / n);
208 if (best_p > 0)
209 {
210 double speedup = 100 * (lehmer_time - best_time) / lehmer_time;
211 printf(" %5.3g%%", speedup);
212 if (speedup < 1.0)
213 {
214 printf(" (ignored)");
215 best_p = 0;
216 }
217 }
218 printf("\n");
219
220 p_table[n] = best_p;
221 }
222 TMP_FREE;
223 gmp_randclear(rands);
224 return 0;
225}