앱 기반 프로파일링

이 페이지에서는 ProfilingManager API를 사용하여 시스템 트레이스를 기록하는 방법을 보여줍니다.

ProfilingManager는 다른 프로필 유형도 기록할 수 있습니다. 이 프로세스는 시스템 트레이스를 기록하는 것과 비슷하지만 각 유형은 다른 빌더를 사용합니다. 지원되는 프로필과 빌더는 다음과 같습니다.

  • 시스템 트레이스: SystemTraceRequestBuilder를 사용하여 기록되며 지연 시간 분석 및 일반 성능 디버깅에 유용합니다.

  • 힙 덤프: JavaHeapDumpRequestBuilder를 사용하여 기록되며 메모리 누수 감지 및 최적화에 유용합니다.

  • 힙 프로필: HeapProfileRequestBuilder를 사용하여 기록되며 메모리 최적화에 유용합니다.

  • 호출 스택 프로필: StackSamplingRequestBuilder를 사용하여 기록되며 코드 실행 및 지연 시간 분석을 이해하는 데 유용합니다.

종속 항목 추가

ProfilingManager API를 최대한 활용하려면 다음 Jetpack 라이브러리를 build.gradle.kts 파일에 추가하세요.

Kotlin

   dependencies {
       implementation("androidx.tracing:tracing:1.3.0")
       implementation("androidx.core:core:1.18.0")
   }
   

Groovy

   dependencies {
       implementation 'androidx.tracing:tracing:1.3.0'
       implementation 'androidx.core:core:1.18.0'
   }
   

시스템 트레이스 기록

필요한 종속 항목을 추가한 후 다음 코드를 사용하여 시스템 트레이스를 기록합니다. 이 예에서는 프로파일링 세션을 시작하고 관리하기 위해 Activity 내에서 기본 설정을 보여줍니다.

Kotlin

@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
fun sampleRecordSystemTrace() {
    val mainExecutor: Executor =
        Dispatchers.IO.asExecutor() // Your choice of executor for the callback to occur on.
    val resultCallback = Consumer<ProfilingResult> { profilingResult ->
        if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
            Log.d(
                "ProfileTest",
                "Received profiling result file=" + profilingResult.resultFilePath
            )
        } else {
            Log.e(
                "ProfileTest",
                "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage
            )
        }
    }
    val stopSignal = CancellationSignal()

    val requestBuilder = SystemTraceRequestBuilder()
    requestBuilder.setCancellationSignal(stopSignal)
    requestBuilder.setTag("FOO") // Caller supplied tag for identification
    requestBuilder.setDurationMs(60000)
    requestBuilder.setBufferFillPolicy(BufferFillPolicy.RING_BUFFER)
    requestBuilder.setBufferSizeKb(20971520)
    requestProfiling(applicationContext, requestBuilder.build(), mainExecutor, resultCallback)

    // Wait some time for profiling to start.

    Trace.beginSection("MyApp:HeavyOperation")
    heavyOperation()
    Trace.endSection()

    // Once the interesting code section is profiled, stop profile
    stopSignal.cancel()
}

fun heavyOperation() {
    // Computations you want to profile
}

자바

void heavyOperation() {
  // Computations you want to profile
}

void sampleRecordSystemTrace() {
  Executor mainExecutor = Executors.newSingleThreadExecutor();
  Consumer<ProfilingResult> resultCallback =
      new Consumer<ProfilingResult>() {
        @Override
        public void accept(ProfilingResult profilingResult) {
          if (profilingResult.getErrorCode() == ProfilingResult.ERROR_NONE) {
            Log.d(
                "ProfileTest",
                "Received profiling result file=" + profilingResult.getResultFilePath());
            setupProfileUploadWorker(profilingResult.getResultFilePath());
          } else {
            Log.e(
                "ProfileTest",
                "Profiling failed errorcode="

                    + profilingResult.getErrorCode()
                    + " errormsg="
                    + profilingResult.getErrorMessage());
          }
        }
      };
  CancellationSignal stopSignal = new CancellationSignal();

  SystemTraceRequestBuilder requestBuilder = new SystemTraceRequestBuilder();
  requestBuilder.setCancellationSignal(stopSignal);
  requestBuilder.setTag("FOO");
  requestBuilder.setDurationMs(60000);
  requestBuilder.setBufferFillPolicy(BufferFillPolicy.RING_BUFFER);
  requestBuilder.setBufferSizeKb(20971520);
  Profiling.requestProfiling(getApplicationContext(), requestBuilder.build(), mainExecutor,
      resultCallback);

  // Wait some time for profiling to start.

  Trace.beginSection("MyApp:HeavyOperation");
  heavyOperation();
  Trace.endSection();

  // Once the interesting code section is profiled, stop profile
  stopSignal.cancel();
}

