GemaCoreLib
The GeMA Core library
Public Member Functions | Protected Attributes | List of all members
GmPerThreadAppendBuffer< T, Base > Class Template Reference

An implementation of the GmAppendBuffer interface based on a "per thread" growing buffer. More...

#include <gmAppendBuffer.h>

Inheritance diagram for GmPerThreadAppendBuffer< T, Base >:
Inheritance graph
[legend]
Collaboration diagram for GmPerThreadAppendBuffer< T, Base >:
Collaboration graph
[legend]

Public Member Functions

 GmPerThreadAppendBuffer (size_t initSize, double resizeFactor=2.0, int numThreads=-1)
 Buffer constructor. Can optionally pre allocate the buffer with initSize entries. If initSize is zero, a call to reserve() MUST be made before any append. More...
 
 ~GmPerThreadAppendBuffer ()
 Destructor.
 
virtual void clear ()
 
virtual void reserve (size_t bsize)
 Pre allocates buffer sizes. See basic description on the base class Should not be called if the size was given in the constructor. More...
 
virtual void append (const T &val)
 
virtual void appendFromThread (int tid, const T &val)
 
virtual size_t size () const
 
virtual T * data ()
 
virtual size_t usedMemory () const
 

Protected Attributes

GmTLS< QVarLengthArray< T >, false > _data
 Per thread buffers.
 
bool _globalOnly
 Flag set to true if the user passed zero as the number of threads for the constructor.
 
int _nt
 Number of threads considered for buffer pre-allocation & parallel memcopy.
 
T * _dataBuffer
 The single buffer after a call to data()
 
size_t _dataSize
 The size in _dataBuffer when _dataBuffer is not NULL.
 

Detailed Description

template<class T, class Base = GmAppendBuffer<T>>
class GmPerThreadAppendBuffer< T, Base >

An implementation of the GmAppendBuffer interface based on a "per thread" growing buffer.

This class uses a TLS strategy for providing a per thread buffer implemented by a QVarLengthArray. Tests show that an implementation with std::vector can be up to 25% slower!!! The drawback is that QVarLengthArray uses an int for control and so can overflow with a large number of appends (but that is not so bad since the global buffer size is splitted between threads). TODO: implement a variable

growing buffer with a size_t controll.

The global initial buffer size needs to be informed either in the constructor or by a call to reserve(). The requested size will be splitted equaly among the number of threads informed in the object constructor (defaulting to the maximum number of threads configured in the thread manager). If the number of threads is zero, only the "local buffer" will be pre allocated with the full requested size (the locall buffer is not allocated at all if the number of threads is greater than zero).

Calling data() will either return the internal vector if there are no threads and only the local buffer was used, or will allocate a new vector and fill it with the per thread data. In that case, thread vectors will be merged one after the other with no guaranteed ordering among the appends.

This calss is in general very efficient but can be a problem in constrained memory scenarios due to the buffer growing algorithm and by the need to allocate a new buffer to consolidate per thread data when data() is called.

OBS: This class inherits from a template parameter Base, defaulted to GmAppendBuffer, in order to make it easy for changing the base class to another one that inherits GmAppendBuffer adding additional methods, as is done in the GmSparseMatrixTripletBuffer class.

Constructor & Destructor Documentation

◆ GmPerThreadAppendBuffer()

template<class T, class Base = GmAppendBuffer<T>>
GmPerThreadAppendBuffer< T, Base >::GmPerThreadAppendBuffer ( size_t  initSize,
double  resizeFactor = 2.0,
int  numThreads = -1 
)
inline

Buffer constructor. Can optionally pre allocate the buffer with initSize entries. If initSize is zero, a call to reserve() MUST be made before any append.

The initSize value represents the total number of expected append() calls in all threads combined. Each thread buffer will be pre-allocated with the given size divided by the number of thread buffers.

The number of threads defaults to the maximum number of threads as seen by the thread manager (when numThreads is -1), but can be given by the numThreads parameter.

Keep in mind that the given parameter does NOT affects the number of buffers in the thread local storage. This will always be equal to the maximum number of threads as seen by the thread manager. It will affect only the number of buffers that will have a pre-allocated size.

If the number of threads is 0, only the Local buffer will be preallocated (with initSize). Otherwise, the first numThread buffers will be pre-allocated (with size equal to initSize / numThreads).

Member Function Documentation

◆ reserve()

template<class T, class Base = GmAppendBuffer<T>>
virtual void GmPerThreadAppendBuffer< T, Base >::reserve ( size_t  bsize)
inlinevirtual

Pre allocates buffer sizes. See basic description on the base class Should not be called if the size was given in the constructor.

The given size will be splitted by the number of threads as explained on the class constructor description.


The documentation for this class was generated from the following file: