Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/*
2
 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
3
 *
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.
8
 *
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.
13
 *
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
17
 *
18
 */
19
 
20
/*
21
 * test_main.c: driver for test programs (linked with fftw_test.c/rfftw_test.c)
22
 */
23
 
24
/* $Id: test_mai.c,v 1.1.1.1 2002-03-29 14:12:59 pj Exp $ */
25
#include <fftw-int.h>
26
#include <stdlib.h>
27
#include <stdio.h>
28
#include <string.h>
29
#include <math.h>
30
#include <time.h>
31
#include <ctype.h>
32
 
33
#include "test_main.h"
34
 
35
#ifdef HAVE_GETOPT
36
#  ifdef HAVE_GETOPT_H
37
#    include <getopt.h>
38
#  elif defined(HAVE_UNISTD_H)
39
#    include <unistd.h>
40
#  endif
41
#endif
42
 
43
double mydrand(void)
44
{
45
     double d = rand();
46
     return (d / (double) RAND_MAX) - .5;
47
}
48
 
49
/* return random 0 or non-zero */
50
int coinflip(void)
51
{
52
     return (rand() & 8192);    /* higher-order bits are often more random
53
                                 *
54
                                 */
55
}
56
 
57
/* parse a string of the form N1xN2x... and return a size structure */
58
struct size parse_size(char *s)
59
{
60
     struct size sz;
61
     int n;
62
 
63
     sz.rank = 0;
64
     sz.is_nd = 0;
65
 
66
     if (*s == 'x' || *s == 'X' || *s == '*') {
67
          ++s;
68
          /* force ND transform of rank 1 */
69
          sz.is_nd = 1;
70
     }
71
   accept_digit:
72
     n = 0;
73
 
74
     CHECK(isdigit(*s),
75
           "invalid digit");
76
 
77
     while (isdigit(*s)) {
78
          n = n * 10 + (*s - '0');
79
          ++s;
80
     }
81
 
82
     sz.narray[sz.rank] = n;
83
     ++sz.rank;
84
 
85
     CHECK(sz.rank < MAX_CMDLINE_RANK,
86
           "maximum rank exceeded");
87
 
88
     if (*s == 'x' || *s == 'X' || *s == '*') {
89
          ++s;
90
          goto accept_digit;
91
     }
92
     /* force ND transform if rank > 1 */
93
     if (sz.rank > 1)
94
          sz.is_nd = 1;
95
     return sz;
96
}
97
 
98
/*******************
99
 * global variables
100
 *******************/
101
int verbose;
102
int wisdom_flag, measure_flag;
103
int speed_flag = FFTW_MEASURE;
104
int chk_mem_leak;
105
int paranoid;
106
int howmany_fields = 1;
107
int max_iterations = 0;         /*
108
                                 * maximum number of iterations to perform
109
                                 * in "infinite" tests--default (0) means
110
                                 * no limit
111
                                 */
112
 
113
/* When testing MPI stuff, only one process gets to do I/O: */
114
int io_okay = 1;
115
#define my_printf if (io_okay) printf
116
#define my_fprintf if (io_okay) fprintf
117
#define my_fflush if (io_okay) fflush
118
 
119
/*******************
120
 * procedures
121
 *******************/
122
 
123
/* smart time printer */
124
char *smart_sprint_time(double x)
125
{
126
     static char buf[128];
127
 
128
     if (x < 1.0E-6)
129
          sprintf(buf, "%f ns", x * 1.0E9);
130
     else if (x < 1.0E-3)
131
          sprintf(buf, "%f us", x * 1.0E6);
132
     else if (x < 1.0)
133
          sprintf(buf, "%f ms", x * 1.0E3);
134
     else
135
          sprintf(buf, "%f s", x);
136
 
137
     return buf;
138
}
139
 
140
/* greet the user */
141
/* jokes stolen from http://whereis.mit.edu/bin/map */
142
void please_wait(void)
143
{
144
     int i;
145
     const char *s[] =
146
     {
147
       "(while a large software vendor in Seattle takes over the world)",
148
       "(and remember, this is faster than Java)",
149
       "(and dream of faster computers)",
150
       "(checking the gravitational constant in your locale)",
151
       "(at least you are not on hold)",
152
       "(while X11 grows by another kilobyte)",
153
       "(while Windows NT reboots)",
154
       "(correcting for the phase of the moon)",
155
       "(your call is important to us)",
156
       "(while the Linux user-base doubles)",
157
       "(while you decide where you want to go tomorrow)",
158
       "(exorcising evil spirits)",
159
     };
160
     int choices = sizeof(s) / sizeof(*s);
161
 
162
     i = rand() % choices;
163
     my_printf("Please wait %s.\n", s[i < 0 ? -i : i]);
164
}
165
 
