From a DSP source file, the Faust compiler typically generates a C++ class. When a rdtable item is used on the source code, the C++ class will contain a table shared by all instances of the class. By default, this table is generated as a static class array, and so allocated in the application global static memory.
In some specific case (usually in more constrained deployment cases), managing where this data is allocated is crucial. By extension this post explains how a custom memory allocator can be used to precisely control the DSP memory allocation.
Faust -mem option to control memory related code generation
A new -mem compiler parameter has been added in the Faust compiler, starting from the 0.9.103 version (or 2.1.4 in Faust2 branch). This parameter will change the way static shared tables are generated. The table is allocated as a class static pointer allocated using a custom memory allocator, which has the following propotype:
Taking the following Faust DSP example:
Here is the generated code in default mode:
The two itbl0 and ftbl0 tables are static class arrays. They are filled in the classInit method. The architecture code will typically call the init method (which calls classInit) on a given DSP, to allocate class related arrays and the DSP itself. If several DSP are going to be allocated, calling classInit only once then the instanceInit method on each allocated DSP is the way to go.
In the new -mem mode, the generated C++ code is now:
The two itbl0 and ftbl0 tables are generated a class static pointers. The classInit method takes the additional dsp_memory_manager object used to allocate tables. A new classDestroy method is available to deallocate the tables. Finally the init method is now empty, since the architecure file is supposed to use the classInit/classDestroy method once to allocate and deallocate static tables, and the instanceInit method on each allocated DSP.
Control of the DSP memory allocation
An architecture file can now define its custom memory manager by subclassing the dsp_memory_manager abstract base class, and implement the two required allocate and destroy methods. Here is an example of a simple heap allocating manager:
Controlling the table memory allocation
To control table memory allocation, the architecture file will have to do:
Controlling the complete DSP memory allocation
Full control the DSP memory allocation can be done using C++ placement new:
More complex custom memory allocators can be developed by refining this malloc_memory_manager example, possibly defining real-time memory allocators…etc… The OWL architecture file already uses this new custom memory allocator model.
This is a work in progress:
- in the Faust2 branch, this model is still not supported yet beside the C++ backend
- custom memory allocator is not yet supported is additional DSP classes (like the mydsp_poly defined in the achitecture/faust/dsp/poly-dsp.h header).