방법

심층적인 성능 고려사항

전문 길이: 8분
3 작성자
Ben Weiss, Breana Tate, Jossi Wolf

마음을 가다듬고 성능에 관한 자세한 배경 정보를 살펴보세요.

Performance Spotlight Week 3일차에 오신 것을 환영합니다. 오늘은 앱 실적의 중요한 영역에 관한 세부정보와 가이드를 계속해서 공유해 드리겠습니다. 프로필 기반 최적화, Jetpack Compose 성능 개선, 백그라운드 작업 시 고려사항을 다룹니다. 바로 시작하겠습니다.

프로필 기반 최적화

기준 프로필과 시작 프로필은 Android 앱의 시작 및 런타임 성능을 개선하는 데 기본이 됩니다. 이러한 기능은 프로필 기반 최적화라는 성능 최적화 그룹에 속합니다.

앱이 패키징되면 d8 dexer가 클래스와 메서드를 가져와 앱의 classes.dex 파일을 채웁니다. 사용자가 앱을 열면 앱이 시작될 때까지 이러한 dex 파일이 하나씩 로드됩니다. 시작 프로필을 제공하면 d8이 첫 번째 classes.dex 파일에 패키징할 클래스와 메서드를 알 수 있습니다. 이 구조를 사용하면 앱이 더 적은 파일을 로드할 수 있으므로 시작 속도가 개선됩니다.

기준 프로필은 JIT (Just in Time) 컴파일 단계를 사용자 기기에서 개발자 머신으로 효과적으로 이동합니다. 생성된 사전 (AOT) 컴파일 코드는 시작 시간과 렌더링 문제를 모두 줄이는 것으로 입증되었습니다.

Trello 및 기준 프로필

Trello 앱의 엔지니어에게 기준 프로필이 앱 성능에 어떤 영향을 미치는지 물었습니다. 주요 사용자 여정에 기준 프로필을 적용한 후 Trello는 앱 시작 시간이 25 % 나 크게 감소했습니다.

image.png

Trello는 기준 프로필을 사용하여 앱의 시작 시간을 25 % 개선할 수 있었습니다.

Meta의 기준 프로필

또한 Meta의 엔지니어들이 최근에 기준 프로필로 Android 앱을 가속화하는 방법에 관한 도움말을 게시했습니다.

image.png

Meta 앱 전반에서 팀은 기준 프로필을 적용한 후 다양한 주요 측정항목이 최대 40 % 까지 개선되는 것을 확인했습니다.

이러한 기술적 개선사항은 사용자 만족도와 비즈니스 성공을 개선하는 데도 도움이 됩니다. 제품 소유자, CTO, 의사 결정권자와 공유하면 앱 성능을 개선하는 데 도움이 됩니다.

기준 프로필 시작하기

기준 프로필 또는 시작 프로필을 생성하려면 앱을 실행하는 macrobenchmark 테스트를 작성합니다. 테스트 중에 앱 컴파일 중에 사용될 프로필 데이터가 수집됩니다. 테스트는 내일 다룰 새로운 UiAutomator API를 사용하여 작성됩니다.

이와 같은 벤치마크를 작성하는 것은 간단하며 GitHub에서 전체 샘플을 확인할 수 있습니다.

  @Test

fun profileGenerator() {

    rule.collect(

        packageName = TARGET_PACKAGE,

        maxIterations = 15,

        stableIterations = 3,

        includeInStartupProfile = true

    ) {

        uiAutomator {

            startApp(TARGET_PACKAGE)

        }

    }


}

고려사항

사용자가 가장 많이 이동하는 경로에 대한 매크로벤치마크 테스트 기준 프로필과 시작 프로필을 작성하는 것으로 시작하세요. 이는 사용자가 앱에 진입하는 기본 진입점을 의미하며, 일반적으로 로그인 후입니다. 그런 다음 기준 프로필에 대해서만 더 완전한 그림을 포착하기 위해 테스트 사례를 더 작성합니다. 기준 프로필로 모든 것을 다룰 필요는 없습니다. 가장 많이 사용되는 경로를 고수하고 필드에서 성능을 측정합니다. 자세한 내용은 내일 게시물에서 확인하세요.

프로필 기반 최적화 시작하기

기준 프로필이 내부적으로 작동하는 방식을 알아보려면 Android Developers Summit의 다음 동영상을 시청하세요.

Android 빌드 시간의 프로필 기반 최적화 에피소드에서 자세히 알아보세요. 

기준 프로필과 시작 프로필에 관한 자세한 안내도 제공됩니다.

Jetpack Compose 성능 개선

Android의 UI 프레임워크에서 엔지니어링팀의 성능 투자가 결실을 맺었습니다. Jetpack Compose 버전 1.9부터 내부 긴 스크롤 벤치마크 테스트 중에 스크롤 지연이 0.2 % 로 감소했습니다. 

