CMSIS-DSP  
CMSIS DSP Software Library
 
Loading...
Searching...
No Matches
Memory allocation

By default, malloc is used.

Vector<float32_t,NB>

is allocating a vector of dimension NB (known at build time) and datatype float32_t.

The definition of the Vector template is:

template<typename P,
int L=DYNAMIC,
template<int> typename Allocator = TMP_ALLOC>
struct Vector:Vector_Base<P>

It means that by default the memory allocator is TMP_ALLOC.

This TMP_ALLOC is a #define and can be changed if you define it before including any header from the library.

An allocator should implement a template like:

template<int L>
struct malloc_allocator {
/* Dynamic dimension allocations (L<0) */
static char* allocate ( vector_length_t sz) noexcept;
/* Dimension L know at build time (L > 0) */
static char* allocate ( ) noexcept;
static void destroy ( char* ptr ) noexcept;
};

It has no state because in practice we observed that compilers were generating more efficient code without state in the memory allocator template.

If you don't want to use a malloc based memory allocator, you can replace it with your own memory allocator and implement an API like the one just shown in malloc_allocator.

For instance, often in DSP pipelines, the dimensions of the vectors and matrixes are fixed and known at build time. In that case, you could replace the memory allocator by one using memory pools.

With memory pools, allocation is nearly cost free and there is no fragmentation.

The test framework of the library is providing an example in allocator.h and allocator.cpp.

There are two memory allocators:

  1. stat_allocator is a malloc based allocator that is making statistics on the memory allocations and how many buffers of each dimension is required
  2. pool_allocator can use the data generated by stat_allocatorto pre-allocate memory pools that will be then used for the memory allocations. The memory pools are also creating aligned buffers.

It is no more difficult (and less difficult) than allocating temporary buffers in CMSIS-DSP.

You could define the TMP_ALLOC with:

#if defined(POOL_ALLOCATOR)
#define TMP_ALLOC pool_allocator
#else
#define TMP_ALLOC stat_allocator
#endif

You use stat_allocator by default. When your code is working, you switch to pool_allocator to have better performance and determinism.

Another possibility is to use different vector types:

template<typename P,int L=arm_cmsis_dsp::DYNAMIC>
using PVector = Vector<P,L,pool_allocator>;

Note that you cannot avoid using TMP_ALLOC because some functions in the library are creating temporary objects. For instance, if you want to make an identity matrix, you can use mk_identity that will make a memory allocation using TMP_ALLOC

Also note that if you create a vector with:

Vector<float32_t> v(NB);

then the dimension NB is a runtime parameter. The memory pool allocator given as example in this library is only working with dimensions known at build time. For runtime dimensions, it is still using a malloc.