Files
UnrealEngine/Engine/Source/Developer/TraceServices/Private/AnalysisCache.h
2025-05-18 13:04:45 +08:00

170 lines
4.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/UnrealString.h"
#include "IO/IoHash.h"
#include "Memory/SharedBuffer.h"
#include "Templates/UniquePtr.h"
#include "Containers/Map.h"
#include "TraceServices/Model/AnalysisCache.h"
class IMappedFileRegion;
class IMappedFileHandle;
class FCbPackage;
namespace TraceServices {
class IAnalysisSession;
//////////////////////////////////////////////////////////////////////
class FAnalysisCache : public IAnalysisCache
{
public:
explicit FAnalysisCache(const TCHAR* Path);
virtual ~FAnalysisCache() override;
virtual FCacheId GetCacheId(const TCHAR* Name, uint16 Flags) override;
virtual FMutableMemoryView GetUserData(FCacheId CacheId) override;
virtual FSharedBuffer CreateBlocks(FCacheId CacheId, uint32 Count) override;
virtual FSharedBuffer GetBlocks(FCacheId CacheId, uint32 BlockIndexStart, uint32 BlockCount = 1) override;
private:
/**
* Compound key identifying a block.
* Warning: Changing this type also affects file contents.
*/
typedef uint32 BlockKeyType;
/**
* Wrapper for file contents
*/
struct FFileContents
{
// Current file format version
static constexpr uint32 CurrentVersion = 2;
// Number of bytes at the start of the file reserved for table of contents and header.
static constexpr uint32 ReservedSizeV1 = 512 * 1024;
static constexpr uint32 ReservedSizeV2 = 1024 * 1024;
// Offset of the table of contents in bytes
static constexpr uint32 IndexOffset = 6;
// Size for the index object
static constexpr uint32 ReservedSizeIndex = ReservedSizeV2 - IndexOffset;
// Number of bytes allocated for user data (per named entry)
static constexpr uint32 UserDataSize = 64;
explicit FFileContents(const TCHAR* FilePath);
~FFileContents();
FCacheId GetId(const TCHAR* Name, uint16 Flags);
FMutableMemoryView GetUserData(FCacheId Id);
uint16 GetFlags(FCacheId Id);
bool Save();
bool Load();
uint64 UpdateBlock(FMemoryView Block, BlockKeyType BlockKey);
uint64 LoadBlock(FMutableMemoryView Block, BlockKeyType BlockKey);
IFileHandle* GetFileHandleForWrite();
IFileHandle* GetFileHandleForRead();
struct FIndexEntry
{
FString Name;
uint32 Id;
uint32 Flags;
uint8 UserData[UserDataSize];
};
struct FBlockEntry
{
BlockKeyType BlockKey;
uint32 Flags;
uint64 Offset;
uint64 CompressedSize;
uint64 UncompressedSize;
FIoHash Hash;
};
FString CacheFilePath;
TUniquePtr<IFileHandle> CacheFile;
TUniquePtr<IFileHandle> CacheFileWrite;
TArray<FIndexEntry> IndexEntries;
TArray<FBlockEntry> Blocks;
// When this is set blocks or table of contents are never written.
bool bTransientMode = false;
uint32 Version = 0;
private:
static uint32 ReadHeader(IFileHandle* File);
static bool WriteHeader(IFileHandle* File, uint32 Version);
void LoadVersion1Index(const FCbPackage& Package);
void SaveVersion1Index(FCbWriter& Writer);
bool SaveVersion1(IFileHandle* File);
bool SaveVersion2(IFileHandle* File);
bool LoadVersion1(IFileHandle* File);
bool LoadVersion2(IFileHandle* File);
};
/**
* Life time statistics
*/
struct FStats
{
uint64 BytesRead;
uint64 BytesWritten;
};
/**
* Called when a shared buffer is released. Checks if content has change and updates cached block correspondingly
* and finally frees memory.
* @param BlockBuffer Allocated memory
* @param CacheId Unique cache id
* @param BlockIndexStart Block index for this cache entry
* @param Size of buffer
*/
void ReleaseBlocks(uint8* BlockBuffer, FCacheId CacheId, uint32 BlockIndexStart, uint64 Size);
/**
* Creates a block key identifier
* @param CacheId Unique cache id
* @param BlockIndex Block index for this cache entry
* @return Unique key identifying a single block
*/
static BlockKeyType CreateBlockKey(FCacheId CacheId, uint32 BlockIndex)
{
// Use 3 top nibbles for cache id and the rest for block index. That gives a space for 4095 unique cache entries
// each containing a maximum of 7 Gb of data.
check(CacheId < 0xfff && BlockIndex < 0x000fffff && CacheId > 0);
return CacheId << 20 | BlockIndex;
}
/**
* Extract the cache id from a block key
* @param BlockKey Unique key identifying a single block
* @return Unique cache id
*/
static uint32 GetCacheId(BlockKeyType BlockKey)
{
return (BlockKey & 0xfff00000) >> 20;
}
/**
* Extract the block index from a block key
* @param BlockKey Unique key identifying a single block
* @return Block index for this cache entry
*/
static uint32 GetBlockIndex(BlockKeyType BlockKey)
{
return BlockKey & 0x000fffff;
}
FAnalysisCache() = delete;
FAnalysisCache(FAnalysisCache& Other) = delete;
constexpr static uint32 BlockAlignment = 1024*4;
TUniquePtr<FFileContents> Contents;
FStats Stats;
TMap<BlockKeyType,FSharedBuffer> CachedBlocks;
TMap<uint32,uint32> IndexBlockCount;
};
}