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::BltFilter bltFilter;
|
||||||
Settings::ConfigHotKey configHotKey;
|
Settings::ConfigHotKey configHotKey;
|
||||||
Settings::CpuAffinity cpuAffinity;
|
Settings::CpuAffinity cpuAffinity;
|
||||||
|
Settings::CpuAffinityRotation cpuAffinityRotation;
|
||||||
Settings::DesktopColorDepth desktopColorDepth;
|
Settings::DesktopColorDepth desktopColorDepth;
|
||||||
Settings::DisplayFilter displayFilter;
|
Settings::DisplayFilter displayFilter;
|
||||||
Settings::DisplayRefreshRate displayRefreshRate;
|
Settings::DisplayRefreshRate displayRefreshRate;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <Config/Settings/BltFilter.h>
|
#include <Config/Settings/BltFilter.h>
|
||||||
#include <Config/Settings/ConfigHotKey.h>
|
#include <Config/Settings/ConfigHotKey.h>
|
||||||
#include <Config/Settings/CpuAffinity.h>
|
#include <Config/Settings/CpuAffinity.h>
|
||||||
|
#include <Config/Settings/CpuAffinityRotation.h>
|
||||||
#include <Config/Settings/DesktopColorDepth.h>
|
#include <Config/Settings/DesktopColorDepth.h>
|
||||||
#include <Config/Settings/DisplayFilter.h>
|
#include <Config/Settings/DisplayFilter.h>
|
||||||
#include <Config/Settings/DisplayRefreshRate.h>
|
#include <Config/Settings/DisplayRefreshRate.h>
|
||||||
@ -43,6 +44,7 @@ namespace Config
|
|||||||
extern Settings::BltFilter bltFilter;
|
extern Settings::BltFilter bltFilter;
|
||||||
extern Settings::ConfigHotKey configHotKey;
|
extern Settings::ConfigHotKey configHotKey;
|
||||||
extern Settings::CpuAffinity cpuAffinity;
|
extern Settings::CpuAffinity cpuAffinity;
|
||||||
|
extern Settings::CpuAffinityRotation cpuAffinityRotation;
|
||||||
extern Settings::DesktopColorDepth desktopColorDepth;
|
extern Settings::DesktopColorDepth desktopColorDepth;
|
||||||
extern Settings::DisplayFilter displayFilter;
|
extern Settings::DisplayFilter displayFilter;
|
||||||
extern Settings::DisplayRefreshRate displayRefreshRate;
|
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/ConfigWindow.h>
|
||||||
#include <Overlay/StatsWindow.h>
|
#include <Overlay/StatsWindow.h>
|
||||||
#include <Win32/DisplayMode.h>
|
#include <Win32/DisplayMode.h>
|
||||||
|
#include <Win32/Thread.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -418,6 +419,7 @@ namespace
|
|||||||
int msUntilUpdateReady = 0;
|
int msUntilUpdateReady = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
Win32::Thread::rotateCpuAffinity();
|
||||||
if (msUntilUpdateReady > 0)
|
if (msUntilUpdateReady > 0)
|
||||||
{
|
{
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
|
@ -166,6 +166,7 @@
|
|||||||
<ClInclude Include="Config\Settings\BltFilter.h" />
|
<ClInclude Include="Config\Settings\BltFilter.h" />
|
||||||
<ClInclude Include="Config\Settings\ConfigHotKey.h" />
|
<ClInclude Include="Config\Settings\ConfigHotKey.h" />
|
||||||
<ClInclude Include="Config\Settings\CpuAffinity.h" />
|
<ClInclude Include="Config\Settings\CpuAffinity.h" />
|
||||||
|
<ClInclude Include="Config\Settings\CpuAffinityRotation.h" />
|
||||||
<ClInclude Include="Config\Settings\DesktopColorDepth.h" />
|
<ClInclude Include="Config\Settings\DesktopColorDepth.h" />
|
||||||
<ClInclude Include="Config\Settings\DisplayFilter.h" />
|
<ClInclude Include="Config\Settings\DisplayFilter.h" />
|
||||||
<ClInclude Include="Config\Settings\DisplayRefreshRate.h" />
|
<ClInclude Include="Config\Settings\DisplayRefreshRate.h" />
|
||||||
|
@ -633,6 +633,9 @@
|
|||||||
<ClInclude Include="Config\Settings\TerminateHotKey.h">
|
<ClInclude Include="Config\Settings\TerminateHotKey.h">
|
||||||
<Filter>Header Files\Config\Settings</Filter>
|
<Filter>Header Files\Config\Settings</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Config\Settings\CpuAffinityRotation.h">
|
||||||
|
<Filter>Header Files\Config\Settings</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Gdi\Gdi.cpp">
|
<ClCompile Include="Gdi\Gdi.cpp">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <process.h>
|
#include <process.h>
|
||||||
|
|
||||||
|
#include <Common/Hook.h>
|
||||||
#include <Dll/Dll.h>
|
#include <Dll/Dll.h>
|
||||||
|
|
||||||
namespace Dll
|
namespace Dll
|
||||||
@ -16,6 +17,7 @@ namespace Dll
|
|||||||
if (thread)
|
if (thread)
|
||||||
{
|
{
|
||||||
SetThreadPriority(thread, priority);
|
SetThreadPriority(thread, priority);
|
||||||
|
CALL_ORIG_FUNC(SetThreadPriorityBoost)(thread, FALSE);
|
||||||
}
|
}
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,181 @@
|
|||||||
|
#include <bitset>
|
||||||
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#include <Common/Hook.h>
|
#include <Common/Hook.h>
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
|
#include <Common/Time.h>
|
||||||
#include <Config/Config.h>
|
#include <Config/Config.h>
|
||||||
|
#include <Dll/Dll.h>
|
||||||
#include <Win32/Thread.h>
|
#include <Win32/Thread.h>
|
||||||
|
|
||||||
namespace
|
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)
|
BOOL WINAPI setProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask)
|
||||||
{
|
{
|
||||||
LOG_FUNC("SetProcessAffinityMask", hProcess, Compat::hex(dwProcessAffinityMask));
|
LOG_FUNC("SetProcessAffinityMask", hProcess, Compat::hex(dwProcessAffinityMask));
|
||||||
@ -44,22 +213,49 @@ namespace Win32
|
|||||||
{
|
{
|
||||||
void applyConfig()
|
void applyConfig()
|
||||||
{
|
{
|
||||||
auto cpuAffinity = Config::cpuAffinity.get();
|
initNextProcessorMap(getProcessorSets());
|
||||||
if (0 != cpuAffinity)
|
|
||||||
{
|
|
||||||
SYSTEM_INFO si = {};
|
|
||||||
GetSystemInfo(&si);
|
|
||||||
const unsigned cpuCount = min(si.dwNumberOfProcessors, 32);
|
|
||||||
cpuAffinity &= UINT_MAX >> (32 - cpuCount);
|
|
||||||
|
|
||||||
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";
|
if (g_nextProcessor.find(i) == g_nextProcessor.end())
|
||||||
Config::cpuAffinity.reset();
|
{
|
||||||
CALL_ORIG_FUNC(SetProcessAffinityMask)(GetCurrentProcess(), Config::cpuAffinity.get());
|
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())
|
switch (Config::threadPriorityBoost.get())
|
||||||
{
|
{
|
||||||
case Config::Settings::ThreadPriorityBoost::OFF:
|
case Config::Settings::ThreadPriorityBoost::OFF:
|
||||||
@ -83,5 +279,27 @@ namespace Win32
|
|||||||
HOOK_FUNCTION(kernel32, SetProcessPriorityBoost, setProcessPriorityBoost);
|
HOOK_FUNCTION(kernel32, SetProcessPriorityBoost, setProcessPriorityBoost);
|
||||||
HOOK_FUNCTION(kernel32, SetThreadPriorityBoost, setThreadPriorityBoost);
|
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 applyConfig();
|
||||||
void installHooks();
|
void installHooks();
|
||||||
|
void rotateCpuAffinity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user