Skip to content

Commit

Permalink
Further performance improvements for the service code
Browse files Browse the repository at this point in the history
- Remove Utils::Callback (and therefore std::function) overhead by directly using function pointers
- Removed redundant copy with a static buffer (also allows the code to be multi threaded when winfsp/winspd#10 gets fixed)
- Builds the service executable with a static CRT to prevent dll calls on memcpy
  • Loading branch information
WorkingRobot committed Jun 6, 2021
1 parent b76563f commit 305afb4
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 169 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cmake_minimum_required (VERSION 3.8)
cmake_minimum_required (VERSION 3.18)
cmake_policy(SET CMP0091 NEW)

## Project Definition and Options ##

Expand Down
22 changes: 21 additions & 1 deletion src/srv/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 3.8)
cmake_minimum_required (VERSION 3.18)

## Project Definition and Options ##

Expand Down Expand Up @@ -53,3 +53,23 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC" AND CMAKE_BUILD_TYPE MATCHES "Release")
COMPILE_PDB_OUTPUT_DIR ${CMAKE_BINARY_DIR}
)
endif()

# Use static CRT (the code is memcpy-heavy, avoid calling those dlls if we have to)
set(CompilerFlags
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_RELEASE
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_RELEASE
)
foreach(CompilerFlag ${CompilerFlags})
string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
string(REPLACE "-MD" "-MT" ${CompilerFlag} "${${CompilerFlag}}")
endforeach()