166
void please_wait_forever(void)
167
{
168
     int i;
169
     const char *s[] =
170
     {
171
          "(but it won't crash, either)",
172
          "(at least in theory)",
173
          "(please be patient)",
174
          "(our next release will complete it more quickly)",
175
#if defined(__WIN32__) || defined(WIN32) || defined(_WINDOWS)
176
          "(by the way, Linux executes infinite loops faster)",
177
#endif
178
     };
179
     int choices = sizeof(s) / sizeof(*s);
180
 
181
     if (!max_iterations) {
182
          i = rand() % choices;
183
          my_printf("This test does not terminate %s.\n", s[i < 0 ? -i : i]);
184
     } else {
185
          my_printf("This test will run for %d iterations.\n", max_iterations);
186
          please_wait();
187
     }
188
}
189
 
190
/*************************************************
191
 * Speed tests
192
 *************************************************/
193
 
194
double mflops(double t, int N)
195
{
196
     return (5.0 * N * log((double) N) / (log(2.0) * t * 1.0e6));
197
}
198
 
199
void print_dims(struct size sz)
200
{
201
     int i;
202
 
203
     my_printf("%d", sz.narray[0]);
204
     for (i = 1; i < sz.rank; ++i)
205
          my_printf("x%d", sz.narray[i]);
206
}
207
 
208
void test_speed(int n)
209
{
210
     int specific;
211
 
212
     please_wait();
213
 
214
     if (howmany_fields > 1)
215
          WHEN_VERBOSE(1, my_printf("TIMING MULTIPLE-FIELD FFT: "
216
                                 "howmany=%d, stride=%d, dist=%d\n\n",
217
                                 howmany_fields, howmany_fields, 1));
218
 
219
     for (specific = 0; specific <= 1; ++specific) {
220
          WHEN_VERBOSE(1,
221
           my_printf("SPEED TEST: n = %d, FFTW_FORWARD, out of place, %s\n",
222
                  n, SPECIFICP(specific)));
223
          test_speed_aux(n, FFTW_FORWARD, 0, specific);
224
 
225
          WHEN_VERBOSE(1,
226
               my_printf("SPEED TEST: n = %d, FFTW_FORWARD, in place, %s\n",
227
                      n, SPECIFICP(specific)));
228
          test_speed_aux(n, FFTW_FORWARD, FFTW_IN_PLACE, specific);
229
 
230
          WHEN_VERBOSE(1,
231
          my_printf("SPEED TEST: n = %d, FFTW_BACKWARD, out of place, %s\n",
232
                 n, SPECIFICP(specific)));
233
          test_speed_aux(n, FFTW_BACKWARD, 0, specific);
234
 
235
          WHEN_VERBOSE(1,
236
              my_printf("SPEED TEST: n = %d, FFTW_BACKWARD, in place, %s\n",
237
                     n, SPECIFICP(specific)));
238
          test_speed_aux(n, FFTW_BACKWARD, FFTW_IN_PLACE, specific);
239
     }
240
}
241
 
242
void test_speed_nd(struct size sz)
243
{
244
     int specific;
245
 
246
     please_wait();
247
 
248
     if (howmany_fields > 1)
249
          WHEN_VERBOSE(1, my_printf("TIMING MULTIPLE-FIELD FFT: "
250
                                 "howmany=%d, stride=%d, dist=%d\n\n",
251
                                 howmany_fields, howmany_fields, 1));
252
 
253
     for (specific = 0; specific <= 1; ++specific) {
254
          my_printf("SPEED TEST: ");
255
          WHEN_VERBOSE(1, print_dims(sz));
256
          WHEN_VERBOSE(1, my_printf(", FFTW_FORWARD, in place, %s\n",
257
                                 SPECIFICP(specific)));
258
          test_speed_nd_aux(sz, FFTW_FORWARD,
259
                            FFTW_IN_PLACE, specific);
260
 
261
          WHEN_VERBOSE(1, my_printf("SPEED TEST: "));
262
          print_dims(sz);
263
          WHEN_VERBOSE(1, my_printf(", FFTW_BACKWARD, in place, %s\n",
264
                                 SPECIFICP(specific)));
265
          test_speed_nd_aux(sz, FFTW_BACKWARD, FFTW_IN_PLACE, specific);
266
     }
267
}
268
 
