FFTW implements a method for saving plans to disk and restoring 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:
plan = fftw_create_plan(..., ... | FFTW_MEASURE | FFTW_USE_WISDOM);
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 very quickly without measurements. (FFTW still needs some time
to compute trigonometric tables, however.) The basic outline is:
fftw_import_wisdom(...);
plan = fftw_create_plan(..., ... | FFTW_USE_WISDOM);
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) quickly, 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 logarithm 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 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.
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
seriously 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.
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.