Repository navigation
feat: add CPU Core Affinity tab with P-core/E-core awareness - #1081
Merged
Merged
Conversation
Implements CPU Core Affinity (replaces its WIP placeholder in Gaming & Profiles). Closes #327. - CpuAffinityService: gets/sets per-process affinity via .NET's Process.ProcessorAffinity (no P/Invoke needed for the set), and detects P-core/E-core topology on Intel hybrid CPUs via kernel32 GetLogicalProcessorInformationEx — walking the variable-length buffer by each record's Size and reading EfficiencyClass (max class = P-core). Single processor group (<=64 logical CPUs), which covers consumer CPUs. - Pure, unit-tested mask helpers (AllCoresMask / MaskFromIndices / IsCoreInMask); an empty mask is rejected (0 means "OS decides" to Windows). - CpuAffinityViewModel: process picker, per-core checkbox map with P/E labels, P-cores / All-cores presets, Apply + Restore (snapshot of the original mask). Access-denied on another user's process is surfaced as "needs admin", never an unhandled exception. - Affinity is per-running-process and reverts on exit, so it's temporary and reversible; no admin for your own processes. - Marked PREVIEW via the badge mechanism. Auto-apply-on-launch + per-game save are noted as future scope.
| { | ||
| uint length = 0; | ||
| // Pass 1: probe required size (must fail with ERROR_INSUFFICIENT_BUFFER). | ||
| if (NativeMethods.GetLogicalProcessorInformationEx(NativeMethods.RelationProcessorCore, IntPtr.Zero, ref length)) |
| IntPtr buffer = Marshal.AllocHGlobal((int)length); | ||
| try | ||
| { | ||
| if (!NativeMethods.GetLogicalProcessorInformationEx(NativeMethods.RelationProcessorCore, buffer, ref length)) |
| // No A/W variant (not a string function) → no EntryPoint suffix needed. | ||
| [DllImport("kernel32.dll", SetLastError = true)] | ||
| [return: MarshalAs(UnmanagedType.Bool)] | ||
| public static extern bool GetLogicalProcessorInformationEx(int relationshipType, IntPtr buffer, ref uint returnedLength); |
| [RelayCommand] | ||
| private void SelectPerformanceCores() | ||
| { | ||
| foreach (var c in Cores) c.IsSelected = IsHybrid ? c.Core.IsPerformance : true; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements CPU Core Affinity (Gaming & Profiles), replacing its WIP placeholder. Closes #327.
Pin a running process to specific CPU cores — useful for games on Intel hybrid CPUs where P-cores and E-cores behave differently.
How
CpuAffinityService:Process.ProcessorAffinity(no P/Invoke for the set; the runtime callsSetProcessAffinityMask).GetLogicalProcessorInformationEx(RelationProcessorCore)— the variable-length buffer is walked by each record'sSize(notMarshal.SizeOf, which would corrupt), readingEfficiencyClassat a fixed offset. Highest class = P-core; if all equal → homogeneous → "Standard". Classic[DllImport](raw IntPtr buffer, no A/W variant → no EntryPoint).0as "let the OS decide", so without this guard an empty selection would silently do the opposite of what the user picked.CpuAffinityViewModel: process picker, per-core checkbox map with P/E labels, P-cores / All cores presets, Apply + Restore.Preview
Marked PREVIEW (sidebar pill + banner).
Tests
CpuAffinityServiceTests—AllCoresMask,MaskFromIndices(incl. out-of-range drop),IsCoreInMask, round-trip.CpuCoreTests— display + P/E type flags.NavLeaf_CpuAffinity_IsImplementedAndMarkedPreviewpins the WIP→real-view swap + preview flag.Verification
Future scope (out of scope here)
Auto-apply-on-launch and per-game saved profiles need a watcher / launcher and are noted for a later pass.