diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index f679aaff7e..9796cce14a 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -127,6 +127,7 @@ target_sources(common PRIVATE emitter/tools.h emitter/x86emitter.h emitter/x86types.h + Darwin/DarwinMisc.h ) if(USE_VTUNE) diff --git a/common/Darwin/DarwinMisc.cpp b/common/Darwin/DarwinMisc.cpp index 4913a93718..9c0804b304 100644 --- a/common/Darwin/DarwinMisc.cpp +++ b/common/Darwin/DarwinMisc.cpp @@ -15,8 +15,11 @@ #if defined(__APPLE__) +#include "common/Darwin/DarwinMisc.h" + #include #include +#include #include #include #include @@ -24,6 +27,7 @@ #include #include "common/Pcsx2Types.h" +#include "common/Console.h" #include "common/General.h" #include "common/Threading.h" #include "common/WindowInfo.h" @@ -89,6 +93,20 @@ static std::string sysctl_str(int category, int name) return std::string(buf, len > 0 ? len - 1 : 0); } +static std::optional sysctlbyname_u32(const char* name) +{ + u32 output; + size_t output_size = sizeof(output); + if (0 != sysctlbyname(name, &output, &output_size, nullptr, 0)) + return std::nullopt; + if (output_size != sizeof(output)) + { + DevCon.WriteLn("(DarwinMisc) sysctl %s gave unexpected size %zd", name, output_size); + return std::nullopt; + } + return output; +} + std::string GetOSVersionString() { std::string type = sysctl_str(CTL_KERN, KERN_OSTYPE); @@ -135,4 +153,46 @@ void Threading::SleepUntil(u64 ticks) nanosleep(&ts, nullptr); } +std::vector DarwinMisc::GetCPUClasses() +{ + std::vector out; + + if (std::optional nperflevels = sysctlbyname_u32("hw.nperflevels")) + { + char name[64]; + for (u32 i = 0; i < *nperflevels; i++) + { + snprintf(name, sizeof(name), "hw.perflevel%u.physicalcpu", i); + std::optional physicalcpu = sysctlbyname_u32(name); + snprintf(name, sizeof(name), "hw.perflevel%u.logicalcpu", i); + std::optional logicalcpu = sysctlbyname_u32(name); + + char levelname[64]; + size_t levelname_size = sizeof(levelname); + snprintf(name, sizeof(name), "hw.perflevel%u.name", i); + if (0 != sysctlbyname(name, levelname, &levelname_size, nullptr, 0)) + strcpy(levelname, "???"); + + if (!physicalcpu.has_value() || !logicalcpu.has_value()) + { + Console.Warning("(DarwinMisc) Perf level %u is missing data on %s cpus!", + i, !physicalcpu.has_value() ? "physical" : "logical"); + continue; + } + + out.push_back({levelname, *physicalcpu, *logicalcpu}); + } + } + else if (std::optional physcpu = sysctlbyname_u32("hw.physicalcpu")) + { + out.push_back({"Default", *physcpu, sysctlbyname_u32("hw.logicalcpu").value_or(0)}); + } + else + { + Console.Warning("(DarwinMisc) Couldn't get cpu core count!"); + } + + return out; +} + #endif diff --git a/common/Darwin/DarwinMisc.h b/common/Darwin/DarwinMisc.h new file mode 100644 index 0000000000..84d6f3c024 --- /dev/null +++ b/common/Darwin/DarwinMisc.h @@ -0,0 +1,36 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2023 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once +#ifdef __APPLE__ + +#include +#include + +#include "common/Pcsx2Types.h" + +namespace DarwinMisc { + +struct CPUClass { + std::string name; + u32 num_physical; + u32 num_logical; +}; + +std::vector GetCPUClasses(); + +} + +#endif diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index be48e24ec9..f7246c41b7 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -77,6 +77,10 @@ #include #endif +#ifdef __APPLE__ +#include "common/Darwin/DarwinMisc.h" +#endif + #ifdef ENABLE_DISCORD_PRESENCE #include "discord_rpc.h" #endif @@ -2379,6 +2383,43 @@ static void SetMTVUAndAffinityControlDefault(SettingsInterface& si) si.SetIntValue("EmuCore/GS", "extrathreads", extra_threads); } +#elif defined(__APPLE__) + +static u32 s_big_cores; +static u32 s_small_cores; + +static void InitializeCPUInfo() +{ + s_big_cores = 0; + s_small_cores = 0; + std::vector classes = DarwinMisc::GetCPUClasses(); + for (size_t i = 0; i < classes.size(); i++) { + const DarwinMisc::CPUClass& cls = classes[i]; + const bool is_big = i == 0 || i < classes.size() - 1; // Assume only one group is small + DevCon.WriteLn("(VMManager) Found %u physical cores and %u logical cores in perf level %u (%s), assuming %s", + cls.num_physical, cls.num_logical, i, cls.name.c_str(), is_big ? "big" : "small"); + (is_big ? s_big_cores : s_small_cores) += cls.num_physical; + } +} + +static void SetMTVUAndAffinityControlDefault(SettingsInterface& si) +{ + VMManager::EnsureCPUInfoInitialized(); + + Console.WriteLn("Detected %u big cores", s_big_cores); + + if (s_big_cores >= 3) + { + Console.WriteLn(" So enabling MTVU."); + si.SetBoolValue("EmuCore/Speedhacks", "vuThread", true); + } + else + { + Console.WriteLn(" So disabling MTVU."); + si.SetBoolValue("EmuCore/Speedhacks", "vuThread", false); + } +} + #else static void InitializeCPUInfo()