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