| Bsoft 1.9 Bernard's software package

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

planner.c
Go to the documentation of this file.
1 /*
2 * Copyright (c) 1997-1999, 2003 Massachusetts Institute of Technology
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20 /*
21 * planner.c -- find the optimal plan
22 */
23
24 /* $Id: planner.c,v 1.88 2003/03/16 23:43:46 stevenj Exp $ */
25 #include "fftw-int.h"
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 extern fftw_generic_codelet fftw_twiddle_generic;
30 extern fftw_generic_codelet fftwi_twiddle_generic;
31 extern fftw_codelet_desc *fftw_config[];
32
33 fftw_plan_hook_ptr fftw_plan_hook = (fftw_plan_hook_ptr) NULL;
34
35 static void init_test_array(fftw_complex *arr, int stride, int n)
36 {
37 int j;
38
39 for (j = 0; j < n; ++j) {
40 c_re(arr[stride * j]) = 0.0;
41 c_im(arr[stride * j]) = 0.0;
42 }
43 }
44
45 /*
46 * The timer keeps doubling the number of iterations
47 * until the program runs for more than FFTW_TIME_MIN
48 */
49 static double fftw_measure_runtime(fftw_plan plan,
50 fftw_complex *in, int istride,
51 fftw_complex *out, int ostride)
52 {
53 fftw_time begin, end, start;
54 double t, tmax, tmin;
55 int i, iter;
56 int n;
57 int repeat;
58 int howmany = plan->vector_size;
59
60 n = plan->n;
61
62 iter = 1;
63
64 for (;;) {
65 tmin = 1.0E10;
66 tmax = -1.0E10;
67 init_test_array(in, istride, n * howmany);
68
69 start = fftw_get_time();
70 /* repeat the measurement FFTW_TIME_REPEAT times */
71 for (repeat = 0; repeat < FFTW_TIME_REPEAT; ++repeat) {
72 begin = fftw_get_time();
73 for (i = 0; i < iter; ++i) {
74 fftw(plan, howmany, in, istride, istride,
75 out, ostride, ostride);
76 }
77 end = fftw_get_time();
78
79 t = fftw_time_to_sec(fftw_time_diff(end, begin));
80 if (t < tmin)
81 tmin = t;
82 if (t > tmax)
83 tmax = t;
84
85 /* do not run for too long */
86 t = fftw_time_to_sec(fftw_time_diff(end, start));
87 if (t > FFTW_TIME_LIMIT)
88 break;
89 }
90
91 if (tmin >= FFTW_TIME_MIN)
92 break;
93
94 iter *= 2;
95 }
96
97 tmin /= (double) iter;
98 tmax /= (double) iter;
99
100 return tmin;
101 }
102
103 /* auxiliary functions */
104 static void compute_cost(fftw_plan plan,
105 fftw_complex *in, int istride,
106 fftw_complex *out, int ostride)
107 {
108 if (plan->flags & FFTW_MEASURE)
109 plan->cost = fftw_measure_runtime(plan, in, istride, out, ostride);
110 else {
111 double c;
112 c = plan->n * fftw_estimate_node(plan->root) * plan->vector_size;
113 plan->cost = c;
114 }
115 }
116
117 static void run_plan_hooks(fftw_plan p)
118 {
119 if (fftw_plan_hook && p) {
120 fftw_complete_twiddle(p->root, p->n);
121 fftw_plan_hook(p);
122 }
123 }
124
125
126 /* macrology */
127 #define FOR_ALL_CODELETS(p) \
128 fftw_codelet_desc **__q, *p; \
129 for (__q = &fftw_config[0]; (p = (*__q)); ++__q)
130
131 /******************************************
132 * Recursive planner *
133 ******************************************/
134 static fftw_plan planner(fftw_plan *table, int n, fftw_direction dir,
135 int flags, int vector_size,
136 fftw_complex *, int, fftw_complex *, int);
137
138 /*
139 * the planner consists of two parts: one that tries to
140 * use accumulated wisdom, and one that does not.
141 * A small driver invokes both parts in sequence
142 */
143
144 /* planner with wisdom: look up the codelet suggested by the wisdom */
145 static fftw_plan planner_wisdom(fftw_plan *table, int n,
146 fftw_direction dir, int flags,
147 int vector_size,
148 fftw_complex *in, int istride,
149 fftw_complex *out, int ostride)
150 {
151 fftw_plan best = (fftw_plan) 0;
152 fftw_plan_node *node;
153 int have_wisdom;
154 enum fftw_node_type wisdom_type;
155 int wisdom_signature;
156 fftw_recurse_kind wisdom_recurse_kind;
157
158 /* see if we remember any wisdom for this case */
159 have_wisdom = fftw_wisdom_lookup(n, flags, dir, FFTW_WISDOM,
160 istride, ostride,
161 &wisdom_type, &wisdom_signature,
162 &wisdom_recurse_kind, 0);
163
164 if (!have_wisdom)
165 return best;
166
167 if (wisdom_type == FFTW_NOTW) {
168 FOR_ALL_CODELETS(p) {
169 if (p->dir == dir && p->type == wisdom_type) {
170 /* see if wisdom applies */
171 if (wisdom_signature == p->signature &&
172 p->size == n) {
173 node = fftw_make_node_notw(n, p);
174 best = fftw_make_plan(n, dir, node, flags,
175 p->type, p->signature,
176 FFTW_NORMAL_RECURSE,
177 vector_size);
178 fftw_use_plan(best);
179 run_plan_hooks(best);
180 return best;
181 }
182 }
183 }
184 }
185 if (wisdom_type == FFTW_TWIDDLE) {
186 FOR_ALL_CODELETS(p) {
187 if (p->dir == dir && p->type == wisdom_type) {
188
189 /* see if wisdom applies */
190 if (wisdom_signature == p->signature &&
191 p->size > 1 &&
192 (n % p->size) == 0) {
193 fftw_plan r = planner(table, n / p->size, dir,
194 flags | FFTW_NO_VECTOR_RECURSE,
195 wisdom_recurse_kind ==
196 FFTW_VECTOR_RECURSE ?
197 p->size : vector_size,
198 in, istride, out, ostride);
199 node = fftw_make_node_twiddle(n, p,
200 r->root, flags);
201 best = fftw_make_plan(n, dir, node, flags,
202 p->type, p->signature,
203 wisdom_recurse_kind,
204 vector_size);
205 fftw_use_plan(best);
206 run_plan_hooks(best);
207 fftw_destroy_plan_internal(r);
208 return best;
209 }
210 }
211 }
212 }
213 /*
214 * BUG (or: TODO) Can we have generic wisdom? This is probably
215 * an academic question
216 */
217
218 return best;
219 }
220
221 /*
222 * planner with no wisdom: try all combinations and pick
223 * the best
224 */
225 static fftw_plan planner_normal(fftw_plan *table, int n, fftw_direction dir,
226 int flags, int vector_size,
227 fftw_complex *in, int istride,
228 fftw_complex *out, int ostride)
229 {
230 fftw_plan best = (fftw_plan) 0;
231 fftw_plan newplan;
232 fftw_plan_node *node;
233
234 /* see if we have any codelet that solves the problem */
235 {
236 FOR_ALL_CODELETS(p) {
237 if (p->dir == dir && p->type == FFTW_NOTW) {
238 if (p->size == n) {
239 node = fftw_make_node_notw(n, p);
240 newplan = fftw_make_plan(n, dir, node, flags,
241 p->type, p->signature,
242 FFTW_NORMAL_RECURSE,
243 vector_size);
244 fftw_use_plan(newplan);
245 compute_cost(newplan, in, istride, out, ostride);
246 run_plan_hooks(newplan);
247 best = fftw_pick_better(newplan, best);
248 }
249 }
250 }
251 }
252
253 /* Then, try all available twiddle codelets */
254 {
255 FOR_ALL_CODELETS(p) {
256 if (p->dir == dir && p->type == FFTW_TWIDDLE) {
257 if ((n % p->size) == 0 &&
258 p->size > 1 &&
259 (!best || n != p->size)) {
260 fftw_plan r = planner(table, n / p->size, dir,
261 flags | FFTW_NO_VECTOR_RECURSE,
262 vector_size,
263 in, istride, out, ostride);
264 node = fftw_make_node_twiddle(n, p,
265 r->root, flags);
266 newplan = fftw_make_plan(n, dir, node, flags,
267 p->type, p->signature,
268 FFTW_NORMAL_RECURSE,
269 vector_size);
270 fftw_use_plan(newplan);
271 fftw_destroy_plan_internal(r);
272 compute_cost(newplan, in, istride, out, ostride);
273 run_plan_hooks(newplan);
274 best = fftw_pick_better(newplan, best);
275 }
276 }
277 }
278 }
279
280 /* try vector recursion unless prohibited by the flags: */
281 if (! (flags & FFTW_NO_VECTOR_RECURSE)) {
282 FOR_ALL_CODELETS(p) {
283 if (p->dir == dir && p->type == FFTW_TWIDDLE) {
284 if ((n % p->size) == 0 &&
285 p->size > 1 &&
286 (!best || n != p->size)) {
287 fftw_plan r = planner(table, n / p->size, dir,
288 flags | FFTW_NO_VECTOR_RECURSE,
289 p->size,
290 in, istride, out, ostride);
291 node = fftw_make_node_twiddle(n, p,
292 r->root, flags);
293 newplan = fftw_make_plan(n, dir, node, flags,
294 p->type, p->signature,
295 FFTW_VECTOR_RECURSE,
296 vector_size);
297 fftw_use_plan(newplan);
298 fftw_destroy_plan_internal(r);
299 compute_cost(newplan, in, istride, out, ostride);
300 run_plan_hooks(newplan);
301 best = fftw_pick_better(newplan, best);
302 }
303 }
304 }
305 }
306
307 /*
308 * resort to generic or rader codelets for unknown factors
309 */
310 {
311 fftw_generic_codelet *codelet = (dir == FFTW_FORWARD ?
312 fftw_twiddle_generic :
313 fftwi_twiddle_generic);
314 int size, prev_size = 0, remaining_factors = n;
315 fftw_plan r;
316
317 while (remaining_factors > 1) {
318 size = fftw_factor(remaining_factors);
319 remaining_factors /= size;
320
321 /* don't try the same factor more than once */
322 if (size == prev_size)
323 continue;
324 prev_size = size;
325
326 /* Look for codelets corresponding to this factor. */
327 {
328 FOR_ALL_CODELETS(p) {
329 if (p->dir == dir && p->type == FFTW_TWIDDLE
330 && p->size == size) {
331 size = 0;
332 break;
333 }
334 }
335 }
336
337 /*
338 * only try a generic/rader codelet if there were no
339 * twiddle codelets for this factor
340 */
341 if (!size)
342 continue;
343
344 r = planner(table, n / size, dir,
345 flags | FFTW_NO_VECTOR_RECURSE,
346 vector_size,
347 in, istride, out, ostride);
348
349 /* Try Rader codelet: */
350 node = fftw_make_node_rader(n, size, dir, r->root, flags);
351 newplan = fftw_make_plan(n, dir, node, flags, FFTW_RADER, 0,
352 FFTW_NORMAL_RECURSE, vector_size);
353 fftw_use_plan(newplan);
354 compute_cost(newplan, in, istride, out, ostride);
355 run_plan_hooks(newplan);
356 best = fftw_pick_better(newplan, best);
357
358 if (size < 100) { /*
359 * only try generic for small
360 * sizes
361 */
362 /* Try generic codelet: */
363 node = fftw_make_node_generic(n, size, codelet,
364 r->root, flags);
365 newplan = fftw_make_plan(n, dir, node, flags,
366 FFTW_GENERIC, 0,
367 FFTW_NORMAL_RECURSE, vector_size);
368 fftw_use_plan(newplan);
369 compute_cost(newplan, in, istride, out, ostride);
370 run_plan_hooks(newplan);
371 best = fftw_pick_better(newplan, best);
372 }
373 fftw_destroy_plan_internal(r);
374 }
375 }
376
377 if (!best)
378 fftw_die("bug in planner\n");
379
380 return best;
381 }
382
383 static fftw_plan planner(fftw_plan *table, int n, fftw_direction dir,
384 int flags, int vector_size,
385 fftw_complex *in, int istride,
386 fftw_complex *out, int ostride)
387 {
388 fftw_plan best = (fftw_plan) 0;
389
390 if (vector_size > 1)
391 flags |= FFTW_NO_VECTOR_RECURSE;
392
393 /* see if plan has already been computed */
394 best = fftw_lookup(table, n, flags, vector_size);
395 if (best) {
396 fftw_use_plan(best);
397 return best;
398 }
399 /* try a wise plan */
400 best = planner_wisdom(table, n, dir, flags, vector_size,
401 in, istride, out, ostride);
402
403 if (!best) {
404 /* No wisdom. Plan normally. */
405 best = planner_normal(table, n, dir, flags,
406 vector_size,
407 in, istride, out, ostride);
408 }
409 if (best) {
410 fftw_insert(table, best);
411
412 /* remember the wisdom */
413 fftw_wisdom_add(n, flags, dir, FFTW_WISDOM, istride, ostride,
414 best->wisdom_type,
415 best->wisdom_signature,
416 best->recurse_kind);
417 }
418 return best;
419 }
420
421 fftw_plan fftw_create_plan_specific(int n, fftw_direction dir, int flags,
422 fftw_complex *in, int istride,
423 fftw_complex *out, int ostride)
424 {
425 fftw_plan table;
426 fftw_plan p1;
427
428 /* validate parameters */
429 if (n <= 0)
430 return (fftw_plan) 0;
431
432 #ifndef FFTW_ENABLE_VECTOR_RECURSE
433 /* TEMPORARY: disable vector recursion until it is more tested. */
434 flags |= FFTW_NO_VECTOR_RECURSE;
435 #endif
436
437 if ((dir != FFTW_FORWARD) && (dir != FFTW_BACKWARD))
438 return (fftw_plan) 0;
439
440 fftw_make_empty_table(&table);
441 p1 = planner(&table, n, dir, flags, 1,
442 in, istride, out, ostride);
443 fftw_destroy_table(&table);
444
445 if (p1)
446 fftw_complete_twiddle(p1->root, n);
447 return p1;
448 }
449
450 fftw_plan fftw_create_plan(int n, fftw_direction dir, int flags)
451 {
452 fftw_complex *tmp_in, *tmp_out;
453 fftw_plan p;
454
455 if (flags & FFTW_MEASURE) {
456 tmp_in = (fftw_complex *) fftw_malloc(2 * n * sizeof(fftw_complex));
457 if (!tmp_in)
458 return 0;
459 tmp_out = tmp_in + n;
460
461 p = fftw_create_plan_specific(n, dir, flags,
462 tmp_in, 1, tmp_out, 1);
463
464 fftw_free(tmp_in);
465 } else
466 p = fftw_create_plan_specific(n, dir, flags,
467 (fftw_complex *) 0, 1, (fftw_complex *) 0, 1);
468
469 return p;
470 }
471
472 void fftw_destroy_plan(fftw_plan plan)
473 {
474 fftw_destroy_plan_internal(plan);
475 }
fftw_codelet_desc
Definition: fftw.h:126
fftw_plan_struct::cost
double cost
Definition: fftw.h:280
fftw_factor
int fftw_factor(int n)
Definition: putils.c:468
fftw_plan_struct
Definition: fftw.h:271
fftw-int.h
fftw
void fftw(fftw_plan plan, int howmany, fftw_complex *in, int istride, int idist, fftw_complex *out, int ostride, int odist)
Definition: executor.c:402
fftw_make_node_twiddle
fftw_plan_node * fftw_make_node_twiddle(int n, const fftw_codelet_desc *config, fftw_plan_node *recurse, int flags)
Definition: putils.c:92
fftw_lookup
fftw_plan fftw_lookup(fftw_plan *table, int n, int flags, int vector_size)
Definition: putils.c:379
fftw_time_to_sec
#define fftw_time_to_sec(t)
Definition: fftw-int.h:358
fftw_complex
Definition: fftw.h:57
fftw_use_plan
void fftw_use_plan(fftw_plan p)
Definition: putils.c:348
fftw_pick_better
fftw_plan fftw_pick_better(fftw_plan p1, fftw_plan p2)
Definition: putils.c:450
FFTW_TWIDDLE
Definition: fftw.h:121
FFTW_TIME_REPEAT
#define FFTW_TIME_REPEAT
Definition: fftw-int.h:487
fftw_destroy_plan
void fftw_destroy_plan(fftw_plan plan)
Definition: planner.c:472
fftw_free
void fftw_free(void *p)
Definition: malloc.c:178
fftw_plan_struct::n
int n
Definition: fftw.h:272
FFTW_GENERIC
Definition: fftw.h:121
fftw_die
void fftw_die(const char *s)
Definition: malloc.c:192
FOR_ALL_CODELETS
#define FOR_ALL_CODELETS(p)
Definition: planner.c:127
fftw_plan_struct::recurse_kind
fftw_recurse_kind recurse_kind
Definition: fftw.h:281
fftw_generic_codelet
void( fftw_generic_codelet)(fftw_complex *, const fftw_complex *, int, int, int, int)
Definition: fftw.h:98
fftw_plan_node_struct::size
int size
Definition: fftw.h:198
fftw_plan_hook_ptr
void(* fftw_plan_hook_ptr)(fftw_plan plan)
Definition: fftw-int.h:138
fftw_create_plan
fftw_plan fftw_create_plan(int n, fftw_direction dir, int flags)
Definition: planner.c:450
FFTW_MEASURE
#define FFTW_MEASURE
Definition: fftw.h:289
fftw_twiddle_generic
fftw_generic_codelet fftw_twiddle_generic
fftw_make_node_generic
fftw_plan_node * fftw_make_node_generic(int n, int size, fftw_generic_codelet *codelet, fftw_plan_node *recurse, int flags)
Definition: putils.c:133
fftw_plan_struct::root
fftw_plan_node * root
Definition: fftw.h:279
fftw_node_type
fftw_node_type
Definition: fftw.h:120
fftw_plan_hook
fftw_plan_hook_ptr fftw_plan_hook
Definition: planner.c:33
fftw_time
struct timeval fftw_time
Definition: fftw-int.h:352
fftw_make_plan
fftw_plan fftw_make_plan(int n, fftw_direction dir, fftw_plan_node *root, int flags, enum fftw_node_type wisdom_type, int wisdom_signature, fftw_recurse_kind recurse_kind, int vector_size)
Definition: putils.c:266
fftw_plan_node_struct::codelet
fftw_notw_codelet * codelet
Definition: fftw.h:199
FFTW_NO_VECTOR_RECURSE
#define FFTW_NO_VECTOR_RECURSE
Definition: fftw.h:302
fftw_create_plan_specific
fftw_plan fftw_create_plan_specific(int n, fftw_direction dir, int flags, fftw_complex *in, int istride, fftw_complex *out, int ostride)
Definition: planner.c:421
fftw_insert
void fftw_insert(fftw_plan *table, fftw_plan this_plan)
Definition: putils.c:372
fftw_malloc
void * fftw_malloc(size_t n)
Definition: malloc.c:160
FFTW_WISDOM
Definition: fftw-int.h:70
FFTW_VECTOR_RECURSE
Definition: fftw.h:268
fftw_recurse_kind
fftw_recurse_kind
Definition: fftw.h:266
fftwi_twiddle_generic
fftw_generic_codelet fftwi_twiddle_generic
fftw_plan_node_struct::dir
fftw_direction dir
Definition: fftw.h:246
FFTW_TIME_MIN
#define FFTW_TIME_MIN
Definition: fftw-int.h:362
fftw_wisdom_add
void fftw_wisdom_add(int n, int flags, fftw_direction dir, enum fftw_wisdom_category cat, int istride, int ostride, enum fftw_node_type type, int signature, fftw_recurse_kind recurse_kind)
Definition: wisdom.c:85
fftw_estimate_node
double fftw_estimate_node(fftw_plan_node *p)
Definition: putils.c:400
FFTW_TIME_LIMIT
#define FFTW_TIME_LIMIT
Definition: fftw-int.h:492
fftw_make_node_rader
fftw_plan_node * fftw_make_node_rader(int n, int size, fftw_direction dir, fftw_plan_node *recurse, int flags)
Definition: rader.c:345
fftw_time_diff
#define fftw_time_diff(t1, t2)
Definition: fftw-int.h:357
FFTW_RADER
Definition: fftw.h:121
fftw_plan_struct::vector_size
int vector_size
Definition: fftw.h:282
c_re
#define c_re(c)
Definition: fftw.h:60
fftw_wisdom_lookup
int fftw_wisdom_lookup(int n, int flags, fftw_direction dir, enum fftw_wisdom_category category, int istride, int ostride, enum fftw_node_type *type, int *signature, fftw_recurse_kind *recurse_kind, int replace_p)
Definition: wisdom.c:46
FFTW_BACKWARD
Definition: fftw.h:64
fftw_make_node_notw
fftw_plan_node * fftw_make_node_notw(int size, const fftw_codelet_desc *config)
Definition: putils.c:57
fftw_destroy_plan_internal
void fftw_destroy_plan_internal(fftw_plan p)
Definition: putils.c:353
fftw_complete_twiddle
void fftw_complete_twiddle(fftw_plan_node *p, int n)
Definition: putils.c:296
fftw_plan_struct::dir
fftw_direction dir
Definition: fftw.h:274
fftw_config
fftw_codelet_desc * fftw_config[]
Definition: config.c:101
c_im
#define c_im(c)
Definition: fftw.h:61
fftw_plan
struct fftw_plan_struct * fftw_plan
Definition: fftw.h:285
fftw_make_empty_table
void fftw_make_empty_table(fftw_plan *table)
Definition: putils.c:367
fftw_plan_node_struct
Definition: fftw.h:192
FFTW_NOTW
Definition: fftw.h:121
fftw_plan_struct::wisdom_type
enum fftw_node_type wisdom_type
Definition: fftw.h:277
FFTW_FORWARD
Definition: fftw.h:64
fftw_direction
fftw_direction
Definition: fftw.h:63
FFTW_NORMAL_RECURSE
Definition: fftw.h:267
fftw_plan_struct::wisdom_signature
int wisdom_signature
Definition: fftw.h:276
fftw_plan_struct::flags
int flags
Definition: fftw.h:275
fftw_get_time
#define fftw_get_time()
Definition: fftw-int.h:356
fftw_destroy_table
void fftw_destroy_table(fftw_plan *table)
Definition: putils.c:390