269
/*************************************************
270
 * correctness tests
271
 *************************************************/
272
 
273
double compute_error_complex(fftw_complex * A, int astride,
274
                             fftw_complex * B, int bstride, int n)
275
{
276
     /* compute the relative error */
277
     double error = 0.0;
278
     int i;
279
 
280
     for (i = 0; i < n; ++i) {
281
          double a;
282
          double mag;
283
          a = sqrt(SQR(c_re(A[i * astride]) - c_re(B[i * bstride])) +
284
                   SQR(c_im(A[i * astride]) - c_im(B[i * bstride])));
285
          mag = 0.5 * (sqrt(SQR(c_re(A[i * astride]))
286
                            + SQR(c_im(A[i * astride]))) +
287
                       sqrt(SQR(c_re(B[i * bstride]))
288
                            + SQR(c_im(B[i * bstride])))) + TOLERANCE;
289
 
290
          a /= mag;
291
          if (a > error)
292
               error = a;
293
 
294
#ifdef HAVE_ISNAN
295
          CHECK(!isnan(a), "NaN in answer");
296
#endif
297
     }
298
     return error;
299
}
300
 
301
/* test forever */
302
void test_all(void)
303
{
304
     int n;
305
 
306
     please_wait_forever();
307
     for (n = 1; !max_iterations || n <= max_iterations; ++n) {
308
          test_correctness(n);
309
          if (!(wisdom_flag & FFTW_USE_WISDOM) && chk_mem_leak)
310
               fftw_check_memory_leaks();
311
     }
312
}
313
 
314
#define MAX_FACTOR 13
315
 
316
int rand_small_factors(int N)
317
{
318
     int f, n = 1;
319
 
320
     f = rand() % MAX_FACTOR + 1;
321
 
322
     while (n * f <= N) {
323
          n *= f;
324
          f = rand() % MAX_FACTOR + 1;
325
     }
326
 
327
     return n;
328
}
329
 
330
#define MAX_N 16384
331
 
332
struct size random_dims(int rank)
333
{
334
     int maxsize, dim;
335
     double maxsize_d;
336
     struct size sz;
337
 
338
     /* workaround to weird gcc warning */
339
     maxsize_d = pow((double) (rank == 1 ? MAX_N / 4 : MAX_N),
340
                     1.0 / (double) rank);
341
     maxsize = (int) maxsize_d;
342
 
343
     if (maxsize < 1)
344
          maxsize = 1;
345
 
346
     sz.rank = rank;
347
     for (dim = 0; dim < rank; ++dim)
348
          sz.narray[dim] = rand_small_factors(maxsize);
349
 
350
     return sz;
351
}
352
 
353
void test_random(void)
354
{
355
     static int counter = 0;
356
     struct size sz;
357
 
358
     if ((++counter) % 16 == 0) {
359
          sz.rank = 1;
360
          sz.narray[0] = rand() % (MAX_N / 16) + 1;
361
     } else {
362
          sz = random_dims(1);
363
     }
364
 
365
     test_correctness(sz.narray[0]);
366
}
367
 
368
/*************************************************
369
 * multi-dimensional correctness tests
370
 *************************************************/
371
 
372
void testnd_correctness_both(struct size sz,
373
                             int alt_api, int specific, int force_buf)
374
{
375
     WHEN_VERBOSE(1,
376
                  my_printf("Testing nd correctness for size = ");
377
                  print_dims(sz);
378
                  my_printf("...");
379
                  my_fflush(stdout));
380
 
381
     if (alt_api)
382
          WHEN_VERBOSE(1, my_printf("alt. api..."));
383
     if (specific)
384
          WHEN_VERBOSE(1, my_printf("specific..."));
385
     if (force_buf)
386
          WHEN_VERBOSE(1, my_printf("force buf..."));
387
 
388
     testnd_correctness(sz, FFTW_FORWARD, alt_api, specific, force_buf);
389
     testnd_correctness(sz, FFTW_BACKWARD, alt_api, specific, force_buf);
390
 
391
     WHEN_VERBOSE(1, my_printf("OK\n"));
392
}
393
 
