Go to the first, previous, next, last section, table of contents.

Words of Wisdom

FFTW implements a method to save plans to disk and restore them. In fact, what FFTW does is more general than just saving and loading plans. The mechanism is called wisdom. Here, we describe this feature at a high level. See section FFTW Reference, for a less casual (but more complete) discussion of how to use wisdom in FFTW.

Plans created with the FFTW_MEASURE option produce near-optimal FFT performance, but it can take a long time to compute a plan because FFTW must actually measure the runtime of many possible plans and select the best one. This is designed for the situations where so many transforms of the same size must be computed that the start-up time is irrelevant. For short initialization times but slightly slower transforms, we have provided FFTW_ESTIMATE. The wisdom mechanism is a way to get the best of both worlds. There are, however, certain caveats that the user must be aware of in using wisdom. For this reason, wisdom is an optional feature which is not enabled by default.

At its simplest, wisdom provides a way of saving plans to disk so that they can be reused in other program runs. You create a plan with the flags FFTW_MEASURE and FFTW_USE_WISDOM, and then save the wisdom using fftw_export_wisdom. The next time you run the program, you can restore the wisdom with fftw_import_wisdom, and then recreate the plan using the same flags as before. This time, however, the same optimal plan will be created (relatively) instantaneously, without measurements.

Wisdom is more than mere rote memorization, however. FFTW's wisdom encompasses all of the knowledge and measurements that were used to create the plan for a given size. Therefore, existing wisdom is also applied to the creation of other plans of different sizes.

Whenever a plan is created with the FFTW_MEASURE and FFTW_USE_WISDOM flags, wisdom is generated. Thereafter, plans for any transform with a similar factorization will be computed more quickly, so long as they use the FFTW_USE_WISDOM flag. In fact, for transforms with the same factors and of equal or lesser size, no measurements at all need to be made and an optimal plan can be created with negligible delay!

For example, suppose that you create a plan for N = 216. Then, for any equal or smaller power of two, FFTW can create a plan (with the same direction and flags) instantaneously, using the precomputed wisdom. Even for larger powers of two, or sizes that are a power of two times some other prime factors, plans will be computed more quickly than they would otherwise (although some measurements still have to be made).

The wisdom is cumulative, and is stored in a global, private data structure managed internally by FFTW. The storage space required is minimal, proportional to the log of the sizes the wisdom was generated from. The wisdom can be forgotten (and its associated memory freed) by a call to fftw_forget_wisdom(); otherwise, it is remembered until the program terminates. It can also be exported to a file, a string, or any other medium using fftw_export_wisdom and restored during a subsequent execution of the program (or a different program) using fftw_import_wisdom (these functions are described below).

Because wisdom is incorporated into FFTW at a very low level, the same wisdom can be used for one-dimensional transforms, multi-dimensional transforms, and even the real-complex and parallel extensions to FFTW. Just include FFTW_USE_WISDOM in the flags for whatever plans you create (i.e., always plan wisely).

Plans created with the FFTW_ESTIMATE plan can use wisdom, but cannot generate it; only FFTW_MEASURE plans actually produce wisdom. Also, plans can only use wisdom generated from plans created with the same direction and flags. For example, a size 42 FFTW_BACKWARD transform will not use wisdom produced by a size 42 FFTW_FORWARD transform. The only exception to this rule is that FFTW_ESTIMATE plans can use wisdom from FFTW_MEASURE plans.

Caveats in using wisdom

For in much wisdom is much grief, and he that increaseth knowledge increaseth sorrow. [Ecclesiastes 1:18]

There are pitfalls to using wisdom, in that it can negate FFTW's ability to adapt to changing hardware and other conditions. For example, it would be perfectly possible to export wisdom from a program running on one processor and import it into a program running on another processor. Doing so, however, would mean that the second program would use plans optimized for the first processor, instead of the one it is running on.

It should be safe to reuse wisdom as long as the hardware and program binaries remain unchanged. (Actually, the optimal plan may change even between runs of the same binary on identical hardware, due to differences in the virtual memory environment, etcetera. Users really interested in performance should worry about this problem, too.) It is likely that, if the same wisdom is used for two different program binaries, even running on the same machine, the plans may be sub-optimal because of differing code alignments. It is therefore wise to recreate wisdom every time an application is recompiled. The more the underlying hardware and software changes between the creation of wisdom and its use, the greater grows the risk of sub-optimal plans.

On an unrelated note, we should point out that the accumulation of wisdom is not thread-safe, although the utilization of wisdom is.

Importing and exporting wisdom

void fftw_export_wisdom_to_file(FILE *output_file);
fftw_status fftw_import_wisdom_from_file(FILE *input_file);

fftw_export_wisdom_to_file writes the wisdom to output_file, which must be a file open for writing. fftw_import_wisdom_from_file reads the wisdom from input_file, which must be a file open for reading, and returns FFTW_SUCCESS if successful and FFTW_FAILURE otherwise. In both cases, the file is left open and must be closed by the caller. It is perfectly fine if other data lie before or after the wisdom in the file, as long as the file is positioned at the beginning of the wisdom data before import.

char *fftw_export_wisdom_to_string(void);
fftw_status fftw_import_wisdom_from_string(const char *input_string)

fftw_export_wisdom_to_string allocates a string, exports the wisdom to it in NULL-terminated format, and returns a pointer to the string. If there is an error in allocating or writing the data, it returns NULL. The caller is responsible for deallocating the string (with fftw_free) when she is done with it. fftw_import_wisdom_from_string imports the wisdom from input_string, returning FFTW_SUCCESS if successful and FFTW_FAILURE otherwise.

Exporting wisdom does not affect the store of wisdom. Imported wisdom supplements the current store rather than replacing it (except when there is conflicting wisdom, in which case the older wisdom is discarded). The format of the exported wisdom is "nerd-readable" LISP-like ASCII text; we will not document it here except to note that it is insensitive to white space (interested users can contact us for more details).

See section FFTW Reference, for more information, and for a description of how you can implement wisdom import/export for other media besides files and strings.

The following is a brief example in which the wisdom is read from a file, a plan is created (possibly generating more wisdom), and then the wisdom is exported to a string and printed to stdout.

{
     fftw_plan plan;
     char *wisdom_string;
     FILE *input_file;

     /* open file to read wisdom from */
     input_file = fopen("sample.wisdom", "r");
     if (FFTW_FAILURE == fftw_import_wisdom_from_file(input_file))
          printf("Error reading wisdom!\n");
     fclose(input_file); /* be sure to close the file! */

     /* create a plan for N=64, possibly creating and/or using wisdom */
     plan = fftw_create_plan(64,FFTW_FORWARD,
                             FFTW_MEASURE | FFTW_USE_WISDOM);

     /* ... do some computations with the plan ... */

     /* always destroy plans when you are done */
     fftw_destroy_plan(plan); 

     /* write the wisdom to a string */
     wisdom_string = fftw_export_wisdom_to_string();
     if (wisdom_string != NULL) {
          printf("Accumulated wisdom: %s\n",wisdom_string);

          /* Just for fun, destroy and restore the wisdom */
          fftw_forget_wisdom(); /* all gone! */
          fftw_import_wisdom_from_string(wisdom_string); 
          /* wisdom is back! */

          fftw_free(wisdom_string); /* deallocate it since we're done */
     }
}

Go to the first, previous, next, last section, table of contents.