mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-30 16:33:01 +00:00
54e93db207
not reliable yet
194 lines
4.9 KiB
C
194 lines
4.9 KiB
C
/*
|
|
* 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 <unistd.h>
|
|
#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 <windows.h> 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
|