Files
FEX-Emu--FEX/Source/Common/SHMStats.cpp
T
Ryan Houdek 6ee77eb1a1 SHMStats: Adds ThreadStats size to header
Reused the padding area so the header format doesn't change. If it is
non-zero then it should be used by the tool.
2025-10-16 14:07:29 -07:00

122 lines
3.3 KiB
C++

// SPDX-License-Identifier: MIT
#include "Common/SHMStats.h"
#include "git_version.h"
#include <FEXCore/Debug/InternalThreadState.h>
namespace FEX::SHMStats {
void StatAllocBase::SaveHeader(FEXCore::SHMStats::AppType AppType) {
if (!Base) {
return;
}
Head = reinterpret_cast<FEXCore::SHMStats::ThreadStatsHeader*>(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)));
Stats = reinterpret_cast<FEXCore::SHMStats::ThreadStats*>(reinterpret_cast<uint64_t>(Base) + sizeof(FEXCore::SHMStats::ThreadStatsHeader));
RemainingSlots = TotalSlotsFromSize();
}
bool StatAllocBase::AllocateMoreSlots() {
const auto OriginalSlotCount = TotalSlotsFromSize();
uint32_t NewSize = FrontendAllocateSlots(CurrentSize * 2);
if (NewSize == CurrentSize) {
return false;
}
CurrentSize = NewSize;
Head->Size.store(CurrentSize, std::memory_order_relaxed);
RemainingSlots = TotalSlotsFromSize() - OriginalSlotCount;
return true;
}
FEXCore::SHMStats::ThreadStats* StatAllocBase::AllocateSlot(uint32_t TID) {
if (!RemainingSlots) {
if (!AllocateMoreSlots()) {
return nullptr;
}
}
// Find a free slot
store_memory_barrier();
FEXCore::SHMStats::ThreadStats* AllocatedSlot {};
for (size_t i = 0; i < TotalSlotsFromSize(); ++i) {
AllocatedSlot = &Stats[i];
if (AllocatedSlot->TID.load(std::memory_order_relaxed) == 0) {
break;
}
}
--RemainingSlots;
// Slot might be reused, just zero it now.
memset(AllocatedSlot, 0, sizeof(*AllocatedSlot));
// TID != 0 means slot is allocated.
AllocatedSlot->TID.store(TID, std::memory_order_relaxed);
// Setup singly-linked list
if (Head->Head.load(std::memory_order_relaxed) == 0) {
Head->Head.store(OffsetFromStat(AllocatedSlot), std::memory_order_relaxed);
} else {
StatTail->Next.store(OffsetFromStat(AllocatedSlot), std::memory_order_relaxed);
}
// Update the tail.
StatTail = AllocatedSlot;
return AllocatedSlot;
}
void StatAllocBase::DeallocateSlot(FEXCore::SHMStats::ThreadStats* AllocatedSlot) {
if (!AllocatedSlot) {
return;
}
// TID == 0 will signal the reader to ignore this slot & deallocate it!
AllocatedSlot->TID.store(0, std::memory_order_relaxed);
store_memory_barrier();
const auto SlotOffset = OffsetFromStat(AllocatedSlot);
const auto AllocatedSlotNext = AllocatedSlot->Next.load(std::memory_order_relaxed);
const bool IsTail = AllocatedSlot == StatTail;
// Update the linked list.
if (Head->Head == SlotOffset) {
Head->Head.store(AllocatedSlotNext, std::memory_order_relaxed);
if (IsTail) {
StatTail = nullptr;
}
} else {
for (size_t i = 0; i < TotalSlotsFromSize(); ++i) {
auto Slot = &Stats[i];
auto NextSlotOffset = Slot->Next.load(std::memory_order_relaxed);
if (NextSlotOffset == SlotOffset) {
Slot->Next.store(AllocatedSlotNext, std::memory_order_relaxed);
if (IsTail) {
// This slot is now the tail.
StatTail = Slot;
}
break;
}
}
}
++RemainingSlots;
}
} // namespace FEX::SHMStats