diff src/fftw-3.3.8/tests/fftw-bench.c @ 167:bd3cc4d1df30

Add FFTW 3.3.8 source, and a Linux build
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 19 Nov 2019 14:52:55 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fftw-3.3.8/tests/fftw-bench.c	Tue Nov 19 14:52:55 2019 +0000
@@ -0,0 +1,287 @@
+/* See bench.c.  We keep a few common subroutines in this file so
+   that they can be re-used in the MPI test program. */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include "tests/fftw-bench.h"
+
+/* define to enable code that traps floating-point exceptions.
+   Disabled by default because I don't want to worry about the
+   portability of such code.  feenableexcept() seems to be a GNU
+   thing */
+#undef TRAP_FP_EXCEPTIONS
+
+#ifdef TRAP_FP_EXCEPTIONS
+#  include <signal.h>
+#  include <fenv.h>
+#endif
+
+#ifdef _OPENMP
+#  include <omp.h>
+#endif
+
+#ifdef HAVE_SMP
+int threads_ok = 1;
+#endif
+
+FFTW(plan) the_plan = 0;
+
+static const char *wisdat = "wis.dat";
+unsigned the_flags = 0;
+int paranoid = 0;
+int usewisdom = 0;
+int havewisdom = 0;
+int nthreads = 1;
+int amnesia = 0;
+
+extern void install_hook(void);  /* in hook.c */
+extern void uninstall_hook(void);  /* in hook.c */
+
+#ifdef FFTW_RANDOM_ESTIMATOR
+extern unsigned FFTW(random_estimate_seed);
+#endif
+
+#ifdef TRAP_FP_EXCEPTIONS
+static void sigfpe_handler(int sig, siginfo_t *info, void *context)
+{
+     /* fftw code is not supposed to generate FP exceptions */
+     UNUSED(sig); UNUSED(info); UNUSED(context);
+     fprintf(stderr, "caught FPE, aborting\n");
+     abort();
+}
+
+static void setup_sigfpe_handler(void)
+{
+  struct sigaction a;
+  feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW);
+  memset(&a, 0, sizeof(a));
+  a.sa_sigaction = sigfpe_handler;
+  a.sa_flags = SA_SIGINFO;
+  if (sigaction(SIGFPE, &a, NULL) == -1) {
+       fprintf(stderr, "cannot install sigfpe handler\n");
+       exit(1);
+  }
+}
+#else
+static void setup_sigfpe_handler(void)
+{
+}
+#endif
+
+void useropt(const char *arg)
+{
+     int x;
+     double y;
+
+     if (!strcmp(arg, "patient")) the_flags |= FFTW_PATIENT;
+     else if (!strcmp(arg, "estimate")) the_flags |= FFTW_ESTIMATE;
+     else if (!strcmp(arg, "estimatepat")) the_flags |= FFTW_ESTIMATE_PATIENT;
+     else if (!strcmp(arg, "exhaustive")) the_flags |= FFTW_EXHAUSTIVE;
+     else if (!strcmp(arg, "unaligned")) the_flags |= FFTW_UNALIGNED;
+     else if (!strcmp(arg, "nosimd")) the_flags |= FFTW_NO_SIMD;
+     else if (!strcmp(arg, "noindirectop")) the_flags |= FFTW_NO_INDIRECT_OP;
+     else if (!strcmp(arg, "wisdom-only")) the_flags |= FFTW_WISDOM_ONLY;
+     else if (sscanf(arg, "flag=%d", &x) == 1) the_flags |= x;
+     else if (sscanf(arg, "bflag=%d", &x) == 1) the_flags |= 1U << x;
+     else if (!strcmp(arg, "paranoid")) paranoid = 1;
+     else if (!strcmp(arg, "wisdom")) usewisdom = 1;
+     else if (!strcmp(arg, "amnesia")) amnesia = 1;
+     else if (sscanf(arg, "nthreads=%d", &x) == 1) nthreads = x;
+#ifdef FFTW_RANDOM_ESTIMATOR
+     else if (sscanf(arg, "eseed=%d", &x) == 1) FFTW(random_estimate_seed) = x;
+#endif
+     else if (sscanf(arg, "timelimit=%lg", &y) == 1) {
+	  FFTW(set_timelimit)(y);
+     }
+
+     else fprintf(stderr, "unknown user option: %s.  Ignoring.\n", arg);
+}
+
+void rdwisdom(void)
+{
+     FILE *f;
+     double tim;
+     int success = 0;
+
+     if (havewisdom) return;
+
+#ifdef HAVE_SMP
+     if (threads_ok) {
+	  BENCH_ASSERT(FFTW(init_threads)());
+	  FFTW(plan_with_nthreads)(nthreads);
+          FFTW(make_planner_thread_safe)();
+#ifdef _OPENMP
+	  omp_set_num_threads(nthreads);
+#endif
+     }
+     else if (nthreads > 1 && verbose > 1) {
+	  fprintf(stderr, "bench: WARNING - nthreads = %d, but threads not supported\n", nthreads);
+	  nthreads = 1;
+     }
+#endif
+
+     if (!usewisdom) return;
+
+     timer_start(USER_TIMER);
+     if ((f = fopen(wisdat, "r"))) {
+	  if (!import_wisdom(f))
+	       fprintf(stderr, "bench: ERROR reading wisdom\n");
+	  else
+	       success = 1;
+	  fclose(f);
+     }
+     tim = timer_stop(USER_TIMER);
+
+     if (success) {
+	  if (verbose > 1) printf("READ WISDOM (%g seconds): ", tim);
+	  
+	  if (verbose > 3)
+	       export_wisdom(stdout);
+	  if (verbose > 1)
+	       printf("\n");
+     }
+     havewisdom = 1;
+}
+
+void wrwisdom(void)
+{
+     FILE *f;
+     double tim;
+     if (!havewisdom) return;
+
+     timer_start(USER_TIMER);
+     if ((f = fopen(wisdat, "w"))) {
+	  export_wisdom(f);
+	  fclose(f);
+     }
+     tim = timer_stop(USER_TIMER);
+     if (verbose > 1) printf("write wisdom took %g seconds\n", tim);
+}
+
+static unsigned preserve_input_flags(bench_problem *p)
+{
+     /*
+      * fftw3 cannot preserve input for multidimensional c2r transforms.
+      * Enforce FFTW_DESTROY_INPUT
+      */
+     if (p->kind == PROBLEM_REAL && 
+	 p->sign > 0 && 
+	 !p->in_place && 
+	 p->sz->rnk > 1)
+	  p->destroy_input = 1;
+
+     if (p->destroy_input)
+	  return FFTW_DESTROY_INPUT;
+     else
+	  return FFTW_PRESERVE_INPUT;
+}
+
+int can_do(bench_problem *p)
+{
+     double tim;
+
+     if (verbose > 2 && p->pstring)
+	  printf("Planning %s...\n", p->pstring);
+     rdwisdom();
+
+     timer_start(USER_TIMER);
+     the_plan = mkplan(p, preserve_input_flags(p) | the_flags | FFTW_ESTIMATE);
+     tim = timer_stop(USER_TIMER);
+     if (verbose > 2) printf("estimate-planner time: %g s\n", tim);
+
+     if (the_plan) {
+	  FFTW(destroy_plan)(the_plan);
+	  return 1;
+     }
+     return 0;
+}
+
+void setup(bench_problem *p)
+{
+     double tim;
+
+     setup_sigfpe_handler();
+     
+     if (amnesia) {
+	  FFTW(forget_wisdom)();
+	  havewisdom = 0;
+     }
+
+     /* Regression test: check that fftw_malloc exists and links
+      * properly */
+     {
+          void *ptr = FFTW(malloc(42));
+          BENCH_ASSERT(FFTW(alignment_of)(ptr) == 0);
+          FFTW(free(ptr));
+     }
+
+     rdwisdom();
+     install_hook();
+
+#ifdef HAVE_SMP
+     if (verbose > 1 && nthreads > 1) printf("NTHREADS = %d\n", nthreads);
+#endif
+
+     timer_start(USER_TIMER);
+     the_plan = mkplan(p, preserve_input_flags(p) | the_flags);
+     tim = timer_stop(USER_TIMER);
+     if (verbose > 1) printf("planner time: %g s\n", tim);
+
+     BENCH_ASSERT(the_plan);
+
+     {
+	  double add, mul, nfma, cost, pcost;
+	  FFTW(flops)(the_plan, &add, &mul, &nfma);
+	  cost = FFTW(estimate_cost)(the_plan);
+	  pcost = FFTW(cost)(the_plan);
+	  if (verbose > 1) {
+	       FFTW(print_plan)(the_plan);
+	       printf("\n");
+	       printf("flops: %0.0f add, %0.0f mul, %0.0f fma\n",
+		      add, mul, nfma);
+	       printf("estimated cost: %f, pcost = %f\n", cost, pcost);
+	  }
+     }
+}
+
+
+void doit(int iter, bench_problem *p)
+{
+     int i;
+     FFTW(plan) q = the_plan;
+
+     UNUSED(p);
+     for (i = 0; i < iter; ++i) 
+	  FFTW(execute)(q);
+}
+
+void done(bench_problem *p)
+{
+     UNUSED(p);
+
+     FFTW(destroy_plan)(the_plan);
+     uninstall_hook();
+}
+
+void cleanup(void)
+{
+     initial_cleanup();
+
+     wrwisdom();
+#ifdef HAVE_SMP
+     FFTW(cleanup_threads)();
+#else
+     FFTW(cleanup)();
+#endif
+
+#    ifdef FFTW_DEBUG_MALLOC
+     {
+	  /* undocumented memory checker */
+	  FFTW_EXTERN void FFTW(malloc_print_minfo)(int v);
+	  FFTW(malloc_print_minfo)(verbose);
+     }
+#    endif
+
+     final_cleanup();
+}