394
void testnd_correctness_aux(struct size sz)
395
{
396
     int alt_api, specific, force_buf;
397
 
398
     for (alt_api = 0; alt_api <= 1; ++alt_api)
399
          for (specific = 0; specific <= 1; ++specific)
400
               for (force_buf = 0; force_buf <= 1; ++force_buf)
401
                    testnd_correctness_both(sz, alt_api, specific,
402
                                            force_buf);
403
}
404
 
405
void testnd_correctness_square(int rank, int size)
406
{
407
     struct size sz;
408
     int alt_api, specific, force_buf;
409
     int i;
410
 
411
     sz.rank = rank;
412
     for (i = 0; i < rank; ++i)
413
          sz.narray[i] = size;
414
 
415
     for (alt_api = 0; alt_api <= 1; ++alt_api)
416
          for (specific = 0; specific <= 1; ++specific)
417
               for (force_buf = 0; force_buf <= 1; ++force_buf)
418
                    testnd_correctness_both(sz, alt_api,
419
                                            specific, force_buf);
420
 
421
}
422
 
423
void testnd_random(int rank)
424
{
425
     struct size sz;
426
 
427
     sz = random_dims(rank);
428
     testnd_correctness_both(sz, coinflip(), coinflip(), coinflip());
429
}
430
 
431
/* loop forever */
432
void test_all_random(int rank)
433
{
434
     int counter;
435
     please_wait_forever();
436
 
437
     for (counter = 0; !max_iterations || counter < max_iterations; ++counter) {
438
          if (rank > 0)
439
               testnd_random(rank);
440
          else if ((counter) % 2 == 0)
441
               test_random();
442
          else
443
               testnd_random(rand() % MAX_RANK + 1);
444
     }
445
 
446
}
447
 
448
int pow2sqrt(int n)
449
/* return greatest power of two <= sqrt(n) */
450
{
451
     int s = 1;
452
 
453
     while (s * s * 4 <= n)
454
          s *= 2;
455
     return s;
456
}
457
 
458
/* test forever */
459
void testnd_all(int rank)
460
{
461
     int n;
462
 
463
     please_wait_forever();
464
 
465
     for (n = 1; !max_iterations || n <= max_iterations; ++n)
466
          testnd_correctness_square(rank, n);
467
}
468
 
469
fftw_direction random_dir(void)
470
{
471
     if (coinflip())
472
          return FFTW_FORWARD;
473
     else
474
          return FFTW_BACKWARD;
475
}
476
 
477
/*************************************************
478
 * timer tests
479
 *************************************************/
480
 
481
static int hack_sum_i;
482
 
483
void negative_time(void)
484
{
485
     my_fprintf(stderr,
486
             "* PROBLEM: I measured a negative time interval.\n"
487
             "* Please make sure you defined the timer correctly\n"
488
             "* or contact fftw@theory.lcs.mit.edu for help.\n");
489
}
490
 
491
/*
492
 * paranoid test to see if time is monotonic.  If not, you are
493
 * really in trouble
494
 */
495
void test_timer_paranoid(void)
496
{
497
     fftw_time start_t, end_t;
498
     double sec;
499
     int i;
500
 
501
     start_t = fftw_get_time();
502
 
503
     /* waste some time */
504
     for (i = 0; i < 10000; ++i)
505
          hack_sum_i = i;
506
 
507
     end_t = fftw_get_time();
508
     sec = fftw_time_to_sec(fftw_time_diff(end_t, start_t));
509
     if (sec < 0.0)
510
          negative_time();
511
}
512
 
513
/* compute useful numbers */
514
static int fib(int n)
515
{
516
     if (n < 2)
517
          return n;
518
     else {
519
          int x, y;
520
          x = fib(n - 1);
521
          y = fib(n - 2);
522
          return x + y;
523
     }
524
}
525
 
526
static int hack_fib;
527
 
