2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * test_main.c: driver for test programs (linked with fftw_test.c/rfftw_test.c)
33 #include "test_main.h"
38 # elif defined(HAVE_UNISTD_H)
47 return (d
/ (double) RAND_MAX
) - .5;
50 /* return random 0 or non-zero */
53 return (rand() & 8192); /* higher-order bits are often more random
58 /* parse a string of the form N1xN2x... and return a size structure */
59 struct size
parse_size(char *s
)
67 if (*s
== 'x' || *s
== 'X' || *s
== '*') {
69 /* force ND transform of rank 1 */
79 n
= n
* 10 + (*s
- '0');
83 sz
.narray
[sz
.rank
] = n
;
86 CHECK(sz
.rank
< MAX_CMDLINE_RANK
,
87 "maximum rank exceeded");
89 if (*s
== 'x' || *s
== 'X' || *s
== '*') {
93 /* force ND transform if rank > 1 */
103 int wisdom_flag
, measure_flag
;
104 int speed_flag
= FFTW_MEASURE
;
107 int howmany_fields
= 1;
108 int max_iterations
= 0; /*
109 * maximum number of iterations to perform
110 * in "infinite" tests--default (0) means
114 /* When testing MPI stuff, only one process gets to do I/O: */
116 #define my_printf if (io_okay) printf
117 #define my_fprintf if (io_okay) fprintf
118 #define my_fflush if (io_okay) fflush
124 /* smart time printer */
125 char *smart_sprint_time(double x
)
127 static char buf
[128];
130 sprintf(buf
, "%f ns", x
* 1.0E9
);
132 sprintf(buf
, "%f us", x
* 1.0E6
);
134 sprintf(buf
, "%f ms", x
* 1.0E3
);
136 sprintf(buf
, "%f s", x
);
142 /* jokes stolen from http://whereis.mit.edu/bin/map */
143 void please_wait(void)
148 "(while a large software vendor in Seattle takes over the world)",
149 "(and remember, this is faster than Java)",
150 "(and dream of faster computers)",
151 "(checking the gravitational constant in your locale)",
152 "(at least you are not on hold)",
153 "(while X11 grows by another kilobyte)",
154 "(while Windows NT reboots)",
155 "(correcting for the phase of the moon)",
156 "(your call is important to us)",
157 "(while the Linux user-base doubles)",
158 "(while you decide where you want to go tomorrow)",
159 "(exorcising evil spirits)",
161 int choices
= sizeof(s
) / sizeof(*s
);
163 i
= rand() % choices
;
164 my_printf("Please wait %s.\n", s
[i
< 0 ? -i
: i
]);
167 void please_wait_forever(void)
172 "(but it won't crash, either)",
173 "(at least in theory)",
174 "(please be patient)",
175 "(our next release will complete it more quickly)",
176 #if defined(__WIN32__) || defined(WIN32) || defined(_WINDOWS)
177 "(by the way, Linux executes infinite loops faster)",
180 int choices
= sizeof(s
) / sizeof(*s
);
182 if (!max_iterations
) {
183 i
= rand() % choices
;
184 my_printf("This test does not terminate %s.\n", s
[i
< 0 ? -i
: i
]);
186 my_printf("This test will run for %d iterations.\n", max_iterations
);
191 /*************************************************
193 *************************************************/
195 double mflops(double t
, int N
)
197 return (5.0 * N
* log((double) N
) / (log(2.0) * t
* 1.0e6
));
200 void print_dims(struct size sz
)
204 my_printf("%d", sz
.narray
[0]);
205 for (i
= 1; i
< sz
.rank
; ++i
)
206 my_printf("x%d", sz
.narray
[i
]);
209 void test_speed(int n
)
215 if (howmany_fields
> 1)
216 WHEN_VERBOSE(1, my_printf("TIMING MULTIPLE-FIELD FFT: "
217 "howmany=%d, stride=%d, dist=%d\n\n",
218 howmany_fields
, howmany_fields
, 1));
220 for (specific
= 0; specific
<= 1; ++specific
) {
222 my_printf("SPEED TEST: n = %d, FFTW_FORWARD, out of place, %s\n",
223 n
, SPECIFICP(specific
)));
224 test_speed_aux(n
, FFTW_FORWARD
, 0, specific
);
227 my_printf("SPEED TEST: n = %d, FFTW_FORWARD, in place, %s\n",
228 n
, SPECIFICP(specific
)));
229 test_speed_aux(n
, FFTW_FORWARD
, FFTW_IN_PLACE
, specific
);
232 my_printf("SPEED TEST: n = %d, FFTW_BACKWARD, out of place, %s\n",
233 n
, SPECIFICP(specific
)));
234 test_speed_aux(n
, FFTW_BACKWARD
, 0, specific
);
237 my_printf("SPEED TEST: n = %d, FFTW_BACKWARD, in place, %s\n",
238 n
, SPECIFICP(specific
)));
239 test_speed_aux(n
, FFTW_BACKWARD
, FFTW_IN_PLACE
, specific
);
243 void test_speed_nd(struct size sz
)
249 if (howmany_fields
> 1)
250 WHEN_VERBOSE(1, my_printf("TIMING MULTIPLE-FIELD FFT: "
251 "howmany=%d, stride=%d, dist=%d\n\n",
252 howmany_fields
, howmany_fields
, 1));
254 for (specific
= 0; specific
<= 1; ++specific
) {
255 my_printf("SPEED TEST: ");
256 WHEN_VERBOSE(1, print_dims(sz
));
257 WHEN_VERBOSE(1, my_printf(", FFTW_FORWARD, in place, %s\n",
258 SPECIFICP(specific
)));
259 test_speed_nd_aux(sz
, FFTW_FORWARD
,
260 FFTW_IN_PLACE
, specific
);
262 WHEN_VERBOSE(1, my_printf("SPEED TEST: "));
264 WHEN_VERBOSE(1, my_printf(", FFTW_BACKWARD, in place, %s\n",
265 SPECIFICP(specific
)));
266 test_speed_nd_aux(sz
, FFTW_BACKWARD
, FFTW_IN_PLACE
, specific
);
270 /*************************************************
272 *************************************************/
274 double compute_error_complex(fftw_complex
* A
, int astride
,
275 fftw_complex
* B
, int bstride
, int n
)
277 /* compute the relative error */
281 for (i
= 0; i
< n
; ++i
) {
284 a
= sqrt(SQR(c_re(A
[i
* astride
]) - c_re(B
[i
* bstride
])) +
285 SQR(c_im(A
[i
* astride
]) - c_im(B
[i
* bstride
])));
286 mag
= 0.5 * (sqrt(SQR(c_re(A
[i
* astride
]))
287 + SQR(c_im(A
[i
* astride
]))) +
288 sqrt(SQR(c_re(B
[i
* bstride
]))
289 + SQR(c_im(B
[i
* bstride
])))) + TOLERANCE
;
296 CHECK(!isnan(a
), "NaN in answer");
307 please_wait_forever();
308 for (n
= 1; !max_iterations
|| n
<= max_iterations
; ++n
) {
310 if (!(wisdom_flag
& FFTW_USE_WISDOM
) && chk_mem_leak
)
311 fftw_check_memory_leaks();
315 #define MAX_FACTOR 13
317 int rand_small_factors(int N
)
321 f
= rand() % MAX_FACTOR
+ 1;
325 f
= rand() % MAX_FACTOR
+ 1;
333 struct size
random_dims(int rank
)
339 /* workaround to weird gcc warning */
340 maxsize_d
= pow((double) (rank
== 1 ? MAX_N
/ 4 : MAX_N
),
341 1.0 / (double) rank
);
342 maxsize
= (int) maxsize_d
;
348 for (dim
= 0; dim
< rank
; ++dim
)
349 sz
.narray
[dim
] = rand_small_factors(maxsize
);
354 void test_random(void)
356 static int counter
= 0;
359 if ((++counter
) % 16 == 0) {
361 sz
.narray
[0] = rand() % (MAX_N
/ 16) + 1;
366 test_correctness(sz
.narray
[0]);
369 /*************************************************
370 * multi-dimensional correctness tests
371 *************************************************/
373 void testnd_correctness_both(struct size sz
,
374 int alt_api
, int specific
, int force_buf
)
377 my_printf("Testing nd correctness for size = ");
383 WHEN_VERBOSE(1, my_printf("alt. api..."));
385 WHEN_VERBOSE(1, my_printf("specific..."));
387 WHEN_VERBOSE(1, my_printf("force buf..."));
389 testnd_correctness(sz
, FFTW_FORWARD
, alt_api
, specific
, force_buf
);
390 testnd_correctness(sz
, FFTW_BACKWARD
, alt_api
, specific
, force_buf
);
392 WHEN_VERBOSE(1, my_printf("OK\n"));
395 void testnd_correctness_aux(struct size sz
)
397 int alt_api
, specific
, force_buf
;
399 for (alt_api
= 0; alt_api
<= 1; ++alt_api
)
400 for (specific
= 0; specific
<= 1; ++specific
)
401 for (force_buf
= 0; force_buf
<= 1; ++force_buf
)
402 testnd_correctness_both(sz
, alt_api
, specific
,
406 void testnd_correctness_square(int rank
, int size
)
409 int alt_api
, specific
, force_buf
;
413 for (i
= 0; i
< rank
; ++i
)
416 for (alt_api
= 0; alt_api
<= 1; ++alt_api
)
417 for (specific
= 0; specific
<= 1; ++specific
)
418 for (force_buf
= 0; force_buf
<= 1; ++force_buf
)
419 testnd_correctness_both(sz
, alt_api
,
420 specific
, force_buf
);
424 void testnd_random(int rank
)
428 sz
= random_dims(rank
);
429 testnd_correctness_both(sz
, coinflip(), coinflip(), coinflip());
433 void test_all_random(int rank
)
436 please_wait_forever();
438 for (counter
= 0; !max_iterations
|| counter
< max_iterations
; ++counter
) {
441 else if ((counter
) % 2 == 0)
444 testnd_random(rand() % MAX_RANK
+ 1);
450 /* return greatest power of two <= sqrt(n) */
454 while (s
* s
* 4 <= n
)
460 void testnd_all(int rank
)
464 please_wait_forever();
466 for (n
= 1; !max_iterations
|| n
<= max_iterations
; ++n
)
467 testnd_correctness_square(rank
, n
);
470 fftw_direction
random_dir(void)
475 return FFTW_BACKWARD
;
478 /*************************************************
480 *************************************************/
482 static int hack_sum_i
;
484 void negative_time(void)
487 "* PROBLEM: I measured a negative time interval.\n"
488 "* Please make sure you defined the timer correctly\n"
489 "* or contact fftw@theory.lcs.mit.edu for help.\n");
493 * paranoid test to see if time is monotonic. If not, you are
496 void test_timer_paranoid(void)
498 fftw_time start_t
, end_t
;
502 start_t
= fftw_get_time();
504 /* waste some time */
505 for (i
= 0; i
< 10000; ++i
)
508 end_t
= fftw_get_time();
509 sec
= fftw_time_to_sec(fftw_time_diff(end_t
, start_t
));
514 /* compute useful numbers */
515 static int fib(int n
)
529 void test_timer(void)
531 double times
[32], acc
, min_time
= 10000.00;
532 unsigned long iters
, iter
;
533 fftw_time begin
, end
, start
;
534 double t
, tmax
, tmin
;
535 int last
= 0, i
, repeat
;
538 test_timer_paranoid();
540 start
= fftw_get_time();
542 for (i
= 0; i
< 32; i
++) {
547 for (repeat
= 0; repeat
< FFTW_TIME_REPEAT
; ++repeat
) {
548 begin
= fftw_get_time();
549 for (iter
= 0; iter
< iters
; ++iter
) {
552 end
= fftw_get_time();
554 t
= fftw_time_to_sec(fftw_time_diff(end
, begin
));
560 /* do not run for too long */
561 t
= fftw_time_to_sec(fftw_time_diff(end
, start
));
562 if (t
> FFTW_TIME_LIMIT
)
572 my_printf("Number of iterations = 2^%d = %lu, time = %g, "
577 my_printf(" (out of %d tries, tmin = %g, tmax = %g)\n",
578 FFTW_TIME_REPEAT
, tmin
, tmax
));
586 * at this point, `last' is the last valid element in the
590 for (i
= 0; i
<= last
; ++i
)
591 if (times
[i
] > 0.0 && times
[i
] < min_time
)
594 WHEN_VERBOSE(1, my_printf("\nMinimum resolvable time interval = %g seconds.\n\n",
597 for (acc
= 0.1; acc
> 0.0005; acc
*= 0.1) {
599 t_final
= times
[last
] / (1 << last
);
601 for (i
= last
; i
>= 0; --i
) {
604 t_cur
= times
[i
] / iters
;
605 error
= (t_cur
- t_final
) / t_final
;
615 my_printf("Minimum time for %g%% consistency = %g seconds.\n",
616 acc
* 100.0, times
[i
]));
619 my_printf("\nMinimum time used in FFTW timing (FFTW_TIME_MIN)"
620 " = %g seconds.\n", FFTW_TIME_MIN
));
623 /*************************************************
625 *************************************************/
627 #ifdef HAVE_GETOPT_LONG
628 # define WHEN_LONG_OPTIONS(x) x
630 # define WHEN_LONG_OPTIONS(x) ""
633 static void usage(int exit_when_done
)
635 my_printf("Usage: %s_test [options]\n", fftw_prefix
);
636 my_printf(WHEN_LONG_OPTIONS(" --speed=<n>\n")
637 " -s <n> : test speed for size n\n");
638 my_printf(WHEN_LONG_OPTIONS("\n --correctness=<n>\n")
639 " -c <n> : test correctness for size n\n");
640 my_printf(WHEN_LONG_OPTIONS("\n --random=<rank>>\n")
641 " -r <rank> : test correctness for random sizes "
642 "(does not terminate)\n");
643 my_printf(WHEN_LONG_OPTIONS("\n --all=<rank>\n")
644 " -a <rank> : test correctness for all sizes "
645 "(does not terminate)\n");
646 my_printf(WHEN_LONG_OPTIONS("\n --fields=<n>\n")
647 " -f <n> : n fields ('howmany' param) in speed tests\n");
648 my_printf(WHEN_LONG_OPTIONS("\n --planner=<rank>\n")
649 " -p <rank> : test planner\n");
650 my_printf(WHEN_LONG_OPTIONS("\n --measure\n")
651 " -m : use FFTW_MEASURE in correctness tests\n");
652 my_printf(WHEN_LONG_OPTIONS("\n --estimate\n")
653 " -e : use FFTW_ESTIMATE in speed tests\n");
654 my_printf(WHEN_LONG_OPTIONS("\n --wisdom=<file>\n")
655 " -w <file> : use wisdom & read/write it from/to file\n");
656 my_printf(WHEN_LONG_OPTIONS("\n --timer\n")
657 " -t : test timer resolution\n");
658 my_printf(WHEN_LONG_OPTIONS("\n --x-repeat=<n>\n")
659 " -x <n> : run non-terminating tests (-r, -a) only n times\n");
660 my_printf(WHEN_LONG_OPTIONS("\n --paranoid\n")
661 " -P : enable paranoid tests\n");
662 my_printf(WHEN_LONG_OPTIONS("\n --verbose\n")
663 " -v : verbose output for subsequent options\n");
664 my_printf(WHEN_LONG_OPTIONS("\n --version\n")
665 " -V : print FFTW version information\n");
666 my_printf(WHEN_LONG_OPTIONS("\n --help\n")
667 " -h : this help\n");
669 my_printf("(When run with no arguments, an interactive mode is used.)\n");
677 void handle_option(char opt
, char *optarg
)
685 sz
= parse_size(optarg
);
687 test_speed(sz
.narray
[0]);
693 sz
= parse_size(optarg
);
695 test_correctness(sz
.narray
[0]);
697 testnd_correctness_aux(sz
);
707 enter_paranoid_mode();
712 test_all_random(rank
);
729 CHECK(n
> 0, "-f requires a positive integer argument");
734 measure_flag
= FFTW_MEASURE
;
738 speed_flag
= FFTW_ESTIMATE
;
742 wisdom_flag
= FFTW_USE_WISDOM
;
743 strcpy(wfname
, optarg
);
744 wf
= fopen(wfname
, "r");
746 my_printf("Couldn't open wisdom file \"%s\".\n", wfname
);
747 my_printf("This file will be created upon completion.\n");
749 CHECK(FFTW_SUCCESS
== fftw_import_wisdom_from_file(wf
),
750 "invalid wisdom file format");
760 my_printf("%s\n", fftw_version
);
761 my_printf("%s test program, compiled in %s precision.\n",
763 sizeof(fftw_real
) == sizeof(double) ? "double"
764 : (sizeof(fftw_real
) == sizeof(float) ? "single"
767 "\nCopyright (C) Massachusetts Institute of Technology.\n"
768 "FFTW comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
769 "you are welcome to redistribute it under the terms of the GNU\n"
770 "General Public License. For more information, see the file COPYING or\n"
771 "the GNU web site at http://www.gnu.org.\n"
772 "\nFor more information regarding FFTW, or to download the latest version,\n"
773 "see the FFTW home page at http://theory.lcs.mit.edu/~fftw.\n");
779 CHECK(n
> 0, "-x requires a positive integer argument");
791 /* every test must free all the used FFTW memory */
792 if (!(wisdom_flag
& FFTW_USE_WISDOM
) && chk_mem_leak
)
793 fftw_check_memory_leaks();
798 short askuser(const char *s
)
800 char line
[200] = "", c
;
805 my_printf("Invalid response. Please enter \"y\" or \"n\".\n");
806 my_printf("%s (y/n) ", s
);
807 /* skip blank lines */
808 while (line
[0] == 0 || line
[0] == '\n')
809 fgets(line
, 200, stdin
);
810 for (i
= 0; line
[i
] && (line
[i
] == ' ' || line
[i
] == '\t'); ++i
);
812 } while (c
!= 'n' && c
!= 'N' && c
!= 'y' && c
!= 'Y');
814 return (c
== 'y' || c
== 'Y');
817 /* Standard function to get the next command-line argument for the program.
818 Returns the option character (or -1 if there are no more options),
819 and the option argument (if any) in argval, which is an array of length
820 at least argval_maxlen.
822 The test programs need to implement a function get_option with the
823 same arguments as this one, which will typically just call
826 The reason we need to put this in a separate function is that the MPI
827 test programs can't rely on all of the processes having direct access
828 to the program arguments--they need to pass them as explicit messages
829 from the master process. Sigh. */
830 int default_get_option(int argc
, char **argv
, char *argval
, int argval_maxlen
)
839 const char short_options
[] = "s:c:w:f:p:Pa:r:tvVmehx:";
843 # if defined(HAVE_GETOPT_LONG) && defined(HAVE_GETOPT_H)
846 const struct option long_options
[] = {
847 {"speed", 1, 0, 's'},
848 {"correctness", 1, 0, 'c'},
849 {"wisdom", 1, 0, 'w'},
850 {"fields", 1, 0, 'f'},
851 {"planner", 1, 0, 'p'},
852 {"paranoid", 0, 0, 'P'},
854 {"random", 1, 0, 'r'},
855 {"timer", 0, 0, 't'},
856 {"verbose", 0, 0, 'v'},
857 {"version", 0, 0, 'V'},
858 {"measure", 0, 0, 'm'},
859 {"estimate", 0, 0, 'e'},
861 {"x-repeat", 1, 0, 'x'},
865 c
= getopt_long(argc
, argv
, short_options
, long_options
,
868 # else /* not HAVE_GETOPT_LONG */
869 c
= getopt(argc
, argv
, short_options
);
870 # endif /* not HAVE_GETOPT_LONG */
872 if (c
== -1 && argc
!= optind
)
873 usage(TRUE
); /* there were invalid args; print usage info */
876 strncpy(argval
, optarg
, argval_maxlen
- 1);
877 argval
[argval_maxlen
- 1] = 0;
882 #endif /* HAVE_GETOPT */
887 int main(int argc
, char *argv
[])
891 measure_flag
= FFTW_ESTIMATE
;
898 srand((unsigned int) time(NULL
));
901 test_init(&argc
, argv
);
904 * To parse the command line, we use getopt, but this does not seem
905 * to be in the ANSI standard (it is only available on UNIX,
910 my_printf("Sorry, command-line arguments are not available on\n"
911 "this system. Run fftw_test with no arguments to\n"
912 "use it in interactive mode.\n");
922 if (askuser("Perform random correctness tests (non-terminating)?"))
923 handle_option('r', "0");
925 if (askuser("Verbose output?"))
926 handle_option('v', "");
927 if (askuser("Paranoid test?"))
928 handle_option('P', "");
930 if (askuser("Use/test wisdom?")) {
931 my_printf(" Enter wisdom file name to use: ");
932 fgets(s
, 128, stdin
);
933 handle_option('w', s
);
935 if (askuser("Test correctness?")) {
936 if (askuser(" -- for all sizes?"))
937 handle_option('a', "");
939 my_printf(" Enter n: ");
940 fgets(s
, 128, stdin
);
941 handle_option('c', s
);
944 if (askuser("Test speed?")) {
945 my_printf(" Enter n: ");
946 fgets(s
, 128, stdin
);
947 handle_option('s', s
);
949 if (askuser("Test planner?"))
950 handle_option('p', "");
951 if (askuser("Test timer?"))
952 handle_option('t', "");
955 * read command-line args using getopt
959 char option_arg
[128];
962 while ((c
= get_option(argc
, argv
, option_arg
, 128)) != -1)
963 handle_option(c
, option_arg
);
967 if (wisdom_flag
& FFTW_USE_WISDOM
) {
971 ws
= fftw_export_wisdom_to_string();
972 CHECK(ws
!= 0, "error exporting wisdom to string");
973 my_printf("\nAccumulated wisdom:\n %s\n", ws
);
974 fftw_forget_wisdom();
975 CHECK(FFTW_SUCCESS
== fftw_import_wisdom_from_string(ws
),
976 "unexpected error reading in wisdom from string");
980 wf
= fopen(wfname
, "w");
981 CHECK(wf
!= 0, "error creating wisdom file");
982 fftw_export_wisdom_to_file(wf
);
986 /* make sure to dispose of wisdom before checking for memory leaks */
987 fftw_forget_wisdom();
989 fftw_check_memory_leaks();
991 fftw_print_max_memory_usage();