mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Added CpuAffinityRotation setting
This commit is contained in:
parent
0c7358b449
commit
89a16d92e8
@ -9,6 +9,7 @@ namespace Config
|
||||
Settings::BltFilter bltFilter;
|
||||
Settings::ConfigHotKey configHotKey;
|
||||
Settings::CpuAffinity cpuAffinity;
|
||||
Settings::CpuAffinityRotation cpuAffinityRotation;
|
||||
Settings::DesktopColorDepth desktopColorDepth;
|
||||
Settings::DisplayFilter displayFilter;
|
||||
Settings::DisplayRefreshRate displayRefreshRate;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <Config/Settings/BltFilter.h>
|
||||
#include <Config/Settings/ConfigHotKey.h>
|
||||
#include <Config/Settings/CpuAffinity.h>
|
||||
#include <Config/Settings/CpuAffinityRotation.h>
|
||||
#include <Config/Settings/DesktopColorDepth.h>
|
||||
#include <Config/Settings/DisplayFilter.h>
|
||||
#include <Config/Settings/DisplayRefreshRate.h>
|
||||
@ -43,6 +44,7 @@ namespace Config
|
||||
extern Settings::BltFilter bltFilter;
|
||||
extern Settings::ConfigHotKey configHotKey;
|
||||
extern Settings::CpuAffinity cpuAffinity;
|
||||
extern Settings::CpuAffinityRotation cpuAffinityRotation;
|
||||
extern Settings::DesktopColorDepth desktopColorDepth;
|
||||
extern Settings::DisplayFilter displayFilter;
|
||||
extern Settings::DisplayRefreshRate displayRefreshRate;
|
||||
|
18
DDrawCompat/Config/Settings/CpuAffinityRotation.h
Normal file
18
DDrawCompat/Config/Settings/CpuAffinityRotation.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <Config/EnumSetting.h>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
class CpuAffinityRotation : public MappedSetting<bool>
|
||||
{
|
||||
public:
|
||||
CpuAffinityRotation()
|
||||
: MappedSetting("CpuAffinityRotation", "on", { {"off", false}, {"on", true} })
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Overlay/StatsWindow.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
#include <Win32/Thread.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -418,6 +419,7 @@ namespace
|
||||
int msUntilUpdateReady = 0;
|
||||
while (true)
|
||||
{
|
||||
Win32::Thread::rotateCpuAffinity();
|
||||
if (msUntilUpdateReady > 0)
|
||||
{
|
||||
Sleep(1);
|
||||
|
@ -166,6 +166,7 @@
|
||||
<ClInclude Include="Config\Settings\BltFilter.h" />
|
||||
<ClInclude Include="Config\Settings\ConfigHotKey.h" />
|
||||
<ClInclude Include="Config\Settings\CpuAffinity.h" />
|
||||
<ClInclude Include="Config\Settings\CpuAffinityRotation.h" />
|
||||
<ClInclude Include="Config\Settings\DesktopColorDepth.h" />
|
||||
<ClInclude Include="Config\Settings\DisplayFilter.h" />
|
||||
<ClInclude Include="Config\Settings\DisplayRefreshRate.h" />
|
||||
|
@ -633,6 +633,9 @@
|
||||
<ClInclude Include="Config\Settings\TerminateHotKey.h">
|
||||
<Filter>Header Files\Config\Settings</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\Settings\CpuAffinityRotation.h">
|
||||
<Filter>Header Files\Config\Settings</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <process.h>
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Dll/Dll.h>
|
||||
|
||||
namespace Dll
|
||||
@ -16,6 +17,7 @@ namespace Dll
|
||||
if (thread)
|
||||
{
|
||||
SetThreadPriority(thread, priority);
|
||||
CALL_ORIG_FUNC(SetThreadPriorityBoost)(thread, FALSE);
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
|
@ -1,12 +1,181 @@
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <Common/Time.h>
|
||||
#include <Config/Config.h>
|
||||
#include <Dll/Dll.h>
|
||||
#include <Win32/Thread.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
DWORD g_cpuAffinity = 0;
|
||||
bool g_cpuAffinityRotationEnabled = false;
|
||||
std::map<BYTE, BYTE> g_nextProcessor;
|
||||
|
||||
std::string maskToString(ULONG_PTR mask);
|
||||
void setNextProcessorSet(DWORD fromSet, DWORD toSet);
|
||||
|
||||
std::map<BYTE, std::vector<DWORD>> getProcessorSets()
|
||||
{
|
||||
std::map<BYTE, std::vector<DWORD>> result;
|
||||
DWORD primaryProcessorGroup = 0;
|
||||
auto getThreadIdealProcessorEx = reinterpret_cast<decltype(&GetThreadIdealProcessorEx)>(
|
||||
Compat::getProcAddress(GetModuleHandle("kernel32"), "GetThreadIdealProcessorEx"));
|
||||
if (getThreadIdealProcessorEx)
|
||||
{
|
||||
PROCESSOR_NUMBER pn = {};
|
||||
getThreadIdealProcessorEx(GetCurrentThread(), &pn);
|
||||
primaryProcessorGroup = pn.Group;
|
||||
LOG_INFO << "Primary CPU group number: " << primaryProcessorGroup;
|
||||
}
|
||||
|
||||
auto getLogicalProcessorInformationEx = reinterpret_cast<decltype(&GetLogicalProcessorInformationEx)>(
|
||||
Compat::getProcAddress(GetModuleHandle("kernel32"), "GetLogicalProcessorInformationEx"));
|
||||
if (getLogicalProcessorInformationEx)
|
||||
{
|
||||
DWORD size = 0;
|
||||
std::vector<BYTE> buffer;
|
||||
getLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &size);
|
||||
buffer.resize(size);
|
||||
getLogicalProcessorInformationEx(RelationProcessorCore,
|
||||
reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(buffer.data()), &size);
|
||||
|
||||
DWORD offset = 0;
|
||||
while (offset < size)
|
||||
{
|
||||
auto& pi = *reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(buffer.data() + offset);
|
||||
for (DWORD i = 0; i < pi.Processor.GroupCount; ++i)
|
||||
{
|
||||
if (primaryProcessorGroup == pi.Processor.GroupMask[i].Group)
|
||||
{
|
||||
result[pi.Processor.EfficiencyClass].push_back(pi.Processor.GroupMask[i].Mask);
|
||||
}
|
||||
}
|
||||
offset += pi.Size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD size = 0;
|
||||
GetLogicalProcessorInformation(nullptr, &size);
|
||||
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> processorInfo;
|
||||
processorInfo.resize(size / sizeof(processorInfo[0]));
|
||||
GetLogicalProcessorInformation(processorInfo.data(), &size);
|
||||
|
||||
for (auto& pi : processorInfo)
|
||||
{
|
||||
if (RelationProcessorCore == pi.Relationship)
|
||||
{
|
||||
result[0].push_back(pi.ProcessorMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.empty())
|
||||
{
|
||||
LOG_INFO << "ERROR: Failed to detect CPU topology!";
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto it = result.rbegin(); it != result.rend(); ++it)
|
||||
{
|
||||
LOG_INFO << "Physical to logical CPU core mapping for efficiency class " << static_cast<DWORD>(it->first) << ':';
|
||||
DWORD core = 0;
|
||||
for (auto& set : it->second)
|
||||
{
|
||||
++core;
|
||||
LOG_INFO << " Physical core #" << core << ": " << maskToString(set);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void initNextProcessorMap(const std::map<BYTE, std::vector<DWORD>>& processorSets)
|
||||
{
|
||||
for (auto& ps : processorSets)
|
||||
{
|
||||
for (BYTE fromIndex = 0; fromIndex < ps.second.size(); ++fromIndex)
|
||||
{
|
||||
auto bitCount = std::bitset<32>(ps.second[fromIndex]).count();
|
||||
bool found = false;
|
||||
for (BYTE toIndex = fromIndex + 1; toIndex < ps.second.size() && !found; ++toIndex)
|
||||
{
|
||||
if (bitCount == std::bitset<32>(ps.second[toIndex]).count())
|
||||
{
|
||||
setNextProcessorSet(ps.second[fromIndex], ps.second[toIndex]);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
for (BYTE toIndex = 0; toIndex < fromIndex && !found; ++toIndex)
|
||||
{
|
||||
if (bitCount == std::bitset<32>(ps.second[toIndex]).count())
|
||||
{
|
||||
setNextProcessorSet(ps.second[fromIndex], ps.second[toIndex]);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
setNextProcessorSet(ps.second[fromIndex], ps.second[fromIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string maskToString(ULONG_PTR mask)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for (BYTE i = 0; i < 32; ++i)
|
||||
{
|
||||
if (mask & (1U << i))
|
||||
{
|
||||
oss << i + 1 << ", ";
|
||||
}
|
||||
}
|
||||
return oss.str().substr(0, max(0, oss.str().length() - 2));
|
||||
}
|
||||
|
||||
DWORD rotateMask(DWORD mask)
|
||||
{
|
||||
DWORD result = 0;
|
||||
for (BYTE i = 0; i < 32; ++i)
|
||||
{
|
||||
if (mask & (1U << i))
|
||||
{
|
||||
auto it = g_nextProcessor.find(i);
|
||||
result |= 1U << (it != g_nextProcessor.end() ? it->second : i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void setNextProcessorSet(DWORD fromSet, DWORD toSet)
|
||||
{
|
||||
BYTE from = 0;
|
||||
BYTE to = 0;
|
||||
while (0 != fromSet)
|
||||
{
|
||||
while (!(fromSet & (1U << from)))
|
||||
{
|
||||
++from;
|
||||
}
|
||||
while (!(toSet & (1U << to)))
|
||||
{
|
||||
++to;
|
||||
}
|
||||
g_nextProcessor[from] = to;
|
||||
fromSet &= ~(1U << from);
|
||||
++from;
|
||||
++to;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI setProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask)
|
||||
{
|
||||
LOG_FUNC("SetProcessAffinityMask", hProcess, Compat::hex(dwProcessAffinityMask));
|
||||
@ -44,22 +213,49 @@ namespace Win32
|
||||
{
|
||||
void applyConfig()
|
||||
{
|
||||
auto cpuAffinity = Config::cpuAffinity.get();
|
||||
if (0 != cpuAffinity)
|
||||
{
|
||||
SYSTEM_INFO si = {};
|
||||
GetSystemInfo(&si);
|
||||
const unsigned cpuCount = min(si.dwNumberOfProcessors, 32);
|
||||
cpuAffinity &= UINT_MAX >> (32 - cpuCount);
|
||||
initNextProcessorMap(getProcessorSets());
|
||||
|
||||
if (0 == cpuAffinity || !CALL_ORIG_FUNC(SetProcessAffinityMask)(GetCurrentProcess(), cpuAffinity))
|
||||
g_cpuAffinity = Config::cpuAffinity.get();
|
||||
if (0 != g_cpuAffinity)
|
||||
{
|
||||
for (BYTE i = 0; i < 32; ++i)
|
||||
{
|
||||
LOG_INFO << (0 == cpuAffinity ? "Invalid" : "Failed to set") << " CPU affinity, falling back to default";
|
||||
Config::cpuAffinity.reset();
|
||||
CALL_ORIG_FUNC(SetProcessAffinityMask)(GetCurrentProcess(), Config::cpuAffinity.get());
|
||||
if (g_nextProcessor.find(i) == g_nextProcessor.end())
|
||||
{
|
||||
g_cpuAffinity &= ~(1U << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == g_cpuAffinity)
|
||||
{
|
||||
LOG_INFO << "Warning: CPU affinity setting doesn't match any existing logical cores, using default";
|
||||
g_cpuAffinity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD processMask = 0;
|
||||
DWORD systemMask = 0;
|
||||
GetProcessAffinityMask(GetCurrentProcess(), &processMask, &systemMask);
|
||||
LOG_INFO << "Current CPU affinity: " << maskToString(processMask);
|
||||
|
||||
if (0 == g_cpuAffinity && 0 != processMask && processMask != systemMask)
|
||||
{
|
||||
g_cpuAffinity = processMask;
|
||||
}
|
||||
|
||||
if (0 != g_cpuAffinity)
|
||||
{
|
||||
LOG_INFO << "Applying configured CPU affinity: " << maskToString(g_cpuAffinity);
|
||||
if (!CALL_ORIG_FUNC(SetProcessAffinityMask)(GetCurrentProcess(), g_cpuAffinity))
|
||||
{
|
||||
LOG_INFO << "ERROR: Failed to set CPU affinity";
|
||||
g_cpuAffinity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
g_cpuAffinityRotationEnabled = Config::cpuAffinityRotation.get() && rotateMask(g_cpuAffinity) != g_cpuAffinity;
|
||||
LOG_INFO << "CPU affinity rotation is " << (g_cpuAffinityRotationEnabled ? "enabled" : "disabled");
|
||||
|
||||
switch (Config::threadPriorityBoost.get())
|
||||
{
|
||||
case Config::Settings::ThreadPriorityBoost::OFF:
|
||||
@ -83,5 +279,27 @@ namespace Win32
|
||||
HOOK_FUNCTION(kernel32, SetProcessPriorityBoost, setProcessPriorityBoost);
|
||||
HOOK_FUNCTION(kernel32, SetThreadPriorityBoost, setThreadPriorityBoost);
|
||||
}
|
||||
|
||||
void rotateCpuAffinity()
|
||||
{
|
||||
if (!g_cpuAffinityRotationEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static auto g_qpcLastRotation = Time::queryPerformanceCounter();
|
||||
auto qpcNow = Time::queryPerformanceCounter();
|
||||
if (qpcNow - g_qpcLastRotation < Time::g_qpcFrequency / 10)
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_qpcLastRotation = qpcNow;
|
||||
|
||||
g_cpuAffinity = rotateMask(g_cpuAffinity);
|
||||
if (!CALL_ORIG_FUNC(SetProcessAffinityMask)(GetCurrentProcess(), g_cpuAffinity))
|
||||
{
|
||||
LOG_ONCE("ERROR: Failed to set rotated CPU affinity: " << maskToString(g_cpuAffinity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,5 +6,6 @@ namespace Win32
|
||||
{
|
||||
void applyConfig();
|
||||
void installHooks();
|
||||
void rotateCpuAffinity();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user