From 88ace6e4aeb607d2239d80cc1693140d92f7bccd Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 14 May 2024 23:50:26 +1000 Subject: [PATCH] CMake: Detect cache line size dynamically on AArch64 Linux --- CMakeLists.txt | 1 + CMakeModules/DuckStationUtils.cmake | 55 +++++++++++++++++++++++++++++ src/common/CMakeLists.txt | 3 ++ src/common/types.h | 4 ++- 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d41ed7619..b4e9ba6df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ detect_operating_system() detect_compiler() detect_architecture() detect_page_size() +detect_cache_line_size() # Build options. Depends on system attributes. include(DuckStationBuildOptions) diff --git a/CMakeModules/DuckStationUtils.cmake b/CMakeModules/DuckStationUtils.cmake index 7088df29e..b2dd91c6a 100644 --- a/CMakeModules/DuckStationUtils.cmake +++ b/CMakeModules/DuckStationUtils.cmake @@ -139,3 +139,58 @@ int main() { set(HOST_PAGE_SIZE ${detect_page_size_output} CACHE STRING "Reported host page size") endif() endfunction() + +function(detect_cache_line_size) + # This is only needed for ARM64, or if the user hasn't overridden it explicitly. + if(NOT CPU_ARCH_ARM64 OR HOST_CACHE_LINE_SIZE) + return() + endif() + + if(NOT LINUX) + # For universal Apple builds, we use preprocessor macros to determine page size. + # Similar for Windows, except it's always 64 bytes. + return() + endif() + + if(CMAKE_CROSSCOMPILING) + message(WARNING "Cross-compiling and can't determine page size, assuming default.") + return() + endif() + + message(STATUS "Determining host cache line size") + set(detect_cache_line_size_file ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c) + file(WRITE ${detect_cache_line_size_file} " +#include +#include +#include +int main() { + int l1i = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + int l1d = sysconf(_SC_LEVEL1_ICACHE_LINESIZE); + int res = (l1i > l1d) ? l1i : l1d; + for (int index = 0; index < 16; index++) { + char buf[128]; + snprintf(buf, sizeof(buf), \"/sys/devices/system/cpu/cpu0/cache/index%d/coherency_line_size\", index); + FILE* fp = fopen(buf, \"rb\"); + if (!fp) + break; + fread(buf, sizeof(buf), 1, fp); + fclose(fp); + int val = atoi(buf); + res = (val > res) ? val : res; + } + printf(\"%d\", res); + return (res > 0) ? EXIT_SUCCESS : EXIT_FAILURE; +}") + try_run( + detect_cache_line_size_run_result + detect_cache_line_size_compile_result + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY} + ${detect_cache_line_size_file} + RUN_OUTPUT_VARIABLE detect_cache_line_size_output) + if(NOT detect_cache_line_size_compile_result OR NOT detect_cache_line_size_run_result EQUAL 0) + message(FATAL_ERROR "Could not determine host cache line size.") + else() + message(STATUS "Host cache line size: ${detect_cache_line_size_output}") + set(HOST_CACHE_LINE_SIZE ${detect_cache_line_size_output} CACHE STRING "Reported host cache line size") + endif() +endfunction() diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e60015533..d2a1fa52f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -111,3 +111,6 @@ endif() if(HOST_PAGE_SIZE) target_compile_definitions(common PUBLIC "-DOVERRIDE_HOST_PAGE_SIZE=${HOST_PAGE_SIZE}") endif() +if(HOST_CACHE_LINE_SIZE) + target_compile_definitions(common PUBLIC "-DOVERRIDE_HOST_CACHE_LINE_SIZE=${HOST_CACHE_LINE_SIZE}") +endif() diff --git a/src/common/types.h b/src/common/types.h index 3ea9afe0d..849d51d72 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -192,7 +192,9 @@ static constexpr u32 HOST_PAGE_SHIFT = 12; #endif // Host cache line sizes. -#if defined(__APPLE__) && defined(__aarch64__) +#if defined(OVERRIDE_HOST_CACHE_LINE_SIZE) +static constexpr u32 HOST_CACHE_LINE_SIZE = OVERRIDE_HOST_CACHE_LINE_SIZE; +#elif defined(__APPLE__) && defined(__aarch64__) static constexpr u32 HOST_CACHE_LINE_SIZE = 128; // Apple Silicon uses 128b cache lines. #else static constexpr u32 HOST_CACHE_LINE_SIZE = 64; // Everything else is 64b.