Edit

kc3-lang/angle/src/common/PoolAlloc.h

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-10-06 21:12:39
    Hash : 161668b6
    Message : Refix ANGLE_DISABLE_POOL_ALLOC build mAlignmentMask was removed in the normal path, but wasn't entirely from this path. This change cleans that up. Bug: angleproject:3167 Change-Id: I34474c114cd50cf94c5bc3c22ad4548414e9baac Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3210627 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Yuly Novikov <ynovikov@chromium.org>

  • src/common/PoolAlloc.h
  • //
    // Copyright 2019 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // PoolAlloc.h:
    //    Defines the class interface for PoolAllocator.
    //
    
    #ifndef COMMON_POOLALLOC_H_
    #define COMMON_POOLALLOC_H_
    
    #if !defined(NDEBUG)
    #    define ANGLE_POOL_ALLOC_GUARD_BLOCKS  // define to enable guard block checking
    #endif
    
    //
    // This header defines an allocator that can be used to efficiently
    // allocate a large number of small requests for heap memory, with the
    // intention that they are not individually deallocated, but rather
    // collectively deallocated at one time.
    //
    // This simultaneously
    //
    // * Makes each individual allocation much more efficient; the
    //     typical allocation is trivial.
    // * Completely avoids the cost of doing individual deallocation.
    // * Saves the trouble of tracking down and plugging a large class of leaks.
    //
    // Individual classes can use this allocator by supplying their own
    // new and delete methods.
    //
    
    #include "angleutils.h"
    #include "common/debug.h"
    
    namespace angle
    {
    class Allocation;
    class PageHeader;
    
    //
    // There are several stacks.  One is to track the pushing and popping
    // of the user, and not yet implemented.  The others are simply a
    // repositories of free pages or used pages.
    //
    // Page stacks are linked together with a simple header at the beginning
    // of each allocation obtained from the underlying OS.  Multi-page allocations
    // are returned to the OS.  Individual page allocations are kept for future
    // re-use.
    //
    // The "page size" used is not, nor must it match, the underlying OS
    // page size.  But, having it be about that size or equal to a set of
    // pages is likely most optimal.
    //
    class PoolAllocator : angle::NonCopyable
    {
      public:
        static const int kDefaultAlignment = sizeof(void *);
        //
        // Create PoolAllocator. If alignment is set to 1 byte then fastAllocate()
        //  function can be used to make allocations with less overhead.
        //
        PoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = kDefaultAlignment);
    
        //
        // Don't call the destructor just to free up the memory, call pop()
        //
        ~PoolAllocator();
    
        //
        // Initialize page size and alignment after construction
        //
        void initialize(int pageSize, int alignment);
    
        //
        // Call push() to establish a new place to pop memory to.  Does not
        // have to be called to get things started.
        //
        void push();
    
        //
        // Call pop() to free all memory allocated since the last call to push(),
        // or if no last call to push, frees all memory since first allocation.
        //
        void pop();
    
        //
        // Call popAll() to free all memory allocated.
        //
        void popAll();
    
        //
        // Call allocate() to actually acquire memory.  Returns 0 if no memory
        // available, otherwise a properly aligned pointer to 'numBytes' of memory.
        //
        void *allocate(size_t numBytes);
    
        //
        // Call fastAllocate() for a faster allocate function that does minimal bookkeeping
        // preCondition: Allocator must have been created w/ alignment of 1
        ANGLE_INLINE uint8_t *fastAllocate(size_t numBytes)
        {
    #if defined(ANGLE_DISABLE_POOL_ALLOC)
            return reinterpret_cast<uint8_t *>(allocate(numBytes));
    #else
            ASSERT(mAlignment == 1);
            // No multi-page allocations
            ASSERT(numBytes <= (mPageSize - mPageHeaderSkip));
            //
            // Do the allocation, most likely case inline first, for efficiency.
            //
            if (numBytes <= mPageSize - mCurrentPageOffset)
            {
                //
                // Safe to allocate from mCurrentPageOffset.
                //
                uint8_t *memory = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset;
                mCurrentPageOffset += numBytes;
                return memory;
            }
            return allocateNewPage(numBytes);
    #endif
        }
    
        // There is no deallocate.  The point of this class is that deallocation can be skipped by the
        // user of it, as the model of use is to simultaneously deallocate everything at once by calling
        // pop(), and to not have to solve memory leak problems.
    
        // Catch unwanted allocations.
        // TODO(jmadill): Remove this when we remove the global allocator.
        void lock();
        void unlock();
    
      private:
        size_t mAlignment;  // all returned allocations will be aligned at
                            // this granularity, which will be a power of 2
    #if !defined(ANGLE_DISABLE_POOL_ALLOC)
        struct AllocState
        {
            size_t offset;
            PageHeader *page;
        };
        using AllocStack = std::vector<AllocState>;
    
        // Slow path of allocation when we have to get a new page.
        uint8_t *allocateNewPage(size_t numBytes);
        // Track allocations if and only if we're using guard blocks
        void *initializeAllocation(uint8_t *memory, size_t numBytes);
    
        // Granularity of allocation from the OS
        size_t mPageSize;
        // Amount of memory to skip to make room for the page header (which is the size of the page
        // header, or PageHeader in PoolAlloc.cpp)
        size_t mPageHeaderSkip;
        // Next offset in top of inUseList to allocate from.  This offset is not necessarily aligned to
        // anything.  When an allocation is made, the data is aligned to mAlignment, and the header (if
        // any) will align to pointer size by extension (since mAlignment is made aligned to at least
        // pointer size).
        size_t mCurrentPageOffset;
        // List of popped memory
        PageHeader *mFreeList;
        // List of all memory currently being used.  The head of this list is where allocations are
        // currently being made from.
        PageHeader *mInUseList;
        // Stack of where to allocate from, to partition pool
        AllocStack mStack;
    
        int mNumCalls;       // just an interesting statistic
        size_t mTotalBytes;  // just an interesting statistic
    
    #else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
        std::vector<std::vector<void *>> mStack;
    #endif
    
        bool mLocked;
    };
    
    }  // namespace angle
    
    #endif  // COMMON_POOLALLOC_H_