Hash :
93b659f9
        
        Author :
  
        
        Date :
2025-07-04T12:35:29
        
      
Remove PoolAllocator push/pop feature PoolAllocator would manage a stack of memory pools upon client calling push() and pop(). This made the code unnecessarily complicated. The feature was only used with nesting of one, to mark the memory unused after a shader compile. Fix by removing the push/pop feature. Instantiate PoolAllocator in places the previous push() was and uninstantiating instead of previous pop(). This removes the feature where the PoolAllocator would hold on to the allocated memory in order to reuse it. This is seen as a progression: the allocator is held by the compiler, the compiler is held by the shader and each shader typically see only one compile. Thus the free pages were just leaking unused until the shader was destroyed. Instead, destructing the PoolAllocator instead of pop() will donate the memory back to platform/OS, where it is likely more useful. To preserve existing Vulkan behavior, add PoolAllocator::reset() which would mark the memory unused but leave them reserved for the PoolAllocator. Removes UB where PageHeader::nextPage would be accessed after ~PageHeader. Bug: angleproject:429513168 Change-Id: I21e58b46e0887380db3a2cab5ce22f0042cfae9e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6701153 Reviewed-by: Geoff Lang <geofflang@chromium.org> Auto-Submit: Kimmo Kinnunen <kkinnunen@apple.com> Commit-Queue: Kimmo Kinnunen <kkinnunen@apple.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
//
// 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_unittest:
//   Tests of the PoolAlloc class
//
#include <gtest/gtest.h>
#include "common/PoolAlloc.h"
namespace angle
{
// Verify the public interface of PoolAllocator class
TEST(PoolAllocatorTest, Interface)
{
    size_t numBytes               = 1024;
    constexpr uint32_t kTestValue = 0xbaadbeef;
    // Create a default pool allocator and allocate from it
    PoolAllocator poolAllocator;
    void *allocation = poolAllocator.allocate(numBytes);
    // Verify non-zero ptr returned
    EXPECT_NE(nullptr, allocation);
    // Write to allocation to check later
    uint32_t *writePtr = static_cast<uint32_t *>(allocation);
    *writePtr          = kTestValue;
    // Test other allocator creating a new allocation
    {
        PoolAllocator poolAllocator2;
        allocation = poolAllocator2.allocate(numBytes);
        EXPECT_NE(nullptr, allocation);
        // Make an allocation that spans multiple pages
        allocation = poolAllocator2.allocate(10 * 1024);
        // Free previous two allocations.
    }
    // Verify first allocation still has data
    EXPECT_EQ(kTestValue, *writePtr);
    // Make a bunch of allocations
    for (uint32_t i = 0; i < 1000; ++i)
    {
        numBytes   = (rand() % (1024 * 4)) + 1;
        allocation = poolAllocator.allocate(numBytes);
        EXPECT_NE(nullptr, allocation);
        // Write data into full allocation. In debug case if we
        //  overwrite any other allocation we get error.
        memset(allocation, 0xb8, numBytes);
    }
}
#if !defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS)
// Verify allocations are correctly aligned for different alignments
class PoolAllocatorAlignmentTest : public testing::TestWithParam<int>
{};
TEST_P(PoolAllocatorAlignmentTest, Alignment)
{
    int alignment = GetParam();
    // Create a pool allocator to allocate from
    PoolAllocator poolAllocator(4096, alignment);
    // Test a number of allocation sizes for each alignment
    for (uint32_t i = 0; i < 100; ++i)
    {
        // Vary the allocation size around 4k to hit some multi-page allocations
        const size_t numBytes = rand() % (1024 * 4) + 1;
        void *allocation      = poolAllocator.allocate(numBytes);
        // Verify alignment of allocation matches expected default
        EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(allocation) % alignment)
            << "Iteration " << i << " allocating " << numBytes;
    }
}
INSTANTIATE_TEST_SUITE_P(,
                         PoolAllocatorAlignmentTest,
                         testing::Values(2, 4, 8, 16, 32, 64, 128),
                         testing::PrintToStringParamName());
#endif
}  // namespace angle