ENGINEERING ARTICLE

xctrace로 iOS 에너지 회귀 게이트 구축하기

xctrace로 iOS 에너지 회귀 게이트 구축하기

겉보기에는 평범한 목록 새로고침 로직도 CPU를 계속 활성 상태로 유지할 수 있습니다. 지나치게 짧은 간격의 타이머, 중복 네트워크 요청, 백그라운드 작업 때문에 기기 깨우기 횟수가 늘어날 수도 있습니다. 기능 테스트는 대개 이런 문제를 감지하지 못하며, 코드 커버리지에서도 이상이 드러나지 않습니다. 병합 전에 이러한 변화를 찾아내려면 OVPS 클라우드 Mac에서 테스트 환경을 고정하고, xctrace로 동일한 사용자 동작을 기록한 뒤 검증된 기준선과 결과를 비교해야 합니다.

먼저 게이트의 측정 대상을 정의하기

에너지 소비량은 실행 상황과 무관한 하나의 값으로 표현할 수 없습니다. 홈 화면에서 대기할 때, 연속으로 스크롤할 때, 이미지를 디코딩할 때, 백그라운드 동기화를 수행할 때의 리소스 특성은 모두 다르므로 하나의 기준선으로 합쳐서는 안 됩니다. 먼저 60~120초 동안 안정적으로 재현할 수 있는 핵심 경로를 선택합니다. 예를 들어 앱 실행, 메시지 목록 진입, 세 화면 분량 스크롤, 상세 화면 열기와 돌아오기를 하나의 시나리오로 구성할 수 있습니다.

각 시나리오에서 최소한 다음 조건을 기록해야 합니다.

  • App 커밋 버전과 빌드 구성
  • 기기 모델, 시스템 버전 및 배터리 잔량 범위
  • 화면 밝기, 네트워크 유형 및 저전력 모드 상태
  • 테스트 계정의 데이터 규모
  • 샘플링 시간, 워밍업 횟수 및 정식 실행 횟수

시뮬레이터는 자동화 스크립트와 동작의 안정성을 검증하는 데 적합하지만, 실제 기기의 에너지 소비를 대표할 수는 없습니다. 정식 게이트는 고정된 실제 기기에 연결해야 하며, 시뮬레이터 결과는 프로세스 활동을 판단하는 보조 증거로만 사용해야 합니다.

첫 번째 실행 결과를 그대로 사용하지 마십시오. 최초 실행에는 데이터베이스 마이그레이션, 셰이더 준비 또는 캐시 채우기가 포함될 수 있습니다. 먼저 한 번 워밍업한 다음 최소 세 번 정식으로 기록하고, 일시적인 시스템 작업에서 발생하는 잡음을 줄이기 위해 중앙값을 사용합니다.

클라우드 Mac과 테스트 기기 상태 고정하기

실행 노드에서는 Xcode의 주 버전을 고정하고 개발자 디렉터리를 명시적으로 선택해야 합니다. 대화형 Shell에서 우연히 적용된 환경 변수에 의존해서는 안 됩니다.

set -euo pipefail

export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
xcodebuild -version
xcrun xctrace version
xcrun xctrace list devices
xcrun xctrace list templates

마지막 두 명령은 호환성 검사 역할도 합니다. Xcode 버전에 따라 사용할 수 있는 템플릿과 내보내기 구조가 달라질 수 있으므로, 스크립트에서 Energy Log가 항상 존재한다고 가정해서는 안 됩니다. 템플릿을 찾지 못하면 의미 없는 빈 샘플링으로 대체하지 말고 즉시 종료한 뒤 버전 정보를 보존해야 합니다.

실제 기기는 시작 전에 항상 동일한 상태로 되돌려야 합니다. 관련 없는 앱을 종료하고, 배터리 잔량을 비슷한 범위로 유지하며, 기기 온도가 정상으로 돌아왔는지 확인하고, 자동 업데이트를 비활성화한 뒤 네트워크 상태를 안정적으로 유지합니다. 테스트 중에는 아카이브 생성, 의존성 다운로드 또는 디스크 정리 작업을 동시에 실행하지 마십시오. 공유 노드의 추가 부하는 CPU 및 I/O 측정값을 오염시킵니다.

