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 * wisdom.c -- manage the wisdom
22 */
23
24 #include "fftw-int.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28
29 struct wisdom {
30 int n;
31 int flags;
32 fftw_direction dir;
33 enum fftw_wisdom_category category;
34 int istride;
35 int ostride;
36 int vector_size;
37 enum fftw_node_type type; /* this is the wisdom */
38 int signature; /* this is the wisdom */
39 fftw_recurse_kind recurse_kind; /* this is the wisdom */
40 struct wisdom *next;
41 };
42
43 /* list of wisdom */
44 static struct wisdom *wisdom_list = (struct wisdom *) 0;
45
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 replacep)46 int fftw_wisdom_lookup(int n, int flags, fftw_direction dir,
47 enum fftw_wisdom_category category,
48 int istride, int ostride,
49 enum fftw_node_type *type,
50 int *signature, fftw_recurse_kind *recurse_kind,
51 int replacep)
52 {
53 struct wisdom *p;
54
55 if (!(flags & FFTW_USE_WISDOM))
56 return 0; /* simply ignore if wisdom is disabled */
57
58 flags |= FFTW_MEASURE; /*
59 * always use (only) wisdom from
60 * measurements
61 */
62
63 for (p = wisdom_list; p; p = p->next) {
64 if (p->n == n && p->flags == flags && p->dir == dir &&
65 p->istride == istride && p->ostride == ostride &&
66 p->category == category) {
67 /* found wisdom */
68 if (replacep) {
69 /* replace old wisdom with new */
70 p->type = *type;
71 p->signature = *signature;
72 p->recurse_kind = *recurse_kind;
73 } else {
74 *type = p->type;
75 *signature = p->signature;
76 *recurse_kind = p->recurse_kind;
77 }
78 return 1;
79 }
80 }
81
82 return 0;
83 }
84
fftw_wisdom_add(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)85 void fftw_wisdom_add(int n, int flags, fftw_direction dir,
86 enum fftw_wisdom_category category,
87 int istride, int ostride,
88 enum fftw_node_type type,
89 int signature,
90 fftw_recurse_kind recurse_kind)
91 {
92 struct wisdom *p;
93
94 if ((flags & FFTW_NO_VECTOR_RECURSE) &&
95 recurse_kind == FFTW_VECTOR_RECURSE)
96 fftw_die("bug in planner (conflicting plan options)\n");
97
98 if (!(flags & FFTW_USE_WISDOM))
99 return; /* simply ignore if wisdom is disabled */
100
101 if (!(flags & FFTW_MEASURE))
102 return; /* only measurements produce wisdom */
103
104 if (fftw_wisdom_lookup(n, flags, dir, category, istride, ostride,
105 &type, &signature, &recurse_kind, 1))
106 return; /* wisdom overwrote old wisdom */
107
108 p = (struct wisdom *) fftw_malloc(sizeof(struct wisdom));
109
110 p->n = n;
111 p->flags = flags;
112 p->dir = dir;
113 p->category = category;
114 p->istride = istride;
115 p->ostride = ostride;
116 p->type = type;
117 p->signature = signature;
118 p->recurse_kind = recurse_kind;
119
120 /* remember this wisdom */
121 p->next = wisdom_list;
122 wisdom_list = p;
123 }
124
fftw_forget_wisdom(void)125 void fftw_forget_wisdom(void)
126 {
127 while (wisdom_list) {
128 struct wisdom *p;
129
130 p = wisdom_list;
131 wisdom_list = wisdom_list->next;
132 fftw_free(p);
133 }
134 }
135
136 /*
137 * user-visible routines, to convert wisdom into strings etc.
138 */
139 static const char *WISDOM_FORMAT_VERSION = "FFTW-" FFTW_VERSION;
140
141 static void (*emit) (char c, void *data);
142
emit_string(const char * s,void * data)143 static void emit_string(const char *s, void *data)
144 {
145 while (*s)
146 emit(*s++, data);
147 }
148
emit_int(int n,void * data)149 static void emit_int(int n, void *data)
150 {
151 char buf[128];
152
153 sprintf(buf, "%d", n);
154 emit_string(buf, data);
155 }
156
157 /* dump wisdom in lisp-like format */
fftw_export_wisdom(void (* emitter)(char c,void *),void * data)158 void fftw_export_wisdom(void (*emitter) (char c, void *), void *data)
159 {
160 struct wisdom *p;
161
162 /* install the output handler */
163 emit = emitter;
164
165 emit('(', data);
166 emit_string(WISDOM_FORMAT_VERSION, data);
167
168 for (p = wisdom_list; p; p = p->next) {
169 emit(' ', data); /* separator to make the output nicer */
170 emit('(', data);
171 emit_int((int) p->n, data);
172 emit(' ', data);
173 emit_int((int) p->flags, data);
174 emit(' ', data);
175 emit_int((int) p->dir, data);
176 emit(' ', data);
177 emit_int((int) p->category, data);
178 emit(' ', data);
179 emit_int((int) p->istride, data);
180 emit(' ', data);
181 emit_int((int) p->ostride, data);
182 emit(' ', data);
183 emit_int((int) p->type, data);
184 emit(' ', data);
185 emit_int((int) p->signature, data);
186 emit(' ', data);
187 emit_int((int) p->recurse_kind, data);
188 emit(')', data);
189 }
190 emit(')', data);
191 }
192
193 /* input part */
194 static int next_char;
195 static int (*get_input) (void *data);
196 static fftw_status input_error;
197
read_char(void * data)198 static void read_char(void *data)
199 {
200 next_char = get_input(data);
201 if (next_char == 0 ||
202 next_char == EOF)
203 input_error = FFTW_FAILURE;
204 }
205
206 /* skip blanks, newlines, tabs, etc */
eat_blanks(void * data)207 static void eat_blanks(void *data)
208 {
209 while (isspace(next_char))
210 read_char(data);
211 }
212
read_int(void * data)213 static int read_int(void *data)
214 {
215 int sign = 1;
216 int n = 0;
217
218 eat_blanks(data);
219 if (next_char == '-') {
220 sign = -1;
221 read_char(data);
222 eat_blanks(data);
223 }
224 if (!isdigit(next_char)) {
225 /* error, no digit */
226 input_error = FFTW_FAILURE;
227 return 0;
228 }
229 while (isdigit(next_char)) {
230 n = n * 10 + (next_char - '0');
231 read_char(data);
232 }
233
234 return sign * n;
235 }
236
237 #define EXPECT(c) \
238 { \
239 eat_blanks(data); \
240 if (input_error == FFTW_FAILURE || \
241 next_char != c) \
242 return FFTW_FAILURE; \
243 read_char(data); \
244 }
245
246 #define EXPECT_INT(n) \
247 { \
248 n = read_int(data); \
249 if (input_error == FFTW_FAILURE) \
250 return FFTW_FAILURE; \
251 }
252
253 #define EXPECT_STRING(s) \
254 { \
255 const char *s1 = s; \
256 while (*s1) { \
257 EXPECT(*s1); \
258 ++s1; \
259 } \
260 }
261
fftw_import_wisdom(int (* g)(void *),void * data)262 fftw_status fftw_import_wisdom(int (*g) (void *), void *data)
263 {
264 int n;
265 int flags;
266 fftw_direction dir;
267 int dir_int;
268 enum fftw_wisdom_category category;
269 int category_int;
270 enum fftw_node_type type;
271 int recurse_kind_int;
272 fftw_recurse_kind recurse_kind;
273 int type_int;
274 int signature;
275 int istride, ostride;
276
277 get_input = g;
278 input_error = FFTW_SUCCESS;
279
280 read_char(data);
281
282 eat_blanks(data);
283 EXPECT('(');
284 eat_blanks(data);
285 EXPECT_STRING(WISDOM_FORMAT_VERSION);
286 eat_blanks(data);
287
288 while (next_char != ')') {
289 EXPECT('(');
290 EXPECT_INT(n);
291 EXPECT_INT(flags);
292 /* paranoid respect for enumerated types */
293 EXPECT_INT(dir_int);
294 dir = (fftw_direction) dir_int;
295 EXPECT_INT(category_int);
296 category = (enum fftw_wisdom_category) category_int;
297 EXPECT_INT(istride);
298 EXPECT_INT(ostride);
299 EXPECT_INT(type_int);
300 type = (enum fftw_node_type) type_int;
301 EXPECT_INT(signature);
302 EXPECT_INT(recurse_kind_int);
303 recurse_kind = (fftw_recurse_kind) recurse_kind_int;
304 eat_blanks(data);
305 EXPECT(')');
306
307 /* the wisdom has been read properly. Add it */
308 fftw_wisdom_add(n, flags, dir, category,
309 istride, ostride,
310 type, signature, recurse_kind);
311
312 /* prepare for next morsel of wisdom */
313 eat_blanks(data);
314 }
315
316 return FFTW_SUCCESS;
317 }
318