From 37eaff93cb8f2585c305f6b723069b60463f399f Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 15 Sep 2026 18:11:21 -0700 Subject: [PATCH] FEXCore: Migrate internal DiskCache header to internal Leave the smaller public header that is required to get the current DiskCache version variable still. NFC --- FEXCore/Source/Interface/Context/Context.h | 2 +- FEXCore/Source/Interface/Core/DiskCache.h | 231 +++++++++++++++++++++ FEXCore/include/FEXCore/Core/DiskCache.h | 231 +-------------------- Source/Tools/CodeSizeValidation/Main.cpp | 5 +- 4 files changed, 238 insertions(+), 231 deletions(-) create mode 100644 FEXCore/Source/Interface/Core/DiskCache.h diff --git a/FEXCore/Source/Interface/Context/Context.h b/FEXCore/Source/Interface/Context/Context.h index ffabdbdae..1a7d2fd9e 100644 --- a/FEXCore/Source/Interface/Context/Context.h +++ b/FEXCore/Source/Interface/Context/Context.h @@ -4,13 +4,13 @@ #include "Common/JitSymbols.h" #include "Interface/Core/CPUBackend.h" #include "Interface/Core/CPUID.h" +#include "Interface/Core/DiskCache.h" #include "Interface/Core/SharedCodeBufferManager.h" #include #include #include #include #include -#include #include #include #include diff --git a/FEXCore/Source/Interface/Core/DiskCache.h b/FEXCore/Source/Interface/Core/DiskCache.h new file mode 100644 index 000000000..217e4cc4c --- /dev/null +++ b/FEXCore/Source/Interface/Core/DiskCache.h @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: MIT +#pragma once +#include "Interface/Core/JIT/Relocations.h" +#include "Interface/Core/Frontend.h" +#include "Interface/Core/CPUBackend.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace FEXCore { + +namespace Context { + class ContextImpl; +} + +namespace DiskCache { + + namespace MesaFOZ { + +#define FOSSILIZE_BLOB_HASH_LENGTH 40 /* SHA1 hexadecimal string length */ + + struct __attribute__((packed)) foz_payload_key { + uint8_t bytes[FOSSILIZE_BLOB_HASH_LENGTH]; + }; + + struct __attribute__((packed)) foz_payload_header { + uint32_t payload_size; + uint32_t format; + uint32_t crc; + uint32_t uncompressed_size; + }; + + } // namespace MesaFOZ + + class IndexedDB; + + struct IndexEntry { + IndexedDB* DB; + uint64_t Offset; + uint32_t Size; + uint32_t GuestSize; + XXH128_hash_t GuestHash; + fextl::vector GuestExtents; + }; + + struct IndexCacheHead { + struct IndexEntry MainEntry; + uint64_t MainEntryFootprint; + fextl::unique_ptr> MoreEntries; // sorted by guest footprint + }; + + struct __attribute__((packed)) BlobFixedHeader { + uint32_t GuestSize; + uint32_t HostSize; + uint32_t EntryPointCount; + uint32_t SmallRelocCount; + uint32_t ThunkRelocCount; + XXH128_hash_t GuestHash; + }; + + // packed struct for types 0, 2 and 3. type 1 is bigger and separate below + struct __attribute__((packed)) BlobSmallRelocation { + uint32_t Offset; + uint8_t Type; + union { + struct __attribute__((packed)) { + uint32_t Symbol; + } Named; + struct __attribute__((packed)) { + uint64_t GuestRIP; + } RIPLiteral; + struct __attribute__((packed)) { + uint8_t RegisterIndex; + uint64_t GuestRIP; + } RIPMove; + struct __attribute__((packed)) { + uint8_t RegisterIndex; + uint8_t ValueSize; + uint32_t SiteOffset; + } PatchableData; + }; + }; + + // type 1, implicit + struct __attribute__((packed)) BlobThunkRelocation { + uint32_t Offset; + uint8_t RegisterIndex; + uint8_t SymbolHash[32]; // sha256sum in the real RelocNamedThunkMove + }; + + struct CodeHitData { + fextl::vector Blob; + std::span HostCode; + std::span GuestPages; + std::span EntryPointRIPs; + std::span EntryPointHostOffsets; + + // the spans above point to memory owned by the Blob vec, so it's important this can't be copied + CodeHitData() = default; + CodeHitData(CodeHitData&&) = default; + CodeHitData& operator=(CodeHitData&&) = default; + CodeHitData(const CodeHitData&) = delete; + CodeHitData& operator=(const CodeHitData&) = delete; + }; + + using Index = fextl::robin_map; + + class FOZFile { + public: + bool Open(const fextl::string& CacheFileName, bool ReadOnly); + bool Lock(uint32_t TimeoutMS) { + if (!FD) { + return false; + } + return FD->Lock(TimeoutMS); + } + bool Unlock() { + if (!FD) { + return false; + } + return FD->Unlock(); + } + File::File::FileHandleType GetHandle() { + return FD ? FD->GetHandle() : (File::File::FileHandleType)-1; + } + ssize_t Size(); + bool ReadAll(fextl::vector& Out); // from first blob + bool ReadBlob(uint64_t Offset, std::span OutBlob); + bool WriteBlob(const MesaFOZ::foz_payload_key& Key, std::span> BlobChunks, uint64_t& OutBlobOffset); + + private: + static constexpr uint32_t OPEN_LOCK_TIMEOUT_MS = 100; + + fextl::string FileName; + fextl::unique_ptr FD; + bool ReadOnly = false; + }; + + class IndexedDB { + public: + bool Open(const fextl::string& CacheDBName, bool ReadOnly); + void PopulateIndex(Index& CacheIndex, bool& FoundMetadata); + bool ReadCacheBlob(uint64_t Offset, std::span OutBlob); + bool StoreCacheBlob(const MesaFOZ::foz_payload_key& UniqueKey, uint64_t LookupKey, std::span Blob, Index& CacheIndex, + std::mutex& IndexMutex, std::span IndexBlob); + + private: + // stores run on the Writer, so returning quick isn't as important + static constexpr uint32_t STORE_LOCK_TIMEOUT_MS = 1000; + static constexpr uint64_t BIG_MAPPING_SIZE = 1ULL << 33; + static constexpr uint32_t LOOKUP_KEY_MAX_BUCKET_DEPTH = 20; + + FOZFile CacheFOZ; + uint8_t* CacheFileMapping = nullptr; + std::atomic CacheFileSize; + FOZFile IndexFOZ; + bool ReadOnly = false; + }; + + class DiskCache { + public: + void Init(FEXCore::Context::ContextImpl* CTX); + + std::optional Lookup(Core::InternalThreadState* Thread, std::optional Region, uint64_t GuestRIP, + std::optional& GuestCodeKey); + void Validate(uint64_t GuestCodeKey, const CodeHitData& Hit, const CPU::CPUBackend::CompiledCode& CompiledCode, + std::optional Region); + bool Store(Core::InternalThreadState* Thread, std::optional Region, uint64_t GuestRIP, uint64_t GuestCodeKey, + std::span GuestCode, const CPU::CPUBackend::CompiledCode& CompiledCode, + std::span Relocations, const Frontend::Decoder::DecodedBlockInformation* DecodedBlockInfo); + + bool IsWritingDiskCache() const { + return WritingDiskCache; + } + bool IsReadingDiskCache() const { + return ReadingDiskCache; + } + bool IsValidating() const { + return Validation; + } + + private: + bool OpenCacheDB(const fextl::string& CacheDBName, bool ReadOnly); + uint64_t MakeLookupKey(Core::InternalThreadState* Thread, const uint64_t ModuleOffset, bool Writable, bool MonoBackpatcher); + + bool ReadingDiskCache {}; + bool WritingDiskCache {}; + FEXCore::Context::ContextImpl* CTX; + XXH128_hash_t BucketHash; + fextl::vector> ROCacheDBs; + fextl::unique_ptr RWCacheDB; + Index Index; + std::mutex IndexLock; + bool FoundMetadata = false; + struct CacheStoreWorkItem; + + // the Writer holds references to all this stuff above and needs to be last + fextl::unique_ptr Writer; + + FEX_CONFIG_OPT(EnableDiskCache, DISKCACHE); + FEX_CONFIG_OPT(Validation, DISKCACHEVALIDATION); + FEX_CONFIG_OPT(MapDiskCacheFiles, DISKCACHEFILEMAPPING); + FEX_CONFIG_OPT(RelocationFilter, DISKCACHERELOCATIONFILTER); + FEX_CONFIG_OPT(AnonCaching, DISKCACHEANONCACHING); + FEX_CONFIG_OPT(BasePathOverride, DISKCACHEPATH); + FEX_CONFIG_OPT(RODBNames, DISKCACHERODBNAMES); + }; + + static constexpr uint16_t AnonPrefixGuestBytes = 64; + // The current version of the diskcache. + // This must be changed any time codegen changes occur! + // Be aware of the impact of changing this frequently! + static constexpr uint16_t FormatVersion = 24; + +} // namespace DiskCache + +} // namespace FEXCore diff --git a/FEXCore/include/FEXCore/Core/DiskCache.h b/FEXCore/include/FEXCore/Core/DiskCache.h index 99fc830cc..22cabec54 100644 --- a/FEXCore/include/FEXCore/Core/DiskCache.h +++ b/FEXCore/include/FEXCore/Core/DiskCache.h @@ -1,231 +1,10 @@ // SPDX-License-Identifier: MIT #pragma once -#include "FEXCore/Core/CodeCache.h" -#include "FEXCore/Core/Context.h" -#include "Interface/Core/JIT/Relocations.h" -#include "Interface/Core/Frontend.h" -#include "Interface/Core/CPUBackend.h" -#include "FEXCore/Config/Config.h" -#include "FEXCore/Utils/File.h" -#include "FEXCore/Utils/WorkQueueThread.h" -#include "FEXCore/fextl/memory.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace FEXCore { +#include "FEXCore/Utils/CompilerDefs.h" -namespace Context { - class ContextImpl; -} +#include -namespace DiskCache { - - namespace MesaFOZ { - -#define FOSSILIZE_BLOB_HASH_LENGTH 40 /* SHA1 hexadecimal string length */ - - struct __attribute__((packed)) foz_payload_key { - uint8_t bytes[FOSSILIZE_BLOB_HASH_LENGTH]; - }; - - struct __attribute__((packed)) foz_payload_header { - uint32_t payload_size; - uint32_t format; - uint32_t crc; - uint32_t uncompressed_size; - }; - - } // namespace MesaFOZ - - class IndexedDB; - - struct IndexEntry { - IndexedDB* DB; - uint64_t Offset; - uint32_t Size; - uint32_t GuestSize; - XXH128_hash_t GuestHash; - fextl::vector GuestExtents; - }; - - struct IndexCacheHead { - struct IndexEntry MainEntry; - uint64_t MainEntryFootprint; - fextl::unique_ptr> MoreEntries; // sorted by guest footprint - }; - - struct __attribute__((packed)) BlobFixedHeader { - uint32_t GuestSize; - uint32_t HostSize; - uint32_t EntryPointCount; - uint32_t SmallRelocCount; - uint32_t ThunkRelocCount; - XXH128_hash_t GuestHash; - }; - - // packed struct for types 0, 2 and 3. type 1 is bigger and separate below - struct __attribute__((packed)) BlobSmallRelocation { - uint32_t Offset; - uint8_t Type; - union { - struct __attribute__((packed)) { - uint32_t Symbol; - } Named; - struct __attribute__((packed)) { - uint64_t GuestRIP; - } RIPLiteral; - struct __attribute__((packed)) { - uint8_t RegisterIndex; - uint64_t GuestRIP; - } RIPMove; - struct __attribute__((packed)) { - uint8_t RegisterIndex; - uint8_t ValueSize; - uint32_t SiteOffset; - } PatchableData; - }; - }; - - // type 1, implicit - struct __attribute__((packed)) BlobThunkRelocation { - uint32_t Offset; - uint8_t RegisterIndex; - uint8_t SymbolHash[32]; // sha256sum in the real RelocNamedThunkMove - }; - - struct CodeHitData { - fextl::vector Blob; - std::span HostCode; - std::span GuestPages; - std::span EntryPointRIPs; - std::span EntryPointHostOffsets; - - // the spans above point to memory owned by the Blob vec, so it's important this can't be copied - CodeHitData() = default; - CodeHitData(CodeHitData&&) = default; - CodeHitData& operator=(CodeHitData&&) = default; - CodeHitData(const CodeHitData&) = delete; - CodeHitData& operator=(const CodeHitData&) = delete; - }; - - using Index = fextl::robin_map; - - class FOZFile { - public: - bool Open(const fextl::string& CacheFileName, bool ReadOnly); - bool Lock(uint32_t TimeoutMS) { - if (!FD) { - return false; - } - return FD->Lock(TimeoutMS); - } - bool Unlock() { - if (!FD) { - return false; - } - return FD->Unlock(); - } - File::File::FileHandleType GetHandle() { - return FD ? FD->GetHandle() : (File::File::FileHandleType)-1; - } - ssize_t Size(); - bool ReadAll(fextl::vector& Out); // from first blob - bool ReadBlob(uint64_t Offset, std::span OutBlob); - bool WriteBlob(const MesaFOZ::foz_payload_key& Key, std::span> BlobChunks, uint64_t& OutBlobOffset); - - private: - static constexpr uint32_t OPEN_LOCK_TIMEOUT_MS = 100; - - fextl::string FileName; - fextl::unique_ptr FD; - bool ReadOnly = false; - }; - - class IndexedDB { - public: - bool Open(const fextl::string& CacheDBName, bool ReadOnly); - void PopulateIndex(Index& CacheIndex, bool& FoundMetadata); - bool ReadCacheBlob(uint64_t Offset, std::span OutBlob); - bool StoreCacheBlob(const MesaFOZ::foz_payload_key& UniqueKey, uint64_t LookupKey, std::span Blob, Index& CacheIndex, - std::mutex& IndexMutex, std::span IndexBlob); - - private: - // stores run on the Writer, so returning quick isn't as important - static constexpr uint32_t STORE_LOCK_TIMEOUT_MS = 1000; - static constexpr uint64_t BIG_MAPPING_SIZE = 1ULL << 33; - static constexpr uint32_t LOOKUP_KEY_MAX_BUCKET_DEPTH = 20; - - FOZFile CacheFOZ; - uint8_t* CacheFileMapping = nullptr; - std::atomic CacheFileSize; - FOZFile IndexFOZ; - bool ReadOnly = false; - }; - - class DiskCache { - public: - void Init(FEXCore::Context::ContextImpl* CTX); - - std::optional Lookup(Core::InternalThreadState* Thread, std::optional Region, uint64_t GuestRIP, - std::optional& GuestCodeKey); - void Validate(uint64_t GuestCodeKey, const CodeHitData& Hit, const CPU::CPUBackend::CompiledCode& CompiledCode, - std::optional Region); - bool Store(Core::InternalThreadState* Thread, std::optional Region, uint64_t GuestRIP, uint64_t GuestCodeKey, - std::span GuestCode, const CPU::CPUBackend::CompiledCode& CompiledCode, - std::span Relocations, const Frontend::Decoder::DecodedBlockInformation* DecodedBlockInfo); - - bool IsWritingDiskCache() const { - return WritingDiskCache; - } - bool IsReadingDiskCache() const { - return ReadingDiskCache; - } - bool IsValidating() const { - return Validation; - } - - private: - bool OpenCacheDB(const fextl::string& CacheDBName, bool ReadOnly); - uint64_t MakeLookupKey(Core::InternalThreadState* Thread, const uint64_t ModuleOffset, bool Writable, bool MonoBackpatcher); - - bool ReadingDiskCache {}; - bool WritingDiskCache {}; - FEXCore::Context::ContextImpl* CTX; - XXH128_hash_t BucketHash; - fextl::vector> ROCacheDBs; - fextl::unique_ptr RWCacheDB; - Index Index; - std::mutex IndexLock; - bool FoundMetadata = false; - struct CacheStoreWorkItem; - - // the Writer holds references to all this stuff above and needs to be last - fextl::unique_ptr Writer; - - FEX_CONFIG_OPT(EnableDiskCache, DISKCACHE); - FEX_CONFIG_OPT(Validation, DISKCACHEVALIDATION); - FEX_CONFIG_OPT(MapDiskCacheFiles, DISKCACHEFILEMAPPING); - FEX_CONFIG_OPT(RelocationFilter, DISKCACHERELOCATIONFILTER); - FEX_CONFIG_OPT(AnonCaching, DISKCACHEANONCACHING); - FEX_CONFIG_OPT(BasePathOverride, DISKCACHEPATH); - FEX_CONFIG_OPT(RODBNames, DISKCACHERODBNAMES); - }; - - static constexpr uint16_t AnonPrefixGuestBytes = 64; - - // TODO: This header is in global installed header path, but uses internal headers. - // Migrate this once that is fixed. - static constexpr uint16_t FormatVersion = 24; - FEX_DEFAULT_VISIBILITY uint16_t GetFormatVersion(); - -} // namespace DiskCache - -} // namespace FEXCore +namespace FEXCore::DiskCache { +FEX_DEFAULT_VISIBILITY uint16_t GetFormatVersion(); +} // namespace FEXCore::DiskCache diff --git a/Source/Tools/CodeSizeValidation/Main.cpp b/Source/Tools/CodeSizeValidation/Main.cpp index f8d4e9b16..834691f14 100644 --- a/Source/Tools/CodeSizeValidation/Main.cpp +++ b/Source/Tools/CodeSizeValidation/Main.cpp @@ -3,6 +3,7 @@ #include "Common/HostFeatures.h" #include #include +#include #include #include #include @@ -13,10 +14,6 @@ #include -namespace FEXCore::DiskCache { -uint16_t GetFormatVersion(); -} - namespace CodeSize { class CodeSizeValidation final { public: