mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-14 11:01:01 +02:00
FEXServer: Implement automatic code cache generation
This commit is contained in:
1 parent
50939df6b5
commit
7ba6cfe651
1 file changed
+61
-10
@@ -24,6 +24,7 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <vector>
|
||||
|
||||
#include <xxhash.h>
|
||||
@@ -371,7 +372,7 @@ static void WriteNewCodeMap(const FEXCore::ExecutableFileInfo& File, const std::
|
||||
// List the main executable and all used libraries
|
||||
OutputCodeMap.AppendSetMainExecutable(File);
|
||||
|
||||
for (auto& Dependency : Dependencies) {
|
||||
for (auto& [Dependency, _] : Dependencies) {
|
||||
OutputCodeMap.AppendLibraryLoad(Dependency);
|
||||
}
|
||||
} else {
|
||||
@@ -384,27 +385,37 @@ static void WriteNewCodeMap(const FEXCore::ExecutableFileInfo& File, const std::
|
||||
}
|
||||
}
|
||||
|
||||
enum class NeedsCacheRefresh {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks and processes new code maps generated by FEX for the given application.
|
||||
*
|
||||
* Processed code maps are merged into the reference code map and deleted afterwards.
|
||||
*
|
||||
* The returned map is a list of all dependencies of the main executables discovered,
|
||||
* associated with a flag to indicate need for cache regeneration.
|
||||
*/
|
||||
static void AggregateCodeMaps(const FEXCore::ExecutableFileInfo& MainFileId, bool HasMultiblock) {
|
||||
std::set<FEXCore::ExecutableFileInfo> Result;
|
||||
static std::map<FEXCore::ExecutableFileInfo, NeedsCacheRefresh> AggregateCodeMaps(const FEXCore::ExecutableFileInfo& MainFileId, bool HasMultiblock) {
|
||||
std::map<FEXCore::ExecutableFileInfo, NeedsCacheRefresh> Result;
|
||||
|
||||
// Read all dependencies discovered in previous runs
|
||||
{
|
||||
auto MainFileCodeMapPath = fmt::format("{}/ready/{}", CodeMapDirectory, FEXCore::CodeMap::GetBaseFilename(MainFileId, !HasMultiblock));
|
||||
std::ifstream MainFileCodeMap(MainFileCodeMapPath, std::ios_base::binary);
|
||||
for (auto& [FileId, Contents] : FEXCore::CodeMap::ParseCodeMap(MainFileCodeMap)) {
|
||||
Result.emplace(nullptr, FileId, Contents.Filename);
|
||||
Result.emplace(std::piecewise_construct, std::forward_as_tuple(nullptr, FileId, Contents.Filename),
|
||||
std::forward_as_tuple(NeedsCacheRefresh::No));
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate information from new code maps
|
||||
auto IncomingCodeMap = ImportPendingCodeMaps(MainFileId, HasMultiblock);
|
||||
for (auto& [File, _] : IncomingCodeMap) {
|
||||
Result.emplace(nullptr, File.FileId, File.Filename);
|
||||
Result.emplace(std::piecewise_construct, std::forward_as_tuple(nullptr, File.FileId, File.Filename),
|
||||
std::forward_as_tuple(NeedsCacheRefresh::No));
|
||||
}
|
||||
|
||||
// For each referenced library, add referenced offsets to that library's reference code map
|
||||
@@ -425,12 +436,40 @@ static void AggregateCodeMaps(const FEXCore::ExecutableFileInfo& MainFileId, boo
|
||||
}
|
||||
}
|
||||
|
||||
// Update code map
|
||||
std::set<FEXCore::ExecutableFileInfo> Empty;
|
||||
// Update code map and queue for cache generation
|
||||
std::map<FEXCore::ExecutableFileInfo, NeedsCacheRefresh> Empty;
|
||||
WriteNewCodeMap(File, OutputName, Blocks, true, File.FileId == MainFileId.FileId ? Result : Empty);
|
||||
Result.at(File) = NeedsCacheRefresh::Yes;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
int32_t EmbedSubprocess(const char* path, char* const* args) {
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
execvp(path, args);
|
||||
_exit(-1);
|
||||
} else {
|
||||
int32_t Status {};
|
||||
while (waitpid(pid, &Status, 0) == -1 && errno == EINTR)
|
||||
;
|
||||
if (WIFEXITED(Status)) {
|
||||
return (int8_t)WEXITSTATUS(Status);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn a FEXOfflineCompiler instance to generate a code cache from the given code map
|
||||
*/
|
||||
static int RunOfflineCompiler(const char* CodeMap) {
|
||||
const char* ExecveArgs[] = {"FEXOfflineCompiler", "generate", CodeMap, nullptr};
|
||||
return EmbedSubprocess("FEXOfflineCompiler", const_cast<char* const*>(&ExecveArgs[0]));
|
||||
};
|
||||
|
||||
void HandleSocketData(fasio::tcp_socket& Socket) {
|
||||
std::vector<uint8_t> Data(1500);
|
||||
|
||||
@@ -554,10 +593,22 @@ void HandleSocketData(fasio::tcp_socket& Socket) {
|
||||
FEXCore::ExecutableFileInfo MainFileId = {nullptr, filename_hash, fextl::string(Tmp, TmpLen)};
|
||||
fmt::print("Requested {}cache generation for {}\n", HasMultiblock ? "" : "nomb-", MainFileId.Filename);
|
||||
|
||||
// Update code maps
|
||||
AggregateCodeMaps(MainFileId, HasMultiblock);
|
||||
// Update code maps; any update necessitates an update of the corresponding cache
|
||||
auto Binaries = AggregateCodeMaps(MainFileId, HasMultiblock);
|
||||
|
||||
// TODO: Implement
|
||||
// Trigger offline-compile for each binary that needs it
|
||||
for (const auto& [File, NeedsRefresh] : Binaries) {
|
||||
if (NeedsRefresh != NeedsCacheRefresh::Yes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto BinaryName = (std::string)FEXCore::CodeMap::GetBaseFilename(File, !HasMultiblock);
|
||||
fmt::println("Generating cache for {}", BinaryName);
|
||||
int Status = RunOfflineCompiler(fmt::format("{}/ready/{}", CodeMapDirectory, BinaryName).c_str());
|
||||
if (Status != 0) {
|
||||
fmt::println("ERROR: Cache generation failed with status {}", Status);
|
||||
}
|
||||
}
|
||||
|
||||
FEXServerClient::FEXServerResultPacket Res {
|
||||
.Header {
|
||||
|
||||
Reference in new issue
Block a user