cannam@127
|
1 /*
|
cannam@127
|
2 * Copyright (c) 2003, 2007-14 Matteo Frigo
|
cannam@127
|
3 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
|
cannam@127
|
4 *
|
cannam@127
|
5 * This program is free software; you can redistribute it and/or modify
|
cannam@127
|
6 * it under the terms of the GNU General Public License as published by
|
cannam@127
|
7 * the Free Software Foundation; either version 2 of the License, or
|
cannam@127
|
8 * (at your option) any later version.
|
cannam@127
|
9 *
|
cannam@127
|
10 * This program is distributed in the hope that it will be useful,
|
cannam@127
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
cannam@127
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
cannam@127
|
13 * GNU General Public License for more details.
|
cannam@127
|
14 *
|
cannam@127
|
15 * You should have received a copy of the GNU General Public License
|
cannam@127
|
16 * along with this program; if not, write to the Free Software
|
cannam@127
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
cannam@127
|
18 *
|
cannam@127
|
19 */
|
cannam@127
|
20
|
cannam@127
|
21
|
cannam@127
|
22 #include "ifftw.h"
|
cannam@127
|
23
|
cannam@127
|
24 #ifdef HAVE_UNISTD_H
|
cannam@127
|
25 # include <unistd.h>
|
cannam@127
|
26 #endif
|
cannam@127
|
27
|
cannam@127
|
28 #ifndef WITH_SLOW_TIMER
|
cannam@127
|
29 # include "cycle.h"
|
cannam@127
|
30 #endif
|
cannam@127
|
31
|
cannam@127
|
32 #ifndef FFTW_TIME_LIMIT
|
cannam@127
|
33 #define FFTW_TIME_LIMIT 2.0 /* don't run for more than two seconds */
|
cannam@127
|
34 #endif
|
cannam@127
|
35
|
cannam@127
|
36 /* the following code is disabled for now, because it seems to
|
cannam@127
|
37 require that we #include <windows.h> in ifftw.h to
|
cannam@127
|
38 typedef LARGE_INTEGER crude_time, and this pulls in the whole
|
cannam@127
|
39 Windows universe and leads to namespace conflicts (unless
|
cannam@127
|
40 we did some hack like assuming sizeof(LARGE_INTEGER) == sizeof(long long).
|
cannam@127
|
41 gettimeofday is provided by MinGW, which we use to cross-compile
|
cannam@127
|
42 FFTW for Windows, and this seems to work well enough */
|
cannam@127
|
43 #if 0 && (defined(__WIN32__) || defined(_WIN32) || defined(_WIN64))
|
cannam@127
|
44 crude_time X(get_crude_time)(void)
|
cannam@127
|
45 {
|
cannam@127
|
46 crude_time tv;
|
cannam@127
|
47 QueryPerformanceCounter(&tv);
|
cannam@127
|
48 return tv;
|
cannam@127
|
49 }
|
cannam@127
|
50
|
cannam@127
|
51 static double elapsed_since(crude_time t0)
|
cannam@127
|
52 {
|
cannam@127
|
53 crude_time t1, freq;
|
cannam@127
|
54 QueryPerformanceCounter(&t1);
|
cannam@127
|
55 QueryPerformanceFrequency(&freq);
|
cannam@127
|
56 return (((double) (t1.QuadPart - t0.QuadPart))) /
|
cannam@127
|
57 ((double) freq.QuadPart);
|
cannam@127
|
58 }
|
cannam@127
|
59
|
cannam@127
|
60 # define TIME_MIN_SEC 1.0e-2
|
cannam@127
|
61
|
cannam@127
|
62 #elif defined(HAVE_GETTIMEOFDAY)
|
cannam@127
|
63 crude_time X(get_crude_time)(void)
|
cannam@127
|
64 {
|
cannam@127
|
65 crude_time tv;
|
cannam@127
|
66 gettimeofday(&tv, 0);
|
cannam@127
|
67 return tv;
|
cannam@127
|
68 }
|
cannam@127
|
69
|
cannam@127
|
70 #define elapsed_sec(t1,t0) ((double)(t1.tv_sec - t0.tv_sec) + \
|
cannam@127
|
71 (double)(t1.tv_usec - t0.tv_usec) * 1.0E-6)
|
cannam@127
|
72
|
cannam@127
|
73 static double elapsed_since(crude_time t0)
|
cannam@127
|
74 {
|
cannam@127
|
75 crude_time t1;
|
cannam@127
|
76 gettimeofday(&t1, 0);
|
cannam@127
|
77 return elapsed_sec(t1, t0);
|
cannam@127
|
78 }
|
cannam@127
|
79
|
cannam@127
|
80 # define TIME_MIN_SEC 1.0e-3
|
cannam@127
|
81
|
cannam@127
|
82 #else /* !HAVE_GETTIMEOFDAY */
|
cannam@127
|
83
|
cannam@127
|
84 /* Note that the only system where we are likely to need to fall back
|
cannam@127
|
85 on the clock() function is Windows, for which CLOCKS_PER_SEC is 1000
|
cannam@127
|
86 and thus the clock wraps once every 50 days. This should hopefully
|
cannam@127
|
87 be longer than the time required to create any single plan! */
|
cannam@127
|
88 crude_time X(get_crude_time)(void) { return clock(); }
|
cannam@127
|
89
|
cannam@127
|
90 #define elapsed_sec(t1,t0) ((double) ((t1) - (t0)) / CLOCKS_PER_SEC)
|
cannam@127
|
91
|
cannam@127
|
92 static double elapsed_since(crude_time t0)
|
cannam@127
|
93 {
|
cannam@127
|
94 return elapsed_sec(clock(), t0);
|
cannam@127
|
95 }
|
cannam@127
|
96
|
cannam@127
|
97 # define TIME_MIN_SEC 2.0e-1 /* from fftw2 */
|
cannam@127
|
98
|
cannam@127
|
99 #endif /* !HAVE_GETTIMEOFDAY */
|
cannam@127
|
100
|
cannam@127
|
101 double X(elapsed_since)(const planner *plnr, const problem *p, crude_time t0)
|
cannam@127
|
102 {
|
cannam@127
|
103 double t = elapsed_since(t0);
|
cannam@127
|
104 if (plnr->cost_hook)
|
cannam@127
|
105 t = plnr->cost_hook(p, t, COST_MAX);
|
cannam@127
|
106 return t;
|
cannam@127
|
107 }
|
cannam@127
|
108
|
cannam@127
|
109 #ifdef WITH_SLOW_TIMER
|
cannam@127
|
110 /* excruciatingly slow; only use this if there is no choice! */
|
cannam@127
|
111 typedef crude_time ticks;
|
cannam@127
|
112 # define getticks X(get_crude_time)
|
cannam@127
|
113 # define elapsed(t1,t0) elapsed_sec(t1,t0)
|
cannam@127
|
114 # define TIME_MIN TIME_MIN_SEC
|
cannam@127
|
115 # define TIME_REPEAT 4 /* from fftw2 */
|
cannam@127
|
116 # define HAVE_TICK_COUNTER
|
cannam@127
|
117 #endif
|
cannam@127
|
118
|
cannam@127
|
119 #ifdef HAVE_TICK_COUNTER
|
cannam@127
|
120
|
cannam@127
|
121 # ifndef TIME_MIN
|
cannam@127
|
122 # define TIME_MIN 100.0
|
cannam@127
|
123 # endif
|
cannam@127
|
124
|
cannam@127
|
125 # ifndef TIME_REPEAT
|
cannam@127
|
126 # define TIME_REPEAT 8
|
cannam@127
|
127 # endif
|
cannam@127
|
128
|
cannam@127
|
129 static double measure(plan *pln, const problem *p, int iter)
|
cannam@127
|
130 {
|
cannam@127
|
131 ticks t0, t1;
|
cannam@127
|
132 int i;
|
cannam@127
|
133
|
cannam@127
|
134 t0 = getticks();
|
cannam@127
|
135 for (i = 0; i < iter; ++i)
|
cannam@127
|
136 pln->adt->solve(pln, p);
|
cannam@127
|
137 t1 = getticks();
|
cannam@127
|
138 return elapsed(t1, t0);
|
cannam@127
|
139 }
|
cannam@127
|
140
|
cannam@127
|
141
|
cannam@127
|
142 double X(measure_execution_time)(const planner *plnr,
|
cannam@127
|
143 plan *pln, const problem *p)
|
cannam@127
|
144 {
|
cannam@127
|
145 int iter;
|
cannam@127
|
146 int repeat;
|
cannam@127
|
147
|
cannam@127
|
148 X(plan_awake)(pln, AWAKE_ZERO);
|
cannam@127
|
149 p->adt->zero(p);
|
cannam@127
|
150
|
cannam@127
|
151 start_over:
|
cannam@127
|
152 for (iter = 1; iter; iter *= 2) {
|
cannam@127
|
153 double tmin = 0;
|
cannam@127
|
154 int first = 1;
|
cannam@127
|
155 crude_time begin = X(get_crude_time)();
|
cannam@127
|
156
|
cannam@127
|
157 /* repeat the measurement TIME_REPEAT times */
|
cannam@127
|
158 for (repeat = 0; repeat < TIME_REPEAT; ++repeat) {
|
cannam@127
|
159 double t = measure(pln, p, iter);
|
cannam@127
|
160
|
cannam@127
|
161 if (plnr->cost_hook)
|
cannam@127
|
162 t = plnr->cost_hook(p, t, COST_MAX);
|
cannam@127
|
163 if (t < 0)
|
cannam@127
|
164 goto start_over;
|
cannam@127
|
165
|
cannam@127
|
166 if (first || t < tmin)
|
cannam@127
|
167 tmin = t;
|
cannam@127
|
168 first = 0;
|
cannam@127
|
169
|
cannam@127
|
170 /* do not run for too long */
|
cannam@127
|
171 if (X(elapsed_since)(plnr, p, begin) > FFTW_TIME_LIMIT)
|
cannam@127
|
172 break;
|
cannam@127
|
173 }
|
cannam@127
|
174
|
cannam@127
|
175 if (tmin >= TIME_MIN) {
|
cannam@127
|
176 X(plan_awake)(pln, SLEEPY);
|
cannam@127
|
177 return tmin / (double) iter;
|
cannam@127
|
178 }
|
cannam@127
|
179 }
|
cannam@127
|
180 goto start_over; /* may happen if timer is screwed up */
|
cannam@127
|
181 }
|
cannam@127
|
182
|
cannam@127
|
183 #else /* no cycle counter */
|
cannam@127
|
184
|
cannam@127
|
185 double X(measure_execution_time)(const planner *plnr,
|
cannam@127
|
186 plan *pln, const problem *p)
|
cannam@127
|
187 {
|
cannam@127
|
188 UNUSED(plnr);
|
cannam@127
|
189 UNUSED(p);
|
cannam@127
|
190 UNUSED(pln);
|
cannam@127
|
191 return -1.0;
|
cannam@127
|
192 }
|
cannam@127
|
193
|
cannam@127
|
194 #endif
|