jankyFrames.png

이러한 개선사항은 최신 버전에 포함된 여러 기능 덕분에 가능했습니다.

맞춤설정 가능한 캐시 기간

기본적으로 지연된 레이아웃은 스크롤 방향으로 미리 한 항목만 구성하며, 화면에서 스크롤된 후에는 삭제됩니다. 이제 뷰포트의 일부 또는 dp 크기를 통해 유지할 항목의 수를 맞춤설정할 수 있습니다. 이렇게 하면 앱이 프레임 사이에 일시중지 가능한 컴포지션을 사용 설정한 후 사용 가능한 시간을 더 효율적으로 사용하여 더 많은 작업을 미리 실행할 수 있습니다.

맞춤설정 가능한 캐시 창을 사용하려면 LazyLayoutCacheWindow를 인스턴스화하고 지연 목록이나 지연 그리드에 전달하세요. 다양한 캐시 창 크기(예: 표시 영역의 50%)를 사용하여 앱의 성능을 측정합니다. 최적의 값은 콘텐츠의 구조와 항목 크기에 따라 달라집니다.

  val dpCacheWindow = LazyLayoutCacheWindow(ahead = 150.dp, behind = 100.dp)

val state = rememberLazyListState(cacheWindow = dpCacheWindow)

LazyColumn(state = state) {

    // column contents

}

일시중지 가능한 컴포지션

이 기능을 사용하면 컴포지션을 일시중지하고 작업을 여러 프레임으로 분할할 수 있습니다. API는 1.9에 도입되었으며 이제 지연 레이아웃 프리패치에서 1.10에 기본적으로 사용됩니다. 합성 시간이 긴 복잡한 항목에서 가장 큰 이점을 얻을 수 있습니다. 

image.png

추가 Compose 성능 최적화

Compose 버전 1.9와 1.10에서는 팀에서 약간 덜 명확한 여러 최적화도 진행했습니다.

내부적으로 코루틴을 사용하는 여러 API가 개선되었습니다. 예를 들어 Draggable 및 Clickable를 사용하는 경우 개발자는 반응 시간이 빨라지고 할당 수가 개선되는 것을 확인할 수 있습니다.

레이아웃 사각형 추적의 최적화로 onVisibilityChanged() 및 onLayoutRectChanged()과 같은 수정자의 성능이 개선되었습니다. 이렇게 하면 이러한 API를 명시적으로 사용하지 않는 경우에도 레이아웃 단계가 빨라집니다.

또 다른 성능 개선사항은 onPlaced()를 통해 위치를 관찰할 때 캐시된 값을 사용하는 것입니다.

백그라운드에서 텍스트 미리 가져오기

버전 1.9부터 Compose는 백그라운드 스레드에서 텍스트를 미리 가져오는 기능을 추가합니다. 이를 통해 캐시를 사전 워밍하여 텍스트 레이아웃을 더 빠르게 할 수 있으며 앱 렌더링 성능과 관련이 있습니다. 레이아웃 중에 단어 캐시가 채워지는 Android 프레임워크에 텍스트를 전달해야 합니다. 기본적으로 UI 스레드에서 실행됩니다. 백그라운드 스레드로 미리 가져오기를 오프로드하고 단어 캐시를 채우면 특히 긴 텍스트의 레이아웃 속도를 높일 수 있습니다. 백그라운드 스레드에서 미리 가져오려면 다음과 같이 LocalBackgroundTextMeasurementExecutor을 CompositionLocalProvider에 전달하여 내부적으로 BasicText를 사용하는 컴포저블에 맞춤 실행기를 전달하면 됩니다.

  val defaultTextMeasurementExecutor = Executors.newSingleThreadExecutor()

CompositionLocalProvider(

    LocalBackgroundTextMeasurementExecutor provides DefaultTextMeasurementExecutor

) {

    BasicText("Some text that should be measured on a background thread!")


}

텍스트에 따라 텍스트 렌더링 성능이 향상될 수 있습니다. 앱의 렌더링 성능이 개선되었는지 확인하려면 결과를 벤치마킹하고 비교하세요.

백그라운드 작업 성능 고려사항

백그라운드 작업은 많은 앱에서 필수적인 부분입니다. WorkManager 또는 JobScheduler와 같은 라이브러리를 사용하여 다음과 같은 작업을 실행할 수 있습니다.

  • 분석 이벤트 주기적으로 업로드
  • 백엔드 서비스와 데이터베이스 간 데이터 동기화
  • 미디어 처리 (예: 이미지 크기 조절 또는 압축)

