[C#] How to monitor CPU, Memory, Disk Usage?

김정환(John.Kim)
OldbeeDev
Published in
7 min readFeb 24, 2020
Image by Lorenzo Cafaro from Pixabay

Windows + .NET Core 기반으로 서버를 구현하고 있습니다. 서버 리소스를 모니터링하고 최근 이력을 관리하는 기능이 요구되어 그 구현 방법을 간단히 정리해 보고자 합니다.

구현할 항목은 아래와 같습니다.

  • 전체 CPU 사용률
  • 서버 Process CPU 사용률
  • Memory 사용률, 전체 Memory 크기, 사용한 Memory 크기
  • Disk 사용률, 전체 Disk 크기, 사용한 Disk 크기
  • 서버 Process의 Commit Memory 크기, Handle 개수, Thread 개수

WMI 패키지 설치

CPU 사용률, Memory 사용률, Disk 사용률 등과 같이 시스템 전반에 대한 성능 데이터는 Windows Management Instrumentation (이하 WMI) 을 통해 알아낼 수 있습니다.

WMI는 Windows 전용 기능이기 때문에 .NET Core에서 포함되어 있지 않습니다. NuGet Packages 를 통해 System.Management 를 설치해야 합니다. 현재 최신 버전은 4.7.0 입니다. 아래 그림을 참고하시길 바랍니다.

그리고 Windows Management Instrumentation 서비스가 Running 상태임을 확인해야 합니다.

전체 CPU 사용률

PowerShell에서 아래와 같이 Win32_PerfFormattedData_PerfOS_Processor 클래스를 조회하면 CPU당 사용률을 알 수 있습니다.

PS C:\Users\john> Get-CimInstance -ClassName Win32_PerfFormattedData_PerfOS_Processor | select Name,PercentProcessorTimeName   PercentProcessorTime
---- --------------------
0 6
1 6
2 0
3 0
4 0
5 0
6 0
7 6
_Total 2

C# 으로 구현하면 아래와 같습니다.

_Total 항목만 사용해도 되지만, 저는 CPU0~CPUx 의 평균을 구했습니다. 후자의 경우는 소수점 아래 1자리까지 값이 나와서 좀더 상세한 정보라는 느낌을 줍니다.

Process 사용률

Win32_PerfFormattedData_PerfProc_Process 클래스를 조회하면 프로세스 별 CPU 사용률을 알 수 있습니다. 아래 그림을 보면 Idle 항목이 788로서 거의 800% 쯤 됩니다. 이는 제 PC의 CPU 개수 8개 *100% 한 값입니다.

PS C:\Users\john> Get-CimInstance -ClassName Win32_PerfFormattedData_PerfProc_Process | select Name,PercentProcessorTimeName                    PercentProcessorTime
---- --------------------
ASDSvc 0
ConferenceServer 0
Evernote 0
EvernoteClipper 0
...
Idle 788
...

C# 으로 구현하면 아래와 같습니다.

procTime을 CPU 개수로 나누어 주고 있습니다.

Momory 사용률

Win32_OperatingSystem 클래스를 조회하면 OS 이름, OS 버전, PC 이름, Memory 사용량 등의 정보를 알 수 있습니다.

PS C:\Users\john> Get-CimInstance -ClassName Win32_OperatingSystem | select *Memory*FreePhysicalMemory     : 9972352
FreeVirtualMemory : 22933856
MaxProcessMemorySize : 137438953344
TotalVirtualMemorySize : 34432340
TotalVisibleMemorySize : 16606548

C# 으로 구현하면 아래와 같습니다.

TotalVisibleMemorySize 항목이 전체 Momory 크기, FreePhysicalMemory 항목이 남은 Momory 크기입니다. 이 두 정보를 이용해서 사용률 및 사용한 Momory 크기를 계산합니다.

Disk 사용률

Disk 사용량 역시 WMI로 조회할 수 있지만, DriverInfo 클래스를 사용하면 좀 더 간단한 것 같습니다.

프로그램 실행 경로에 해당하는 드라이브를 찾아서 전체 Disk 크기 및 남은 Disk 크기를 알아냅니다. 이 두 정보를 이용해서 사용률 및 사용한 Disk 크기를 계산합니다.

Process의 Commit Memory 크기, Handle 개수, Thread 개수

서버 Process의 Memory 누수 여부를 알기 위해 Commit Memory의 추이를 확인할 필요가 있습니다. Handle 리소스나 Thread 역시 과다하게 생성되는지 확인해야 합니다. 다행히 구현은 매우 쉽습니다.

vs. PerformanceCounter API

WMI 대신 PerformanceCounter API를 사용할 수 도 있습니다. 그러나 몇 가지 불편한 점이 있었습니다.

  • 이 API로는 전체 Memory 크기를 알 수 없었습니다.
  • Memory 구분도 Committed, Paged 등으로 세세하게 구분되어 있어서 내용 파악이 좀 힘듭니다.
  • Process별 CPU 사용률이 WMI에 비해 편차가 좀 큰 것 같습니다.
  • NextValue() 메소드가 상태 값을 리턴하는 메소드입니다만, 아래와 같이 두번씩 불러줘야 하는 점이 약간 불편합니다.
cpuCounter.NextValue();           // Start 
await Task.Delay(1000); // 잠시 시간 지연을 해줘야 합니다.
var cpu = cpuCounter.NextValue(); // 사용률이 계산되어 리턴.
return cpu;

Limitation

.NET Core 기반임에도 불구하고 WMI 및 PerformanceCounter 등은 윈도우 전용 패키지입니다. 만약 이 서버 프로그램을 Linux 상에서 돌리면 런타임에 exception이 발생할 것으로 예상됩니다. 이에 대한 API 레벨의 해결책은 아직 찾지 못했습니다.

References

끝 : )

--

--