From 72a3c772fec107836f3fccceda490fffd6ccf1d9 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Mon, 13 Jan 2025 04:26:23 +1100 Subject: [PATCH] osd: Added helper for getting CPU cache line size. --- src/devices/cpu/drcbex64.cpp | 17 +++++++++++-- src/devices/cpu/drcbex86.cpp | 16 ++++++++++-- src/osd/modules/lib/osdlib_macosx.cpp | 17 +++++++++++++ src/osd/modules/lib/osdlib_unix.cpp | 26 +++++++++++++++++++ src/osd/modules/lib/osdlib_win32.cpp | 36 +++++++++++++++++++++++++++ src/osd/osdcore.h | 11 ++++++++ 6 files changed, 119 insertions(+), 4 deletions(-) diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp index 17b25bba95862..891b8c69dd574 100644 --- a/src/devices/cpu/drcbex64.cpp +++ b/src/devices/cpu/drcbex64.cpp @@ -945,8 +945,21 @@ void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint3 m_hash.block_begin(block, instlist, numinst); m_map.block_begin(block); - // compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) - x86code *dst = (x86code *)(uint64_t(m_cache.top() + 63) & ~63); + // compute the base by aligning the cache top to a cache line + auto [err, linesize] = osd_get_cache_line_size(); + uintptr_t linemask = 63; + if (err) + { + osd_printf_verbose("Error getting cache line size (%s:%d %s), assuming 64 bytes\n", err.category().name(), err.value(), err.message()); + } + else + { + assert(linesize); + linemask = linesize - 1; + for (unsigned shift = 1; linemask & (linemask + 1); ++shift) + linemask |= linemask >> shift; + } + x86code *dst = (x86code *)(uintptr_t(m_cache.top() + linemask) & ~linemask); CodeHolder ch; ch.init(Environment::host(), uint64_t(dst)); diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp index 6e187e6846a36..d9a6b79e13742 100644 --- a/src/devices/cpu/drcbex86.cpp +++ b/src/devices/cpu/drcbex86.cpp @@ -840,8 +840,20 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3 m_hash.block_begin(block, instlist, numinst); m_map.block_begin(block); - // compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) - x86code *dst = (x86code *)(uint64_t(m_cache.top() + 63) & ~63); + // compute the base by aligning the cache top to a cache line + auto [err, linesize] = osd_get_cache_line_size(); + uintptr_t linemask = 63; + if (err) + { + osd_printf_verbose("Error getting cache line size (%s:%d %s), assuming 64 bytes\n", err.category().name(), err.value(), err.message()); + } + else + { + assert(linesize); + linemask = linesize - 1; + for (unsigned shift = 1; linemask & (linemask + 1); ++shift) + linemask |= linemask >> shift; + } CodeHolder ch; ch.init(Environment::host(), uint64_t(dst)); diff --git a/src/osd/modules/lib/osdlib_macosx.cpp b/src/osd/modules/lib/osdlib_macosx.cpp index 9d13f118ff2aa..54836f9ec69a8 100644 --- a/src/osd/modules/lib/osdlib_macosx.cpp +++ b/src/osd/modules/lib/osdlib_macosx.cpp @@ -56,6 +56,7 @@ void osd_process_kill() kill(getpid(), SIGKILL); } + //============================================================ // osd_break_into_debugger //============================================================ @@ -81,6 +82,22 @@ void osd_break_into_debugger(const char *message) } +//============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair osd_get_cache_line_size() noexcept +{ + size_t result = 0; + size_t resultsize = sizeof(result); + int const err = sysctlbyname("hw.cachelinesize", &result, &resultsize, 0, 0); + if (!err) + return std::make_pair(std::error_condition(), unsigned(result)); + else + return std::make_pair(std::error_condition(err, std::generic_category()), 0U); +} + + //============================================================ // osd_get_clipboard_text //============================================================ diff --git a/src/osd/modules/lib/osdlib_unix.cpp b/src/osd/modules/lib/osdlib_unix.cpp index 20f6a9ab40c3c..3600458022283 100644 --- a/src/osd/modules/lib/osdlib_unix.cpp +++ b/src/osd/modules/lib/osdlib_unix.cpp @@ -53,6 +53,7 @@ void osd_process_kill() kill(getpid(), SIGKILL); } + //============================================================ // osd_break_into_debugger //============================================================ @@ -68,6 +69,31 @@ void osd_break_into_debugger(const char *message) #endif } + +//============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair osd_get_cache_line_size() noexcept +{ +#if defined(__linux__) + FILE *const f = std::fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r"); + if (!f) + return std::make_pair(std::error_condition(errno, std::generic_category()), 0U); + + unsigned result = 0; + auto const cnt = std::fscanf(f, "%u", &result); + std::fclose(f); + if (1 == cnt) + return std::make_pair(std::error_condition(), result); + else + return std::make_pair(std::errc::io_error, 0U); +#else // defined(__linux__) + return std::make_pair(std::errc::not_supported, 0U); +#endif +} + + #ifdef SDLMAME_ANDROID std::string osd_get_clipboard_text() noexcept { diff --git a/src/osd/modules/lib/osdlib_win32.cpp b/src/osd/modules/lib/osdlib_win32.cpp index d42ad14d3df64..cf3fd7c9320ab 100644 --- a/src/osd/modules/lib/osdlib_win32.cpp +++ b/src/osd/modules/lib/osdlib_win32.cpp @@ -106,6 +106,42 @@ void osd_break_into_debugger(const char *message) #endif } + +//============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair osd_get_cache_line_size() noexcept +{ + DWORD resultsize = 0; + if (GetLogicalProcessorInformation(nullptr, &resultsize) || (ERROR_INSUFFICIENT_BUFFER != GetLastError()) || !resultsize) + return std::make_pair(std::errc::operation_not_permitted, 0U); + + auto const result = reinterpret_cast(std::malloc(resultsize)); + if (!result) + return std::make_pair(std::errc::not_enough_memory, 0U); + + if (!GetLogicalProcessorInformation(result, &resultsize)) + { + std::free(result); + return std::make_pair(std::errc::operation_not_permitted, 0U); + } + + for (unsigned i = 0; i < (resultsize / sizeof(result[0])); ++i) + { + if ((RelationCache == result[i].Relationship) && (1 == result[i].Cache.Level)) + { + unsigned const linesize = result[i].Cache.LineSize; + std::free(result); + return std::make_pair(std::error_condition(), linesize); + } + } + + std::free(result); + return std::make_pair(std::errc::operation_not_permitted, 0U); +} + + //============================================================ // get_clipboard_text_by_format //============================================================ diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h index f3f5fc2e9b33c..b3dc209991304 100644 --- a/src/osd/osdcore.h +++ b/src/osd/osdcore.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,8 @@ osd_ticks_t osd_ticks_per_second() noexcept; -----------------------------------------------------------------------------*/ void osd_sleep(osd_ticks_t duration) noexcept; + + /*************************************************************************** WORK ITEM INTERFACES ***************************************************************************/ @@ -350,6 +353,14 @@ void osd_work_item_release(osd_work_item *item); void osd_break_into_debugger(const char *message); +/// \brief Get cache line size in bytes +/// +/// This function gets the host CPU's level 1 cache line size in bytes. +/// \return A pair consisting of an error condition and the cache line +/// size in bytes if successful. +std::pair osd_get_cache_line_size() noexcept; + + /*************************************************************************** UNCATEGORIZED INTERFACES