Mac이 열로 인해 성능 저하(thermal throttling) 상태인지 알려주는 macOS 앱 개발기
(stanislas.blog)- MacThrottle은 Mac이 과열로 인해 성능을 제한할 때 이를 메뉴 막대에서 시각적으로 알려주는 SwiftUI 기반 앱 - 오픈소스
- macOS의
ProcessInfo.thermalStateAPI와powermetrics명령어를 비교하며, 시스템의 실제 열 상태를 정확히 감지하기 위한 방법을 탐색 - 최종적으로
thermald가 Darwin의notifyd시스템에 게시하는 알림을 활용해 루트 권한 없이 열 상태를 읽는 방식 구현 - 앱은 온도·팬 속도 그래프, 상태별 색상 아이콘, macOS 알림 기능을 포함하며, 로그인 시 자동 실행도 지원
- Apple Silicon Mac의 열 관리 상태를 실시간으로 파악할 수 있는 도구로, 개발자와 파워유저에게 유용한 진단 수단 제공
Mac의 열 스로틀링 문제 인식
- M2 MacBook Air에서 외부 4K 120Hz 디스플레이 사용 시 성능 저하와 반응 지연이 발생
- 팬이 없어 소음을 감지할 수 없지만, CPU 사용률이 100%인 상태에서 전력 사용량이 감소함
- iStat Menus와 MX Power Gadget을 통해 CPU 주파수와 전력 하락을 확인하며 열 스로틀링을 진단
- M4 Max MacBook Pro에서도 동일 현상 발생, 14인치 모델의 열 설계 한계로 인한 문제로 언급
- Apple Silicon의 전력 효율은 여전히 높지만, 열 상태를 직접 감지할 방법을 찾고자 함
macOS에서 열 상태를 프로그래밍적으로 확인하기
- macOS는 여러 방식으로 열 상태를 노출하지만 일관성이 부족
- Apple이 권장하는 방법은
Foundation의ProcessInfo.thermalState사용- 출력 예시:
nominal,fair,serious,critical
- 출력 예시:
- 루트 권한이 필요한
powermetrics -s thermal명령어도 동일한 정보를 제공하지만,
두 방식의 상태 구분 단위가 다름- 예:
fair는powermetrics의moderate와heavy두 상태를 모두 포함
- 예:
- 실제 스로틀링 시점은
powermetrics에서heavy로 표시되지만,ProcessInfo에서는 구분 불가
thermald와 Darwin 알림 시스템 활용
-
powermetrics의 데이터는thermald데몬에서 가져오며,
thermald는 현재 열 압력 상태를notifyd시스템 이벤트로 게시 -
notifyutil -g com.apple.system.thermalpressurelevel명령으로 상태 확인 가능 -
OSThermalNotification.h헤더에서 정의된 열 압력 수준:-
nominal,moderate,heavy,trapping,sleeping
-
- Swift 코드로
notify_register_check와notify_get_state를 호출해
루트 권한 없이 실시간 열 상태를 읽는 기능 구현
MacThrottle 앱 개발
-
SwiftUI와 MenuBarExtra를 사용해 메뉴 막대 전용 앱 제작
- 온도계 아이콘 색상으로 상태 표시 (녹색→적색)
-
Info.plist의LSUIElement를true로 설정해 Dock 아이콘 비활성화
초기 접근: powermetrics 루트 헬퍼
- 초기에 루트 권한이 필요한
powermetrics를 사용하기 위해
LaunchDaemon과 bash 스크립트로 헬퍼 프로세스 구성-
/usr/local/bin/mac-throttle-thermal-monitor가 10초마다 상태를/tmp파일에 기록 - 앱은 해당 파일을 주기적으로 읽어 표시
-
개선: thermald IPC 알림 사용
-
notifyd이벤트를 직접 구독하는 방식으로 전환- 루트 권한 불필요, 코드 단순화
온도 및 팬 속도 표시
- CPU/GPU 온도와 팬 속도를 그래프로 표시
- 초기에는 IOKit 비공개 API 사용 시 온도가 실제보다 낮게 표시됨 (~80°C)
- 오픈소스 Stats 프로젝트를 참고해 SMC 인터페이스로 전환
- SoC 세대별로 다른 키(
Tp0D,Tf0E등)를 사용해야 함
- SoC 세대별로 다른 키(
- SMC가 작동하지 않을 경우 IOKit으로 폴백
메뉴 막대 그래프 구현
- 그래프는 3가지 정보를 동시에 표시
- 배경 색상: 열 상태 (녹색~적색)
- 실선: CPU 온도
- 점선: 팬 속도 비율
- 2초 간격으로 데이터 수집, 10분 단위 히스토리 유지
-
onContinuousHover로 툴팁 제공,
.drawingGroup을 추가해 GPU 렌더링으로 120Hz 디스플레이에서도 부드럽게 표시
macOS 알림 및 자동 실행
- 열 상태 변화 시 알림 전송 기능 추가
- 특정 상태 전환이나 복구 시 알림 가능
-
SMAppServiceAPI로 로그인 시 자동 실행 설정 지원-
register()/unregister()/status메서드로 제어
-
배포 및 사용
- Apple Developer 계정이 없어 공식 공증(notarization) 불가
- GitHub 릴리스에서 설치 시
Privacy and Security에서 수동 승인 필요 - 일부 Mac에서는 Xcode로 직접 빌드해야 실행 가능
- GitHub 릴리스에서 설치 시
- 설치 및 빌드 방법은 GitHub README에 명시
결론
- MacThrottle은 Apple Silicon Mac의 열 스로틀링 상태를 실시간 감시할 수 있는 경량 도구
- 루트 권한 없이 동작하며, 시각적 피드백·알림·그래프 기능을 통해
개발자와 고성능 작업 사용자에게 시스템 열 상태 인식을 제공
Hacker News 의견들
-
2019년형 MacBook Pro i9을 썼는데, 열 스로틀링 감지 함수는 이렇게 간단히 쓸 수 있을 것 같음
function isThermalThrottling() { return true; }농담이지만, 고가의 i9 CPU를 샀는데 i7보다 성능이 떨어지는 게 꽤 실망스러웠음
- 나도 같은 모델을 쓰는데, 오른쪽 포트로 충전해야만 문제를 해결할 수 있었음
이유는 모르겠지만 그렇게 하니 스로틀링이 사라졌음
그래도 macOS와 Logic 기반 워크플로우가 익숙해서 계속 쓰고 있음
리눅스로 옮길 수도 있겠지만, 지금은 꽤 쓸 만한 머신임 - 나도 2019 i9 모델을 썼는데, VRM 모듈에 써멀 패드를 붙이니 완전히 새 컴퓨터처럼 변했음
두 개의 외부 모니터와 Adobe Creative Suite를 쓸 때마다 스로틀링이 심했는데, 이 패드로 해결됨
단점은 하판이 뜨거워져 무릎 위에 두기 어렵다는 점이지만, 전혀 후회하지 않음
지금은 M3 MacBook Air(24GB RAM) 로 바꿨고 매우 만족 중임
아직 2019 모델을 쓰는 사람이라면 꼭 VRM 써멀 패드 개조를 고려해보길 추천함 - 사실 i9 자체가 노트북용으로 부적합한 CPU였다고 생각함
Dell에서도 i9을 i7으로 바꾸자마자 훨씬 나아졌음
“큰 숫자 = 더 좋은 CPU”라는 마케팅에 속은 셈임 - 나도 같은 문제를 겪었음, 특히 외부 모니터 두 대를 연결했을 때 심했음
이후 M1 Max로 바꾸자 완전히 다른 세상이었음
지금은 M3 Max로 업그레이드했고, Apple Silicon은 오래 버틸 것 같음 - 그 노트북은 내가 써본 최악의 컴퓨터였음
부팅하자마자 팬이 돌고, Thunderbolt 장치 연결 시 커널 패닉도 자주 발생했음
지금 쓰는 M1 Max MBP는 완벽하게 안정적임
- 나도 같은 모델을 쓰는데, 오른쪽 포트로 충전해야만 문제를 해결할 수 있었음
-
프로젝트가 꽤 괜찮아 보임
다만 macOS에서 개발이 점점 어려워지고 있는데, 스로틀링을 감지해도 실제로 무엇을 할 수 있을지는 의문임
팬 속도 조정도 안 되고, 언더볼팅도 불가능하지 않나?- 나 같은 경우 iStat Menus로 팬 커브를 직접 조정했음
기본 커브가 너무 느려서 스로틀링이 먼저 발생했거든
Apple Silicon에서는 High Power Mode를 쓰면 팬이 더 빠르게 돌아감
지금은 커스텀 커브를 안 쓰지만, 14" M4 Max에서는 꽤 시끄러움
MacBook Air는 팬이 없으니 그냥 열을 식히는 수밖에 없음 - 나는 Macs Fan Control을 써서 CPU 온도에 따라 팬 RPM을 조절함
기본 설정으로는 90도 이상 올라가서, 더 보수적으로 세팅했음
GitHub 링크 - 이런 앱이 꼭 필요했는데 이제 생겼음
가끔 프로세스가 폭주해서 스로틀링이 생기는데, 그걸 알아차리기 전까지 배터리가 반쯤 닳아 있음 - 결국 할 수 있는 건 앱을 종료하거나 잠시 쉬는 것뿐임
백그라운드에서 돌아가는 앱이 많을 때 이런 문제가 자주 생김
- 나 같은 경우 iStat Menus로 팬 커브를 직접 조정했음
-
Homebrew에 넣으면 무료로 코드 서명과 공증을 받을 수 있음
그렇게 배포되면 정말 좋겠음- 좋은 정보임. 혹시 Windows용 무료 서명 방법도 있는지 궁금함
- 오, 몰랐음. 개발자 설정에 따라 달라지는 줄 알았는데 찾아봐야겠음
-
내 가설은 CPU 문제가 아니라 USB 컨트롤러가 열을 포화시키는 것임
CPU/GPU가 아니라 본체가 과열돼서 열 방출이 막히고 결국 스로틀링이 생기는 구조 같음
다른 어댑터나 모니터로 실험해볼 필요가 있음- 나도 2019 i9을 쓰는데, 충전 포트를 바꾸자 스로틀링이 사라졌음
네 말이 맞는 것 같음 - 완전히 이해한 건 아니지만, 내 M2 Air도 비슷한 증상이 있음
4K 144Hz 모니터에 연결해 Zoom이나 영상 스트림을 여러 개 켜면 발열이 심해짐
USB 컨트롤러 때문이라기보단 단순히 부하가 커서 그런 듯함 - 이런 현상을 thermal soaking이라고 부름
- 나도 2019 i9을 쓰는데, 충전 포트를 바꾸자 스로틀링이 사라졌음
-
사이트가 트래픽 폭주로 죽은 듯함
저장소는 angristan/MacThrottle- 수정 완료했음. Cloudflare Workers가 fail closed 모드로 설정돼 있어서 트래픽을 막고 있었음
-
iStat Menus에서 CPU 100%인데 전력 사용량이 낮으면 스로틀링이라 생각할 수 있지만,
저전력 USB-C 충전기에 연결된 경우에도 같은 현상이 생김
충전기 전력을 감지하는 기능을 추가하면 좋을 듯함- 나도 M1 MacBook Air로 D&D 세션을 하다가 같은 문제를 겪었음
충전 중이라 더워져서 스로틀링이 심했는데, 세션 전에 미리 충전하니 해결됨 - 예전에 전원 어댑터 출력이 부족해서 게임을 하다 배터리가 닳아 꺼진 적이 있었음
이후 세대에서 더 큰 전원 어댑터가 나온 이유를 이해했음 - 그렇다면 왜 코어 온도만으로는 스로틀링을 판단할 수 없는지 궁금함
온도가 바로 제어 변수 아닌가? - iStat Menus에서 충전기 전력을 보여주긴 하지만, 왜 이런 현상이 생기는지는 여전히 의문임
- 나도 M1 MacBook Air로 D&D 세션을 하다가 같은 문제를 겪었음
-
CPU 사용률과 시스템 전력량을 메뉴바에 표시해두면 이상 징후를 바로 알 수 있음
exelban/stats- 나도 그렇게 해서 스로틀링을 처음 의심했음
CPU 사용률은 높은데 전력량이 줄어드는 걸 보고 눈치챘음
- 나도 그렇게 해서 스로틀링을 처음 의심했음
-
다음 MacBook Air M5에는 Vapor Chamber 냉각이 들어갔으면 좋겠음
지금은 Apple이 소음 최소화를 열 방출보다 우선시하는 것 같음
그래서 팬 최소 속도를 강제로 높여둠- Vapor Chamber는 순간적인 열 분산에는 좋지만, 결국 열은 알루미늄 바디로 전달됨
바디가 환경과 열평형에 도달하면 방출량이 한계에 부딪힘
팬이 있다면 구리판과 바람으로 충분히 해결 가능함
결국 에너지 보존의 문제임
- Vapor Chamber는 순간적인 열 분산에는 좋지만, 결국 열은 알루미늄 바디로 전달됨
-
thermal pressure 알림 버그가 있는 것 같음
혹시 앱에서 그런 문제를 겪었는지 궁금함
관련 이슈- 나도
ProcessInfo.processInfo.thermalState를 쓸 때 상태가 갱신되지 않는 걸 봤음
하지만 지금 쓰는 thermald 알림 방식에서는 그런 문제가 없음
- 나도
-
왜
@_silgen_name으로 Darwin API를 직접 선언했는지 궁금함
import Darwin으로는 접근이 안 되나?- 실제로
import Darwin만으로는 해당 API가 노출되지 않는 것 같음
- 실제로