실행 전 검사 구성하기

기기 UDID, Bundle ID, 시나리오 이름 및 커밋 번호를 동일한 실행 디렉터리에 기록합니다. 디렉터리 이름은 고유해야 하지만 토큰이나 서명 자료를 경로와 로그에 포함해서는 안 됩니다.

RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-${GIT_COMMIT:-local}"
OUT_DIR="artifacts/energy/${RUN_ID}"
mkdir -p "$OUT_DIR"

xcrun simctl list devices > "$OUT_DIR/devices.txt"
xcrun xctrace list templates > "$OUT_DIR/templates.txt"
git rev-parse HEAD > "$OUT_DIR/commit.txt"

실제 기기를 연결할 때는 첫 번째 명령을 팀에서 사용하는 기기 탐지 명령으로 바꿀 수 있습니다. 중요한 것은 명령 형식이 아니라, 실패 시 측정을 중단해 ‘기기가 연결되지 않음’을 ‘에너지 소비 감소’로 잘못 판단하지 않는 것입니다.

재현 가능한 xctrace 트레이스 기록하기

먼저 측정할 프로세스를 실행하고 워밍업을 완료한 다음 프로세스 이름으로 연결합니다. 다음 스크립트에서는 기기, 프로세스 및 템플릿을 모두 CI 매개변수로 명시해야 합니다.

DEVICE_UDID="${DEVICE_UDID:?missing DEVICE_UDID}"
PROCESS_NAME="${PROCESS_NAME:?missing PROCESS_NAME}"
TRACE="$OUT_DIR/energy.trace"

xcrun xctrace record \
  --template "Energy Log" \
  --device "$DEVICE_UDID" \
  --attach "$PROCESS_NAME" \
  --time-limit 90s \
  --output "$TRACE"

기록이 시작된 후 UI 자동화로 고정된 동작을 실행합니다. 동작 스크립트는 화면 좌표가 아니라 접근성 식별자를 사용해야 합니다. 테스트 데이터는 미리 로드하고, 네트워크 요청은 가능한 한 안정적인 테스트 환경으로 보내야 합니다. 특정 실행에서 로그인 실패, 팝업 가림 또는 목표 화면 미도달이 발생하면 해당 실행을 무효로 표시하고 중앙값 계산에서 제외해야 합니다.

xctrace가 성공을 반환했다는 것은 trace가 생성되었다는 의미일 뿐, 시나리오가 올바르게 실행되었다는 뜻은 아닙니다. 각 기록마다 UI 테스트 결과, 시작 및 종료 시간, 애플리케이션 로그 요약, 시나리오 완료 표시도 함께 보관해야 합니다. 하나라도 누락되면 게이트는 성능 통과가 아니라 ‘측정 무효’로 보고해야 합니다.

지표를 내보내 기준선과 비교하기

먼저 trace의 목차 구조를 내보내 현재 Xcode에서 제공하는 테이블을 확인한 다음, 해당 버전에 맞는 파싱 규칙을 관리합니다.

xcrun xctrace export \
  --input "$TRACE" \
  --toc \
  --output "$OUT_DIR/toc.xml"

취약한 정규식 하나로 바이너리 trace를 직접 파싱하지 마십시오. 더 안정적인 방법은 Xcode 주 버전별로 XPath 또는 XML 파서를 관리하고 원본 trace도 함께 보관하는 것입니다. 게이트에서는 지속적인 CPU 활성 상태, 스레드 깨우기, 타이머 실행 밀도, 네트워크 전송량이라는 네 가지 변화를 살펴볼 수 있습니다. 이러한 지표는 문제를 찾기 위한 단서이며, 하나의 ‘에너지 점수’로 무리하게 합쳐서는 안 됩니다.

