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