Por que a chamada de desempenho NextValueCounter altera a máscara de afinidade de encadeamento
Eu tenho um projeto C #, no qual tenho que acessar a carga de trabalho atual do meu processador e garantir que eu execute algum código específico em cada kernel do processador. Meu problema é que acessar a carga de trabalho do meu processador parece me impedir de atribuir corretamente uma máscara de afinidade de thread. Eu tenho algum código aqui, que ilustra o problema:
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;
}
}
}
A execução desse código produz a seguinte saída:
Pre: thread affinity: 3
Pre: all kernels accessible
Post: thread affinity: 2
Post: some kernels not accessible: 1
Portanto, parece que a chamada cpuUsage.NextValue altera a máscara de afinidade do encadeamento e também torna impossível alterar a máscara para 1. Faz sentido que a chamada Nextvalue precise interagir com a máscara de afinidade do encadeamento de alguma maneira , se estiver agregando uma contagem de desempenho de cada kernel, mas não consigo entender, por que isso deve afetar alterações futuras na máscara de afinidade de encadeamento. Alguém tem uma explicação ou solução alternativa para esse problema?