이러한 작업을 실행하는 동안의 주요 과제는 성능과 전력 효율성의 균형을 맞추는 것입니다. WorkManager를 사용하면 이러한 균형을 달성할 수 있습니다. 전력 효율성을 높이고 사용자가 지정한 제약 조건이나 시스템에서 부과한 제약 조건 등 여러 요인의 영향을 받는 최적의 실행 창으로 작업을 지연할 수 있도록 설계되었습니다. 

하지만 WorkManager는 모든 상황에 적합한 단일 솔루션이 아닙니다. Android에는 특정 일반적인 핵심 사용자 여정 (CUJ)을 염두에 두고 특별히 설계된 여러 전력 최적화 API도 있습니다.  

위젯 업데이트,  백그라운드에서 위치 가져오기 등 이러한 작업의 일부 목록은 백그라운드 작업 방문 페이지를 참고하세요.

백그라운드 작업의 로컬 디버깅 도구: 일반적인 시나리오

백그라운드 작업을 디버그하고 작업이 지연되거나 실패한 이유를 파악하려면 시스템에서 작업을 예약한 방식을 파악해야 합니다. 

이를 위해 WorkManager에는 로컬에서 디버그하고 성능을 최적화하는 데 도움이 되는 여러 관련 도구가 있습니다 (일부는 JobScheduler에서도 작동함). 다음은 WorkManager를 사용할 때 발생할 수 있는 일반적인 시나리오와 이를 디버그하는 데 사용할 수 있는 도구에 관한 설명입니다.

예약된 작업이 실행되지 않는 이유 디버깅

예약된 작업이 지연되거나 전혀 실행되지 않는 것은 지정된 제약 조건이 충족되지 않거나 시스템에서 부과된 제약 조건 등 여러 요인 때문일 수 있습니다. 

예약된 작업이 실행되지 않는 이유를 조사하는 첫 번째 단계는 작업이 예약되었는지 확인하는 것입니다.  예약 상태를 확인한 후 작업 실행을 방해하는 충족되지 않은 제약 조건이나 사전 조건이 있는지 확인합니다.

이 시나리오를 디버깅하는 데 사용할 수 있는 도구가 몇 가지 있습니다.

Background Task Inspector

Background Task Inspector는 Android 스튜디오에 직접 통합된 강력한 도구입니다. 모든 WorkManager 작업과 연결된 상태 (실행 중, 대기열에 추가됨, 실패, 성공)를 시각적으로 표현합니다. 

Background Task Inspector로 예약된 작업이 실행되지 않는 이유를 디버그하려면 나열된 작업 상태를 참고하세요. '대기열에 추가됨' 상태는 작업이 예약되었지만 아직 실행되기를 기다리고 있음을 나타냅니다.

이점: 모든 작업을 쉽게 볼 수 있을 뿐만 아니라, 연쇄된 작업이 있는 경우 특히 유용합니다. Background Task Inspector는 이전 작업 실패가 다음 작업 실행에 영향을 미쳤는지 시각화할 수 있는 그래프 뷰를 제공합니다.

image.png

Background Task Inspector 목록 보기

image.png

Background Task Inspector 그래프 뷰

adb shell dumpsys jobscheduler

이 명령어는 지정된 제약 조건 및 시스템에서 부과한 제약 조건과 함께 활성 JobScheduler 작업 (WorkManager 작업자 포함)의 목록을 반환합니다. 작업 기록도 반환합니다. 

예정된 작업과 연결된 제약 조건을 다른 방식으로 보려면 이 옵션을 사용하세요. WorkManager 2.10.0 이전 버전의 경우 adb shell dumpsys jobscheduler는 이 이름의 작업자 목록을 반환합니다.

  [package name]/androidx.work.impl.background.systemjob.SystemJobService

앱에 작업자가 여러 개 있는 경우 WorkManager 2.10.0으로 업데이트하면 작업자 이름을 확인하고 작업자를 쉽게 구분할 수 있습니다.

  #WorkerName#@[package name]/androidx.work.impl.background.systemjob.SystemJobService

혜택: 이 명령어는 백그라운드 작업 검사기로는 확인할 수 없는 시스템에서 부과한 제약 조건 이 있는지 파악하는 데 유용합니다. 예를 들어 예약된 작업이 완료되는 창에 영향을 줄 수 있는 앱의 대기 모드 버킷이 반환됩니다.

디버그 로깅 사용 설정

맞춤 로깅을 사용 설정하여 WM—이 첨부된 상세 WorkManager 로그를 확인할 수 있습니다. 

이점: 이를 통해 작업이 예약된 시점, 제약 조건이 충족된 시점, 수명 주기 이벤트를 파악할 수 있으며 앱을 개발하는 동안 이러한 로그를 참고할 수 있습니다.

WorkInfo.StopReason

