Control SMT

This commit is contained in:
Kamil Trzciński 2022-11-18 21:00:52 +01:00
parent d7ad2f1d71
commit 7dc418a0e0
6 changed files with 259 additions and 32 deletions

View file

@ -0,0 +1,190 @@
using PowerControl.External;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PowerControl.Helpers
{
internal class ProcessorCores
{
public static int GetProcessorCoreCount()
{
return GetProcessorCores().Count();
}
public static IntPtr GetProcessorMask(bool firstThreadOnly = false)
{
Int64 mask = 0;
foreach (var process in GetProcessorCores())
{
// This works only up-to 63 CPUs
Int64 processorMask = (Int64)process.ProcessorMask.ToUInt64();
if (firstThreadOnly)
processorMask = LSB(processorMask);
mask |= processorMask;
}
return new IntPtr(mask);
}
public static bool HasSMTThreads()
{
foreach (var processorMask in GetProcessorMasks())
{
if (processorMask != LSB(processorMask))
return true;
}
return false;
}
public static bool IsUsingSMT(int processId)
{
try
{
var p = Process.GetProcessById(processId);
UInt64 mask = (UInt64)p.ProcessorAffinity.ToInt64();
foreach (var processorMask in GetProcessorMasks())
{
// look for CPU that has more than 1 thread
// and has both assigned to process
var filtered = mask & processorMask;
if (filtered != LSB(filtered))
return true;
}
return false;
}
catch(ArgumentException)
{
return false;
}
}
public static bool SetProcessSMT(int processId, bool allThreads)
{
try
{
var p = Process.GetProcessById(processId);
UInt64 mask = (UInt64)p.ProcessorAffinity.ToInt64();
foreach (var processorMask in GetProcessorMasks())
{
var selectedMask = mask & processorMask;
if (selectedMask == 0)
continue; // ignore not assigned processors
else if (allThreads)
mask |= processorMask; // assign all threads
else
mask = LSB(selectedMask) | (mask & ~processorMask); // assign only first thread
}
p.ProcessorAffinity = new IntPtr((Int64)mask);
return true;
}
catch (ArgumentException)
{
return false;
}
}
private static UInt64 LSB(UInt64 value)
{
return (UInt64)LSB((Int64)value);
}
private static Int64 LSB(Int64 value)
{
return (value & -value);
}
static IEnumerable<UInt64> GetProcessorMasks()
{
return GetProcessorCores().Select((p) => p.ProcessorMask.ToUInt64());
}
static IEnumerable<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> GetProcessorCores()
{
return GetLogicalProcessorInformation().Where((p) => p.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore);
}
static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] GetLogicalProcessorInformation()
{
int bufferSize = 0;
GetLogicalProcessorInformation(IntPtr.Zero, ref bufferSize);
if (bufferSize == 0)
return new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[0];
int sizeOfEntry = Marshal.SizeOf<SYSTEM_LOGICAL_PROCESSOR_INFORMATION>();
int numEntries = bufferSize / sizeOfEntry;
var processors = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[numEntries];
var handle = Marshal.AllocHGlobal(bufferSize);
try
{
if (!GetLogicalProcessorInformation(handle, ref bufferSize))
return new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[0];
for (int i = 0; i < processors.Length; i++)
processors[i] = Marshal.PtrToStructure<SYSTEM_LOGICAL_PROCESSOR_INFORMATION>(IntPtr.Add(handle, sizeOfEntry * i));
return processors;
}
finally
{
Marshal.FreeHGlobal(handle);
}
}
// Taken from: https://stackoverflow.com/a/63744912
[StructLayout(LayoutKind.Sequential)]
struct CACHE_DESCRIPTOR
{
public byte Level;
public byte Associativity;
public ushort LineSize;
public uint Size;
public uint Type;
};
[StructLayout(LayoutKind.Explicit)]
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
{
[FieldOffset(0)] public byte ProcessorCore;
[FieldOffset(0)] public uint NumaNode;
[FieldOffset(0)] public CACHE_DESCRIPTOR Cache;
[FieldOffset(0)] private UInt64 Reserved1;
[FieldOffset(8)] private UInt64 Reserved2;
};
public enum LOGICAL_PROCESSOR_RELATIONSHIP
{
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll = 0xffff
}
[StructLayout(LayoutKind.Sequential)]
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
public UIntPtr ProcessorMask;
public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
}
[DllImport("kernel32.dll")]
static extern bool GetLogicalProcessorInformation(IntPtr buffer, ref int bufferSize);
}
}

