iOS-Trace: 자율 애플리케이션 성능 최적화
iOS-Trace는 물리적 iPhone/iPad 기기 및 로컬 iOS 시뮬레이터(SwiftUI, UIKit, Metal, CoreAudio / AVAudioEngine, URLSession 네트워킹)에서 실행되는 iOS 및 iPadOS 애플리케이션을 위한 폐쇄 루프 성능 최적화 엔진입니다.
핵심 목표는 수동 Instruments GUI 상호 작용을 제거하는 것입니다. AI 에이전트가 자율적으로 진단, 병목 지점 식별, 코드 변경 구현, 차등 벤치마킹으로 재테스트를 수행하고, 실증 데이터로 성능 목표가 검증될 때까지 반복할 수 있습니다.
+-------------------------------------------------------------------------+
| 자율 최적화 루프 |
| |
| 1. 목표 정렬 ──> 2. 진단 트레이스 ──> 3. 타겟 코드 수정 |
| ^ │ |
| │ ▼ |
| └────── 목표 미달 시 반복 <── 4. 재테스트 검증 |
+-------------------------------------------------------------------------+
1단계: 사용자 목표 정렬 (사전 설문)
코드를 수정하거나 모바일 기기에서 트레이스를 수집하기 전에, 에이전트는 최적화 목표와 성공 기준에 대해 사용자와 합의해야 합니다.
모달 도구 vs 채팅 상호 작용
- 에이전트 플랫폼에 인터랙티브 설문지/모달 도구가 있는 경우 (예:
ask_question, 입력 대화상자, 선택 가능한 옵션 목록), 이를 호출하여 사용자에게 선택지를 깔끔하게 제시하십시오. - 모달 도구를 사용할 수 없는 경우, 구조화된 옵션과 구체적인 권장값을 포함하여 대화에서 직접 사용자에게 질문하십시오.
사용자에게 물어볼 질문
-
주요 최적화 목표:
- 옵션 A: 배터리 소모, CPU 사용률, 발열 스로틀링 감소.
- 옵션 B: 메모리 발자국 및 일시적 할당 스파이크 감소, Jetsam OOM 크래시 방지.
- 옵션 C: UI 프레임 끊김 및 드롭된 애니메이션 프레임 제거 (ProMotion 120Hz 히치).
- 옵션 D: 모바일 애플리케이션 콜드 런칭 시간 단축.
- 옵션 E: 네트워크 무선 오버헤드 및 배치 요청 효율성 최적화.
-
구체적인 성능 목표 (권장 기본값 제공):
- 배터리 및 CPU 목표:
- 유휴 기준 목표: < 15 M/s 명령어, CPU 영향 < 0.3.
- 활성 워크로드 목표: < 80 M/s 명령어 (또는 지정: 30% - 50% 감소).
- 메모리 및 Jetsam 목표:
- 최대 상주 RAM: < 150 MB (일반 유틸리티) 또는 < 300 MB (미디어/풍부한 인터랙티브 앱)으로 제한.
- 할당 이벤트 속도: 정상 상태 상호 작용 중 < 400 이벤트/초.
- 메모리 누수: 정확히 0개의 지속적인 누수.
- UI 부드러움 및 프레임 속도 목표:
- 히치 비율: < 5.0 ms/s (허용 가능), < 1.0 ms/s (부드러움 / 120Hz ProMotion 수준).
- 최대 히치 지속 시간: < 16.6ms (60Hz) 또는 < 8.33ms (120Hz).
- 런칭 시간 목표:
- 첫 프레임까지의 시간: < 400 ms (우수), < 800 ms (허용 가능).
- 네트워크 및 무선 목표:
- 무선 오버헤드: 주기적인 핑을 단일 버스트 요청으로 배치하여 무선 테일 대기 전력을 방지.
- 배터리 및 CPU 목표:
-
벤치마크 사용자 시나리오:
- 벤치마크할 특정 화면, 사용자 상호 작용, 물리적 기기 또는 시뮬레이터를 사용자에게 문의하십시오.
목표가 확인되면 2단계로 진행합니다.
범위 및 전제 조건
- 대상 플랫폼: USB 또는 로컬 네트워크로 연결된 물리적 iPhone/iPad 기기, 또는 로컬 iOS 시뮬레이터에서 실행되는 iOS 및 iPadOS 애플리케이션. (macOS 데스크탑 애플리케이션의 경우 macOS-Trace를 사용하십시오).
- 호스트 시스템: Apple Silicon 또는 Intel Mac에서 실행되는 macOS 12+ 및 전체 Xcode 또는 Xcode 명령줄 도구 (
xcode-select -p,xcrun xctrace version). - 기기 준비 상태:
- 물리적 iPhone/iPad는 잠금 해제되어야 하며 Mac 호스트에서 신뢰되어야 합니다.
xcrun xctrace list devices실행 시== Devices ==(== Devices Offline ==가 아님) 아래에 기기가 표시되어야 합니다.- 자동 잠금을 "안 함"으로 설정하거나 기록 중에 디스플레이를 깨운 상태로 유지하여 iOS가 백그라운드 프로세스를 일시 중단하는 것을 방지해야 합니다.
- Python: 호스트 Mac에 Python 3.8+ (표준 라이브러리만 사용, 외부 pip 종속성 없음).
- 프로세스 권한:
--attach <PID>에get-task-allow자격이 있는 디버그 빌드 또는 개발자 프로비저닝 빌드가 필요합니다.
에이전트 규칙
자동 프로파일링 중 다음 협상 불가 규칙을 따르십시오:
- 기기 연결 상태 확인: 기록하기 전에 항상
xcrun xctrace list devices를 실행하십시오.== Devices Offline ==아래에 나열된 기기에 대해 기록을 시도하지 마십시오. - 화면 잠금 및 백그라운드 전환 방지: iOS 기기가 잠기거나 홈 화면으로 돌아가면 iOS는 프로세스를 일시 중단하거나 스로틀링하여 잘못된 측정값을 생성합니다. 기기를 깨운 상태로 유지하고 앱을 포그라운드에 유지하십시오.
- 먼저 기준을 설정하십시오: 활성 워크로드만 기록하지 마십시오. 활성 상태를 기록하기 전에 항상 유휴 기준 실행(앱 포그라운드, 기기 화면 켜짐, 워크로드 일시 중지)을 캡처하십시오. 계산:
델타 = 활성 - 기준. - 동일한 테스트 매개변수 사용: 동일한 샘플 기간(기본값:
60s), 동일한 기기 배터리 상태(배터리 20% 미만 또는 저전력 모드에서 프로파일링 방지), 동일한 테스트 입력 데이터로 실행을 비교하십시오. - 타사 Python 종속성 없음: 번들된 모든 스크립트(
scripts/compare_elements.py,scripts/parse_power.py,scripts/top_categories.py)는 Python 3 표준 라이브러리만 사용합니다. - 출력을
/tmp/ios-traces/에 저장: 모든.trace번들 및.xml내보내기를 타임스탬프 및 시나리오 태그가 포함된 파일 이름으로/tmp/ios-traces/에 저장하십시오. - 대화 컨텍스트 예산 보호: 트레이스 파일 및 원시 내보낸 XML 문서는 수십 또는 수백 메가바이트가 될 수 있습니다. 원시
.trace출력, 전체 호출 트리 또는 구문 분석되지 않은 할당 XML을 에이전트 대화 컨텍스트에 덤프하지 마십시오. 항상 번들된 Python 스크립트를 사용하여 데이터를 스트리밍, 필터링, 순위 지정 및 요약한 후 읽으십시오. - 주요 병목 지점에 집중: 수십 개의 무관한 유틸리티 함수에 걸쳐 마이크로 최적화를 분산하지 마십시오. 먼저 프로파일링하여 지배적인 기여자(예: 중복 표면 인스턴스, 고주파 타이머 재평가, 버퍼링되지 않은 I/O)를 확인하고 최적화 노력을 해당 근본 원인에만 집중하십시오.
- UI, 시각 효과 또는 핵심 동작을 절대 조용히 변경하지 마십시오: 성능 병목 현상이 시각적 충실도(예: 블러/재질, 프레임 애니메이션, 그림자, 레이아웃 전환) 또는 필수 소프트웨어 동작과 관련된 경우:
- 시각적 기능을 일방적으로 제거하거나 다운그레이드하지 마십시오.
- 공식적으로 사용자에게 먼저 권한을 요청하십시오 (인터랙티브 프롬프트 또는 명시적 채팅 메시지 사용).
- 트레이드오프를 명확히 설명하십시오: 변경 전후의 시각적 변화를 설명하고, 기능이 리소스를 소비하는 이유를 설명하며, 구체적인 예상 성능 이점을 제시하십시오 (예: "카드 보기에서 동적 그림자와 블러를 비활성화하면 GPU 평균 영향을 1.8에서 0.2로 줄이고 120Hz ProMotion 히치를 제거합니다").
- 기록 아티팩트 정리: 모든
xctrace기록은 수 GB의 일시적인 커널 트레이스(instruments*.ktrace) 및 Instruments CLI 캐시(C/com.apple.dt.InstrumentsCLI)를 사용자별 시스템 임시 폴더($TMPDIR)에 씁니다.scripts/run_trace.sh는 종료 시(성공 및 실패 모두) 자동으로 제거합니다.xctrace를 직접 실행하는 경우, 결론을 내리기 전에 직접 정리하십시오:수백 GB의 임시 기록 데이터를 남겨두고 세션을 종료하지 마십시오.find "${TMPDIR:-/tmp}" -maxdepth 1 -type f -name 'instruments*.ktrace' -delete 2>/dev/null || true
4단계 최적화 프로토콜
2단계: 진단 프로파일링 및 속성 분석
코드를 작성하기 전에 기기에서 현재 상태를 측정하고 근본 원인을 분리하십시오:
# 1. 대상 기기가 온라인이고 잠금 해제되었는지 확인 (선택적 확인;
# run_trace.sh는 --device를 생략하면 첫 번째 연결된 iPhone/iPad를 자동 감지)
xcrun xctrace list devices
BUNDLE_ID="com.example.MyApp"
# SKILL_DIR = 이 스킬이 설치된 디렉토리 (다른 곳에 설치된 경우 조정)
SKILL_DIR="$HOME/.claude/skills/ios-trace"
# 2. 60초 유휴 기준 기록 (기기 잠금 해제, 앱 포그라운드, 워크로드 일시 중지)
"$SKILL_DIR/scripts/run_trace.sh" \
--bundle-id "$BUNDLE_ID" \
--template power \
--duration 60s \
--label "01-baseline"
# 3. 앱에서 대상 워크로드 트리거, 활성 상태 기록
"$SKILL_DIR/scripts/run_trace.sh" \
--process "MyApp" \
--template power \
--duration 60s \
--label "02-pre-opt"
# 4. 최적화 전 델타 계산
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/ios-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/ios-traces/02-pre-opt-power.xml:"Active Pre-Opt"
특수 템플릿을 사용하여 병목 현상의 원인을 파악하십시오:
--template time을 실행하여 작업자 스레드의 핫 콜 트리 함수를 분리합니다.--template alloc을scripts/top_categories.py와 함께 실행하여 메모리 압력을 유발하는 쓰래싱 할당을 식별합니다.- 스크롤 중
--template hitches를 실행하여 ProMotion 디스플레이에서 렌더링 지연과 커밋 지연을 분리합니다. --template network를 실행하여 지속적인 배치되지 않은 무선 웨이크업을 감지합니다.
3단계: 타겟 코드 수정
발견 사항을 기반으로 최소한의 정밀한 수정을 적용하십시오:
- 메모리 스파이크 및 Jetsam: 전체 크기
UIImage를 로드하는 대신CGImageSourceCreateThumbnailAtIndex로 고해상도 이미지에 다운샘플링을 채택합니다. - ProMotion 히치: 복잡한 그림자 및 오프스크린 블렌딩 패스를 제거합니다. 무거운 뷰 레이아웃 계산을 메인 스레드에서 오프로드합니다.
- 무선 에너지 오버헤드: 주기적인 네트워크 요청을 통합된 페이로드 버스트로 배치하여 무선 테일 대기 전력을 제거합니다.
- 실시간 오디오: CoreAudio 렌더 콜백(
AVAudioEngine또는 RemoteIO)에서 힙 할당이 전혀 없도록 보장합니다.
애플리케이션을 다시 빌드하고 기기에 배포합니다.
4단계: 재테스트, 정량적 검토 및 결정 게이트
동일한 조건에서 프로필을 다시 실행하고 델타를 평가합니다:
# 1. 최적화 후 활성 워크로드 기록
"$SKILL_DIR/scripts/run_trace.sh" \
--process "MyApp" \
--template power \
--duration 60s \
--label "03-post-opt"
# 2. 최적화 전 vs 최적화 후를 기준과 비교
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/ios-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/ios-traces/02-pre-opt-power.xml:"Active Pre-Opt" \
/tmp/ios-traces/03-post-opt-power.xml:"Active Post-Opt"
예시 결정 출력:
시나리오 초 CPU 평균 CPU 최대 디스플레이 GPU 평균 총 명령어 명령어 M/s WiFi 송/수신
=========================================================================================================
유휴 기준 60 0.12 0.60 0.05 0.00 0.85G 14.2 0.0/0.0MB
최적화 전 활성 60 2.40 4.80 1.10 1.80 15.60G 260.0 14.2/1.8MB
최적화 후 활성 60 0.55 1.10 0.15 0.20 4.20G 70.0 2.1/0.4MB
---------------------------------------------------------------------------------------------------------
기준 대비 차이 [유휴 기준]:
최적화 전 활성 +245.8 M/s 명령어, CPU 평균 델타 +2.28, WiFi 송신 델타 +14.20MB
최적화 후 활성 +55.8 M/s 명령어, CPU 평균 델타 +0.43, WiFi 송신 델타 +2.10MB
최적화 델타 (최적화 후 vs 최적화 전):
명령어 처리량: -73.1% (70.0 vs 260.0 M/s)
CPU 평균 영향: -77.1% (0.55 vs 2.40)
GPU 평균 영향: -88.9% (0.20 vs 1.80)
WiFi 무선 트래픽: -85.2% (2.1MB vs 14.2MB)
결정 게이트 로직:
- 목표 달성: 실증 비교 테이블을 사용자에게 제시하고 종료합니다.
- 목표 미달: 이전 최적화를 유지하고, 다음 남은 핫스팟을 분리한 후 3단계와 4단계를 반복합니다.
보고 후 정리: 사용자가 최종 최적화 보고서를 수락한 후, /tmp/ios-traces/ 아래에 누적된 .trace 번들을 삭제합니다(각각 수십 GB일 수 있음). 사용자가 명시적으로 보관을 요청하지 않는 한 삭제합니다. 보고서에 표시된 최종 비교 테이블과 .xml 내보내기로 충분한 증거가 됩니다.
직접 CLI 명령어
run_trace.sh 없이 xctrace를 직접 실행하는 경우:
기록
# 실행 중인 앱에 기기에서 연결
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/ios-traces/power.trace \
--attach <PID>
# 기기에서 앱 콜드 런칭
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Time Profiler' \
--time-limit 30s \
--output /tmp/ios-traces/launch.trace \
--launch -- com.example.MyApp <LaunchArgs>
내보내기
# 전력 영향 테이블 내보내기 (CPU 명령어, 에너지, GPU, 디스플레이, WiFi/셀룰러)
xcrun xctrace export \
--input /tmp/ios-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/ios-traces/power.xml
# 할당 요약 테이블 내보내기
xcrun xctrace export \
--input /tmp/ios-traces/alloc.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='all-allocations-summary']" \
> /tmp/ios-traces/alloc.xml
템플릿 참조
scripts/run_trace.sh 및 헤드리스 xctrace를 통해 iOS에서 지원되는 Instruments 템플릿:
컴퓨팅, 배터리 및 에너지
| 템플릿 | 약칭 | 대상 메트릭 및 내보내기 스키마 | 사용 사례 |
|---|---|---|---|
Power Profiler | power | 초당 명령어 (M/s), CPU/GPU/디스플레이/WiFi/셀룰러 에너지 영향 (ProcessSubsystemPowerImpact). | 포괄적인 배터리 소모, 발열 스로틀링 및 A/B 벤치마킹. |
Time Profiler | time | 스레드별 CPU 샘플 가중치, 콜 트리 핫스팟, 메인 스레드 차단 메서드. | 높은 CPU 사용률, 실행 중인 작업자 스레드 및 핫 함수 경로. |
CPU Counters | cpu | 주기별 CPU 분기 예측 오류, 캐시 미스, 명령어 역추적. | 세분화된 마이크로아키텍처 성능 분석. |
메모리
| 템플릿 | 약칭 | 대상 메트릭 및 내보내기 스키마 | 사용 사례 |
|---|---|---|---|
Allocations | alloc | 할당 이벤트 분류 (객체별, 호출 스택별), 바이트 누수 (all-allocations-summary). | 메모리 압력, Jetsam 방지, 할당 스파이크. |
Leaks | leaks | 지속적인 바이트 누수 호출 스택 및 객체 그래프 탐색. | 해제되지 않은 순환 참조 및 Core Foundation 누수. |
UI 및 그래픽
| 템플릿 | 약칭 | 대상 메트릭 및 내보내기 스키마 | 사용 사례 |
|---|---|---|---|
Hitches | hitches | 프레임 드로우 타임라인, 히치 비율 (ms/s), 최대 히치 지속 시간 (hitches-*). | ProMotion 120Hz, 스크롤 끊김, 느린 커밋. |
Metal System Trace | metal | GPU 프레임 경계, 셰이더 컴파일, 버퍼 제출. | Metal 프레임 시간의 GPU 측 프로파일링. |
네트워크
| 템플릿 | 약칭 | 대상 메트릭 및 내보내기 스키마 | 사용 사례 |
|---|---|---|---|
Network | network | 연결 수명, 데이터 볼륨(WiFi Tx/Rx), DNS 조회, 요청 일괄 처리. | 불필요한 무선 웨이크업, 테일 에너지. |
Radiator | rad | 셀룰러 무선 상태 머신(연결됨/유휴/테일/검색), 신호 강도. | 셀룰러 무선 접속 기술(3G/LTE/5G) 전력 상태. |
오디오
| 템플릿 | 약칭 | 대상 메트릭 및 내보내기 스키마 | 사용 사례 |
|---|---|---|---|
Audio | audio | 오디오 단위 그래프 토폴로지, 콜백 지속 시간, 버퍼 언더런. | 실시간 CoreAudio 렌더 사이클. |
AVAudioEngine | avae | 엔진 구성, 노드 연결, 렌더 블록 힙 할당. | AVAudioEngine 최적화 (오디오 앱). |
스크립트 문서
scripts/run_trace.sh
단일 통합 래퍼로, 연결된 iOS 기기 감지, 자동 잠금 비활성화, xctrace 기록 및 내보내기를 처리하고, <label>-<template>.trace 및 <label>-<template>.xml을 /tmp/ios-traces/에 저장하며, 세션 정리를 수행합니다.
사용법
"$SKILL_DIR/scripts/run_trace.sh" --help
사용법: run_trace.sh [옵션]
옵션:
--process <이름> 프로세스 이름으로 연결 (예: "MyApp")
--bundle-id <ID> 번들 ID로 런칭 (예: com.example.MyApp)
--template <템플릿> Instruments 템플릿 (기본값: power)
--duration <기간> 기록 기간 (예: 60s, 30s, 120s) (기본값: 60s)
--device <UDID> 대상 기기 UDID (생략 시 첫 번째 온라인 기기 자동 감지)
--label <레이블> 출력 파일 레이블 (기본값: profile)
--no-clean 종료 시 ktrace 파일 정리 건너뛰기
--help 이 도움말 메시지 표시
참고: --process와 --bundle-id 중 정확히 하나를 제공해야 합니다.
예시
앱에 연결 (실행 중인 프로세스):
"$SKILL_DIR/scripts/run_trace.sh" --process MyApp --template power --duration 60s --label "my-baseline"
앱 콜드 런칭:
"$SKILL_DIR/scripts/run_trace.sh" --bundle-id com.example.MyApp --template time --duration 30s --label "cold-launch"
scripts/compare_elements.py
여러 .xml 내보내기를 구문 분석하고 기계 판독 가능 및 사람 판독 가능 비교를 생성합니다. 각 XML 파일은 하나의 전력 영향 점검을 나타내며, 유휴 기준, 최적화 전 활성 및 최적화 후 활성으로 전달됩니다. 점검 간 델타를 계산하고 차등 요약을 출력합니다.
사용법
python3 scripts/compare_elements.py <xml1:label1> [<xml2:label2> ...]
예시
기준 및 최적화 후 결과:
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/ios-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/ios-traces/03-post-opt-power.xml:"Active Post-Opt"
scripts/top_categories.py
할당 XML 내보내기(all-allocations-summary 스키마)를 구문 분석하고 할당 이벤트별 상위 범주를 표시합니다.
사용법
python3 scripts/top_categories.py <alloc.xml> [--limit N]
--limit 매개변수는 표시할 상위 범주 수를 제어합니다. 기본값: 20.
예시
python3 "$SKILL_DIR/scripts/top_categories.py" /tmp/ios-traces/02-pre-opt-alloc.xml --limit 10
scripts/parse_power.py
전력 영향 XML 내보내기(ProcessSubsystemPowerImpact 스키마)를 구문 분석하고 에이전트 소비를 위한 요약 JSON을 출력합니다.
사용법
python3 scripts/parse_power.py <power.xml>
트러블슈팅
기기 연결 및 감지
| 증상 | 원인 및 해결책 |
|---|---|
xctrace list devices가 기기를 표시하지 않음 | USB 케이블, 신뢰 상태 확인. Xcode > Window > Devices and Simulators에서 기기 열기. |
기기가 == Devices Offline ==에 표시됨 | 기기를 잠금 해제하고, Mac을 신뢰하고, 화면을 켠 상태로 유지. 개발자 디스크 이미지 마운트 시도. |
--attach 실패: 권한 오류 | 디버그 빌드에 get-task-allow 자격이 필요합니다. Apple 개발자 포털에서 다시 프로비저닝하거나 디버그 체계를 사용. |
run_trace.sh가 잘못된 기기를 선택함 | --device <UDID>로 명시적으로 기기 UDID를 전달. 올바른 UDID는 xcrun xctrace list devices에서 확인. |
Error Domain=DTXConnectionServicesErrorDomain Code=5 | 기기가 잠겨 있거나 연결이 끊어졌거나 화면이 꺼짐. 잠금 해제하고 연결을 다시 시작. |
macOS 허가
| 오류 | 해결책 |
|---|---|
Could not launch service: ... | 시스템 설정 > 개인정보 보호 및 보안 > 전체 디스크 접근 권한에서 터미널 앱에 전체 디스크 접근 권한을 부여. |
instruments에 대한 PID 작업, 권한 문제 | 개발 도구 권한 부여: DevToolsSecurity -enable && sudo dseditgroup -o edit -a $USER -t user _developer |