CPU의 스레드별 사용률을 프로그래밍으로 얻기위해 NtQuerySystemInformation 함수로 얻어진 카운터로 사용률 계산해보니 작업 관리자의 성능 모니터 값과 두배 이상 차이나는 현상이 발생하였다.
작업관리자의 프로세스와 성능 화면은 아래와같다.
ConsoleApp1의 소스코드 (C#, .NET 6.0)
bool finish = false;
Random random = new Random();
Thread[] threads = new Thread[6];
Console.CancelKeyPress += delegate (object? sender, ConsoleCancelEventArgs e) { e.Cancel = true; finish = true; };
for (int i = 0; i < threads.Length; i++)
{
threads[i] = new Thread(OnThread);
threads[i].Start(random.NextDouble());
}
for (int i = 0; i < threads.Length; i++)
{
if (threads[i].IsAlive)
{
threads[i].Join();
}
}
void OnThread(object? args)
{
long loop = 0;
decimal sum = new decimal((double)(args ?? 0.0));
Random random = new Random();
while (finish == false)
{
sum += new decimal(random.NextDouble());
loop++;
if (loop > 100000000L)
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}, {sum}");
loop = 0;
}
}
}
논리 프로세서가 20개인 CPU에서 루프 돌리면 스레드당 약 5%, 6개 스레드면 약 25%가 계산되어야한다. 닷넷의 객체관리 등 추가적인 내부연산을 생각하면 Visual Studio의 진단도구에 나타나는 사용률 약 20~30%가 예상되는 사용률과 근접하다는걸 알 수 있다.
HWiNFO의 센서 상태를 보아도 근접한 사용률을 보여준다.
윈도우에서 재공되는 성능 모니터에서도 동일하다.
결국 이런 상황을 생각해보면 유일하게 40%를 넘기는 작업 관리자의 프로세서 사용률을 온전하게 믿을 수 없다고 생각된다. 도대체 작업 관리자는 어떻게 사용률을 계산하길레 혼자만 결과가 다른걸까?
문제는 이거로 끝이 아니다. 퀘이사존의 어느 글에 따르면 NtQuerySystemInformation 함수의 결과가 문제라고 하는데… 과연 그간 핫픽스 등 업데이트로 해결된걸까 아니면 애프터버너가 잘못 구현한걸까. 좀… 어처구니없는 현상이다. 난 NtQuerySystemInformation 함수의 결과가 옮다고 생각해야겠다.
덧) 작업 관리자의 잊고있던 기능인 ‘프로세서 선호도’가 생각나여 추가.
결과는 아래와같다. 6개의 코어만 100%를 찍고 나머지는 높아야 10%, 대다수가 5%안되는데 사용률은 43%로 표시된다. 이 CPU는 고성능/고효율로 구성된것도 아닌 전부 고성능 코어라 각각 비율이 다르게 사용률이 계산되었을것이라는 예상마저도 할 수 없는 환경이다.
프로세서 선호도를 선택한 후 자세히를 보면 CPU가 30%이지만 프로세스 화면에서는 약 44%로 작업 관리자 내에서도 차이가 발생한다. 물론 Visual Studio에서는 30%로 표시된다.
작업 관리자의 사용률 표시가 문제있다는 방향으로 더 확고하게 결정할 수 있는 상황이였다.