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