Class AlignedAllocator

Synopsis

#include <Source/Falcor/Utils/AlignedAllocator.h>

class AlignedAllocator

Description

Utility class for aligned memory allocations on the GPU.

AlignedAllocator can enforce various alignment requirements, including minimum byte alignment and (optionally) that allocated objects don't span two cache lines if they can fit into one. Note that it's intended to be used to manage GPU allocations and so it assumes that the base pointer starts at a cache line. As such, it doesn't provide any alignment guarantees on the CPU side (where it doesn't matter anyway).

Methods

allocateAllocates an object of given type and executes its constructor.
allocateSizedAllocates an object of given type, potentially including additional memory at the end of it, and executes its constructor.
getCapacity
getSize
getStartPointerReturns the pointer to the start of the allocated buffer.
offsetOfReturns of the offset of the given pointer inside the allocation buffer.
reserve
reset
resize
setCacheLineSizeSets the cache line size so that allocations can be aligned so that they don't span multiple cache lines (if possible)
setMinimumAlignmentSets the minimum alignment for allocated objects

Source

Lines 45-154 in Source/Falcor/Utils/AlignedAllocator.h.

class AlignedAllocator
{
public:
    /** Sets the minimum alignment for allocated objects. If a value of
        zero is provided, no additional alignment is performed.
    */
    void setMinimumAlignment(int minAlignment)
    {
        assert(minAlignment == 0 || isPowerOf2(minAlignment));
        mMinAlignment = minAlignment;
    }
    /** Sets the cache line size so that allocations can be aligned so
        that they don't span multiple cache lines (if possible).  If a
        value of zero is provided, then the allocator doesn't prevent
        objects from spanning cache lines.
    */
    void setCacheLineSize(int cacheLineSize)
    {
        assert(cacheLineSize == 0 || isPowerOf2(cacheLineSize));
        mCacheLineSize = cacheLineSize;
    }
    /** Allocates an object of given type and executes its constructor.
        \param[in] args Arguments to pass to the constructor.
        \return pointer to allocated object.
    */
    template <typename T, typename ...Args> T* allocate(Args&&... args)
    {
        const size_t size = sizeof(T);
        computeAndAllocatePadding(size);
        void* ptr = allocInternal(size);
        return new (ptr) T(std::forward<Args>(args)...);
    }
    /** Allocates an object of given type, potentially including additional memory at
        the end of it, and executes its constructor.
        \param[in] size Amount of memory to allocate. Must be >= sizeof(T).
        \param[in] args Arguments to pass to the constructor.
        \return pointer to allocated object.
    */
    template <typename T, typename ...Args> T* allocateSized(size_t size, Args&&... args)
    {
        assert(size >= sizeof(T));
        computeAndAllocatePadding(size);
        void* ptr = allocInternal(size);
        return new (ptr) T(std::forward<Args>(args)...);
    }
    void reserve(size_t size) { mBuffer.reserve(size); }
    void resize(size_t size) { mBuffer.resize(size, 0); }
    /** Returns the pointer to the start of the allocated buffer.
    */
    void* getStartPointer() { return mBuffer.data(); }
    const void* getStartPointer() const { return mBuffer.data(); }
    /** Returns of the offset of the given pointer inside the allocation buffer.
    */
    size_t offsetOf(void* ptr) const
    {
        assert(ptr >= mBuffer.data() && ptr < mBuffer.data() + mBuffer.size());
        return static_cast<uint8_t*>(ptr) - mBuffer.data();
    }
    void reset() { mBuffer.clear(); }
    size_t getSize() const { return mBuffer.size(); }
    size_t getCapacity() const { return mBuffer.capacity(); }
private:
    void computeAndAllocatePadding(size_t size)
    {
        const size_t currentOffset = mBuffer.size();
        if (mCacheLineSize > 0)
        {
            const size_t cacheLineOffset = currentOffset % mCacheLineSize;
            if (size < mCacheLineSize && cacheLineOffset + size > mCacheLineSize)
            {
                // The allocation is smaller than a cache line but
                // would span two cache lines; move to the start of the
                // next cache line.
                const size_t pad = mCacheLineSize - cacheLineOffset;
                (void)allocInternal(pad);
                // There's need to worry about any further alignment
                // issues now.
                return;
            }
        }
        if (mMinAlignment > 0 && currentOffset % mMinAlignment)
        {
            // We're not at the minimum alignment; get aligned.
            const size_t pad = mMinAlignment - (currentOffset % mMinAlignment);
            (void)allocInternal(pad);
        }
    }
    void* allocInternal(size_t size)
    {
        auto iter = mBuffer.insert(mBuffer.end(), size, {});
        return &*iter;
    }
    size_t mMinAlignment = 16;
    size_t mCacheLineSize = 128;
    std::vector<uint8_t> mBuffer;
};





Add Discussion as Guest

Log in to DocsForge