528
void test_timer(void)
529
{
530
     double times[32], acc, min_time = 10000.00;
531
     unsigned long iters, iter;
532
     fftw_time begin, end, start;
533
     double t, tmax, tmin;
534
     int last = 0, i, repeat;
535
 
536
     please_wait();
537
     test_timer_paranoid();
538
 
539
     start = fftw_get_time();
540
 
541
     for (i = 0; i < 32; i++) {
542
          iters = 1 << i;
543
          tmin = 1.0E10;
544
          tmax = -1.0E10;
545
 
546
          for (repeat = 0; repeat < FFTW_TIME_REPEAT; ++repeat) {
547
               begin = fftw_get_time();
548
               for (iter = 0; iter < iters; ++iter) {
549
                    hack_fib = fib(10);
550
               }
551
               end = fftw_get_time();
552
 
553
               t = fftw_time_to_sec(fftw_time_diff(end, begin));
554
               if (t < tmin)
555
                    tmin = t;
556
               if (t > tmax)
557
                    tmax = t;
558
 
559
               /* do not run for too long */
560
               t = fftw_time_to_sec(fftw_time_diff(end, start));
561
               if (t > FFTW_TIME_LIMIT)
562
                    break;
563
          }
564
 
565
          if (tmin < 0.0)
566
               negative_time();
567
 
568
          times[i] = tmin;
569
 
570
          WHEN_VERBOSE(2,
571
                  my_printf("Number of iterations = 2^%d = %lu, time = %g, "
572
                         "time/iter = %g\n",
573
                         i, iters, times[i],
574
                         times[i] / iters));
575
          WHEN_VERBOSE(2,
576
                   my_printf("   (out of %d tries, tmin = %g, tmax = %g)\n",
577
                          FFTW_TIME_REPEAT, tmin, tmax));
578
 
579
          last = i;
580
          if (times[i] > 10.0)
581
               break;
582
     }
583
 
584
     /*
585
      * at this point, `last' is the last valid element in the
586
      * `times' array.
587
      */
588
 
589
     for (i = 0; i <= last; ++i)
590
          if (times[i] > 0.0 && times[i] < min_time)
591
               min_time = times[i];
592
 
593
     WHEN_VERBOSE(1, my_printf("\nMinimum resolvable time interval = %g seconds.\n\n",
594
                            min_time));
595
 
596
     for (acc = 0.1; acc > 0.0005; acc *= 0.1) {
597
          double t_final;
598
          t_final = times[last] / (1 << last);
599
 
600
          for (i = last; i >= 0; --i) {
601
               double t_cur, error;
602
               iters = 1 << i;
603
               t_cur = times[i] / iters;
604
               error = (t_cur - t_final) / t_final;
605
               if (error < 0.0)
606
                    error = -error;
607
               if (error > acc)
608
                    break;
609
          }
610
 
611
          ++i;
612
 
613
          WHEN_VERBOSE(1,
614
              my_printf("Minimum time for %g%% consistency = %g seconds.\n",
615
                     acc * 100.0, times[i]));
616
     }
617
     WHEN_VERBOSE(1,
618
              my_printf("\nMinimum time used in FFTW timing (FFTW_TIME_MIN)"
619
                     " = %g seconds.\n", FFTW_TIME_MIN));
620
}
621
 
622
/*************************************************
623
 * help
624
 *************************************************/
625
 
626
#ifdef HAVE_GETOPT_LONG
627
#  define WHEN_LONG_OPTIONS(x) x
628
#else
629
#  define WHEN_LONG_OPTIONS(x) ""
630
#endif
631
 
