A Modern GPGPU API & wip linux RDNA2+ Driver
rdna driver linux gpu
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

amdgpu: added unit tests for TLSF

+199 -13
+2
CMakeLists.txt
··· 7 7 LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 8 8 LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/sanitizers") 9 9 10 + include(cmake/CPM.cmake) 11 + 10 12 find_package(Sanitizers) 11 13 12 14 include(GitSubmoduleInit)
+24
cmake/CPM.cmake
··· 1 + # SPDX-License-Identifier: MIT 2 + # 3 + # SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors 4 + 5 + set(CPM_DOWNLOAD_VERSION 0.42.1) 6 + set(CPM_HASH_SUM "f3a6dcc6a04ce9e7f51a127307fa4f699fb2bade357a8eb4c5b45df76e1dc6a5") 7 + 8 + if(CPM_SOURCE_CACHE) 9 + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 10 + elseif(DEFINED ENV{CPM_SOURCE_CACHE}) 11 + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 12 + else() 13 + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 14 + endif() 15 + 16 + # Expand relative path. This is important if the provided path contains a tilde (~) 17 + get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) 18 + 19 + file(DOWNLOAD 20 + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake 21 + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} 22 + ) 23 + 24 + include(${CPM_DOWNLOAD_LOCATION})
+26 -1
drivers/CMakeLists.txt
··· 10 10 function(add_kestrel_driver DRIVER_NAME) 11 11 set(TARGET_NAME "kes_${DRIVER_NAME}") 12 12 13 - file(GLOB_RECURSE DRIVER_SOURCES CONFIGURE_DEPENDS 13 + file(GLOB_RECURSE DRIVER_ALL_SOURCES CONFIGURE_DEPENDS 14 14 "${CMAKE_CURRENT_SOURCE_DIR}/${DRIVER_NAME}/*.cpp" 15 15 ) 16 + 17 + set(DRIVER_SOURCES ${DRIVER_ALL_SOURCES}) 18 + set(TEST_SOURCES "") 19 + 20 + foreach(FILE ${DRIVER_ALL_SOURCES}) 21 + if(FILE MATCHES ".*_test\\.cpp$") 22 + list(APPEND TEST_SOURCES ${FILE}) 23 + list(REMOVE_ITEM DRIVER_SOURCES ${FILE}) 24 + endif() 25 + endforeach() 16 26 17 27 add_library(${TARGET_NAME} SHARED ${DRIVER_SOURCES}) 18 28 ··· 53 63 libdrm::libdrm 54 64 ${ARGN} 55 65 ) 66 + 67 + if(TEST_SOURCES) 68 + set(TEST_EXE_NAME "test_${TARGET_NAME}") 69 + 70 + add_executable(${TEST_EXE_NAME} ${TEST_SOURCES}) 71 + 72 + # Link the driver itself so tests can access its internal logic 73 + # Note: If you need to test private symbols, you might need a OBJECT library approach 74 + target_link_libraries(${TEST_EXE_NAME} PRIVATE 75 + ${TARGET_NAME} 76 + Catch2::Catch2WithMain 77 + ) 78 + 79 + add_test(${DRIVER_NAME} ${TEST_EXE_NAME}) 80 + endif() 56 81 57 82 add_sanitizers(${TARGET_NAME}) 58 83 endfunction()
+145
drivers/amdgpu/memory/tlsf_test.cpp
··· 1 + #include <cassert> 2 + #include <cstddef> 3 + #include <cstdint> 4 + #include <vector> 5 + 6 + #include "tlsf.h" 7 + 8 + #define CATCH_CONFIG_MAIN 9 + #include <catch2/catch_test_macros.hpp> 10 + 11 + TEST_CASE("Basic allocation and free", "[tlsf]") { 12 + TlsfAllocator alloc(1024); 13 + 14 + TlsfAllocator::Allocation a; 15 + 16 + REQUIRE(alloc.allocate(128, 8, a)); 17 + REQUIRE(a.offset == 0); 18 + REQUIRE(a.size >= 128); 19 + 20 + alloc.free(a); 21 + 22 + // Should reuse same space 23 + TlsfAllocator::Allocation b; 24 + 25 + REQUIRE(alloc.allocate(128, 8, b)); 26 + REQUIRE(b.offset == 0); 27 + } 28 + 29 + TEST_CASE("Split and merge behavior", "[tlsf]") { 30 + TlsfAllocator alloc(2048); 31 + 32 + TlsfAllocator::Allocation a1, a2; 33 + 34 + REQUIRE(alloc.allocate(256, 8, a1)); 35 + REQUIRE(alloc.allocate(256, 8, a2)); 36 + 37 + alloc.free(a1); 38 + alloc.free(a2); 39 + 40 + TlsfAllocator::Allocation a3; 41 + 42 + REQUIRE(alloc.allocate(1024, 8, a3)); 43 + REQUIRE(a3.offset == 0); 44 + } 45 + 46 + TEST_CASE("Alignment correctness", "[tlsf]") { 47 + TlsfAllocator alloc(16000); 48 + 49 + for (uint64_t align = 1; align <= 128; align <<= 1) { 50 + TlsfAllocator::Allocation a; 51 + 52 + REQUIRE(alloc.allocate(100, align, a)); 53 + REQUIRE(a.offset % align == 0); 54 + 55 + alloc.free(a); 56 + } 57 + } 58 + 59 + TEST_CASE("Full heap allocation", "[tlsf]") { 60 + TlsfAllocator alloc(1024); 61 + 62 + TlsfAllocator::Allocation a; 63 + 64 + REQUIRE(alloc.allocate(1024, 1, a)); 65 + REQUIRE(a.offset == 0); 66 + 67 + alloc.free(a); 68 + } 69 + 70 + TEST_CASE("Fragmentation stress", "[tlsf]") { 71 + TlsfAllocator alloc(2048); 72 + 73 + std::vector<TlsfAllocator::Allocation> handles; 74 + 75 + // Fill with small blocks 76 + for (int i = 0; i < 16; ++i) { 77 + TlsfAllocator::Allocation a; 78 + REQUIRE(alloc.allocate(64, 8, a)); 79 + handles.push_back(a); 80 + } 81 + 82 + // Free every other 83 + for (size_t i = 0; i < handles.size(); i += 2) 84 + alloc.free(handles[i]); 85 + 86 + // Try larger alloc 87 + TlsfAllocator::Allocation big; 88 + 89 + REQUIRE(alloc.allocate(256, 8, big)); 90 + } 91 + 92 + // stress test 93 + #include <random> 94 + 95 + TEST_CASE("Randomized stress test", "[tlsf][fuzz]") { 96 + const uint64_t HEAP_SIZE = 1 << 20; 97 + TlsfAllocator alloc(HEAP_SIZE); 98 + std::byte *data = new std::byte[HEAP_SIZE]; 99 + 100 + std::mt19937_64 rng(123456); 101 + 102 + struct Active { 103 + TlsfAllocator::Allocation a; 104 + uint64_t offset; 105 + uint64_t size; 106 + }; 107 + 108 + std::vector<Active> active; 109 + 110 + for (int iter = 0; iter < 200000; ++iter) { 111 + bool doAlloc = active.empty() || (rng() % 2 == 0); 112 + 113 + if (doAlloc) { 114 + uint64_t size = (rng() % 4096) + 1; 115 + uint64_t align = 1ull << (rng() % 6); 116 + 117 + TlsfAllocator::Allocation a; 118 + 119 + if (alloc.allocate(size, align, a)) { 120 + REQUIRE((uintptr_t)a.offset % align == 0); 121 + 122 + for (auto& other : active) { 123 + bool overlap = 124 + !(a.offset + a.size <= other.offset || 125 + other.offset + other.size <= a.offset); 126 + 127 + REQUIRE_FALSE(overlap); 128 + } 129 + 130 + active.push_back({a, a.offset, a.size}); 131 + 132 + // write some data to ensure safe! 133 + std::memset(data + a.offset, 1, size); 134 + } 135 + } else { 136 + size_t idx = rng() % active.size(); 137 + alloc.free(active[idx].a); 138 + active.erase(active.begin() + idx); 139 + } 140 + 141 + if (iter % 1000 == 0) { 142 + alloc.validate(); 143 + } 144 + } 145 + }
-12
test/CMakeLists.txt
··· 1 1 include(FetchContent) 2 2 3 - FetchContent_Declare( 4 - Catch2 5 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git 6 - GIT_TAG v3.5.1 7 - ) 8 - FetchContent_MakeAvailable(Catch2) 9 - 10 3 add_library(kestrel_test_common STATIC 11 4 common/test_utils.cpp 12 5 ) ··· 31 24 endif() 32 25 33 26 include(CTest) 34 - include(Catch) 35 - 36 - if(TARGET kestrel_unit_tests) 37 - catch_discover_tests(kestrel_unit_tests) 38 - endif() 39 27 40 28 file(GLOB EXAMPLE_DIRS CONFIGURE_DEPENDS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/examples ${CMAKE_CURRENT_SOURCE_DIR}/examples/*) 41 29 foreach(example_dir ${EXAMPLE_DIRS})
+2
vendor/CMakeLists.txt
··· 55 55 add_dependencies(libdrm::libdrm libdrm_project) 56 56 add_dependencies(libdrm::amdgpu libdrm_project) 57 57 add_dependencies(libdrm::i915 libdrm_project) 58 + 59 + CPMAddPackage("gh:catchorg/Catch2#v3.13.0")