Skip to content

Commit 305afb4

Browse files
committed
Further performance improvements for the service code
- 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
1 parent b76563f commit 305afb4

File tree

7 files changed

+148
-169
lines changed

7 files changed

+148
-169
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
cmake_minimum_required (VERSION 3.8)
1+
cmake_minimum_required (VERSION 3.18)
2+
cmake_policy(SET CMP0091 NEW)
23

34
## Project Definition and Options ##
45

src/srv/CMakeLists.txt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required (VERSION 3.8)
1+
cmake_minimum_required (VERSION 3.18)
22

33
## Project Definition and Options ##
44

@@ -53,3 +53,23 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC" AND CMAKE_BUILD_TYPE MATCHES "Release")
5353
COMPILE_PDB_OUTPUT_DIR ${CMAKE_BINARY_DIR}
5454
)
5555
endif()
56+
57+
# Use static CRT (the code is memcpy-heavy, avoid calling those dlls if we have to)
58+
set(CompilerFlags
59+
CMAKE_CXX_FLAGS
60+
CMAKE_CXX_FLAGS_DEBUG
61+
CMAKE_CXX_FLAGS_RELEASE
62+
CMAKE_C_FLAGS
63+
CMAKE_C_FLAGS_DEBUG
64+
CMAKE_C_FLAGS_RELEASE
65+
)
66+
foreach(CompilerFlag ${CompilerFlags})
67+
string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
68+
string(REPLACE "-MD" "-MT" ${CompilerFlag} "${${CompilerFlag}}")
69+
endforeach()
70+
71+
if (CMAKE_BUILD_TYPE MATCHES "Debug")
72+
set_property(TARGET EGL3_SRV PROPERTY MSVC_RUNTIME_LIBRARY MultiThreadedDebug)
73+
else()
74+
set_property(TARGET EGL3_SRV PROPERTY MSVC_RUNTIME_LIBRARY MultiThreaded)
75+
endif()

src/srv/MountedArchive.cpp

Lines changed: 63 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,54 @@
66
namespace EGL3::Service {
77
using namespace Storage;
88

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

14-
int Idx = 0;
15-
for (auto& File : Files) {
16-
MountedFiles.push_back({
17-
.Path = File.Filename,
18-
.FileSize = File.FileSize,
19-
.UserContext = (void*)Idx++
20-
});
18+
Disk.Create();
19+
20+
Disk.Mount();
21+
}
22+
23+
MountedArchive::~MountedArchive()
24+
{
25+
}
26+
27+
char MountedArchive::GetDriveLetter() const
28+
{
29+
if (!DriveLetter) {
30+
DriveLetter = Disk.GetDriveLetter();
2131
}
32+
return DriveLetter;
33+
}
2234

23-
return MountedFiles;
35+
std::filesystem::path MountedArchive::GetArchivePath() const
36+
{
37+
return Archive.GetPath();
2438
}
2539

26-
MountedArchive::MountedArchive(const std::filesystem::path& Path, Storage::Game::Archive&& Archive) :
27-
DriveLetter(0),
28-
Archive(std::move(Archive)),
29-
ArchiveLists(this->Archive),
30-
Disk(GetMountFiles(ArchiveLists.Files), Utils::Random())
40+
MountedArchive::Stats MountedArchive::QueryStats() const
3141
{
32-
Disk.HandleFileCluster.Set([this](void* Ctx, uint64_t LCN, uint8_t Buffer[4096]) { HandleFileCluster(Ctx, LCN, Buffer); });
42+
if (!Counter.IsValid()) {
43+
Counter = DriveCounter(GetDriveLetter());
44+
}
45+
if (Counter.IsValid()) {
46+
return Counter.GetData();
47+
}
48+
return Stats{};
49+
}
3350

34-
Disk.Initialize();
51+
MountedArchive::SectionLUT::SectionLUT(const Lists& ArchiveLists)
52+
{
53+
LUT.reserve(ArchiveLists.Files.size());
3554

36-
SectionLUT.reserve(ArchiveLists.Files.size());
3755
for (auto& File : ArchiveLists.Files) {
38-
auto& Sections = SectionLUT.emplace_back();
56+
auto& Sections = LUT.emplace_back();
3957
uint32_t ClusterCount = Utils::Align<4096>(File.FileSize) / 4096;
4058
Sections.reserve(ClusterCount);
4159

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

53-
Sections.emplace_back(SectionParts.size());
71+
Sections.emplace_back(Parts.size());
5472
do {
5573
if (ItrDataOffset == Itr->Size) {
5674
++Itr;
5775
ItrDataOffset = 0;
5876
}
5977
auto& ChunkPart = *Itr;
6078
auto SectionPartSize = std::min(ChunkPart.Size - ItrDataOffset, BytesToSelect);
61-
SectionParts.emplace_back(
79+
Parts.emplace_back(
6280
GetDataItr(ChunkPart.ChunkIdx) + ChunkPart.Offset + ItrDataOffset,
6381
SectionPartSize
6482
);
6583
BytesToSelect -= SectionPartSize;
6684
ItrDataOffset += SectionPartSize;
6785
EGL3_VERIFY(ItrDataOffset <= Itr->Size, "Invalid data offset");
6886
} while (BytesToSelect);
69-
SectionParts.emplace_back();
87+
Parts.emplace_back();
7088
}
71-
}
72-
73-
Disk.Create();
7489

75-
Disk.Mount();
90+
Contexts.emplace_back(Sections, Parts, ArchiveLists.ChunkDatas.begin());
91+
}
7692
}
7793