632
static void usage(int exit_when_done)
633
{
634
     my_printf("Usage:  %s_test [options]\n", fftw_prefix);
635
     my_printf(WHEN_LONG_OPTIONS("  --speed=<n>\n")
636
               "  -s <n>    : test speed for size n\n");
637
     my_printf(WHEN_LONG_OPTIONS("\n  --correctness=<n>\n")
638
               "  -c <n>    : test correctness for size n\n");
639
     my_printf(WHEN_LONG_OPTIONS("\n  --random=<rank>>\n")
640
               "  -r <rank> : test correctness for random sizes "
641
               "(does not terminate)\n");
642
     my_printf(WHEN_LONG_OPTIONS("\n  --all=<rank>\n")
643
               "  -a <rank> : test correctness for all sizes "
644
               "(does not terminate)\n");
645
     my_printf(WHEN_LONG_OPTIONS("\n  --fields=<n>\n")
646
               "  -f <n>    : n fields ('howmany' param) in speed tests\n");
647
     my_printf(WHEN_LONG_OPTIONS("\n  --planner=<rank>\n")
648
               "  -p <rank> : test planner\n");
649
     my_printf(WHEN_LONG_OPTIONS("\n  --measure\n")
650
               "  -m        : use FFTW_MEASURE in correctness tests\n");
651
     my_printf(WHEN_LONG_OPTIONS("\n  --estimate\n")
652
               "  -e        : use FFTW_ESTIMATE in speed tests\n");
653
     my_printf(WHEN_LONG_OPTIONS("\n  --wisdom=<file>\n")
654
               "  -w <file> : use wisdom & read/write it from/to file\n");
655
     my_printf(WHEN_LONG_OPTIONS("\n  --timer\n")
656
               "  -t        : test timer resolution\n");
657
     my_printf(WHEN_LONG_OPTIONS("\n  --x-repeat=<n>\n")
658
               "  -x <n>    : run non-terminating tests (-r, -a) only n times\n");
659
     my_printf(WHEN_LONG_OPTIONS("\n  --paranoid\n")
660
               "  -P        : enable paranoid tests\n");
661
     my_printf(WHEN_LONG_OPTIONS("\n  --verbose\n")
662
               "  -v        : verbose output for subsequent options\n");
663
     my_printf(WHEN_LONG_OPTIONS("\n  --version\n")
664
               "  -V        : print FFTW version information\n");
665
     my_printf(WHEN_LONG_OPTIONS("\n  --help\n")
666
               "  -h        : this help\n");
667
#ifndef HAVE_GETOPT
668
     my_printf("(When run with no arguments, an interactive mode is used.)\n");
669
#endif
670
     if (exit_when_done)
671
          exit(EXIT_FAILURE);
672
}
673
 
674
char wfname[128];
675
 
676
void handle_option(char opt, char *optarg)
677
{
678
     FILE *wf;
679
     struct size sz;
680
     int rank, n;
681
 
682
     switch (opt) {
683
         case 's':
684
              sz = parse_size(optarg);
685
              if (!sz.is_nd)
686
                   test_speed(sz.narray[0]);
687
              else
688
                   test_speed_nd(sz);
689
              break;
690
 
691
         case 'c':
692
              sz = parse_size(optarg);
693
              if (!sz.is_nd)
694
                   test_correctness(sz.narray[0]);
695
              else
696
                   testnd_correctness_aux(sz);
697
              break;
698
 
699
         case 'p':
700
              rank = atoi(optarg);
701
              test_planner(rank);
702
              break;
703
 
704
         case 'P':
705
              paranoid = 1;
706
              enter_paranoid_mode();
707
              break;
708
 
709
         case 'r':
710
              rank = atoi(optarg);
711
              test_all_random(rank);
712
              break;
713
 
714
         case 'a':
715
              rank = atoi(optarg);
716
              if (rank == 0)
717
                   test_all();
718
              else
719
                   testnd_all(rank);
720
              break;
721
 
722
         case 't':
723
              test_timer();
724
              break;
725
 
726
         case 'f':
727
              n = atoi(optarg);
728
              CHECK(n > 0, "-f requires a positive integer argument");
729
              howmany_fields = n;
730
              break;
731
 
732
         case 'm':
733
              measure_flag = FFTW_MEASURE;
734
              break;
735
 
736
         case 'e':
737
              speed_flag = FFTW_ESTIMATE;
738
              break;
739
 
740
         case 'w':
741
              wisdom_flag = FFTW_USE_WISDOM;
742
              strcpy(wfname, optarg);
743
              wf = fopen(wfname, "r");
744
              if (wf == 0) {
745
                   my_printf("Couldn't open wisdom file \"%s\".\n", wfname);
746
                   my_printf("This file will be created upon completion.\n");
747
              } else {
748
                   CHECK(FFTW_SUCCESS == fftw_import_wisdom_from_file(wf),
749
                         "invalid wisdom file format");
750
                   fclose(wf);
751
              }
752
              break;
753
 
754
         case 'v':
755
              verbose++;
756
              break;
757
 
758
         case 'V':
759
              my_printf("%s\n", fftw_version);
760
              my_printf("%s test program, compiled in %s precision.\n",
761
                        fftw_prefix,
762
                        sizeof(fftw_real) == sizeof(double) ? "double"
763
                        : (sizeof(fftw_real) == sizeof(float) ? "single"
764
                           : "unknown"));
765
              my_printf(
766
  "\nCopyright (C) Massachusetts Institute of Technology.\n"
767
  "FFTW comes with ABSOLUTELY NO WARRANTY.  This is free software, and\n"
768
  "you are welcome to redistribute it under the terms of the GNU\n"
769
  "General Public License.  For more information, see the file COPYING or\n"
770
  "the GNU web site at http://www.gnu.org.\n"
771
  "\nFor more information regarding FFTW, or to download the latest version,\n"
772
  "see the FFTW home page at http://theory.lcs.mit.edu/~fftw.\n");
773
 
774
              break;
775
 
776
         case 'x':
777
              n = atoi(optarg);
778
              CHECK(n > 0, "-x requires a positive integer argument");
779
              max_iterations = n;
780
              break;
781
 
782
         case 'h':
783
              usage(FALSE);
784
              break;
785
 
786
         default:
787
              usage(TRUE);
788
     }
789
 
790
     /* every test must free all the used FFTW memory */
791
     if (!(wisdom_flag & FFTW_USE_WISDOM) && chk_mem_leak)
792
          fftw_check_memory_leaks();
793
}
794
 
