diff --git a/FEXCore/include/FEXCore/Utils/SHMStats.h b/FEXCore/include/FEXCore/Utils/SHMStats.h index 20767620c..fba5cec22 100644 --- a/FEXCore/include/FEXCore/Utils/SHMStats.h +++ b/FEXCore/include/FEXCore/Utils/SHMStats.h @@ -39,10 +39,12 @@ enum class AppType : uint8_t { WIN_WOW64, }; +// Only append new members to the end of {ThreadStatsHeader, ThreadStats} to allow old tools time to support new information. +// FEX isn't guaranteeing /not/ breaking compatibility with versions, but trying to not cause too much churn. struct ThreadStatsHeader { uint8_t Version; AppType app_type; - uint8_t _pad[2]; + uint16_t ThreadStatsSize; char fex_version[48]; std::atomic Head; std::atomic Size; @@ -63,6 +65,9 @@ struct ThreadStats { uint64_t AccumulatedFloatFallbackCount; }; +// Ensure 16-byte alignment to take advantage of ARM single-copy atomicity. +static_assert(sizeof(ThreadStats) % 16 == 0, "Needs to be 16-byte aligned!"); + template class AccumulationBlock final { public: diff --git a/Source/Common/SHMStats.cpp b/Source/Common/SHMStats.cpp index eb124ad83..c522f42f8 100644 --- a/Source/Common/SHMStats.cpp +++ b/Source/Common/SHMStats.cpp @@ -13,10 +13,11 @@ void StatAllocBase::SaveHeader(FEXCore::SHMStats::AppType AppType) { Head = reinterpret_cast(Base); Head->Size.store(CurrentSize, std::memory_order_relaxed); Head->Version = FEXCore::SHMStats::STATS_VERSION; + Head->app_type = AppType; + Head->ThreadStatsSize = sizeof(FEXCore::SHMStats::ThreadStats); std::string_view GitString = GIT_DESCRIBE_STRING; strncpy(Head->fex_version, GitString.data(), std::min(GitString.size(), sizeof(Head->fex_version))); - Head->app_type = AppType; Stats = reinterpret_cast(reinterpret_cast(Base) + sizeof(FEXCore::SHMStats::ThreadStatsHeader));