게임 또는 서비스를 출시하기에 앞서 서버의 성능을 측정하고 최적화하는 작업은 필수라고 할 수 있습니다. 이때 서버를 포함하여 애플리케이션의 성능 측정에는 CPU 관련 메트릭을 모니터링하는 것이 매우 중요합니다. CPU 성능 모니터링에는 CPU 이용률, 멀티 코어 부하 평균, 코어별 사용률, 컨텍스트 스위치, 유휴 스레드, 대기 큐 길이, 인터럽트 및 시스템 호출 등의 주요 메트릭이 있습니다. 이러한 메트릭을 모니터링하면 애플리케이션의 성능 병목 현상을 식별하고, 리소스 사용을 최적화하며, 전반적인 시스템 성능을 개선할 수 있습니다.
그런데 이 글에서 다룰 CPU 이용률 메트릭은 윈도우에서 두 가지 다른 개념으로 나뉘어 있습니다. 그리고 그 두 가지 개념을 정확하게 이해해야 성능 측정을 효율적으로 수행할 수 있습니다.
같은 CPU 이용률이지만 그 의미가 다릅니다.
Windows 작업 관리자(Task Manager)의 [프로세스] 탭에서 표시되는 특정 프로세스의 CPU 이용률 메트릭과 [세부 정보] 탭에서 표시되는 CPU 이용률 메트릭은 모두 ‘모든 코어에서의 총 프로세스 이용률’이라고 표시하지만 서로 일치하지 않습니다.
작업 관리자의 두 탭에서 표시되는 CPU 이용률 메트릭이 서로 일치하지 않는 이유는 각 탭에서 표시되는 CPU 이용률 메트릭이 의미하는 바가 서로 다르기 때문입니다(최신 CPU의 경우 일반적으로 [프로세스] 탭에서 CPU 이용률이 더 높게 표시됩니다).
이는 Windows 8과 Windows Server 2012 버전부터 변경된 사양입니다. Windows 7과 Windows Server 2008 R2 버전까지는 작업 관리자에 표시되는 CPU 이용률은 CPU 사용량(Usage)으로써 그 의미가 동일하였습니다.
Windows 8과 Windows Server 2012 버전부터 CPU 이용률 계산 방식이 변경되면서 작업 관리자의 [프로세스] 탭 및 [성능] 탭에서 표시되는 CPU 이용률은 CPU 활용률(Utilization)을 의미하고, [세부 정보] 탭에서 표시되는 CPU 이용률은 CPU 사용량(Usage)을 의미합니다.
CPU 활용률(Utilization)은 주파수 기반(Frequency-based)으로 측정되는 메트릭이고, CPU 사용량(Usage)은 시간 기반(Time-based)으로 측정되는 메트릭입니다. 즉, 이용률이라는 동일한 용어가 사용되고 있지만 각 탭별로 이용률 메트릭이 측정되는 방식과 그 의미가 다르기 때문에 탭별로 표시되는 CPU 이용률 메트릭은 일치하지 않습니다.
지금부터 작업 관리자가 CPU 이용률을 표시하기 위하여 사용하는 두 가지 메트릭 측정 방식에 대해서 조금 더 상세하게 알아보도록 하겠습니다. 설명은 논리 프로세서 단위로 진행되며 우선 CPU 코어 사용량(Usage) 메트릭에 대한 설명입니다.
CPU 코어 사용량(Usage)
Windows 작업 관리자에서 표시되는 CPU 코어 사용량(Usage) 메트릭은 성능 카운터 카테고리(Performance Object) Processor Information 하위의 % Processor Time이라는 성능 카운터에 해당합니다. 성능 카운터에 대한 자세한 사항은 Microsoft 사이트의 Performance Counters API를 참고하기 바랍니다.
Windows 성능 모니터(Performance Monitor)에서 수집되는 Processor(_Total)∖% Processor Time 또는 Processor Information(_Total)∖% Processor Time 메트릭은 Windows 작업 관리자의 [세부 정보] 탭에서 표시되는 CPU 칼럼의 메트릭과 일치합니다.
CPU 코어 사용량(Usage)은 시간 기반(Time-based)으로 측정되는 메트릭으로써 100ns(nanosecond) 간격으로 샘플링된 횟수를 기반으로 측정되고, 측정 공식은 다음과 같습니다.
\% Processor \; Time = 1 - (B / T)
B : 측정 범위 시간 내에 논리 프로세서에서 “유휴(Idle) 스레드”가 소비하는 100ns 간격의 수(샘플링 횟수)
T : 측정 범위 시간 내에 100ns 간격의 수 (샘플링 횟수)
유휴(Idle) 스레드란 Windows의 내장 프로세스인 “System Idle Process(시스템 유휴 시간 프로세스)”가 생성한 스레드입니다. 실행 가능한 스레드(Ready or Running 상태의 스레드)가 특정 논리 프로세서에 없을 경우, 해당 논리 프로세서에 이 유휴 스레드가 할당됩니다. 유휴 스레드는 스케줄러에서 발생할 수 있는 특수한 케이스(실행 가능한 스레드가 없는 상황)를 방지하기 위한 목적으로 할당됩니다. 이러한 이유로 “System Idle Process”가 생성하는 유휴 스레드의 수는 논리 프로세서 수와 같습니다. 더 자세한 내용은 『Windows Internals 7/e Vol. 1』 4장에서 소개하는 “유휴 스레드” 항목을 참고하길 바랍니다.
CPU 코어 사용량(Usage)은 측정 범위 시간 내에서 논리 프로세서가 스레드 실행에 소비하는 시간의 비율(백분율)을 의미합니다. 그러나 이 측정은 “유휴(Idle) 스레드”가 소비하는 시간을 기반으로 계산된 값의 역원(Inverse)을 구하는 방식으로 이루어집니다.
만약, 1초 간격(샘플링 간격은 100ns)으로 CPU 코어 사용량(Usage)을 수집한다고 할 때, 샘플링 횟수( T )가 총 10,000,000회이고, 이 샘플링 횟수 중 “유휴(Idle) 스레드”가 소비한 샘플링 횟수( B )가 1,000,000회라고 한다면 1 - (1000000 / 10000000) = 0.9이므로 1초 동안의 CPU 코어 사용량(Usage)은 90%가 됩니다.
컴퓨터 시간 단위 1s == 1,000ms == 1,000,000μs == 1,000,000,000ns
참고
Processor(_Total)∖% Privileged Time 또는 Processor Information(_Total)∖% Privileged Time 메트릭을 통해서 논리 프로세서가 커널 명령을 실행하는 데 소비하는 시간의 백분율을 확인할 수 있습니다.
모니터링
서두에서 설명한 대로 Windows 작업 관리자의 [성능] 탭에서 표시되는 CPU 이용률은 CPU 활용률(Utilization)를 의미합니다. 따라서 CPU 코어 사용량(Usage)을 모니터링하기 위해서는 Process Explorer, System Informer 등과 같은 OSS/서드파티 프로그램을 사용해야 합니다.
참고
Windows 리소스 모니터(Resource Monitor)의 [CPU] 탭에서 표시되는 프로세스 전체 CPU 이용률과 우측 패널의 CPU 이용률은 CPU 활용률(Utilization)을 의미하지만, 프로세스 뷰의 CPU 칼럼에서 표시되는 CPU 이용률은 CPU 사용량(Usage)을 의미합니다.
리소스 모니터 [CPU] 탭 비교
CPU 코어 활용률(Utilization)
Windows 작업 관리자에서 표시되는 CPU 코어 활용률(Utilization) 메트릭은 성능 카운터 카테고리(Performance Object) Processor Information 하위의 % Processor Utility라는 성능 카운터에 해당합니다. 성능 카운터에 대한 자세한 사항은 Microsoft 사이트의 Performance Counters API를 참고하기 바랍니다.
Windows 성능 모니터(Performance Monitor)에서 수집되는 Processor Information(_Total)∖% Processor Utility 메트릭은 Windows 작업 관리자의 [프로세스] 탭에서 표시되는 CPU 칼럼의 메트릭과 일치합니다(Processor Information(<cpu-group>,<core-num>)∖% Processor Utility 메트릭은 [성능] 탭의 각 논리 프로세서 CPU 이용률 메트릭과 일치합니다).
CPU 코어 활용률(Utilization)은 주파수 기반(Frequency-based)으로 측정되는 메트릭으로써 초당 CPU 클럭 사이클 수인 Hz를 기반으로 측정되고, 측정 공식은 다음과 같습니다.
\% Processor \; Utility = (E/B)
E : 주어진 시간 범위 내에 논리 프로세서의 유효 주파수(Processor Effective Frequency)
CPU 코어 활용률(Utilization)은 논리 프로세서가 명목(Nominal − 이론적으로 달성할 수 있는 −) 성능으로 실행되며 유휴(Idle) 상태가 되지 않는 경우에 완료할 수 있는 작업량(논리 프로세서가 명령을 실행하는 데 소비하는 클럭 사이클 수)을 의미합니다. 즉, CPU의 기본 클럭 속도를 기준으로 CPU의 실제 클럭 속도를 측정한 값이 CPU 코어 활용률(Utilization) 메트릭입니다. 따라서 CPU 코어 활용률(Utilization) 메트릭은 100%를 초과하는 값으로 측정될 수 있습니다. 예를 들어 Intel CPU 제품 스펙에서 기본 클럭이 2.5GHz이고 터보 부스트를 사용한 최대 클럭이 4.8GHz일 때, 특정 코어가 터보 부스트로 동작해 3.1GHz로 실행된다면 해당 코어의 활용률(Utilization)은 100%를 초과하는 값으로 측정되게 됩니다.
작업 관리자의 CPU 코어 활용률논리 프로세서의 유효 주파수작업 관리자의 CPU 코어 활용률과 논리 프로세서의 유효 주파수 비교
참고
Windows 작업 관리자의 경우 CPU 코어 활용률(Utilization) 메트릭이 100%를 초과할지라도 100%로 절삭하여 표시됩니다.
Processor Information(_Total)∖% Privileged Utility 메트릭을 통해서 논리 프로세서가 명목 성능으로 실행되며 유휴 상태가 되지 않는 경우 완료할 수 있는 커널 명령어 작업량의 백분율을 확인할 수 있습니다. 이 메트릭은 100%를 초과하는 값으로 측정될 수 있습니다.
모니터링
성능 모니터링을 수행할 때는 % Processor Time 카운터로 측정되는 CPU 코어 사용량(Usage) 메트릭 정보를 참고하는 것이 가장 기본이라고 할 수 있습니다. 왜냐하면 % Processor Utility 카운터로 측정되는 CPU 코어 활용률(Utilization) 메트릭은 100%를 초과하여 표시될 수 있기 때문에 해당 메트릭만으로 성능 모니터링을 수행할 경우, 부정확한 결과를 도출할 수 있기 때문입니다.
하지만 성능 모니터링 시 % Processor Utility 카운터로 측정되는 CPU 코어 활용률(Utilization) 메트릭 정보가 아무런 의미가 없는 것은 아닙니다.
위 그림은 성능과 관련하여 Windows가 사용하는 세 가지 스레드 상태를 표현한 그림입니다.
앞서 설명해 드린 것처럼, CPU 코어 사용량(Usage)은 논리 프로세서가 스레드 — System Idle Process가 아닌 Application Process가 생성한 스레드 ― 실행에 소비하는 시간을 의미합니다. 이는 논리 프로세서에서 실행 가능한 스레드(Ready or Running 상태의 스레드)가 소비하는 시간을 나타냅니다. 따라서 CPU 코어 사용량(Usage)만으로는 논리 프로세서에서 “대기(Waiting)” 상태의 스레드와 관련된 CPU 자원 소모 정보를 확인할 수 없습니다. 그러므로 CPU 코어 활용률(Utilization) 메트릭을 이용하여 “대기(Waiting)” 상태의 스레드와 관련된 불필요한 CPU 자원 소모 여부를 확인하는 것이 중요합니다.
참고
컨텍스트 스위치(Context Switch)는 OS의 스케줄러에 의해서 자동으로 발생(위 그림의 3번과 4번)되거나, WaitForSingleObject 또는 Sleep(> 0) 함수 등의 명시적인 호출에 의해서 발생(위 그림의 1번)됩니다. 그리고 DPC/ISR 또는 SetEvent 함수 등의 명시적인 호출에 의해서 ReadyThread 이벤트가 발생(위 그림의 2번)됩니다.
CPU의 디테일을 아는 것이 큰 효율을 만듭니다.
여러 가지 내용을 소개했지만 이 글의 내용을 결론 내자면 다음과 같이 말할 수 있겠습니다.
CPU 코어 활용률과 CPU 코어 사용량을 모니터링하면서 서버의 성능을 측정하여 최적의 성능을 이끌어 낼 수 있습니다.
게임이나 서비스를 출시할 때 ‘성능 최적화’를 이끌어 낸 서버란, 주어진 장비(Bare-metal, VM, Container 등등) 스펙을 최대한 효율적으로 사용하는 서버를 의미합니다. 그런 의미에서 지금까지 CPU 이용률을 단순하게 고민하셨던 분이라면 이 글을 읽고 서버 성능 최적화를 위한 더 디테일한 성능 측정을 해보면 어떨까 합니다.