if (CMAKE_BUILD_TYPE MATCHES "Debug")
set_property(TARGET EGL3_SRV PROPERTY MSVC_RUNTIME_LIBRARY MultiThreadedDebug)
else()
set_property(TARGET EGL3_SRV PROPERTY MSVC_RUNTIME_LIBRARY MultiThreaded)
endif()
119 changes: 63 additions & 56 deletions src/srv/MountedArchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,54 @@
namespace EGL3::Service {
using namespace Storage;

std::vector<MountedFile> GetMountFiles(const Game::ArchiveList<Game::RunlistId::File>& Files)
MountedArchive::MountedArchive(const std::filesystem::path& Path, Game::Archive&& Archive) :
Archive(std::move(Archive)),
ArchiveLists(this->Archive),
LUT(ArchiveLists),
Disk(GetMountedFiles(), Utils::Random(), HandleCluster),
DriveLetter(0)
{
std::vector<MountedFile> MountedFiles;
MountedFiles.reserve(Files.size());
Disk.Initialize();

int Idx = 0;
for (auto& File : Files) {
MountedFiles.push_back({
.Path = File.Filename,
.FileSize = File.FileSize,
.UserContext = (void*)Idx++
});
Disk.Create();

Disk.Mount();
}

MountedArchive::~MountedArchive()
{
}

char MountedArchive::GetDriveLetter() const
{
if (!DriveLetter) {
DriveLetter = Disk.GetDriveLetter();
}
return DriveLetter;
}

return MountedFiles;
std::filesystem::path MountedArchive::GetArchivePath() const
{
return Archive.GetPath();
}

MountedArchive::MountedArchive(const std::filesystem::path& Path, Storage::Game::Archive&& Archive) :
DriveLetter(0),
Archive(std::move(Archive)),
ArchiveLists(this->Archive),
Disk(GetMountFiles(ArchiveLists.Files), Utils::Random())
MountedArchive::Stats MountedArchive::QueryStats() const
{
Disk.HandleFileCluster.Set([this](void* Ctx, uint64_t LCN, uint8_t Buffer[4096]) { HandleFileCluster(Ctx, LCN, Buffer); });
if (!Counter.IsValid()) {
Counter = DriveCounter(GetDriveLetter());
}
if (Counter.IsValid()) {
return Counter.GetData();
}
return Stats{};
}

Disk.Initialize();
MountedArchive::SectionLUT::SectionLUT(const Lists& ArchiveLists)
{
LUT.reserve(ArchiveLists.Files.size());

SectionLUT.reserve(ArchiveLists.Files.size());
for (auto& File : ArchiveLists.Files) {
auto& Sections = SectionLUT.emplace_back();
auto& Sections = LUT.emplace_back();
uint32_t ClusterCount = Utils::Align<4096>(File.FileSize) / 4096;
Sections.reserve(ClusterCount);

Expand All @@ -50,70 +68,59 @@ namespace EGL3::Service {
for (uint32_t i = 0; i < ClusterCount; ++i) {
uint32_t BytesToSelect = std::min(4096llu, File.FileSize - i * 4096llu);

Sections.emplace_back(SectionParts.size());
Sections.emplace_back(Parts.size());
do {
if (ItrDataOffset == Itr->Size) {
++Itr;
ItrDataOffset = 0;
}
auto& ChunkPart = *Itr;
auto SectionPartSize = std::min(ChunkPart.Size - ItrDataOffset, BytesToSelect);
SectionParts.emplace_back(
Parts.emplace_back(
GetDataItr(ChunkPart.ChunkIdx) + ChunkPart.Offset + ItrDataOffset,
SectionPartSize
);
BytesToSelect -= SectionPartSize;
ItrDataOffset += SectionPartSize;
EGL3_VERIFY(ItrDataOffset <= Itr->Size, "Invalid data offset");
} while (BytesToSelect);
SectionParts.emplace_back();
Parts.emplace_back();
}
}

Disk.Create();

Disk.Mount();
Contexts.emplace_back(Sections, Parts, ArchiveLists.ChunkDatas.begin());
}
}

MountedArchive::~MountedArchive()
MountedArchive::SectionContext::SectionContext(const std::vector<uint32_t>& const LUT, const std::vector<SectionPart>& const Parts, const Storage::Game::ArchiveListIteratorReadonly<Storage::Game::RunlistId::ChunkData> DataBegin) :
LUT(LUT),
Parts(Parts),
DataBegin(DataBegin)
{
}

char MountedArchive::GetDriveLetter() const
{
if (!DriveLetter) {
DriveLetter = Disk.GetDriveLetter();
}
return DriveLetter;
}

std::filesystem::path MountedArchive::GetArchivePath() const
std::vector<MountedFile> MountedArchive::GetMountedFiles()
{
return Archive.GetPath();
}
std::vector<MountedFile> MountedFiles;
MountedFiles.reserve(ArchiveLists.Files.size());

MountedArchive::Stats MountedArchive::QueryStats() const
{
if (!Counter.IsValid()) {
Counter = DriveCounter(GetDriveLetter());
}
if (Counter.IsValid()) {
return Counter.GetData();
size_t Idx = 0;
for (auto& File : ArchiveLists.Files) {
MountedFiles.push_back({
.Path = File.Filename,
.FileSize = File.FileSize,
.UserContext = (void*)&LUT.Contexts[Idx++]
});
}
return Stats{};
}

void MountedArchive::HandleFileCluster(void* Ctx, uint64_t LCN, uint8_t Buffer[4096]) const noexcept
{
auto& File = SectionLUT[(size_t)Ctx];
return MountedFiles;
}

if (File.size() < LCN) [[unlikely]] {
ZeroMemory(Buffer, 4096);
return;
}
void MountedArchive::HandleCluster(void* CtxPtr, uint64_t LCN, uint8_t Buffer[4096]) noexcept {
auto& Ctx = *(MountedArchive::SectionContext*)CtxPtr;

for(auto Itr = SectionParts.begin() + File[LCN]; Itr->IsValid(); ++Itr) {
auto Ptr = ArchiveLists.ChunkDatas.begin() + Itr->GetPtr();
for (auto Itr = Ctx.Parts.begin() + Ctx.LUT[LCN]; Itr->IsValid(); ++Itr) {
auto Ptr = Ctx.DataBegin + Itr->GetPtr();
Ptr.FastCopy((char*)Buffer, Itr->GetSize());
Buffer = (uint8_t*)Buffer + Itr->GetSize();
}
Expand Down
43 changes: 31 additions & 12 deletions src/srv/MountedArchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ namespace EGL3::Service {
Stats QueryStats() const;

private:
void HandleFileCluster(void* Ctx, uint64_t LCN, uint8_t Buffer[4096]) const noexcept;

struct Lists {
const Storage::Game::ArchiveList<Storage::Game::RunlistId::File> Files;
const Storage::Game::ArchiveList<Storage::Game::RunlistId::ChunkPart> ChunkParts;
const Storage::Game::ArchiveList<Storage::Game::RunlistId::ChunkInfo> ChunkInfos;
const Storage::Game::ArchiveList<Storage::Game::RunlistId::ChunkData> ChunkDatas;

Lists(Storage::Game::Archive& Archive) :
Lists(const Storage::Game::Archive& Archive) :
Files(Archive),
ChunkParts(Archive),
ChunkInfos(Archive),
Expand All @@ -41,39 +39,60 @@ namespace EGL3::Service {
struct SectionPart {
uint64_t Data;

SectionPart() :
SectionPart() noexcept :
Data(0)
{

}

SectionPart(uint64_t Ptr, uint16_t Size) :
SectionPart(uint64_t Ptr, uint16_t Size) noexcept :
Data(uint64_t(Size) << 48 | Ptr)
{

}

bool IsValid() const
bool IsValid() const noexcept
{
return Data;
}

uint64_t GetPtr() const
uint64_t GetPtr() const noexcept
{
return Data & (1llu << 48) - 1;
}

uint16_t GetSize() const
uint16_t GetSize() const noexcept
{
return Data >> 48;
}
};

Storage::Game::Archive Archive;
Lists ArchiveLists;
struct SectionLUT;

struct SectionContext {
const std::vector<uint32_t>& const LUT;
const std::vector<SectionPart>& const Parts;
const Storage::Game::ArchiveListIteratorReadonly<Storage::Game::RunlistId::ChunkData> DataBegin;

SectionContext(const std::vector<uint32_t>& const LUT, const std::vector<SectionPart>& const Parts, const Storage::Game::ArchiveListIteratorReadonly<Storage::Game::RunlistId::ChunkData> DataBegin);
};

struct SectionLUT {
std::vector<SectionPart> Parts;
std::vector<std::vector<uint32_t>> LUT;
std::vector<SectionContext> Contexts;

SectionLUT(const Lists& ArchiveLists);
};

std::vector<MountedFile> GetMountedFiles();

static void HandleCluster(void* CtxPtr, uint64_t LCN, uint8_t Buffer[4096]) noexcept;

const Storage::Game::Archive Archive;
const Lists ArchiveLists;
const SectionLUT LUT;
MountedDisk Disk;
std::vector<SectionPart> SectionParts;
std::vector<std::vector<uint32_t>> SectionLUT;
mutable DriveCounter Counter;
mutable char DriveLetter;
};
Expand Down
Loading

0 comments on commit 305afb4

Please sign in to comment.