1 | /* |
2 | Name: imtimer.c |
3 | Purpose: Timing tests for the imath library. |
4 | Author: M. J. Fromberger |
5 | |
6 | Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved. |
7 | |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | of this software and associated documentation files (the "Software"), to deal |
10 | in the Software without restriction, including without limitation the rights |
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | copies of the Software, and to permit persons to whom the Software is |
13 | furnished to do so, subject to the following conditions: |
14 | |
15 | The above copyright notice and this permission notice shall be included in |
16 | all copies or substantial portions of the Software. |
17 | |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
24 | SOFTWARE. |
25 | */ |
26 | |
27 | #include <limits.h> |
28 | #include <stdio.h> |
29 | #include <stdlib.h> |
30 | #include <string.h> |
31 | #include <time.h> |
32 | |
33 | #include <getopt.h> |
34 | #include <unistd.h> |
35 | |
36 | #include "imath.h" |
37 | |
38 | double clocks_to_seconds(clock_t start, clock_t end); |
39 | double get_multiply_time(int nt, int prec); |
40 | double get_exptmod_time(int nt, int prec); |
41 | mp_int alloc_values(int nt, int prec); |
42 | void randomize_values(mp_int values, int nt, int prec); |
43 | void release_values(mp_int values, int nt); |
44 | void mp_int_random(mp_int z, int prec); |
45 | |
46 | const int g_mul_factor = 1000; |
47 | |
48 | int main(int argc, char *argv[]) { |
49 | int do_mul = 0, do_exp = 0, = 1; |
50 | int num_tests, precision = 0, opt; |
51 | mp_size threshold = 0; |
52 | unsigned int seed = (unsigned int)time(NULL); |
53 | |
54 | while ((opt = getopt(argc: argc, argv: argv, shortopts: "ehmnp:s:t:" )) != EOF) { |
55 | switch (opt) { |
56 | case 'e': |
57 | do_exp = 1; |
58 | break; |
59 | case 'm': |
60 | do_mul = 1; |
61 | break; |
62 | case 'n': |
63 | do_header = 0; |
64 | break; |
65 | case 'p': |
66 | precision = atoi(nptr: optarg); |
67 | break; |
68 | case 's': |
69 | seed = atoi(nptr: optarg); |
70 | break; |
71 | case 't': |
72 | threshold = (mp_size)atoi(nptr: optarg); |
73 | break; |
74 | default: |
75 | fprintf(stderr, |
76 | format: "Usage: imtimer [options] <num-tests>\n\n" |
77 | "Options understood:\n" |
78 | " -e -- test modular exponentiation speed.\n" |
79 | " -h -- display this help message.\n" |
80 | " -m -- test multiplication speed.\n" |
81 | " -n -- no header line.\n" |
82 | " -p <dig> -- use values with <dig> digits.\n" |
83 | " -s <rnd> -- set random seed to <rnd>.\n" |
84 | " -t <dig> -- set recursion threshold to <dig> digits.\n\n" ); |
85 | return (opt != 'h'); |
86 | } |
87 | } |
88 | |
89 | if (optind >= argc) { |
90 | fprintf(stderr, |
91 | format: "Usage: imtimer [options] <num-tests>\n" |
92 | "[use \"imtimer -h\" for help with options]\n\n" ); |
93 | return 1; |
94 | } else |
95 | num_tests = atoi(nptr: argv[optind]); |
96 | |
97 | srand(seed: seed); |
98 | |
99 | if (num_tests <= 0) { |
100 | fprintf(stderr, format: "You must request at least one test.\n" ); |
101 | return 1; |
102 | } |
103 | if (precision < 0) { |
104 | fprintf(stderr, format: "Precision must be non-negative (0 means default).\n" ); |
105 | return 1; |
106 | } |
107 | mp_int_multiply_threshold(ndigits: threshold); |
108 | |
109 | if (do_header) printf(format: "NUM\tPREC\tBITS\tREC\tRESULT\n" ); |
110 | printf(format: "%d\t%d\t%d\t%u" , num_tests, precision, |
111 | (int)(precision * MP_DIGIT_BIT), threshold); |
112 | |
113 | if (do_mul) { |
114 | double m_time = get_multiply_time(nt: num_tests, prec: precision); |
115 | |
116 | printf(format: "\tMUL %.3f %.3f" , m_time, m_time / num_tests); |
117 | } |
118 | |
119 | if (do_exp) { |
120 | double e_time = get_exptmod_time(nt: num_tests, prec: precision); |
121 | |
122 | printf(format: "\tEXP %.3f %.3f" , e_time, e_time / num_tests); |
123 | } |
124 | fputc(c: '\n', stdout); |
125 | fflush(stdout); |
126 | |
127 | return 0; |
128 | } |
129 | |
130 | double clocks_to_seconds(clock_t start, clock_t end) { |
131 | return (double)(end - start) / CLOCKS_PER_SEC; |
132 | } |
133 | |
134 | mp_int alloc_values(int nt, int prec) { |
135 | mp_int out = malloc(size: nt * sizeof(mpz_t)); |
136 | int i; |
137 | |
138 | if (out == NULL) return NULL; |
139 | |
140 | for (i = 0; i < nt; ++i) { |
141 | if (mp_int_init_size(z: out + i, prec) != MP_OK) { |
142 | while (--i >= 0) mp_int_clear(z: out + i); |
143 | return NULL; |
144 | } |
145 | } |
146 | |
147 | return out; |
148 | } |
149 | |
150 | void randomize_values(mp_int values, int nt, int prec) { |
151 | int i; |
152 | |
153 | for (i = 0; i < nt; ++i) mp_int_random(z: values + i, prec); |
154 | } |
155 | |
156 | void release_values(mp_int values, int nt) { |
157 | int i; |
158 | |
159 | for (i = 0; i < nt; ++i) mp_int_clear(z: values + i); |
160 | |
161 | free(ptr: values); |
162 | } |
163 | |
164 | double get_multiply_time(int nt, int prec) { |
165 | clock_t start, end; |
166 | mp_int values; |
167 | int i; |
168 | |
169 | if ((values = alloc_values(nt: 3, prec)) == NULL) return 0.0; |
170 | randomize_values(values, nt: 2, prec); |
171 | |
172 | start = clock(); |
173 | for (i = 0; i < nt; ++i) mp_int_mul(a: values, b: values + 1, c: values + 2); |
174 | end = clock(); |
175 | |
176 | release_values(values, nt: 3); |
177 | |
178 | return clocks_to_seconds(start, end); |
179 | } |
180 | |
181 | double get_exptmod_time(int nt, int prec) { |
182 | clock_t start, end; |
183 | mp_int values; |
184 | int i; |
185 | |
186 | if ((values = alloc_values(nt: 4, prec)) == NULL) return 0.0; |
187 | randomize_values(values, nt: 3, prec); |
188 | |
189 | start = clock(); |
190 | for (i = 0; i < nt; ++i) |
191 | mp_int_exptmod(a: values, b: values + 1, m: values + 2, c: values + 3); |
192 | end = clock(); |
193 | |
194 | release_values(values, nt: 4); |
195 | |
196 | return clocks_to_seconds(start, end); |
197 | } |
198 | |
199 | void mp_int_random(mp_int z, int prec) { |
200 | int i; |
201 | |
202 | if (prec > (int)MP_ALLOC(Z: z)) prec = (int)MP_ALLOC(Z: z); |
203 | |
204 | for (i = 0; i < prec; ++i) { |
205 | mp_digit d = 0; |
206 | int j; |
207 | |
208 | for (j = 0; j < (int)sizeof(d); ++j) { |
209 | d = (d << CHAR_BIT) | (rand() & UCHAR_MAX); |
210 | } |
211 | |
212 | z->digits[i] = d; |
213 | } |
214 | z->used = prec; |
215 | } |
216 | |