Windows 앱 개발자를 위한 CPU 설정 입문: 우선순위·선호도·P코어/E코어
· 小村 豪 · Windows, Windows 앱, CPU, 성능, 우선순위, 선호도, P코어, E코어, 절전, EcoQoS
Windows 앱의 성능은 코드만으로 결정되지 않습니다. 같은 .exe라도, 실행하는 PC에 따라 체감이 달라지는 경우가 있습니다.
어떤 PC에서는 주기 처리가 안정적이다. 다른 PC에서는, 가끔 지연된다. AC 전원에서는 문제없는데, 배터리로 구동하면 이상하게 느리다. 작업 관리자에서 우선순위를 올렸는데, 생각만큼 빨라지지 않는다. P코어로 몰았다고 생각했는데, 여전히 처리 시간이 흔들린다. 반대로, 성능을 올리려고 했더니 팬이 계속 돌아가고, 다른 앱이 무거워진다.
Windows 앱을 만들다 보면, 이런 「코드만으로는 설명하기 어려운 현상」을 만나게 됩니다.
그럴 때 봐야 할 것이 이 4가지입니다.
| 보는 것 | 대략적인 의미 |
|---|---|
| 우선순위 | 어느 스레드를 먼저 움직일지 |
| 선호도 | 어느 CPU에서 움직여도 되는지 |
| P코어 / E코어 | 그 CPU가 성능 지향인지, 절전 지향인지 |
| 절전 설정 | CPU를 얼마나 본격적으로 돌릴지 |
게다가 현대의 Windows에서는, 여기에 EcoQoS와 작업 관리자의 Efficiency mode도 관련됩니다.
즉, Windows 앱의 실행 환경은 단순히 「CPU가 빠른지 느린지」로 끝나지 않습니다.
언제 실행되는가
어디에서 실행되는가
어떤 종류의 코어에서 실행되는가
CPU가 어느 정도의 성능 상태로 움직이고 있는가
OS에게 「성능 중시」로 여겨지고 있는가, 「절전으로 충분」하다고 여겨지고 있는가
이러한 것들이 조합되어, 실제 응답성과 처리 시간이 결정됩니다.
이 글에서는 Windows 앱 개발에서 놓치기 쉬운, 우선순위, 선호도, P코어/E코어, 절전 설정의 관계를 정리합니다.
또한, 이 글에 등장하는 코드는 빌드·실행할 수 있는 샘플 코드 세트(우선순위·선호도를 다루는 C# 라이브러리와 데모, PowerShell 스크립트, 단위 테스트)로 GitHub에 공개되어 있습니다.
windows-app-cpu-priority-affinity-power - komurasoft-blog-samples (GitHub)
1. 먼저 전체 그림
먼저, 전체 그림을 도식화하면 이렇습니다.
flowchart LR A["앱 코드"] --> B["Windows 스케줄러"] P["우선순위<br/>언제 실행되기 쉬운가"] --> B AF["선호도 / CPU Sets<br/>어느 CPU에서 실행할 수 있는가"] --> B Q["QoS / EcoQoS<br/>성능 중시인가, 절전 중시인가"] --> B B --> C["실행할 스레드를 선택"] C --> D["실행할 논리 프로세서를 선택"] PE["P코어 / E코어<br/>성능 지향인가, 절전 지향인가"] --> D PM["전원 모드 / 전원 관리 옵션 / PPM<br/>주파수·부스트·Core Parking"] --> D D --> R["실제 응답성<br/>처리 시간<br/>발열<br/>배터리 소비<br/>다른 앱에 대한 영향"]
중요한 것은, 이것들이 서로 독립되어 있지 않다는 점입니다.
우선순위를 올리면, 실행되기는 쉬워집니다. 하지만 CPU 자체가 절전 쪽으로 제어되고 있다면, 기대한 만큼 빨라지지 않는 경우가 있습니다.
선호도로 CPU를 제한하면, 스레드의 이동은 줄어들지도 모릅니다. 하지만 제한한 대상이 절전 지향 코어였거나, Core Parking이나 전원 관리와 맞물리지 않는다면, 반대로 불리해질 수 있습니다.
P코어로 몰면, 계산 처리는 빨라질지도 모릅니다. 하지만 모든 것을 고성능 쪽으로 몰면, 발열, 팬 소음, 배터리 소비, 다른 프로세스에 대한 영향이 늘어납니다.
Windows 앱의 성능 조정은, 단순한 「빠르게 만드는 버튼 찾기」가 아닙니다.
어느 처리를 빠르게 하고 싶은가. 어느 처리는 느려도 괜찮은가. 사용자 조작의 응답성을 우선할 것인가. 백그라운드 처리의 완료 시간을 우선할 것인가. 배터리나 발열을 어디까지 허용할 것인가.
그런 설계의 이야기가 됩니다.
2. 우선순위는 「언제 실행되기 쉬운가」
Windows에서는, 실행 가능한 스레드가 여러 개 있을 때, 스케줄러가 「다음에 어느 스레드를 CPU에 올릴지」를 결정합니다. 이때 작용하는 것이 우선순위입니다.
우선순위는, 크게 보면 2단계로 결정됩니다.
프로세스의 우선순위 클래스
+ 스레드의 상대 우선순위
= 스레드의 기본 우선순위
Win32 API로 말하면, 프로세스 쪽에는 SetPriorityClass, 스레드 쪽에는 SetThreadPriority가 있습니다.
PowerShell로 지금 실행 중인 프로세스의 우선순위를 보려면, 예를 들면 이렇습니다.
Get-Process -Id $PID | Select-Object Id, ProcessName, PriorityClass
현재 PowerShell 프로세스의 우선순위를 올리려면, 이렇게 합니다.
$p = Get-Process -Id $PID
$p.PriorityClass = "AboveNormal"
C#이라면, 다음과 같이 작성할 수 있습니다.
using System.Diagnostics;
using var process = Process.GetCurrentProcess();
process.PriorityClass = ProcessPriorityClass.AboveNormal;
여기서 주의하고 싶은 것은, 우선순위가 「CPU를 빠르게 만드는 설정」이 아니라는 점입니다. 우선순위가 관여하는 것은, 경쟁이 있을 때 어느 스레드를 먼저 움직일지입니다.
CPU 주파수를 올리는 설정이 아닙니다. P코어를 선택하는 설정도 아닙니다. I/O를 빠르게 하는 설정도 아닙니다. 잠금 대기나 네트워크 대기를 없애는 설정도 아닙니다.
그래서, 「우선순위를 올렸는데 빨라지지 않는다」는 흔히 있는 일입니다. 예를 들어, 느린 원인이 다음과 같은 것이라면, 우선순위를 올려도 본질적으로는 해결되지 않습니다.
- 디스크 I/O 대기
- 네트워크 대기
- DB 응답 대기
- 잠금 경쟁
- GC 정지
- UI 스레드의 블로킹
- GPU나 드라이버 쪽의 대기
- 백신 소프트웨어에 의한 파일 스캔
- CPU 주파수가 절전 쪽으로 억제되어 있음
또한, HIGH_PRIORITY_CLASS나 REALTIME_PRIORITY_CLASS는 함부로 사용해서는 안 됩니다.
높은 우선순위로 장시간 계속 움직이는 스레드는, 다른 스레드에 CPU 시간을 넘기기 어려워집니다. 그것이 자신의 앱 안에서만이라면 그렇다 쳐도, 시스템 전체의 응답성을 나쁘게 만드는 경우가 있습니다.
우선순위는, 약과 같은 것입니다.
효과가 있는 상황에서는 효과가 있습니다. 하지만 양을 늘리면 좋아지는 것은 아닙니다.
우선순위를 올리기 전에 생각할 것
우선순위를 올리기 전에, 먼저 생각하고 싶은 것이 있습니다.
| 질문 | 확인할 것 |
|---|---|
| 그 처리는 정말로 CPU 대기인가 | CPU 사용률, ETW, 프로파일러 |
| UI 스레드를 막고 있지 않은가 | UI 응답, 비동기화, 큐 설계 |
| 고우선순위로 하는 범위는 짧은가 | 일시적으로 올리고, 끝나면 되돌린다 |
| 다른 앱에 폐를 끼치지 않는가 | 입력, 인쇄, 브라우저, 상주 소프트웨어에 대한 영향 |
| 고객 환경에서 권한이나 정책에 막히지 않는가 | 관리자 권한, 실행 사용자, 보안 제품 |
Windows 앱에서 중요한 것은, 항상 최고 우선순위로 움직이는 것이 아니라, 필요한 처리를, 필요한 시점에, 필요한 범위만 우선하는 것입니다.
3. 선호도는 「어느 CPU에서 실행할 수 있는가」
우선순위가 「언제 실행되기 쉬운가」라면, 선호도는 「어느 CPU에서 실행할 수 있는가」입니다.
Windows에서는, 프로세스나 스레드에 대해, 실행 가능한 논리 프로세서의 집합을 지정할 수 있습니다.
Win32 API에서는, 프로세스에 대해 SetProcessAffinityMask, 스레드에 대해 SetThreadAffinityMask가 있습니다.
PowerShell로 프로세스의 선호도를 보려면, 예를 들면 이렇습니다.
Get-Process -Id $PID | Select-Object Id, ProcessName, ProcessorAffinity
검증 목적으로, 현재 PowerShell 프로세스를 처음 4개의 논리 프로세서로 제한하려면, 이렇게 작성할 수 있습니다.
$p = Get-Process -Id $PID
$p.ProcessorAffinity = [IntPtr]0xF
0xF는 2진수로 1111입니다.
즉, 논리 프로세서 0~3을 허용한다는 의미입니다.
다만, 이것은 어디까지나 검증용 예시입니다.
선호도를 제한하면, CPU 캐시의 지역성이 좋아지거나, 주기 처리의 흔들림이 줄어드는 경우가 있습니다. 한편, Windows가 원래는 비어 있는 CPU로 도피시킬 수 있었던 스레드를, 좁은 곳에 가두는 결과가 되기도 합니다.
특히, 이런 환경에서는 주의가 필요합니다.
- P코어/E코어가 혼재하고 있다
- SMT/Hyper-Threading으로 논리 프로세서와 물리 코어의 대응이 직관적이지 않다
- NUMA 구성이다
- 64개 논리 프로세서를 넘어 Processor Group이 관련된다
- Core Parking이 활성화되어 있다
- OEM이나 BIOS의 전원 제어가 강하다
- 가상 환경에서 동작하고 있다
선호도는, 시스템에 「이 CPU에서만 움직여 달라」고 강하게 제약을 거는 설정입니다.
제약은, 안정화의 도구가 되기도 합니다. 하지만 잘못하면 도피처를 없애버립니다.
지금은 CPU Sets도 있다
고전적인 선호도 마스크는, 상당히 강한 제약입니다.
한편, Windows에는 CPU Sets라는 방식도 있습니다.
CPU Sets는, 애플리케이션 쪽이 CPU에 대한 희망을 좀 더 부드럽게 전달하기 위한 API입니다.
Microsoft의 설명에서는, CPU Sets가 OS의 전원 관리와 호환되는 「soft」한 선호도 지정으로 자리매김되어 있습니다.
엄격하게 CPU를 고정하고 싶은가. OS의 전원 관리나 스케줄링과 협조하면서, 대략적인 실행 위치를 몰아주고 싶은가.
이 차이는 중요합니다.
옛날 방식인 SetProcessAffinityMask로 모든 것을 해결하려 하지 말고, 현대의 Windows 앱에서는 CPU Sets나 QoS까지 포함해서 생각할 필요가 있습니다.
4. P코어/E코어는 「CPU에도 성격이 있다」는 이야기
최근 CPU에서는, 모든 코어가 같은 성능·같은 전력 소비라고 할 수 없습니다. 대표적인 것이 P코어와 E코어로, 대략적으로 말하면 P코어는 성능 지향, E코어는 효율 지향 코어입니다.
| 종류 | 잘하는 것 |
|---|---|
| P코어 | 낮은 지연, 높은 단일 성능, 무거운 포그라운드 처리 |
| E코어 | 절전, 백그라운드 처리, 병렬 처리의 받이 |
다만, 개발자가 안이하게 「CPU 0~7이 P코어이고, 8~15가 E코어」라고 단정하는 것은 위험합니다. CPU 번호의 배열은, CPU, BIOS, Windows 버전, 펌웨어, OEM 설정, 가상화 환경에 따라 달라질 수 있습니다.
Windows 쪽에서는, CPU Sets의 정보에 EfficiencyClass라는 개념이 있습니다.
이것은, 이종 프로세서를 가진 시스템에서, 그 CPU Set의 효율 특성을 나타내는 값입니다. Microsoft의 문서에서는, 이 값이 높은 CPU Set일수록, 더 빠르지만 전력 효율은 낮은 프로세서를 가진다고 설명되어 있습니다.
P코어/E코어를 다루고 싶다면, 단순히 CPU 번호만 봐서는 부족합니다. 정말로 파고들려면, 이런 관찰이 필요합니다.
- CPU Sets API로
EfficiencyClass를 본다 - Windows Performance Recorder / Analyzer로 스레드의 실행 CPU를 본다
- 작업 관리자의 논리 프로세서 표시에서 경향을 본다
- 실제 기기별로 처리 시간을 측정한다
- AC 전원 시와 배터리 시를 비교한다
- 전원 모드를 바꿔서 비교한다
P코어/E코어는 단순한 하드웨어 사양이 아니라, Windows의 스케줄러, QoS, 절전 설정과 조합되어, 실제 실행 위치가 결정됩니다.
5. 절전 설정은 「CPU를 얼마나 본격적으로 돌릴지」에 관여한다
이 부분이, 현장에서는 꽤 중요합니다.
우선순위는 「어느 스레드를 먼저 움직일지」. 선호도는 「어느 CPU에서 움직여도 되는지」. P코어/E코어는 「그 CPU가 성능 지향인지, 절전 지향인지」.
그리고 절전 설정은,
애초에 CPU를 어느 정도의 주파수·전력 상태로 움직일지
에 관여합니다.
즉, 이런 일이 일어납니다.
우선순위를 올렸다.
P코어로 몰았다.
그런데 전원 설정이 절전 쪽이라면,
CPU는 본격적으로 돌지 않을 수 있다.
이것은, 꽤 Windows다운 이야기입니다.
Windows 11에서는, 설정 앱의 「시스템 > 전원 및 배터리」에서 전원 모드를 선택할 수 있습니다. 표기는 환경이나 버전에 따라 달라지지만, 방향성은 대략 이렇습니다.
| 전원 모드 | 방향성 |
|---|---|
| 최고의 전력 효율 / Best power efficiency | 배터리나 절전을 우선 |
| 균형 조정 / Balanced | 성능과 전력의 균형 |
| 최고의 성능 / Best performance | 성능을 우선 |
또한 예전부터 있던 전원 관리 옵션에는, Power Saver, Balanced, High Performance가 있습니다.
Balanced는 수요에 따라 성능과 전력 소비를 조정하고, High Performance는 전력 소비와 맞바꿔 최대 성능을 내기 쉽게 하는 방향의 설정입니다.
사용자에게 보이는 설정은 단순해도, 그 뒤에는 Processor Power Management, PPM의 설정이 있습니다.
6. P-state, C-state, 부스트, EPP
CPU는, 항상 최대 주파수로 움직이고 있는 것이 아니라, 전력 소비를 낮추기 위한 상태를 가지고 있습니다.
| 용어 | 대략적인 의미 |
|---|---|
| P-state | CPU의 주파수나 전압을 바꾸는 성능 상태 |
| C-state | 유휴 시에 CPU의 일부 기능을 정지시키는 절전 상태 |
| 부스트 | 조건이 맞으면 정격 이상의 높은 성능 상태로 들어가는 방식 |
| EPP | Energy Performance Preference. 성능 중시인지 절전 중시인지의 선호 |
P-state는, CPU의 주파수나 전압을 바꿔서 전력 소비를 낮추는 방식입니다. C-state는, CPU가 유휴 시에 일부 기능을 정지시켜, 더 깊은 절전 상태로 들어가는 방식입니다.
Windows의 전원 관리는, 이런 방식을 사용해서, 성능과 전력 소비의 균형을 잡습니다.
그래서, 「고우선순위인데 느리다」는 현상이 있을 수 있습니다.
스레드는 우선적으로 실행되고 있다. 하지만 CPU 주파수가 낮다. 부스트에 잘 들어가지 않는다. EPP가 절전 쪽이다. Core Parking으로 사용할 수 있는 코어가 제한되어 있다. 배터리 구동으로 OS 전체가 절전 쪽으로 움직이고 있다.
이런 경우, 우선순위만 봐서는 원인에 도달할 수 없습니다.
특히, 주기 처리, 이미지 처리, 계측기 제어, 동영상 처리, 음성 처리, USB 카메라 캡처, 시리얼 통신 등에서는, 평균 처리 시간뿐만 아니라 「가끔 지연되는 것」이 문제가 됩니다.
평균은 빠르다. 하지만, 1000번에 1번만 지연된다. 그 1번으로 버퍼가 막힌다. UI가 멈춘다. 장비와의 타이밍이 어긋난다.
이런 현상에서는, CPU 사용률의 평균만으로는 부족합니다.
처리 시간의 분포, 최댓값, 특이값, 전원 상태, 실행 CPU, 백그라운드 부하를 함께 봐야 합니다.
7. Core Parking은 「사용할 수 있는 코어의 수」에 관여한다
Windows에는, Core Parking이라는 방식이 있습니다. 이것은, 사용하지 않는 논리 프로세서를 쉬게 하는 방향의 제어입니다. 사용률이 낮을 때 일부 코어를 저전력 상태로 몰아서, 전력 소비를 억제합니다.
Microsoft의 자료에서는, CPMinCores가 임의의 시점에 최소 몇 %의 논리 프로세서를 un-parked, 즉 사용 가능한 상태로 유지할지를 지정하는 설정으로 설명되어 있습니다.
값을 100%로 하면, Core Parking 알고리즘은 비활성화됩니다.
여기서 문제가 되는 것이, 선호도와의 조합입니다.
선호도로 「이 CPU 그룹에서 움직여 달라」고 제한했다. 하지만, 전원 관리상, 그 부근의 코어가 어떻게 취급되고 있는지는 별개의 문제입니다.
Windows Server용 자료에서도, 활성 스레드가 NUMA 노드 내의 CPU 일부에 강하게 선호도가 지정되어 있는 경우, Core Parking의 판단과 맞물리지 않는 상황이 있다고 설명되어 있습니다.
이것은 클라이언트 PC에서도, 사고방식으로는 참고가 됩니다.
선호도는, 스케줄러에 제약을 겁니다. Core Parking은, 전원 관리가 「어느 코어를 사용 가능한 상태로 할지」에 관여합니다.
이 두 가지를 따로 생각하면, 원인을 잘못 짚게 됩니다.
8. EcoQoS / Efficiency Mode는 「이 처리는 절전으로 충분하다」를 전달하는 방식
예전에는, Windows 앱의 성능 조정이라고 하면, 우선순위를 올리거나 내리거나, 선호도를 바꾸는 이야기가 중심이었습니다. 하지만, 현대의 Windows에는 조금 다른 사고방식이 있습니다. 그것이 QoS입니다.
QoS, Quality of Service는, 스레드에 대해 「이 처리는 얼마나 성능 중시인지, 얼마나 절전 중시인지」를 나타내는 개념입니다.
Microsoft의 문서에서는, 스케줄링 우선순위가 다음에 어느 스레드를 실행할지를 정하는 주요 지표로 계속 남아 있는 한편, QoS는 코어 선택이나 프로세서 전원 관리에 영향을 줄 수 있다고 설명되어 있습니다.
특히 EcoQoS는, 성능이 최우선이 아닌 처리를 절전 쪽으로 다루기 위한 방식입니다.
C++에서는, 예를 들어 SetThreadInformation과 ThreadPowerThrottling을 사용해서, 현재 스레드를 EcoQoS로 만들 수 있습니다.
#include <windows.h>
void EnableEcoQoSForCurrentThread()
{
THREAD_POWER_THROTTLING_STATE powerThrottling = {};
powerThrottling.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
powerThrottling.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
powerThrottling.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
SetThreadInformation(
GetCurrentThread(),
ThreadPowerThrottling,
&powerThrottling,
sizeof(powerThrottling));
}
반대로, 성능 중시로 되돌리는 경우는, 같은 제어 대상에 대해 StateMask를 0으로 합니다.
void DisableEcoQoSForCurrentThread()
{
THREAD_POWER_THROTTLING_STATE powerThrottling = {};
powerThrottling.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
powerThrottling.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
powerThrottling.StateMask = 0;
SetThreadInformation(
GetCurrentThread(),
ThreadPowerThrottling,
&powerThrottling,
sizeof(powerThrottling));
}
EcoQoS는, 무엇이든 절전으로 하면 된다는 기능이 아닙니다. 적합한 것은, 예를 들면 이런 처리입니다.
- 백그라운드 동기화
- 낮은 우선순위의 인덱스 작성
- 급하지 않은 로그 집계
- 사용자 조작과 직접 관계없는 캐시 업데이트
- 나중에 끝나면 되는 유지보수 처리
반면, 이런 처리에는 신중해야 합니다.
- UI 조작에 직결되는 처리
- 카메라 캡처
- 음성 처리
- 제어 주기에 관련된 처리
- 검사 장비의 판정 처리
- 사용자가 기다리고 있는 내보내기 처리
- 실시간성에 가까운 응답이 필요한 처리
작업 관리자의 Efficiency mode도, 이 사고방식과 관계가 있습니다.
Microsoft의 Performance Diagnostics 블로그에서는, Efficiency mode를 활성화하면, 프로세스의 기본 우선순위를 Low로 낮추고, QoS를 EcoQoS로 설정한다고 설명되어 있습니다.
즉, Efficiency mode는 단순한 「절전 아이콘」이 아니라, 낮은 우선순위화와 EcoQoS를 조합해서, 포그라운드 앱의 응답성과 전력 효율을 지키기 위한 방식입니다.
개발자 관점에서는, 이것이 꽤 중요합니다.
「이 처리는 빨리 끝나줬으면 좋겠다」뿐만 아니라, 「이 처리는 사용자를 방해하지 않는 범위에서 움직이면 된다」 고 OS에게 전달하는 설계가 가능해지기 때문입니다.
9. 판단 흐름도
여기까지의 이야기는 복잡하므로, Windows 앱의 성능이나 주기의 흔들림을 조사할 때의 판단 흐름을 정리해 둡니다.
flowchart TD
A["증상<br/>느리다·주기가 흔들린다·UI가 멈춘다·팬이 시끄럽다"] --> B["먼저 기록한다<br/>처리 시간 / 최댓값 / CPU 사용률 / 전원 상태 / AC 또는 배터리 / 대상 PC"]
B --> C{"CPU가 주된 원인인가?"}
C -- "아니오 / 불명" --> D["I/O·잠금·DB·네트워크·GC·GPU·드라이버를 확인<br/>우선순위나 선호도보다 먼저 대기 시간을 없앤다"]
C -- "예" --> E{"다른 프로세스와의 CPU 경쟁이 강한가?"}
E -- "예" --> F["우선순위를 검토<br/>다만 범위를 한정한다<br/>High/Realtime의 상시 사용은 피한다"]
E -- "아니오" --> G{"특정 CPU에 편중되어 있는가?"}
G -- "예" --> H["선호도 / CPU Sets를 확인<br/>과도하게 고정하고 있지 않은가<br/>P/E코어나 NUMA를 보고 있는가"]
G -- "아니오" --> I{"주파수·전원 상태가 의심스러운가?"}
I -- "예" --> J["전원 모드 / 전원 관리 옵션 / PPM을 확인<br/>P-state / EPP / 부스트 / Core Parking을 의심한다"]
I -- "아니오" --> K{"백그라운드 처리가 포그라운드를 방해하고 있는가?"}
K -- "예" --> L["EcoQoS / Efficiency Mode / 낮은 우선도화를 검토<br/>급하지 않은 처리를 절전 쪽으로 옮긴다"]
K -- "아니오" --> M["알고리즘·병렬도·큐 설계·UI 스레드 설계를 재검토"]
F --> N["한 항목씩 바꿔가며 A/B 측정"]
H --> N
J --> N
L --> N
M --> N
N --> O["평균뿐 아니라<br/>최댓값·특이값·발열·다른 앱에 대한 영향을 본다"]
이 흐름에서 중요한 것은, 처음부터 설정을 만지지 않는 것입니다. 먼저 기록합니다.
- 항상 느린가
- 가끔 느린가
- AC 전원인가 배터리인가
- 전원 모드는 무엇인가
- 작업 관리자에서 Efficiency mode가 되어 있지 않은가
- CPU 사용률은 높은가
- 주파수는 올라가 있는가
- 어느 스레드가 CPU를 사용하고 있는가
- 처리 시간의 최댓값은 어느 정도인가
- 다른 상주 소프트웨어나 백신 소프트웨어가 관련되어 있지 않은가
그런 다음, 하나씩 바꿉니다.
우선순위를 바꾼다. 선호도를 바꾼다. 전원 모드를 바꾼다. EcoQoS를 붙인다. 백그라운드 처리를 분리한다. 큐를 넣는다. UI 스레드에서 제외한다.
여러 개를 동시에 바꾸면, 무엇이 효과가 있었는지 알 수 없게 됩니다.
10. 현장에서의 확인 명령
Windows 앱의 동작이 환경에 따라 다를 때, 먼저 상태를 확인할 수 있게 해두면 편리합니다.
CPU 정보를 본다
Get-CimInstance Win32_Processor |
Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed
활성화된 전원 관리 옵션을 본다
powercfg /getactivescheme
프로세서 전원 관리 설정을 본다
powercfg /q SCHEME_CURRENT SUB_PROCESSOR
출력은 상당히 길지만, 최소·최대 프로세서 상태, EPP, 부스트, Core Parking에 관련된 설정을 확인할 수 있습니다. 환경에 따라 보이는 항목은 다릅니다.
전력 효율 진단 리포트를 만든다
관리자 권한의 터미널에서 실행합니다.
powercfg /energy
일정 시간 계측 후, HTML 리포트가 출력됩니다. 드라이버, 디바이스, 타이머 해상도, USB의 절전, 절전 방해 등을 살펴보는 입구가 됩니다.
대상 프로세스의 우선순위와 선호도를 본다
Get-Process -Name MyApp |
Select-Object Id, ProcessName, PriorityClass, ProcessorAffinity
CPU의 성능 상태를 본다
환경에 따라 사용할 수 있는 카운터 이름은 달라지지만, 이 근처의 Performance Counter가 참고가 됩니다.
Get-Counter '\Processor Information(_Total)\% Processor Performance'
Get-Counter '\Processor Information(_Total)\% Processor Utility'
제대로 보려면, Windows Performance Recorder와 Windows Performance Analyzer로 ETW를 수집하는 쪽이 확실합니다. 주기의 흔들림, 컨텍스트 스위치, 실행 CPU, DPC/ISR, 디스크 I/O, CPU 주파수의 변화를 함께 추적할 수 있습니다.
11. 소프트 리얼타임 처리에서는, 전부 함께 생각한다
Windows는, 일반적인 의미에서의 리얼타임 OS가 아닙니다. 하지만, 현장의 Windows 앱에서는, 리얼타임에 가까운 성질을 요구받는 경우가 있습니다.
- USB 카메라에서 일정 주기로 이미지를 가져온다
- 시리얼 통신으로 장비와 주고받는다
- 계측기에서 데이터를 읽는다
- PLC나 외부 기기와 동기화한다
- 음성이나 동영상을 처리한다
- 검사 결과를 일정 시간 내에 반환한다
- UI를 멈추지 않고 무거운 계산을 돌린다
이런 처리에서는, 코드의 속도만으로는 부족합니다.
스레드 설계가 필요합니다. 큐 설계가 필요합니다. 로그가 필요합니다. 타임아웃이 필요합니다. 백프레셔가 필요합니다. 지연되었을 때 버릴지, 기다릴지, 재시도할지를 결정해야 합니다.
그리고, 그 위에서, 우선순위, 선호도, P코어/E코어, 절전 설정을 봐야 합니다.
예를 들어, 카메라 캡처 스레드를 생각해봅니다.
이 스레드는, 사용자 조작에 가깝고, 주기성도 있습니다. EcoQoS로 해서는 안 될지도 모릅니다. 우선순위를 조금 올릴 가치는 있을지도 모릅니다. 다만, 너무 올리면 UI나 다른 처리에 악영향이 나옵니다. 선호도를 고정하면 안정될지도 모릅니다. 하지만, 고정한 곳이 E코어 쪽이면 역효과일지도 모릅니다. 전원 모드가 절전 쪽이면, 배터리 시에만 지연될지도 모릅니다.
한편, 오래된 로그 압축 처리라면 어떨까요.
이것은 사용자가 기다리고 있지 않은 처리일지도 모릅니다. 그렇다면, 우선순위를 내린다. EcoQoS로 한다. 유휴 시에 움직인다. AC 전원 시에만 움직인다. 이런 설계 쪽이, 앱 전체로서 친절합니다.
모든 처리를 「빠르게」 하는 것이 아니라, 빠르게 해야 할 처리와, 방해하지 말아야 할 처리를 나눕니다.
12. 설계의 기본 방침
Windows 앱에서, 이 부분을 다룰 때의 기본 방침은 6가지입니다.
1. 처음부터 고정하지 않는다
처음부터 우선순위나 선호도를 강하게 고정하지 않는 것이 좋습니다.
Windows의 스케줄러는, 많은 경우 상당히 잘 처리해줍니다. 앱 쪽이 불필요한 제약을 걸면, 오히려 나빠지는 경우가 있습니다.
먼저 보통으로 만든다. 측정한다. 문제가 나오면, 가설을 세운다. 조금씩 바꾼다. 다시 측정한다.
이 순서입니다.
2. 우선순위는 일시적으로 사용한다
높은 우선순위는, 필요한 구간에만 적용합니다.
계속 고우선순위로 두는 것보다,
중요한 처리 직전에 올린다
끝나면 되돌린다
쪽이 안전합니다.
3. 선호도는 마지막 단계에서 검토한다
선호도는 강한 설정입니다.
주기의 흔들림이나 CPU 이동의 영향이 의심될 때는 효과가 있는 경우가 있습니다. 하지만, 처음에 손대는 설정은 아닙니다.
특히, 고객 PC가 여러 종류라면, CPU 번호를 단정하는 것은 위험합니다.
4. P코어/E코어는 「단정」이 아니라 「관찰」한다
P코어/E코어를 구분해서 쓰고 싶다면, 먼저 실제 기기에서 관찰합니다.
CPU 번호로 단정하지 말고, CPU Sets, EfficiencyClass, ETW, 실측으로 봅니다.
5. 절전 설정을 전제로 테스트한다
개발 머신이 AC 전원·고성능 설정이어서 빠르다는 것만으로는 부족합니다.
고객 환경에서는, 이런 상태가 흔히 있습니다.
- 노트북의 배터리 구동
- Best power efficiency
- Energy saver
- OEM 고유의 절전 유틸리티
- 회사 정책으로 고정된 전원 설정
- 열로 성능이 떨어지는 슬림형 PC
- 상주 소프트웨어가 많은 업무 단말
성능 테스트에서는, 적어도 이 정도의 조건은 나누어서 보고 싶습니다.
| 조건 | 확인할 것 |
|---|---|
| AC + Best performance | 최대 성능에 가까운 상태 |
| AC + Balanced | 표준적인 업무 이용 |
| Battery + Balanced | 노트북의 현실 |
| Battery + Best power efficiency | 절전 쪽의 하한 |
| 장시간 연속 실행 | 열, 팬, 서멀 스로틀링 |
| 다른 앱 동시 이용 | 브라우저, Teams, Excel, 백신 소프트웨어와의 공존 |
6. 백그라운드 처리에는 EcoQoS를 검토한다
사용자 경험에 직결되지 않는 처리는, 성능을 얻으러 가기보다 방해하지 않는 것을 우선하는 편이 좋은 경우가 있습니다.
모든 것을 고성능으로 움직이는 앱은, 빠를지도 모릅니다. 하지만, 다른 작업을 방해합니다. 노트북의 팬을 돌립니다. 배터리를 소비합니다. 결과적으로, 사용하기 어려운 앱이 됩니다.
Windows 앱에서는, 속도뿐만 아니라 「공존을 잘하는 것」도 품질입니다.
13. 흔한 오해
우선순위를 올리면 빨라진다
반드시 빨라지는 것은 아닙니다.
CPU 경쟁이 원인이라면 효과가 있는 경우가 있습니다. 하지만, I/O 대기, 잠금 대기, 절전에 의한 저주파수, E코어 쪽에서의 실행 등이 원인이라면, 우선순위만으로는 부족합니다.
P코어에 고정하면 항상 정답이다
항상 정답은 아닙니다.
P코어는 고성능이지만, 발열이나 전력 소비도 늘어납니다. 또한, 다른 중요한 포그라운드 처리와 경쟁할 가능성도 있습니다.
P코어로 몰아야 할 처리와, E코어로 충분한 처리를 나누는 것이 더 중요합니다.
절전 설정은 사용자의 취향이고, 앱과는 관계없다
관계있습니다.
같은 앱이라도, 전원 모드, 전원 관리 옵션, EPP, 부스트, Core Parking에 따라, 실행되는 방식이 달라집니다.
특히 노트북에서는, AC 전원과 배터리에서 동작이 달라집니다.
Efficiency mode는 그냥 느리게 만들 뿐이다
그냥 느리게 만드는 것만은 아닙니다.
낮은 우선순위화와 EcoQoS에 의해, 포그라운드 앱의 응답성과 전력 효율을 지키기 위한 방식입니다. 급하지 않은 백그라운드 처리에는, 오히려 적극적으로 고려할 가치가 있습니다.
Windows라서 안정적이지 않다
이것도 대충 본 견해입니다.
Windows는 리얼타임 OS가 아닙니다. 하지만, 스케줄링, 전원 관리, QoS, 측정, 로그, 스레드 설계를 이해하면, 현장 수준으로 충분히 안정화시킬 수 있습니다.
문제는 「Windows라서 무리」가 아니라, 어느 층에서 무엇이 일어나고 있는지를 보지 않고 있다는 것입니다.
14. 구현보다 먼저, 로그를 설계한다
이런 종류의 문제는, 고객 환경에서만 발생하는 경우가 있습니다. 그래서 앱 쪽에서 최소한의 진단 정보를 남길 수 있게 해두면 도움이 됩니다.
예를 들어, 진단 로그에는 이런 정보를 출력합니다.
- 앱 버전
- Windows 버전
- CPU 이름
- 논리 프로세서 수
- AC 전원인지 배터리인지
- 처리 시간의 평균·최댓값·백분위수
- 처리 주기의 지연 횟수
- 대상 스레드의 우선순위
- 프로세스 우선순위
- 선호도 설정 여부
- EcoQoS 설정 여부
- 시작 시의 전원 관리 옵션
- 대상 처리가 타임아웃된 횟수
고객사에서 「가끔 느리다」는 말을 들었을 때, 아무런 기록이 없으면 추측 싸움이 됩니다. 로그가 있으면, 가설을 세울 수 있습니다.
배터리 시에만 느리다
특정 PC에서만 느리다
시작 직후에만 느리다
30분 후부터 느리다
다른 앱 실행 중에만 느리다
일정 주기로 특이값이 나온다
이런 차이가 보이면, 우선순위인지, 선호도인지, 전원 설정인지, 열인지, 다른 대기인지, 나누어 보기 쉬워집니다.
15. 코무라소프트식 관점
Windows 앱 개발에서는, 깔끔한 이론만으로는 부족합니다.
고객의 PC에서 동작하는 것. 현장의 단말에서 동작하는 것. 오래된 주변 기기와 공존하는 것. 백신 소프트웨어나 프린터, 사내 정책이 있는 환경에서 동작하는 것. 노트북의 절전 설정에서도 무너지지 않는 것. 성능이 필요한 곳에서는, 제대로 성능을 내는 것. 급하지 않은 처리에서는, 사용자를 방해하지 않는 것.
그러기 위해서는, Windows를 단순한 「블랙박스 OS」로 보지 않는 것이 좋습니다.
Windows는, 스레드를 어떻게 움직일지를 생각하고 있습니다. 어느 CPU에서 움직일지를 생각하고 있습니다. 전력과 성능의 균형을 잡고 있습니다. P코어/E코어 같은 이종 코어를 다루고 있습니다. 포그라운드 앱과 백그라운드 처리를 구분하려 하고 있습니다.
개발자는, 그것에 맞서는 것이 아니라, 필요한 곳에서 의도를 전달해야 합니다.
이 처리는 사용자를 기다리게 하고 있다. 이 처리는 다소 느려도 괜찮다. 이 처리는 주기가 중요하다. 이 처리는 백그라운드에서 조용히 움직이면 된다. 이 처리는 다른 처리를 방해해서는 안 된다.
그런 설계를, 우선순위, 선호도, QoS, 절전 설정의 이해에 담아냅니다.
16. 정리
Windows 앱의 성능은, 코드만으로 결정되지 않습니다.
우선순위를 올려도, 선호도로 E코어 쪽에 몰려 있다면 기대한 대로 움직이지 않을지도 모릅니다. P코어로 몰아도, 전원 모드가 절전 쪽이면 CPU는 최대 성능을 내지 않을지도 모릅니다. CPU Sets나 QoS를 생각하지 않고 강한 선호도를 걸면, Windows의 전원 관리나 스케줄러의 도피처를 없애버릴지도 모릅니다. 모든 것을 고성능 쪽으로 몰면, 발열, 팬 소음, 배터리 소비, 다른 앱에 대한 영향이 늘어납니다.
Windows 앱 개발에서는, 속도뿐만 아니라 응답성, 안정성, 전력 소비, 발열, 다른 프로세스와의 공존까지 포함해서 설계해야 합니다.
그래서 봐야 할 것은, 역시 이 4가지입니다.
우선순위
선호도
P코어 / E코어
절전 설정
그리고 현대의 Windows에서는, 여기에 EcoQoS나 Efficiency mode도 더해집니다.
걱정할 것은 많습니다.
하지만, 걱정을 그대로 불안으로 남겨둘 필요는 없습니다.
걱정을, 측정으로 바꾼다. 걱정을, 로그로 바꾼다. 걱정을, 설계로 바꾼다. 걱정을, 테스트 조건으로 바꾼다.
그렇게 하면, Windows는 단순히 변덕스러운 실행 환경이 아니라, 꽤 관찰할 가치가 있는, 현장을 위한 플랫폼이 됩니다.
Windows는 리얼타임 OS가 아닙니다. 그래도, 실행 환경을 이해하고 설계하면, 현장에서 충분히 신뢰할 수 있는 앱을 만들 수 있습니다.
그리고, 그 어려움이야말로, Windows 앱 개발의 재미이기도 합니다.
참고 링크
- 이 글의 샘플 코드 세트(C# / PowerShell / 단위 테스트) - komurasoft-blog-samples (GitHub)
- Scheduling Priorities - Microsoft Learn
- SetProcessAffinityMask function - Microsoft Learn
- SetThreadAffinityMask function - Microsoft Learn
- CPU Sets - Microsoft Learn
- SYSTEM_CPU_SET_INFORMATION structure - Microsoft Learn
- Change the power mode for your Windows PC - Microsoft Support
- Power Policy Settings - Microsoft Learn
- P-states and C-States - Microsoft Learn
- Processor power management options - Microsoft Learn
- CPMinCores - Microsoft Learn
- Quality of Service - Microsoft Learn
- SetThreadInformation function - Microsoft Learn
- Reduce Process Interference with Task Manager Efficiency Mode - Microsoft DevBlogs
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
Windows 앱 외주·수탁 개발을 의뢰하기 전에 정리해야 할 것
Windows 앱의 외주·수탁 개발을 의뢰하기 전에, 기존 소프트웨어 개수, 장치 연계, COM/ActiveX, 배포·업데이트, 보수와 관련해 정리해야 할 포인트를 설명합니다.
Windows의 「프로세서 스케줄링」을 「백그라운드 서비스」로 바꾸면 무슨 일이 일어나는가 - quantum, 우선도 부스트, P 코어 / E 코어까지 정리
Windows의 프로세서 스케줄링을 백그라운드 서비스로 바꾸면 quantum 배분과 foreground 우대가 어떻게 달라지는지, 음성 드롭아웃과의 관계, 그리고 P 코어와 E 코어 시대에 QoS와 hybrid scheduling이 차지하는 역할...
Windows의 세션 분리를 어떻게 이해할까 ── Session 0・RDP・다중 사용자 동시 실행
Windows 앱 개발자가 혼란스러워하기 쉬운 '세션' 개념을 정리합니다. 서비스가 UI를 표시할 수 없는 Session 0 분리의 이유, RDP 접속 시 세션의 동작, 명명된 개체의 세션 분리, 공유 PC・RDS 환경에서 흔히 발생하는 설계 실...
Windows 앱의 중복 실행 방지 ── 네임드 Mutex와 재실행 시 창 활성화
업무용 Windows 앱의 정석 요건인 「같은 앱을 두 번 실행시키지 않는다」를 네임드 Mutex로 구현하는 방법을 정리합니다. Global\ 과 Local\ 네임스페이스의 차이로 인한 RDP 환경의 함정, 소유 스레드 제약과 AbandonedM...
WinForms/WPF 앱에 Entra ID 인증 넣기 ── MSAL.NET과 WAM 브로커 실무 구성
WinForms/WPF 데스크톱 앱에 Entra ID(구 Azure AD) 인증을 도입하는 절차를 실무 관점에서 정리합니다. 퍼블릭 클라이언트의 개념, ROPC 폐지 현황, 앱 등록, MSAL.NET의 AcquireTokenSilent 패턴, W...
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- CPU 우선순위는 어떻게 설정하나요?
- 우선순위는 프로세스의 우선순위 클래스와 스레드의 상대 우선순위, 이 2단계로 결정됩니다. Win32 API에서는 프로세스 쪽에 SetPriorityClass, 스레드 쪽에 SetThreadPriority가 있습니다. PowerShell이라면 Get-Process로 가져온 객체의 PriorityClass 속성에 "AboveNormal" 등을 설정할 수 있고, C#에서는 Process.GetCurrentProcess()의 PriorityClass에 ProcessPriorityClass.AboveNormal을 대입합니다. 다만 HIGH_PRIORITY_CLASS나 REALTIME_PRIORITY_CLASS를 상시 사용하면 시스템 전체의 응답성이 나빠지므로 피해야 합니다.
- 우선순위를 올렸는데 앱이 빨라지지 않는 이유는 무엇인가요?
- 우선순위는 「경쟁이 있을 때 어느 스레드를 먼저 움직일지」를 정하는 설정이지, CPU를 빠르게 만드는 설정이 아니기 때문입니다. 느린 원인이 디스크 I/O 대기, 네트워크 대기, 잠금 경쟁, GC 정지, UI 스레드의 블로킹, 백신 소프트웨어의 스캔, 또는 절전 설정으로 CPU 주파수가 억제되어 있는 것이라면, 우선순위를 올려도 본질적으로는 해결되지 않습니다. 먼저 처리 시간의 분포와 전원 상태, 실행 CPU를 기록해서 원인을 나누어 보는 것이 중요합니다.
- SetThreadInformation으로 EcoQoS를 설정하면 무슨 일이 일어나나요?
- SetThreadInformation에 ThreadPowerThrottling과 THREAD_POWER_THROTTLING_EXECUTION_SPEED를 지정하면, 해당 스레드를 EcoQoS(절전 쪽 QoS)로 다루도록 OS에 전달할 수 있습니다. QoS는 코어 선택이나 프로세서 전원 관리에 영향을 줄 수 있기 때문에, 백그라운드 동기화나 급하지 않은 로그 집계 같은 처리를, 포그라운드 앱을 방해하지 않는 절전 쪽으로 옮길 수 있습니다. 반면, UI 조작에 직결되는 처리나 카메라 캡처, 제어 주기에 관련된 처리에는 신중해야 합니다. StateMask를 0으로 하면 성능 중시로 되돌릴 수 있습니다.
- powercfg의 CPMinCores란 무엇인가요?
- CPMinCores는 Windows의 Core Parking에 관한 전원 설정으로, 임의의 시점에 최소 몇 %의 논리 프로세서를 un-parked(사용 가능 상태)로 유지할지를 지정합니다. 값을 100%로 하면 Core Parking 알고리즘이 비활성화됩니다. 현재 설정은 관리자 권한으로 powercfg /q SCHEME_CURRENT SUB_PROCESSOR를 실행하면 확인할 수 있으며, 선호도로 CPU를 제한하고 있는 경우 Core Parking의 판단과 맞물리지 않는 상황이 있으므로 두 가지를 함께 살펴봐야 합니다.
저자 프로필
기사 저자의 프로필 페이지입니다.
Go Komura
합동회사 코무라소프트 대표
Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.
공개 링크