Why does the NextValue call of the performanceCounter function change the thread merge mask

I have a C # project where I need to both access the current workload of my processor, and make sure that I run certain code on each processor core. My problem is that accessing the workload of my processor seems to prevent me from properly assigning a thread affinity mask. I have code here that illustrates the problem:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Diagnostics; namespace KernelAffinitySpike { class Program { [DllImport("kernel32.dll", SetLastError = true)] private static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetCurrentThread(); private static PerformanceCounter cpuUsage; private static UIntPtr oldMask, newMask, testMask; // thread-level processor affinity masks. static void Main(string[] args) { InitPerformanceCounter(); Console.WriteLine("Pre: thread affinity: " + CurrentThreadAffinityMask()); if (AllKernelsAccessible()) Console.WriteLine("Pre: all kernels accessible"); else { Console.Write("Pre: some kernels not accessible: "); foreach (UInt32 kernel in InaccessibleKernels()) Console.Write(kernel + " "); Console.WriteLine(); } float load = cpuUsage.NextValue(); Console.WriteLine("Post: thread affinity: " + CurrentThreadAffinityMask()); if (AllKernelsAccessible()) Console.WriteLine("Post: all kernels accessible"); else { Console.Write("Post: some kernels not accessible: "); foreach (UInt32 kernel in InaccessibleKernels()) Console.Write(kernel + " "); Console.WriteLine(); } Console.ReadLine(); } static void InitPerformanceCounter() { cpuUsage = new PerformanceCounter(); cpuUsage.CategoryName = "Processor"; cpuUsage.CounterName = "% Processor Time"; cpuUsage.InstanceName = "_Total"; } static UInt32 CurrentThreadAffinityMask() { oldMask = SetThreadAffinityMask(GetCurrentThread(), (UIntPtr) 3); // 3 just enables all processors on a dual core. I'm only interested in the return value. SetThreadAffinityMask(GetCurrentThread(), oldMask); return (UInt32) oldMask; } static List<UInt32> InaccessibleKernels() { List<UInt32> inaccessible = new List<UInt32>(); for (int i = 0; i < Environment.ProcessorCount; i++) { newMask = (UIntPtr)(1 << i); oldMask = SetThreadAffinityMask(GetCurrentThread(), newMask); testMask = SetThreadAffinityMask(GetCurrentThread(), oldMask); if (newMask != testMask) inaccessible.Add((UInt32) newMask); } return inaccessible; } static bool AllKernelsAccessible() { return InaccessibleKernels().Count == 0; } } } 

Running this code gives the following output:

 Pre: thread affinity: 3 Pre: all kernels accessible Post: thread affinity: 2 Post: some kernels not accessible: 1 

So it seems that calling cpuUsage.NextValue somehow changes the thread merge mask, and also makes it impossible to change the mask to 1. It makes sense that the Nextvalue call should interact with the stream affinity mask in some way, if it aggregates the performance count from each kernels, but I can’t understand why this should affect future changes to the thread merge mask. Does anyone have an explanation or workaround for this problem?

+4
source share
1 answer

Here is another guy with the same problem

Seems like an unresolved issue with Microsoft.

Here is the statement of the problem - Performance counters alter the flow affinity. Microsoft support .

They suggest calling SetThreadAffinity. ) Obviously, their solution does not work.

+1
source

All Articles