/* * Copyright (c) 2003, 2007-14 Matteo Frigo * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "kernel/ifftw.h" #ifdef HAVE_UNISTD_H # include #endif #ifndef WITH_SLOW_TIMER # include "cycle.h" #endif #ifndef FFTW_TIME_LIMIT #define FFTW_TIME_LIMIT 2.0 /* don't run for more than two seconds */ #endif /* the following code is disabled for now, because it seems to require that we #include in ifftw.h to typedef LARGE_INTEGER crude_time, and this pulls in the whole Windows universe and leads to namespace conflicts (unless we did some hack like assuming sizeof(LARGE_INTEGER) == sizeof(long long). gettimeofday is provided by MinGW, which we use to cross-compile FFTW for Windows, and this seems to work well enough */ #if 0 && (defined(__WIN32__) || defined(_WIN32) || defined(_WIN64)) crude_time X(get_crude_time)(void) { crude_time tv; QueryPerformanceCounter(&tv); return tv; } static double elapsed_since(crude_time t0) { crude_time t1, freq; QueryPerformanceCounter(&t1); QueryPerformanceFrequency(&freq); return (((double) (t1.QuadPart - t0.QuadPart))) / ((double) freq.QuadPart); } # define TIME_MIN_SEC 1.0e-2 #elif defined(HAVE_GETTIMEOFDAY) crude_time X(get_crude_time)(void) { crude_time tv; gettimeofday(&tv, 0); return tv; } #define elapsed_sec(t1,t0) ((double)(t1.tv_sec - t0.tv_sec) + \ (double)(t1.tv_usec - t0.tv_usec) * 1.0E-6) static double elapsed_since(crude_time t0) { crude_time t1; gettimeofday(&t1, 0); return elapsed_sec(t1, t0); } # define TIME_MIN_SEC 1.0e-3 #else /* !HAVE_GETTIMEOFDAY */ /* Note that the only system where we are likely to need to fall back on the clock() function is Windows, for which CLOCKS_PER_SEC is 1000 and thus the clock wraps once every 50 days. This should hopefully be longer than the time required to create any single plan! */ crude_time X(get_crude_time)(void) { return clock(); } #define elapsed_sec(t1,t0) ((double) ((t1) - (t0)) / CLOCKS_PER_SEC) static double elapsed_since(crude_time t0) { return elapsed_sec(clock(), t0); } # define TIME_MIN_SEC 2.0e-1 /* from fftw2 */ #endif /* !HAVE_GETTIMEOFDAY */ double X(elapsed_since)(const planner *plnr, const problem *p, crude_time t0) { double t = elapsed_since(t0); if (plnr->cost_hook) t = plnr->cost_hook(p, t, COST_MAX); return t; } #ifdef WITH_SLOW_TIMER /* excruciatingly slow; only use this if there is no choice! */ typedef crude_time ticks; # define getticks X(get_crude_time) # define elapsed(t1,t0) elapsed_sec(t1,t0) # define TIME_MIN TIME_MIN_SEC # define TIME_REPEAT 4 /* from fftw2 */ # define HAVE_TICK_COUNTER #endif #ifdef HAVE_TICK_COUNTER # ifndef TIME_MIN # define TIME_MIN 100.0 # endif # ifndef TIME_REPEAT # define TIME_REPEAT 8 # endif static double measure(plan *pln, const problem *p, int iter) { ticks t0, t1; int i; t0 = getticks(); for (i = 0; i < iter; ++i) pln->adt->solve(pln, p); t1 = getticks(); return elapsed(t1, t0); } double X(measure_execution_time)(const planner *plnr, plan *pln, const problem *p) { int iter; int repeat; X(plan_awake)(pln, AWAKE_ZERO); p->adt->zero(p); start_over: for (iter = 1; iter; iter *= 2) { double tmin = 0; int first = 1; crude_time begin = X(get_crude_time)(); /* repeat the measurement TIME_REPEAT times */ for (repeat = 0; repeat < TIME_REPEAT; ++repeat) { double t = measure(pln, p, iter); if (plnr->cost_hook) t = plnr->cost_hook(p, t, COST_MAX); if (t < 0) goto start_over; if (first || t < tmin) tmin = t; first = 0; /* do not run for too long */ if (X(elapsed_since)(plnr, p, begin) > FFTW_TIME_LIMIT) break; } if (tmin >= TIME_MIN) { X(plan_awake)(pln, SLEEPY); return tmin / (double) iter; } } goto start_over; /* may happen if timer is screwed up */ } #else /* no cycle counter */ double X(measure_execution_time)(const planner *plnr, plan *pln, const problem *p) { UNUSED(plnr); UNUSED(p); UNUSED(pln); return -1.0; } #endif