From 8c64192ac74d596b99cea3c99ebbb09b39d5e884 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 25 Aug 2024 04:57:40 +0300 Subject: [PATCH] Implement basic system info detection on macos using sysctl --- .../CPU/Backends/AArch64/AArch64Common.cpp | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp b/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp index 765c9f7e04..9334984289 100644 --- a/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp +++ b/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp @@ -6,6 +6,7 @@ namespace aarch64 { +#if !defined(__APPLE__) struct cpu_entry_t { u32 vendor; @@ -194,4 +195,87 @@ namespace aarch64 result += suffix; return result; } +#else + // Sysctl wrappers. Maybe should be moved somewhere else later. + static std::pair cli_exec(const std::string_view& command) + { + std::array buffer; // iobuf for stdout + std::string result; // accumulated output + int exit_code = -1; + + // Invoke command, stream result over pipe + FILE* pipe = ::popen(command.data(), "r"); + if (!pipe) + { + return { exit_code, result }; + } + + // Accumulate stdout buffer + while (true) + { + memset(buffer.data(), 0, buffer.size()); + if (!::fgets(buffer.data(), buffer.size(), pipe)) + { + break; + } + result += buffer.data(); + } + + // Grab exit code. This is not really definitive but should be good enough to detect problems. + exit_code = ::pclose(pipe); + + // Return the output and exit code + return { exit_code, result }; + } + + static std::string sysctl_s(const std::string_view& variable_name) + { + const auto command = fmt::format("sysctl -n %s", variable_name); + const auto [exit_code, result] = cli_exec(command); + + if (exit_code != 0) + { + return {}; + } + + return fmt::trim(result, "\n\t "); + } + + static u64 sysctl_u64(const std::string_view& variable_name) + { + const auto value = sysctl_s(variable_name); + if (value.empty()) + { + return umax; + } + return std::stoull(value, nullptr, 16); + } + + // We can get the brand name from sysctl directly + // Once we have windows implemented, we should probably separate the different OS-dependent bits to avoid clutter + std::string get_cpu_brand() + { + const auto brand = sysctl_s("machdep.cpu.brand_string"); + if (brand.empty()) + { + return "Unidentified CPU"; + } + + // Parse extra core information (P and E cores) + if (sysctl_u64("hw.nperflevels") < 2) + { + return brand; + } + + u64 pcores = sysctl_u64("hw.perflevel0.physicalcpu"); + u64 ecores = sysctl_u64("hw.perflevel1.physicalcpu"); + + if (sysctl_s("hw.perflevel0.name") == "Efficiency") + { + std::swap(ecores, pcores); + } + + return fmt::format("%s (%lluP+%lluE)", brand, pcores, ecores); + } +#endif }