mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-08 20:00:17 +02:00
Due to Intel dropping support for legacy segment registers[1] there is a concern that this will break legacy 32-bit software that is doing some magic segment register handling. Adds some simple telemetry for 32-bit applications that when they encounter an instruction that sets the segment register or uses a segment register that the JIT will do a /relatively/ quick four instruction check to see if it is not a null segment. It's not enough to just check if the segment index is 0 or not, 32-bit Linux software starts with non-zero segment register indexes but the LDT for each segment index is a null-descriptor. Once the segment address is loaded, the IR operation will do a quick check against zero and if it /isn't/ zero then set the telemetry value. A very minor optimization that segment registers only get checked once per block to ensure overhead stays low. [1] https://www.intel.com/content/www/us/en/developer/articles/technical/envisioning-future-simplified-architecture.html - 3.6 - Restricted Subset of Segmentation - `Bases are supported for FS, GS, GDT, IDT, LDT, and TSS registers; the base for CS, DS, ES, and SS is ignored for 32-bit mode, same as 64-bit mode (treated as zero).` - 4.2.17 - MOV to Segment Register - Will fault if SS is written (Breaking anything that writes to SS). - Will not fault if CS, DS, ES are written (Thus it sets the segment but gets ignored due to 3.6).
77 lines
2.4 KiB
C++
77 lines
2.4 KiB
C++
#include <FEXCore/Config/Config.h>
|
|
#include <FEXCore/Utils/File.h>
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
#include <FEXCore/Utils/Telemetry.h>
|
|
#include <FEXCore/fextl/fmt.h>
|
|
#include <FEXCore/fextl/string.h>
|
|
#include <FEXHeaderUtils/Filesystem.h>
|
|
|
|
#include <array>
|
|
#include <stddef.h>
|
|
#include <string_view>
|
|
#include <system_error>
|
|
|
|
namespace FEXCore::Telemetry {
|
|
#ifndef FEX_DISABLE_TELEMETRY
|
|
static std::array<Value, FEXCore::Telemetry::TelemetryType::TYPE_LAST> TelemetryValues = {{ }};
|
|
const std::array<std::string_view, FEXCore::Telemetry::TelemetryType::TYPE_LAST> TelemetryNames {
|
|
"64byte Split Locks",
|
|
"16byte Split atomics",
|
|
"VEX instructions (AVX)",
|
|
"EVEX instructions (AVX512)",
|
|
"16bit CAS Tear",
|
|
"32bit CAS Tear",
|
|
"64bit CAS Tear",
|
|
"128bit CAS Tear",
|
|
"Crash mask",
|
|
"Write 32-bit Segment ES",
|
|
"Write 32-bit Segment SS",
|
|
"Write 32-bit Segment CS",
|
|
"Write 32-bit Segment DS",
|
|
"Uses 32-bit Segment ES",
|
|
"Uses 32-bit Segment SS",
|
|
"Uses 32-bit Segment CS",
|
|
"Uses 32-bit Segment DS",
|
|
};
|
|
void Initialize() {
|
|
auto DataDirectory = Config::GetDataDirectory();
|
|
DataDirectory += "Telemetry/";
|
|
|
|
// Ensure the folder structure is created for our configuration
|
|
if (!FHU::Filesystem::Exists(DataDirectory) &&
|
|
!FHU::Filesystem::CreateDirectories(DataDirectory)) {
|
|
LogMan::Msg::IFmt("Couldn't create telemetry Folder");
|
|
}
|
|
}
|
|
|
|
void Shutdown(fextl::string const &ApplicationName) {
|
|
auto DataDirectory = Config::GetDataDirectory();
|
|
DataDirectory += "Telemetry/" + ApplicationName + ".telem";
|
|
|
|
if (FHU::Filesystem::Exists(DataDirectory)) {
|
|
// If the file exists, retain a single backup
|
|
auto Backup = DataDirectory + ".1";
|
|
FHU::Filesystem::CopyFile(DataDirectory, Backup, FHU::Filesystem::CopyOptions::OVERWRITE_EXISTING);
|
|
}
|
|
|
|
auto File = FEXCore::File::File(DataDirectory.c_str(),
|
|
FEXCore::File::FileModes::WRITE |
|
|
FEXCore::File::FileModes::CREATE |
|
|
FEXCore::File::FileModes::TRUNCATE);
|
|
|
|
if (File.IsValid()) {
|
|
for (size_t i = 0; i < TelemetryType::TYPE_LAST; ++i) {
|
|
auto &Name = TelemetryNames.at(i);
|
|
auto &Data = TelemetryValues.at(i);
|
|
fextl::fmt::print(File, "{}: {}\n", Name, *Data);
|
|
}
|
|
File.Flush();
|
|
}
|
|
}
|
|
|
|
Value &GetTelemetryValue(TelemetryType Type) {
|
|
return TelemetryValues.at(Type);
|
|
}
|
|
#endif
|
|
}
|