View file

@ -0,0 +1,151 @@
using RTSSSharedMemoryNET;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PowerControl.Helpers
{
internal static class RTSS
{
public static bool IsOSDForeground()
{
return IsOSDForeground(out _);
}
public static bool IsOSDForeground(out int? processId)
{
try
{
processId = (int?)Helpers.TopLevelWindow.GetTopLevelProcessId();
if (processId is null)
return true;
foreach (var app in OSD.GetAppEntries(AppFlags.MASK))
{
if (app.ProcessId == processId)
return true;
}
return false;
}
catch
{
processId = null;
return true;
}
}
public static bool GetProfileProperty<T>(string propertyName, out T value)
{
var bytes = new byte[Marshal.SizeOf<T>()];
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
value = default;
try
{
if (!GetProfileProperty(propertyName, handle.AddrOfPinnedObject(), (uint)bytes.Length))
return false;
value = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
return true;
}
catch
{
return false;
}
finally
{
handle.Free();
}
}
public static bool SetProfileProperty<T>(string propertyName, T value)
{
var bytes = new byte[Marshal.SizeOf<T>()];
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
return SetProfileProperty(propertyName, handle.AddrOfPinnedObject(), (uint)bytes.Length);
}
catch
{
return false;
}
finally
{
handle.Free();
}
}
[DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", SetLastError = true)]
public static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll")]
public static extern uint SetFlags(uint dwAND, uint dwXOR);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)]
public static extern void LoadProfile(string profile = GLOBAL_PROFILE);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)]
public static extern void SaveProfile(string profile = GLOBAL_PROFILE);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)]
public static extern void DeleteProfile(string profile = GLOBAL_PROFILE);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)]
public static extern bool GetProfileProperty(string propertyName, IntPtr value, uint size);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)]
public static extern bool SetProfileProperty(string propertyName, IntPtr value, uint size);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)]
public static extern void ResetProfile(string profile = GLOBAL_PROFILE);
[DllImport("C:\\Program Files (x86)\\RivaTuner Statistics Server\\RTSSHooks64.dll", CharSet = CharSet.Ansi)]
public static extern void UpdateProfiles();
private static void PostMessage(uint Msg, IntPtr wParam, IntPtr lParam)
{
var hWnd = FindWindow(null, "RTSS");
if (hWnd == IntPtr.Zero)
hWnd = FindWindow(null, "RivaTuner Statistics Server");
if (hWnd != IntPtr.Zero)
PostMessage(hWnd, Msg, wParam, lParam);
}
public static uint EnableFlag(uint flag, bool status)
{
var current = SetFlags(~flag, status ? flag : 0);
UpdateSettings();
return current;
}
public static void UpdateSettings()
{
PostMessage(WM_RTSS_UPDATESETTINGS, IntPtr.Zero, IntPtr.Zero);
}
public const uint WM_APP = 0x8000;
public const uint WM_RTSS_UPDATESETTINGS = WM_APP + 100;
public const uint WM_RTSS_SHOW_PROPERTIES = WM_APP + 102;
public const uint RTSSHOOKSFLAG_OSD_VISIBLE = 1;
public const uint RTSSHOOKSFLAG_LIMITER_DISABLED = 4;
public const string GLOBAL_PROFILE = "";
}
}