샘플 코드는 다음 단계를 거쳐 프로파일링 세션을 설정하고 관리합니다.

  1. 실행기 설정. Executor를 만들어 프로파일링 결과를 수신할 스레드를 정의합니다. 프로파일링은 백그라운드에서 이루어집니다. 나중에 콜백에 더 많은 처리를 추가하는 경우 비 UI 스레드 실행기를 사용하면 ANR (애플리케이션 응답 없음) 오류를 방지하는 데 도움이 됩니다.

  2. 프로파일링 결과 처리. Consumer<ProfilingResult> 객체를 만듭니다. 시스템은 이 객체를 사용하여 ProfilingManager의 프로파일링 결과를 앱에 다시 보냅니다.

  3. 프로파일링 요청 빌드. SystemTraceRequestBuilder를 만들어 프로파일링 세션을 설정합니다. 이 빌더를 사용하면 ProfilingManager 트레이스 설정을 맞춤설정할 수 있습니다. 빌더 맞춤설정은 선택사항입니다. 맞춤설정하지 않으면 시스템에서 기본 설정을 사용합니다.

    • 태그 정의. setTag()를 사용하여 트레이스 이름에 태그를 추가합니다. 이 태그는 트레이스를 식별하는 데 도움이 됩니다.
    • 선택사항: 기간 설정. setDurationMs()를 사용하여 프로파일링할 기간을 밀리초 단위로 지정합니다. 예를 들어 60000은 60초 트레이스를 설정합니다. 지정된 기간 전에 CancellationSignal이 트리거되지 않으면 지정된 기간이 지난 후 트레이스가 자동으로 종료됩니다.
    • 버퍼 정책 선택. setBufferFillPolicy()를 사용하여 트레이스 데이터가 저장되는 방식을 정의합니다. BufferFillPolicy.RING_BUFFER 는 버퍼가 가득 차면 새 데이터가 가장 오래된 데이터를 덮어쓰고 최근 활동의 연속 기록을 유지한다는 의미입니다.
    • 버퍼 크기 설정. setBufferSizeKb()를 사용하여 트레이스 버퍼 사이즈를 지정합니다. 이 버퍼 사이즈를 사용하여 출력 트레이스 파일의 크기를 제어할 수 있습니다.
  4. 선택사항: 세션 수명 주기 관리. CancellationSignal을 만듭니다. 이 객체를 사용하면 언제든지 프로파일링 세션을 중지하여 길이를 정확하게 제어할 수 있습니다.

  5. 결과 시작 및 수신. requestProfiling()을 호출하면 ProfilingManager가 백그라운드에서 프로파일링 세션을 시작합니다. 프로파일링이 완료되면 ProfilingResultresultCallback#accept 메서드로 보냅니다. 프로파일링이 성공적으로 완료되면 ProfilingResult는 기기에 트레이스가 저장된 경로를 제공합니다ProfilingResult#getResultFilePath. 이 파일은 프로그래매틱 방식으로 가져오거나 로컬 프로파일링의 경우 컴퓨터에서 adb pull <trace_path> 을(를) 실행하여 가져올 수 있습니다.

  6. 커스텀 트레이스 포인트 추가. 앱의 코드에 커스텀 트레이스 포인트를 추가할 수 있습니다. 이전 코드 예에서는 Trace.beginSection()Trace.endSection()을 사용하여 MyApp:HeavyOperation이라는 트레이스 슬라이스가 추가됩니다. 이 커스텀 슬라이스는 생성된 프로필에 표시되어 앱 내의 특정 작업을 강조표시합니다.