특정 작업자의 실적이 예측할 수 없는 경우 WorkInfo.getStopReason를 사용하여 이전 실행 시도에서 작업자가 중지된 이유를 프로그래매틱 방식으로 관찰할 수 있습니다. 

getWorkInfoByIdFlow를 사용하여 WorkInfo를 관찰하도록 앱을 구성하여 작업이 백그라운드 제한, 제약 조건, 빈번한 타임아웃의 영향을 받는지 또는 사용자에 의해 중지되었는지 식별하는 것이 좋습니다.

이점: WorkInfo.StopReason을 사용하여 작업자의 실적에 관한 필드 데이터를 수집할 수 있습니다.

Android vitals에서 플래그가 지정된 WorkManager에 기인한 높은 절전 모드 해제 시간 디버깅

Android vitals에는 배터리 소모에 기여하는 wake lock을 강조 표시하는 과도한 부분적인 wake lock 측정항목이 있습니다. WorkManager는 작업을 실행하기 위해 절전 모드 해제 잠금을 획득하며, 절전 모드 해제 잠금이 Google Play에서 설정한 기준을 초과하면 앱의 가시성에 영향을 미칠 수 있습니다. 직장에 기인한 절전 모드 해제 시간이 많은 이유를 어떻게 디버그할 수 있나요? 다음 도구를 사용할 수 있습니다.

Android vitals 대시보드

먼저 Android vitals 과도한 장기간 wake lock 대시보드에서 장기간 wake lock이 알람이나 다른 wake lock이 아닌 WorkManager에서 비롯된 것인지 확인합니다. 다른 API에서 생성된 절전 모드 해제 식별 문서를 사용하여 WorkManager로 인해 유지되는 절전 모드 해제를 파악할 수 있습니다. 

Perfetto

Perfetto는 시스템 트레이스를 분석하는 도구입니다. 특히 WorkManager 디버깅에 사용하는 경우 '기기 상태' 섹션을 확인하여 작업이 시작된 시간, 실행된 시간, 전력 소비에 미치는 영향을 확인할 수 있습니다. 

'기기 상태: 작업' 트랙에서 실행된 작업자와 연결된 절전 모드 해제 잠금을 확인할 수 있습니다.

deviceState.png

Perfetto의 기기 상태 섹션에 CleanupWorker 및 BlurWorker 실행이 표시됩니다.

리소스

발생할 수 있는 다른 시나리오에 사용할 수 있는 디버깅 방법의 개요는 WorkManager 디버그 페이지를 참고하세요.

이러한 메서드를 직접 사용해 보고 WorkManager 디버깅에 관해 자세히 알아보려면 고급 WorkManager 및 테스트 Codelab을 참고하세요.

다음 단계

오늘은 코드 축소를 넘어 Android 런타임과 Jetpack Compose가 실제로 앱을 렌더링하는 방법을 살펴봤습니다. 기준 프로필로 중요한 경로를 사전 컴파일하든 새로운 Compose 1.9 및 1.10 기능으로 스크롤 상태를 부드럽게 하든 이러한 도구는 앱의 느낌에 중점을 둡니다. 또한 백그라운드 작업 디버깅에 관한 권장사항을 자세히 살펴봤습니다.

Android에 질문하기

금요일에는 실적에 관한 라이브 AMA가 진행됩니다. 지금 #AskAndroid를 사용하여 질문하고 전문가의 답변을 받아보세요.

과제

월요일에 R8을 사용 설정하라는 메시지가 표시되었습니다. 오늘은 앱의 기준 프로필을 하나 생성해 주시기 바랍니다.

Android 스튜디오 Otter를 사용하면 기준 프로필 생성기 모듈 마법사를 통해 이 작업을 그 어느 때보다 쉽게 수행할 수 있습니다. 가장 중요한 사용자 여정(앱 시작 및 로그인 포함)을 선택하고 프로필을 생성합니다.

이 기기를 확보한 후 Macrobenchmark를 실행하여 CompilationMode.None과 CompilationMode.Partial을 비교합니다.

#optimizationEnabled를 사용하여 소셜 미디어에 시작 시간 개선사항을 공유하세요.

내일 시청하세요

R8로 앱을 축소하고 프로필 기반 최적화로 런타임을 최적화했습니다. 하지만 이해관계자에게 이러한 성과를 증명하려면 어떻게 해야 할까요? 프로덕션에 영향을 미치기 전에 회귀를 포착하려면 어떻게 해야 하나요?

내일 4일차: 실적 레벨링 가이드에 참여하세요. Play Vitals의 필드 데이터부터 Perfetto를 사용한 심층 로컬 추적까지 성공을 측정하는 방법을 정확히 알아봅니다.

작성자:

계속 읽기