795
 
796
 
797
short askuser(const char *s)
798
{
799
     char line[200] = "", c;
800
     int i, count = 0;
801
 
802
     do {
803
          if (count++ > 0)
804
               my_printf("Invalid response.  Please enter \"y\" or \"n\".\n");
805
          my_printf("%s (y/n) ", s);
806
          /* skip blank lines */
807
          while (line[0] == 0 || line[0] == '\n')
808
               fgets(line, 200, stdin);
809
          for (i = 0; line[i] && (line[i] == ' ' || line[i] == '\t'); ++i);
810
          c = line[i];
811
     } while (c != 'n' && c != 'N' && c != 'y' && c != 'Y');
812
 
813
     return (c == 'y' || c == 'Y');
814
}
815
 
816
/* Standard function to get the next command-line argument for the program.
817
   Returns the option character (or -1 if there are no more options),
818
   and the option argument (if any) in argval, which is an array of length
819
   at least argval_maxlen.
820
 
821
   The test programs need to implement a function get_option with the
822
   same arguments as this one, which will typically just call
823
   default_get_option.
824
 
825
   The reason we need to put this in a separate function is that the MPI
826
   test programs can't rely on all of the processes having direct access
827
   to the program arguments--they need to pass them as explicit messages
828
   from the master process.   Sigh. */
829
int default_get_option(int argc, char **argv, char *argval, int argval_maxlen)
830
{
831
     int c = -1;
832
 
833
     if (argc <= 1)
834
          usage(TRUE);
835
 
836
#ifdef HAVE_GETOPT
837
     {
838
          const char short_options[] = "s:c:w:f:p:Pa:r:tvVmehx:";
839
          extern char *optarg;
840
          extern int optind;
841
 
842
#  if defined(HAVE_GETOPT_LONG) && defined(HAVE_GETOPT_H)
843
          {
844
               int option_index;
845
               const struct option long_options[] = {
846
                    {"speed", 1, 0, 's'},
847
                    {"correctness", 1, 0, 'c'},
848
                    {"wisdom", 1, 0, 'w'},
849
                    {"fields", 1, 0, 'f'},
850
                    {"planner", 1, 0, 'p'},
851
                    {"paranoid", 0, 0, 'P'},
852
                    {"all", 1, 0, 'a'},
853
                    {"random", 1, 0, 'r'},
854
                    {"timer", 0, 0, 't'},
855
                    {"verbose", 0, 0, 'v'},
856
                    {"version", 0, 0, 'V'},
857
                    {"measure", 0, 0, 'm'},
858
                    {"estimate", 0, 0, 'e'},
859
                    {"help", 0, 0, 'h'},
860
                    {"x-repeat", 1, 0, 'x'},
861
                    {0, 0, 0, 0}
862
               };
863
 
864
               c = getopt_long(argc, argv, short_options, long_options,
865
                               &option_index);
866
          }
867
#  else /* not HAVE_GETOPT_LONG */
868
          c = getopt(argc, argv, short_options);
869
#  endif /* not HAVE_GETOPT_LONG */
870
 
871
          if (c == -1 && argc != optind)
872
               usage(TRUE);  /* there were invalid args; print usage info */
873
 
874
          if (optarg) {
875
               strncpy(argval, optarg, argval_maxlen - 1);
876
               argval[argval_maxlen - 1] = 0;
877
          }
878
          else
879
               argval[0] = 0;
880
     }
881
#endif /* HAVE_GETOPT */
882
 
883
     return c;
884
}
885
 
