cannam@167: /* Re-use libbench2 and the test program, but override bench_main so that cannam@167: we can have different command-line syntax. */ cannam@167: #include "libbench2/my-getopt.h" cannam@167: #include "libbench2/bench.h" cannam@167: cannam@167: #include cannam@167: #include cannam@167: #include cannam@167: #include "api/fftw3.h" cannam@167: #include cannam@167: #include cannam@167: cannam@167: #if defined(HAVE_THREADS) || defined(HAVE_OPENMP) cannam@167: # define HAVE_SMP cannam@167: extern int threads_ok; cannam@167: #endif cannam@167: cannam@167: #define CONCAT(prefix, name) prefix ## name cannam@167: #if defined(BENCHFFT_SINGLE) cannam@167: #define FFTW(x) CONCAT(fftwf_, x) cannam@167: #elif defined(BENCHFFT_LDOUBLE) cannam@167: #define FFTW(x) CONCAT(fftwl_, x) cannam@167: #elif defined(BENCHFFT_QUAD) cannam@167: #define FFTW(x) CONCAT(fftwq_, x) cannam@167: #else cannam@167: #define FFTW(x) CONCAT(fftw_, x) cannam@167: #endif cannam@167: cannam@167: /* from bench.c: */ cannam@167: extern unsigned the_flags; cannam@167: extern int usewisdom; cannam@167: extern int nthreads; cannam@167: cannam@167: /* dummy routines to replace those in hook.c */ cannam@167: void install_hook(void) {} cannam@167: void uninstall_hook(void) {} cannam@167: cannam@167: int verbose; cannam@167: cannam@167: static void do_problem(bench_problem *p) cannam@167: { cannam@167: if (verbose) cannam@167: printf("Planning transform: %s\n", p->pstring); cannam@167: /* BENCH_ASSERT(can_do(p)); */ cannam@167: problem_alloc(p); cannam@167: setup(p); cannam@167: done(p); cannam@167: } cannam@167: cannam@167: static void add_problem(const char *pstring, cannam@167: bench_problem ***p, int *ip, int *np) cannam@167: { cannam@167: if (*ip >= *np) { cannam@167: *np = *np * 2 + 1; cannam@167: *p = (bench_problem **) realloc(*p, sizeof(bench_problem *) * *np); cannam@167: } cannam@167: (*p)[(*ip)++] = problem_parse(pstring); cannam@167: } cannam@167: cannam@167: static int sz(const bench_problem *p) cannam@167: { cannam@167: return tensor_sz(p->sz) * tensor_sz(p->vecsz); cannam@167: } cannam@167: cannam@167: static int prob_size_cmp(const void *p1_, const void *p2_) cannam@167: { cannam@167: const bench_problem * const *p1 = (const bench_problem * const *) p1_; cannam@167: const bench_problem * const *p2 = (const bench_problem * const *) p2_; cannam@167: return (sz(*p1) - sz(*p2)); cannam@167: } cannam@167: cannam@167: static struct my_option options[] = cannam@167: { cannam@167: {"help", NOARG, 'h'}, cannam@167: {"version", NOARG, 'V'}, cannam@167: {"verbose", NOARG, 'v'}, cannam@167: cannam@167: {"canonical", NOARG, 'c'}, cannam@167: {"time-limit", REQARG, 't'}, cannam@167: cannam@167: {"output-file", REQARG, 'o'}, cannam@167: cannam@167: {"impatient", NOARG, 'i'}, cannam@167: {"measure", NOARG, 'm'}, cannam@167: {"estimate", NOARG, 'e'}, cannam@167: {"exhaustive", NOARG, 'x'}, cannam@167: cannam@167: {"no-system-wisdom", NOARG, 'n'}, cannam@167: {"wisdom-file", REQARG, 'w'}, cannam@167: cannam@167: #ifdef HAVE_SMP cannam@167: {"threads", REQARG, 'T'}, cannam@167: #endif cannam@167: cannam@167: /* options to restrict configuration to rdft-only, etcetera? */ cannam@167: cannam@167: {0, NOARG, 0} cannam@167: }; cannam@167: cannam@167: static void help(FILE *f, const char *program_name) cannam@167: { cannam@167: fprintf( cannam@167: f, cannam@167: "Usage: %s [options] [sizes]\n" cannam@167: " Create wisdom (pre-planned/optimized transforms) for specified sizes,\n" cannam@167: " writing wisdom to stdout (or to a file, using -o).\n" cannam@167: "\nOptions:\n" cannam@167: " -h, --help: print this help\n" cannam@167: " -V, --version: print version/copyright info\n" cannam@167: " -v, --verbose: verbose output\n" cannam@167: " -c, --canonical: plan/optimize canonical set of sizes\n" cannam@167: " -t , --time-limit=: time limit in hours (default: 0, no limit)\n" cannam@167: " -o FILE, --output-file=FILE: output to FILE instead of stdout\n" cannam@167: " -m, --measure: plan in MEASURE mode (PATIENT is default)\n" cannam@167: " -e, --estimate: plan in ESTIMATE mode (not recommended)\n" cannam@167: " -x, --exhaustive: plan in EXHAUSTIVE mode (may be slow)\n" cannam@167: " -n, --no-system-wisdom: don't read /etc/fftw/ system wisdom file\n" cannam@167: " -w FILE, --wisdom-file=FILE: read wisdom from FILE (stdin if -)\n" cannam@167: #ifdef HAVE_SMP cannam@167: " -T N, --threads=N: plan with N threads\n" cannam@167: #endif cannam@167: "\nSize syntax: \n" cannam@167: " = c/r/k for complex/real(r2c,c2r)/r2r\n" cannam@167: " = i/o for in/out-of place\n" cannam@167: " = f/b for forward/backward, omitted for k transforms\n" cannam@167: " = [x[x...]], e.g. 10x12x14\n" cannam@167: " -- for k transforms, after each dimension is a :\n" cannam@167: " = f/b/h/e00/e01/e10/e11/o00/o01/o10/o11\n" cannam@167: " for R2HC/HC2R/DHT/REDFT00/.../RODFT11\n" cannam@167: , program_name); cannam@167: } cannam@167: cannam@167: /* powers of two and ten up to 2^20, for now */ cannam@167: static char canonical_sizes[][32] = { cannam@167: "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", cannam@167: "2048", "4096", "8192", "16384", "32768", "65536", "131072", cannam@167: "262144", "524288", "1048576", cannam@167: cannam@167: "10", "100", "1000", "10000", "100000", "1000000", cannam@167: cannam@167: "2x2", "4x4", "8x8", "10x10", "16x16", "32x32", "64x64", "100x100", cannam@167: "128x128", "256x256", "512x512", "1000x1000", "1024x1024", cannam@167: cannam@167: "2x2x2", "4x4x4", "8x8x8", "10x10x10", "16x16x16", "32x32x32", cannam@167: "64x64x64", "100x100x100" cannam@167: }; cannam@167: cannam@167: #define NELEM(array)(sizeof(array) / sizeof((array)[0])) cannam@167: cannam@167: int bench_main(int argc, char *argv[]) cannam@167: { cannam@167: int c; cannam@167: unsigned i; cannam@167: int impatient = 0; cannam@167: int system_wisdom = 1; cannam@167: int canonical = 0; cannam@167: double hours = 0; cannam@167: FILE *output_file; cannam@167: char *output_fname = 0; cannam@167: bench_problem **problems = 0; cannam@167: int nproblems = 0, iproblem = 0; cannam@167: time_t begin; cannam@167: cannam@167: verbose = 0; cannam@167: usewisdom = 0; cannam@167: cannam@167: bench_srand(1); cannam@167: #ifdef HAVE_SMP cannam@167: /* do not configure FFTW with threads, unless the cannam@167: user requests -T */ cannam@167: threads_ok = 0; cannam@167: #endif cannam@167: cannam@167: while ((c = my_getopt(argc, argv, options)) != -1) { cannam@167: switch (c) { cannam@167: case 'h': cannam@167: help(stdout, argv[0]); cannam@167: exit(EXIT_SUCCESS); cannam@167: break; cannam@167: cannam@167: case 'V': cannam@167: printf("fftw-wisdom tool for FFTW version " VERSION ".\n"); cannam@167: printf( cannam@167: "\n" cannam@167: "Copyright (c) 2003, 2007-14 Matteo Frigo\n" cannam@167: "Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology\n" cannam@167: "\n" cannam@167: "This program is free software; you can redistribute it and/or modify\n" cannam@167: "it under the terms of the GNU General Public License as published by\n" cannam@167: "the Free Software Foundation; either version 2 of the License, or\n" cannam@167: "(at your option) any later version.\n" cannam@167: "\n" cannam@167: "This program is distributed in the hope that it will be useful,\n" cannam@167: "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" cannam@167: "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" cannam@167: "GNU General Public License for more details.\n" cannam@167: "\n" cannam@167: "You should have received a copy of the GNU General Public License\n" cannam@167: "along with this program; if not, write to the Free Software\n" cannam@167: "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" cannam@167: ); cannam@167: exit(EXIT_SUCCESS); cannam@167: break; cannam@167: cannam@167: case 'v': cannam@167: verbose = 1; cannam@167: break; cannam@167: cannam@167: case 'c': cannam@167: canonical = 1; cannam@167: break; cannam@167: cannam@167: case 't': cannam@167: hours = atof(my_optarg); cannam@167: break; cannam@167: cannam@167: case 'o': cannam@167: if (output_fname) cannam@167: bench_free(output_fname); cannam@167: cannam@167: if (!strcmp(my_optarg, "-")) cannam@167: output_fname = 0; cannam@167: else { cannam@167: output_fname = (char *) bench_malloc(sizeof(char) * cannam@167: (strlen(my_optarg) + 1)); cannam@167: strcpy(output_fname, my_optarg); cannam@167: } cannam@167: break; cannam@167: cannam@167: case 'm': cannam@167: case 'i': cannam@167: impatient = 1; cannam@167: break; cannam@167: cannam@167: case 'e': cannam@167: the_flags |= FFTW_ESTIMATE; cannam@167: break; cannam@167: cannam@167: case 'x': cannam@167: the_flags |= FFTW_EXHAUSTIVE; cannam@167: break; cannam@167: cannam@167: case 'n': cannam@167: system_wisdom = 0; cannam@167: break; cannam@167: cannam@167: case 'w': { cannam@167: FILE *w = stdin; cannam@167: if (strcmp(my_optarg, "-") && !(w = fopen(my_optarg, "r"))) { cannam@167: fprintf(stderr, cannam@167: "fftw-wisdom: error opening \"%s\": ", my_optarg); cannam@167: perror(""); cannam@167: exit(EXIT_FAILURE); cannam@167: } cannam@167: if (!FFTW(import_wisdom_from_file)(w)) { cannam@167: fprintf(stderr, "fftw_wisdom: error reading wisdom " cannam@167: "from \"%s\"\n", my_optarg); cannam@167: exit(EXIT_FAILURE); cannam@167: } cannam@167: if (w != stdin) cannam@167: fclose(w); cannam@167: break; cannam@167: } cannam@167: cannam@167: #ifdef HAVE_SMP cannam@167: case 'T': cannam@167: nthreads = atoi(my_optarg); cannam@167: if (nthreads < 1) nthreads = 1; cannam@167: threads_ok = 1; cannam@167: BENCH_ASSERT(FFTW(init_threads)()); cannam@167: break; cannam@167: #endif cannam@167: cannam@167: case '?': cannam@167: /* `my_getopt' already printed an error message. */ cannam@167: cleanup(); cannam@167: return EXIT_FAILURE; cannam@167: cannam@167: default: cannam@167: abort (); cannam@167: } cannam@167: } cannam@167: cannam@167: if (!impatient) cannam@167: the_flags |= FFTW_PATIENT; cannam@167: cannam@167: if (system_wisdom) cannam@167: if (!FFTW(import_system_wisdom)() && verbose) cannam@167: fprintf(stderr, "fftw-wisdom: system-wisdom import failed\n"); cannam@167: cannam@167: if (canonical) { cannam@167: for (i = 0; i < NELEM(canonical_sizes); ++i) { cannam@167: unsigned j; cannam@167: char types[][8] = { cannam@167: "cof", "cob", "cif", "cib", "rof", "rob", "rif", "rib" cannam@167: }; cannam@167: cannam@167: for (j = 0; j < NELEM(types); ++j) { cannam@167: char ps[64]; cannam@167: if (!strchr(canonical_sizes[i],'x') cannam@167: || !strchr(types[j],'o')) { cannam@167: #ifdef HAVE_SNPRINTF cannam@167: snprintf(ps, sizeof(ps), "%s%s", types[j], canonical_sizes[i]); cannam@167: #else cannam@167: sprintf(ps, "%s%s", types[j], canonical_sizes[i]); cannam@167: #endif cannam@167: add_problem(ps, &problems, &iproblem, &nproblems); cannam@167: } cannam@167: } cannam@167: } cannam@167: } cannam@167: cannam@167: while (my_optind < argc) { cannam@167: if (!strcmp(argv[my_optind], "-")) { cannam@167: char s[1025]; cannam@167: while (1 == fscanf(stdin, "%1024s", s)) cannam@167: add_problem(s, &problems, &iproblem, &nproblems); cannam@167: } cannam@167: else cannam@167: add_problem(argv[my_optind], &problems, &iproblem, &nproblems); cannam@167: ++my_optind; cannam@167: } cannam@167: cannam@167: nproblems = iproblem; cannam@167: qsort(problems, nproblems, sizeof(bench_problem *), prob_size_cmp); cannam@167: cannam@167: if (!output_fname) cannam@167: output_file = stdout; cannam@167: else cannam@167: if (!(output_file = fopen(output_fname, "w"))) { cannam@167: fprintf(stderr, cannam@167: "fftw-wisdom: error creating \"%s\"", output_fname); cannam@167: perror(""); cannam@167: exit(EXIT_FAILURE); cannam@167: } cannam@167: cannam@167: begin = time((time_t*)0); cannam@167: for (iproblem = 0; iproblem < nproblems; ++iproblem) { cannam@167: if (hours <= 0 cannam@167: || hours > (time((time_t*)0) - begin) / 3600.0) cannam@167: do_problem(problems[iproblem]); cannam@167: problem_destroy(problems[iproblem]); cannam@167: cannam@167: } cannam@167: free(problems); cannam@167: cannam@167: if (verbose && hours > 0 cannam@167: && hours < (time((time_t*)0) - begin) / 3600.0) cannam@167: fprintf(stderr, "EXCEEDED TIME LIMIT OF %g HOURS.\n", hours); cannam@167: cannam@167: FFTW(export_wisdom_to_file)(output_file); cannam@167: if (output_file != stdout) cannam@167: fclose(output_file); cannam@167: if (output_fname) cannam@167: bench_free(output_fname); cannam@167: cannam@167: cleanup(); cannam@167: cannam@167: return EXIT_SUCCESS; cannam@167: }