cannam@95
|
1 /* Re-use libbench2 and the test program, but override bench_main so that
|
cannam@95
|
2 we can have different command-line syntax. */
|
cannam@95
|
3 #include "my-getopt.h"
|
cannam@95
|
4 #include "bench.h"
|
cannam@95
|
5
|
cannam@95
|
6 #include <stdio.h>
|
cannam@95
|
7 #include <stdlib.h>
|
cannam@95
|
8 #include <ctype.h>
|
cannam@95
|
9 #include <fftw3.h>
|
cannam@95
|
10 #include <string.h>
|
cannam@95
|
11 #include <time.h>
|
cannam@95
|
12
|
cannam@95
|
13 #if defined(HAVE_THREADS) || defined(HAVE_OPENMP)
|
cannam@95
|
14 # define HAVE_SMP
|
cannam@95
|
15 extern int threads_ok;
|
cannam@95
|
16 #endif
|
cannam@95
|
17
|
cannam@95
|
18 #define CONCAT(prefix, name) prefix ## name
|
cannam@95
|
19 #if defined(BENCHFFT_SINGLE)
|
cannam@95
|
20 #define FFTW(x) CONCAT(fftwf_, x)
|
cannam@95
|
21 #elif defined(BENCHFFT_LDOUBLE)
|
cannam@95
|
22 #define FFTW(x) CONCAT(fftwl_, x)
|
cannam@95
|
23 #elif defined(BENCHFFT_QUAD)
|
cannam@95
|
24 #define FFTW(x) CONCAT(fftwq_, x)
|
cannam@95
|
25 #else
|
cannam@95
|
26 #define FFTW(x) CONCAT(fftw_, x)
|
cannam@95
|
27 #endif
|
cannam@95
|
28
|
cannam@95
|
29 /* from bench.c: */
|
cannam@95
|
30 extern unsigned the_flags;
|
cannam@95
|
31 extern int usewisdom;
|
cannam@95
|
32 extern int nthreads;
|
cannam@95
|
33
|
cannam@95
|
34 /* dummy routines to replace those in hook.c */
|
cannam@95
|
35 void install_hook(void) {}
|
cannam@95
|
36 void uninstall_hook(void) {}
|
cannam@95
|
37
|
cannam@95
|
38 int verbose;
|
cannam@95
|
39
|
cannam@95
|
40 static void do_problem(bench_problem *p)
|
cannam@95
|
41 {
|
cannam@95
|
42 if (verbose)
|
cannam@95
|
43 printf("PLANNING PROBLEM: %s\n", p->pstring);
|
cannam@95
|
44 /* BENCH_ASSERT(can_do(p)); */
|
cannam@95
|
45 problem_alloc(p);
|
cannam@95
|
46 setup(p);
|
cannam@95
|
47 done(p);
|
cannam@95
|
48 }
|
cannam@95
|
49
|
cannam@95
|
50 static void add_problem(const char *pstring,
|
cannam@95
|
51 bench_problem ***p, int *ip, int *np)
|
cannam@95
|
52 {
|
cannam@95
|
53 if (*ip >= *np) {
|
cannam@95
|
54 *np = *np * 2 + 1;
|
cannam@95
|
55 *p = (bench_problem **) realloc(*p, sizeof(bench_problem *) * *np);
|
cannam@95
|
56 }
|
cannam@95
|
57 (*p)[(*ip)++] = problem_parse(pstring);
|
cannam@95
|
58 }
|
cannam@95
|
59
|
cannam@95
|
60 static int sz(const bench_problem *p)
|
cannam@95
|
61 {
|
cannam@95
|
62 return tensor_sz(p->sz) * tensor_sz(p->vecsz);
|
cannam@95
|
63 }
|
cannam@95
|
64
|
cannam@95
|
65 static int prob_size_cmp(const void *p1_, const void *p2_)
|
cannam@95
|
66 {
|
cannam@95
|
67 const bench_problem * const *p1 = (const bench_problem * const *) p1_;
|
cannam@95
|
68 const bench_problem * const *p2 = (const bench_problem * const *) p2_;
|
cannam@95
|
69 return (sz(*p1) - sz(*p2));
|
cannam@95
|
70 }
|
cannam@95
|
71
|
cannam@95
|
72 static struct my_option options[] =
|
cannam@95
|
73 {
|
cannam@95
|
74 {"help", NOARG, 'h'},
|
cannam@95
|
75 {"version", NOARG, 'V'},
|
cannam@95
|
76 {"verbose", NOARG, 'v'},
|
cannam@95
|
77
|
cannam@95
|
78 {"canonical", NOARG, 'c'},
|
cannam@95
|
79 {"time-limit", REQARG, 't'},
|
cannam@95
|
80
|
cannam@95
|
81 {"output-file", REQARG, 'o'},
|
cannam@95
|
82
|
cannam@95
|
83 {"impatient", NOARG, 'i'},
|
cannam@95
|
84 {"measure", NOARG, 'm'},
|
cannam@95
|
85 {"estimate", NOARG, 'e'},
|
cannam@95
|
86 {"exhaustive", NOARG, 'x'},
|
cannam@95
|
87
|
cannam@95
|
88 {"no-system-wisdom", NOARG, 'n'},
|
cannam@95
|
89 {"wisdom-file", REQARG, 'w'},
|
cannam@95
|
90
|
cannam@95
|
91 #ifdef HAVE_SMP
|
cannam@95
|
92 {"threads", REQARG, 'T'},
|
cannam@95
|
93 #endif
|
cannam@95
|
94
|
cannam@95
|
95 /* options to restrict configuration to rdft-only, etcetera? */
|
cannam@95
|
96
|
cannam@95
|
97 {0, NOARG, 0}
|
cannam@95
|
98 };
|
cannam@95
|
99
|
cannam@95
|
100 static void help(FILE *f, const char *program_name)
|
cannam@95
|
101 {
|
cannam@95
|
102 fprintf(
|
cannam@95
|
103 f,
|
cannam@95
|
104 "Usage: %s [options] [sizes]\n"
|
cannam@95
|
105 " Create wisdom (pre-planned/optimized transforms) for specified sizes,\n"
|
cannam@95
|
106 " writing wisdom to stdout (or to a file, using -o).\n"
|
cannam@95
|
107 "\nOptions:\n"
|
cannam@95
|
108 " -h, --help: print this help\n"
|
cannam@95
|
109 " -V, --version: print version/copyright info\n"
|
cannam@95
|
110 " -v, --verbose: verbose output\n"
|
cannam@95
|
111 " -c, --canonical: plan/optimize canonical set of sizes\n"
|
cannam@95
|
112 " -t <h>, --time-limit=<h>: time limit in hours (default: 0, no limit)\n"
|
cannam@95
|
113 " -o FILE, --output-file=FILE: output to FILE instead of stdout\n"
|
cannam@95
|
114 " -m, --measure: plan in MEASURE mode (PATIENT is default)\n"
|
cannam@95
|
115 " -e, --estimate: plan in ESTIMATE mode (not recommended)\n"
|
cannam@95
|
116 " -x, --exhaustive: plan in EXHAUSTIVE mode (may be slow)\n"
|
cannam@95
|
117 " -n, --no-system-wisdom: don't read /etc/fftw/ system wisdom file\n"
|
cannam@95
|
118 " -w FILE, --wisdom-file=FILE: read wisdom from FILE (stdin if -)\n"
|
cannam@95
|
119 #ifdef HAVE_SMP
|
cannam@95
|
120 " -T N, --threads=N: plan with N threads\n"
|
cannam@95
|
121 #endif
|
cannam@95
|
122 "\nSize syntax: <type><inplace><direction><geometry>\n"
|
cannam@95
|
123 " <type> = c/r/k for complex/real(r2c,c2r)/r2r\n"
|
cannam@95
|
124 " <inplace> = i/o for in/out-of place\n"
|
cannam@95
|
125 " <direction> = f/b for forward/backward, omitted for k transforms\n"
|
cannam@95
|
126 " <geometry> = <n1>[x<n2>[x...]], e.g. 10x12x14\n"
|
cannam@95
|
127 " -- for k transforms, after each dimension is a <kind>:\n"
|
cannam@95
|
128 " <kind> = f/b/h/e00/e01/e10/e11/o00/o01/o10/o11\n"
|
cannam@95
|
129 " for R2HC/HC2R/DHT/REDFT00/.../RODFT11\n"
|
cannam@95
|
130 , program_name);
|
cannam@95
|
131 }
|
cannam@95
|
132
|
cannam@95
|
133 /* powers of two and ten up to 2^20, for now */
|
cannam@95
|
134 static char canonical_sizes[][32] = {
|
cannam@95
|
135 "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024",
|
cannam@95
|
136 "2048", "4096", "8192", "16384", "32768", "65536", "131072",
|
cannam@95
|
137 "262144", "524288", "1048576",
|
cannam@95
|
138
|
cannam@95
|
139 "10", "100", "1000", "10000", "100000", "1000000",
|
cannam@95
|
140
|
cannam@95
|
141 "2x2", "4x4", "8x8", "10x10", "16x16", "32x32", "64x64", "100x100",
|
cannam@95
|
142 "128x128", "256x256", "512x512", "1000x1000", "1024x1024",
|
cannam@95
|
143
|
cannam@95
|
144 "2x2x2", "4x4x4", "8x8x8", "10x10x10", "16x16x16", "32x32x32",
|
cannam@95
|
145 "64x64x64", "100x100x100"
|
cannam@95
|
146 };
|
cannam@95
|
147
|
cannam@95
|
148 #define NELEM(array)(sizeof(array) / sizeof((array)[0]))
|
cannam@95
|
149
|
cannam@95
|
150 int bench_main(int argc, char *argv[])
|
cannam@95
|
151 {
|
cannam@95
|
152 int c;
|
cannam@95
|
153 unsigned i;
|
cannam@95
|
154 int impatient = 0;
|
cannam@95
|
155 int system_wisdom = 1;
|
cannam@95
|
156 int canonical = 0;
|
cannam@95
|
157 double hours = 0;
|
cannam@95
|
158 FILE *output_file;
|
cannam@95
|
159 char *output_fname = 0;
|
cannam@95
|
160 bench_problem **problems = 0;
|
cannam@95
|
161 int nproblems = 0, iproblem = 0;
|
cannam@95
|
162 time_t begin;
|
cannam@95
|
163
|
cannam@95
|
164 verbose = 0;
|
cannam@95
|
165 usewisdom = 0;
|
cannam@95
|
166
|
cannam@95
|
167 bench_srand(1);
|
cannam@95
|
168 #ifdef HAVE_SMP
|
cannam@95
|
169 /* do not configure FFTW with threads, unless the
|
cannam@95
|
170 user requests -T */
|
cannam@95
|
171 threads_ok = 0;
|
cannam@95
|
172 #endif
|
cannam@95
|
173
|
cannam@95
|
174 while ((c = my_getopt(argc, argv, options)) != -1) {
|
cannam@95
|
175 switch (c) {
|
cannam@95
|
176 case 'h':
|
cannam@95
|
177 help(stdout, argv[0]);
|
cannam@95
|
178 exit(EXIT_SUCCESS);
|
cannam@95
|
179 break;
|
cannam@95
|
180
|
cannam@95
|
181 case 'V':
|
cannam@95
|
182 printf("fftw-wisdom tool for FFTW version " VERSION ".\n");
|
cannam@95
|
183 printf(
|
cannam@95
|
184 "\n"
|
cannam@95
|
185 "Copyright (c) 2003, 2007-11 Matteo Frigo\n"
|
cannam@95
|
186 "Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology\n"
|
cannam@95
|
187 "\n"
|
cannam@95
|
188 "This program is free software; you can redistribute it and/or modify\n"
|
cannam@95
|
189 "it under the terms of the GNU General Public License as published by\n"
|
cannam@95
|
190 "the Free Software Foundation; either version 2 of the License, or\n"
|
cannam@95
|
191 "(at your option) any later version.\n"
|
cannam@95
|
192 "\n"
|
cannam@95
|
193 "This program is distributed in the hope that it will be useful,\n"
|
cannam@95
|
194 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
cannam@95
|
195 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
cannam@95
|
196 "GNU General Public License for more details.\n"
|
cannam@95
|
197 "\n"
|
cannam@95
|
198 "You should have received a copy of the GNU General Public License\n"
|
cannam@95
|
199 "along with this program; if not, write to the Free Software\n"
|
cannam@95
|
200 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
|
cannam@95
|
201 );
|
cannam@95
|
202 exit(EXIT_SUCCESS);
|
cannam@95
|
203 break;
|
cannam@95
|
204
|
cannam@95
|
205 case 'v':
|
cannam@95
|
206 verbose = 1;
|
cannam@95
|
207 break;
|
cannam@95
|
208
|
cannam@95
|
209 case 'c':
|
cannam@95
|
210 canonical = 1;
|
cannam@95
|
211 break;
|
cannam@95
|
212
|
cannam@95
|
213 case 't':
|
cannam@95
|
214 hours = atof(my_optarg);
|
cannam@95
|
215 break;
|
cannam@95
|
216
|
cannam@95
|
217 case 'o':
|
cannam@95
|
218 if (output_fname)
|
cannam@95
|
219 bench_free(output_fname);
|
cannam@95
|
220
|
cannam@95
|
221 if (!strcmp(my_optarg, "-"))
|
cannam@95
|
222 output_fname = 0;
|
cannam@95
|
223 else {
|
cannam@95
|
224 output_fname = (char *) bench_malloc(sizeof(char) *
|
cannam@95
|
225 (strlen(my_optarg) + 1));
|
cannam@95
|
226 strcpy(output_fname, my_optarg);
|
cannam@95
|
227 }
|
cannam@95
|
228 break;
|
cannam@95
|
229
|
cannam@95
|
230 case 'm':
|
cannam@95
|
231 case 'i':
|
cannam@95
|
232 impatient = 1;
|
cannam@95
|
233 break;
|
cannam@95
|
234
|
cannam@95
|
235 case 'e':
|
cannam@95
|
236 the_flags |= FFTW_ESTIMATE;
|
cannam@95
|
237 break;
|
cannam@95
|
238
|
cannam@95
|
239 case 'x':
|
cannam@95
|
240 the_flags |= FFTW_EXHAUSTIVE;
|
cannam@95
|
241 break;
|
cannam@95
|
242
|
cannam@95
|
243 case 'n':
|
cannam@95
|
244 system_wisdom = 0;
|
cannam@95
|
245 break;
|
cannam@95
|
246
|
cannam@95
|
247 case 'w': {
|
cannam@95
|
248 FILE *w = stdin;
|
cannam@95
|
249 if (strcmp(my_optarg, "-") && !(w = fopen(my_optarg, "r"))) {
|
cannam@95
|
250 fprintf(stderr,
|
cannam@95
|
251 "fftw-wisdom: error opening \"%s\": ", my_optarg);
|
cannam@95
|
252 perror("");
|
cannam@95
|
253 exit(EXIT_FAILURE);
|
cannam@95
|
254 }
|
cannam@95
|
255 if (!FFTW(import_wisdom_from_file)(w)) {
|
cannam@95
|
256 fprintf(stderr, "fftw_wisdom: error reading wisdom "
|
cannam@95
|
257 "from \"%s\"\n", my_optarg);
|
cannam@95
|
258 exit(EXIT_FAILURE);
|
cannam@95
|
259 }
|
cannam@95
|
260 if (w != stdin)
|
cannam@95
|
261 fclose(w);
|
cannam@95
|
262 break;
|
cannam@95
|
263 }
|
cannam@95
|
264
|
cannam@95
|
265 #ifdef HAVE_SMP
|
cannam@95
|
266 case 'T':
|
cannam@95
|
267 nthreads = atoi(my_optarg);
|
cannam@95
|
268 if (nthreads < 1) nthreads = 1;
|
cannam@95
|
269 threads_ok = 1;
|
cannam@95
|
270 BENCH_ASSERT(FFTW(init_threads)());
|
cannam@95
|
271 break;
|
cannam@95
|
272 #endif
|
cannam@95
|
273
|
cannam@95
|
274 case '?':
|
cannam@95
|
275 /* `my_getopt' already printed an error message. */
|
cannam@95
|
276 cleanup();
|
cannam@95
|
277 return EXIT_FAILURE;
|
cannam@95
|
278
|
cannam@95
|
279 default:
|
cannam@95
|
280 abort ();
|
cannam@95
|
281 }
|
cannam@95
|
282 }
|
cannam@95
|
283
|
cannam@95
|
284 if (!impatient)
|
cannam@95
|
285 the_flags |= FFTW_PATIENT;
|
cannam@95
|
286
|
cannam@95
|
287 if (system_wisdom)
|
cannam@95
|
288 if (!FFTW(import_system_wisdom)() && verbose)
|
cannam@95
|
289 fprintf(stderr, "fftw-wisdom: system-wisdom import failed\n");
|
cannam@95
|
290
|
cannam@95
|
291 if (canonical) {
|
cannam@95
|
292 for (i = 0; i < NELEM(canonical_sizes); ++i) {
|
cannam@95
|
293 unsigned j;
|
cannam@95
|
294 char types[][8] = {
|
cannam@95
|
295 "cof", "cob", "cif", "cib", "rof", "rob", "rif", "rib"
|
cannam@95
|
296 };
|
cannam@95
|
297
|
cannam@95
|
298 for (j = 0; j < NELEM(types); ++j) {
|
cannam@95
|
299 char ps[64];
|
cannam@95
|
300 if (!strchr(canonical_sizes[i],'x')
|
cannam@95
|
301 || !strchr(types[j],'o')) {
|
cannam@95
|
302 #ifdef HAVE_SNPRINTF
|
cannam@95
|
303 snprintf(ps, sizeof(ps), "%s%s", types[j], canonical_sizes[i]);
|
cannam@95
|
304 #else
|
cannam@95
|
305 sprintf(ps, "%s%s", types[j], canonical_sizes[i]);
|
cannam@95
|
306 #endif
|
cannam@95
|
307 add_problem(ps, &problems, &iproblem, &nproblems);
|
cannam@95
|
308 }
|
cannam@95
|
309 }
|
cannam@95
|
310 }
|
cannam@95
|
311 }
|
cannam@95
|
312
|
cannam@95
|
313 while (my_optind < argc) {
|
cannam@95
|
314 if (!strcmp(argv[my_optind], "-")) {
|
cannam@95
|
315 char s[1025];
|
cannam@95
|
316 while (1 == fscanf(stdin, "%1024s", s))
|
cannam@95
|
317 add_problem(s, &problems, &iproblem, &nproblems);
|
cannam@95
|
318 }
|
cannam@95
|
319 else
|
cannam@95
|
320 add_problem(argv[my_optind], &problems, &iproblem, &nproblems);
|
cannam@95
|
321 ++my_optind;
|
cannam@95
|
322 }
|
cannam@95
|
323
|
cannam@95
|
324 nproblems = iproblem;
|
cannam@95
|
325 qsort(problems, nproblems, sizeof(bench_problem *), prob_size_cmp);
|
cannam@95
|
326
|
cannam@95
|
327 if (!output_fname)
|
cannam@95
|
328 output_file = stdout;
|
cannam@95
|
329 else
|
cannam@95
|
330 if (!(output_file = fopen(output_fname, "w"))) {
|
cannam@95
|
331 fprintf(stderr,
|
cannam@95
|
332 "fftw-wisdom: error creating \"%s\"", output_fname);
|
cannam@95
|
333 perror("");
|
cannam@95
|
334 exit(EXIT_FAILURE);
|
cannam@95
|
335 }
|
cannam@95
|
336
|
cannam@95
|
337 begin = time((time_t*)0);
|
cannam@95
|
338 for (iproblem = 0; iproblem < nproblems; ++iproblem) {
|
cannam@95
|
339 if (hours <= 0
|
cannam@95
|
340 || hours > (time((time_t*)0) - begin) / 3600.0)
|
cannam@95
|
341 do_problem(problems[iproblem]);
|
cannam@95
|
342 problem_destroy(problems[iproblem]);
|
cannam@95
|
343
|
cannam@95
|
344 }
|
cannam@95
|
345 free(problems);
|
cannam@95
|
346
|
cannam@95
|
347 if (verbose && hours > 0
|
cannam@95
|
348 && hours < (time((time_t*)0) - begin) / 3600.0)
|
cannam@95
|
349 fprintf(stderr, "EXCEEDED TIME LIMIT OF %g HOURS.\n", hours);
|
cannam@95
|
350
|
cannam@95
|
351 FFTW(export_wisdom_to_file)(output_file);
|
cannam@95
|
352 if (output_file != stdout)
|
cannam@95
|
353 fclose(output_file);
|
cannam@95
|
354 if (output_fname)
|
cannam@95
|
355 bench_free(output_fname);
|
cannam@95
|
356
|
cannam@95
|
357 cleanup();
|
cannam@95
|
358
|
cannam@95
|
359 return EXIT_SUCCESS;
|
cannam@95
|
360 }
|