886
int main(int argc, char *argv[])
887
{
888
     verbose = 1;
889
     wisdom_flag = 0;
890
     measure_flag = FFTW_ESTIMATE;
891
     chk_mem_leak = 1;
892
     paranoid = 0;
893
 
894
#ifdef DETERMINISTIC
895
     srand(1123);
896
#else
897
     srand((unsigned int) time(NULL));
898
#endif
899
 
900
     test_init(&argc, argv);
901
 
902
     /*
903
      * To parse the command line, we use getopt, but this does not seem
904
      * to be in the ANSI standard (it is only available on UNIX,
905
      * apparently).
906
      */
907
#ifndef HAVE_GETOPT
908
     if (argc > 1)
909
          my_printf("Sorry, command-line arguments are not available on\n"
910
                 "this system.  Run fftw_test with no arguments to\n"
911
                 "use it in interactive mode.\n");
912
 
913
     if (argc <= 1) {
914
          int n = 0;
915
          char s[128] = "";
916
 
917
          usage(FALSE);
918
 
919
          my_printf("\n");
920
 
921
          if (askuser("Perform random correctness tests (non-terminating)?"))
922
               handle_option('r', "0");
923
 
924
          if (askuser("Verbose output?"))
925
               handle_option('v', "");
926
          if (askuser("Paranoid test?"))
927
               handle_option('P', "");
928
 
929
          if (askuser("Use/test wisdom?")) {
930
               my_printf("  Enter wisdom file name to use: ");
931
               fgets(s, 128, stdin);
932
               handle_option('w', s);
933
          }
934
          if (askuser("Test correctness?")) {
935
               if (askuser("  -- for all sizes?"))
936
                    handle_option('a', "");
937
               else {
938
                    my_printf("  Enter n: ");
939
                    fgets(s, 128, stdin);
940
                    handle_option('c', s);
941
               }
942
          }
943
          if (askuser("Test speed?")) {
944
               my_printf("  Enter n: ");
945
               fgets(s, 128, stdin);
946
               handle_option('s', s);
947
          }
948
          if (askuser("Test planner?"))
949
               handle_option('p', "");
950
          if (askuser("Test timer?"))
951
               handle_option('t', "");
952
     }
953
#else                           /* 
954
                                 * read command-line args using getopt
955
                                 * facility  
956
                                 */
957
     {
958
          char option_arg[128];
959
          int c;
960
 
961
          while ((c = get_option(argc, argv, option_arg, 128)) != -1)
962
               handle_option(c, option_arg);
963
     }
964
#endif
965
 
966
     if (wisdom_flag & FFTW_USE_WISDOM) {
967
          char *ws;
968
          FILE *wf;
969
 
970
          ws = fftw_export_wisdom_to_string();
971
          CHECK(ws != 0, "error exporting wisdom to string");
972
          my_printf("\nAccumulated wisdom:\n     %s\n", ws);
973
          fftw_forget_wisdom();
974
          CHECK(FFTW_SUCCESS == fftw_import_wisdom_from_string(ws),
975
                "unexpected error reading in wisdom from string");
976
          fftw_free(ws);
977
 
978
          if (io_okay) {
979
               wf = fopen(wfname, "w");
980
               CHECK(wf != 0, "error creating wisdom file");
981
               fftw_export_wisdom_to_file(wf);
982
               fclose(wf);
983
          }
984
     }
985
     /* make sure to dispose of wisdom before checking for memory leaks */
986
     fftw_forget_wisdom();
987
 
988
     fftw_check_memory_leaks();
989
     if (io_okay)
990
          fftw_print_max_memory_usage();
991
 
992
     test_finish();
993
 
994
     return EXIT_SUCCESS;
995
}