기준선은 동일한 기기, 동일한 시나리오, 동일한 빌드 유형에서 여러 차례 정상 실행한 결과로 생성합니다. 최근 확인된 버전의 중앙값을 저장하는 동시에 각 실행의 원시 값도 보관하는 것이 좋습니다. 비교할 때는 상대적 변화와 절대 하한을 함께 적용해야 합니다. 값이 매우 작다면 두 배로 증가하더라도 엔지니어링 관점에서는 의미가 없을 수 있습니다.

이상 징후를 단계별로 처리하기

경미한 편차는 먼저 경고만 생성하고 병합을 차단하지 않습니다. 여러 차례 연속으로 임계값을 초과하거나 CPU와 깨우기 지표가 동시에 악화될 때 실패로 처리합니다. 임계값은 팀의 과거 샘플을 바탕으로 정해야 하며, 일반적인 백분율을 그대로 복사해서는 안 됩니다.

실패 보고서에는 최소한 커밋 번호, 기기 및 시스템 버전, 세 번의 샘플링 값, 중앙값, 기준선, 변화율, trace 경로, UI 시나리오 결과를 포함해야 합니다. 그래야 개발자가 ‘에너지 소비가 너무 높음’이라는 문장만 보는 대신 근거 자료를 직접 열어볼 수 있습니다.

비정상적인 트레이스에서 코드로 돌아가기

CPU 사용량이 지속적으로 높다면 먼저 메인 스레드 폴링, 이미지 처리, 반복적인 레이아웃 계산, 종료되지 않은 백그라운드 큐를 확인합니다. 깨우기 횟수가 증가했다면 짧은 주기의 타이머, 잦은 디스크 쓰기, 중복 알림, 병합되지 않은 네트워크 재시도를 집중적으로 살펴봅니다. 네트워크 활동이 비정상적이라면 페이지네이션 요청, 캐시 적중, 텔레메트리 배치, 재연결 전략을 점검해야 합니다.

흔한 오판 요인도 별도로 배제해야 합니다. 기기를 방금 충전해 온도가 달라졌거나, 최초 실행에서 아직 캐시를 생성 중이거나, 테스트 계정의 데이터 양이 변경되었거나, 시스템 팝업이 동작을 중단했거나, 클라우드 Mac에서 다른 무거운 작업이 동시에 실행되었을 수 있습니다. 수정 후에는 반드시 동일한 조건에서 세 번의 전체 측정을 다시 실행해야 하며, 한 번의 양호한 결과로 실패 기록을 덮어서는 안 됩니다.

궁극적으로 에너지 회귀 게이트의 가치는 보기 좋은 점수를 만드는 데 있지 않습니다. 테스트 시나리오, 기기 조건, 원본 트레이스, 코드 커밋을 서로 연결하는 데 있습니다. 이러한 증거를 반복해서 수집할 수 있어야 이상 원인을 명확히 귀속할 수 있으며, 게이트도 자주 건너뛰게 되는 잡음으로 전락하지 않습니다.

자주 묻는 질문

iOS 시뮬레이터만으로 에너지 회귀를 판정할 수 있나요?

아니요. 시뮬레이터는 스크립트와 시나리오 안정성을 검증하는 데 적합하지만 최종 기준선은 모델과 OS 버전을 고정한 실제 기기에서 만들어야 합니다.

기준선을 한 번 초과하면 병합을 차단해야 하나요?

아니요. 최소 세 번 측정한 중앙값을 기준선과 비교하고, 초과가 반복되며 확인 가능한 trace가 남아 있을 때만 차단하는 편이 안전합니다.

OVPS CLOUD MAC

다음 빌드는 독점 물리 노드에서 실행하세요

세 가지 Apple Silicon 구성과 현재 판매 중인 여섯 개 노드 중에서 선택할 수 있으며, 실제 이용 가능 여부는 콘솔에 실시간으로 표시되는 상태를 기준으로 합니다.

구성 선택 및 주문