78-
MountedArchive::~MountedArchive()
94+
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) :
95+
LUT(LUT),
96+
Parts(Parts),
97+
DataBegin(DataBegin)
7998
{
80-
}
8199

82-
char MountedArchive::GetDriveLetter() const
83-
{
84-
if (!DriveLetter) {
85-
DriveLetter = Disk.GetDriveLetter();
86-
}
87-
return DriveLetter;
88100
}
89101

90-
std::filesystem::path MountedArchive::GetArchivePath() const
102+
std::vector<MountedFile> MountedArchive::GetMountedFiles()
91103
{
92-
return Archive.GetPath();
93-
}
104+
std::vector<MountedFile> MountedFiles;
105+
MountedFiles.reserve(ArchiveLists.Files.size());
94106

95-
MountedArchive::Stats MountedArchive::QueryStats() const
96-
{
97-
if (!Counter.IsValid()) {
98-
Counter = DriveCounter(GetDriveLetter());
99-
}
100-
if (Counter.IsValid()) {
101-
return Counter.GetData();
107+
size_t Idx = 0;
108+
for (auto& File : ArchiveLists.Files) {
109+
MountedFiles.push_back({
110+
.Path = File.Filename,
111+
.FileSize = File.FileSize,
112+
.UserContext = (void*)&LUT.Contexts[Idx++]
113+
});
102114
}
103-
return Stats{};
104-
}
105115

106-
void MountedArchive::HandleFileCluster(void* Ctx, uint64_t LCN, uint8_t Buffer[4096]) const noexcept
107-
{
108-
auto& File = SectionLUT[(size_t)Ctx];
116+
return MountedFiles;
117+
}
109118

110-
if (File.size() < LCN) [[unlikely]] {
111-
ZeroMemory(Buffer, 4096);
112-
return;
113-
}
119+
void MountedArchive::HandleCluster(void* CtxPtr, uint64_t LCN, uint8_t Buffer[4096]) noexcept {
120+
auto& Ctx = *(MountedArchive::SectionContext*)CtxPtr;
114121

115-
for(auto Itr = SectionParts.begin() + File[LCN]; Itr->IsValid(); ++Itr) {
116-
auto Ptr = ArchiveLists.ChunkDatas.begin() + Itr->GetPtr();
122+
for (auto Itr = Ctx.Parts.begin() + Ctx.LUT[LCN]; Itr->IsValid(); ++Itr) {
123+
auto Ptr = Ctx.DataBegin + Itr->GetPtr();
117124
Ptr.FastCopy((char*)Buffer, Itr->GetSize());
118125
Buffer = (uint8_t*)Buffer + Itr->GetSize();
119126
}

src/srv/MountedArchive.h

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@ namespace EGL3::Service {
2020
Stats QueryStats() const;
2121

2222
private:
23-
void HandleFileCluster(void* Ctx, uint64_t LCN, uint8_t Buffer[4096]) const noexcept;
24-
2523
struct Lists {
2624
const Storage::Game::ArchiveList<Storage::Game::RunlistId::File> Files;
2725
const Storage::Game::ArchiveList<Storage::Game::RunlistId::ChunkPart> ChunkParts;
2826
const Storage::Game::ArchiveList<Storage::Game::RunlistId::ChunkInfo> ChunkInfos;
2927
const Storage::Game::ArchiveList<Storage::Game::RunlistId::ChunkData> ChunkDatas;
3028

31-
Lists(Storage::Game::Archive& Archive) :
29+
Lists(const Storage::Game::Archive& Archive) :
3230
Files(Archive),
3331
ChunkParts(Archive),
3432
ChunkInfos(Archive),
@@ -41,39 +39,60 @@ namespace EGL3::Service {
4139
struct SectionPart {
4240
uint64_t Data;
4341

44-
SectionPart() :
42+
SectionPart() noexcept :
4543
Data(0)
4644
{
4745

4846
}
4947

50-
SectionPart(uint64_t Ptr, uint16_t Size) :
48+
SectionPart(uint64_t Ptr, uint16_t Size) noexcept :
5149
Data(uint64_t(Size) << 48 | Ptr)
5250
{
5351

5452
}
5553

56-
bool IsValid() const
54+
bool IsValid() const noexcept
5755
{
5856
return Data;
5957
}
6058

61-
uint64_t GetPtr() const
59+
uint64_t GetPtr() const noexcept
6260
{
6361
return Data & (1llu << 48) - 1;
6462
}
6563

66-
uint16_t GetSize() const
64+
uint16_t GetSize() const noexcept
6765
{
6866
return Data >> 48;
6967
}
7068
};
7169

72-
Storage::Game::Archive Archive;
73-
Lists ArchiveLists;
70+
struct SectionLUT;
71+
72+
struct SectionContext {
73+
const std::vector<uint32_t>& const LUT;
74+
const std::vector<SectionPart>& const Parts;
75+
const Storage::Game::ArchiveListIteratorReadonly<Storage::Game::RunlistId::ChunkData> DataBegin;
76+
77+
SectionContext(const std::vector<uint32_t>& const LUT, const std::vector<SectionPart>& const Parts, const Storage::Game::ArchiveListIteratorReadonly<Storage::Game::RunlistId::ChunkData> DataBegin);
78+
};
79+
80+
struct SectionLUT {
81+
std::vector<SectionPart> Parts;
82+
std::vector<std::vector<uint32_t>> LUT;
83+
std::vector<SectionContext> Contexts;
84+
85+
SectionLUT(const Lists& ArchiveLists);
86+
};
87+
88+
std::vector<MountedFile> GetMountedFiles();
89+
90+
static void HandleCluster(void* CtxPtr, uint64_t LCN, uint8_t Buffer[4096]) noexcept;
91+
92+
const Storage::Game::Archive Archive;
93+
const Lists ArchiveLists;
94+
const SectionLUT LUT;
7495
MountedDisk Disk;
75-
std::vector<SectionPart> SectionParts;
76-
std::vector<std::vector<uint32_t>> SectionLUT;
7796
mutable DriveCounter Counter;
7897
mutable char DriveLetter;
7998
};

0 commit comments

Comments
 (0)