이 페이지에서는 ProfilingManager API를 사용하여 시스템 트레이스를 기록하는 방법을 보여줍니다.
ProfilingManager는 다른 프로필 유형도 기록할 수 있습니다. 이 프로세스는 시스템 트레이스를 기록하는 것과 유사하지만 유형마다 다른 빌더를 사용합니다. 지원되는 프로필과 빌더는 다음과 같습니다.
시스템 트레이스:
SystemTraceRequestBuilder를 사용하여 기록되며 지연 시간 분석 및 일반적인 성능 디버깅에 유용합니다.힙 덤프:
JavaHeapDumpRequestBuilder를 사용하여 기록되며 메모리 누수 감지 및 최적화에 유용합니다.힙 프로필:
HeapProfileRequestBuilder를 사용하여 기록되며 메모리 최적화에 유용합니다.호출 스택 프로필:
StackSamplingRequestBuilder를 사용하여 기록되며 코드 실행 및 지연 시간 분석을 이해하는 데 유용합니다.
종속 항목 추가
ProfilingManager API를 최적의 환경에서 사용하려면 다음 Jetpack 라이브러리를 build.gradle.kts 파일에 추가하세요.
Kotlin
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.5") implementation("androidx.core:core:1.19.1") }
Groovy
dependencies { implementation 'androidx.tracing:tracing:2.0.5' implementation 'androidx.core:core:1.19.1' }
시스템 트레이스 기록
필수 종속 항목을 추가한 후 다음 코드를 사용하여 시스템 트레이스를 기록합니다. 이 예시에서는 기본 스레드 외부에서 무거운 작업을 안전하게 관리하면서 컴포저블에서 프로파일링 세션을 시작하는 방법을 보여줍니다.
Kotlin
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Composable
fun ProfiledScreen(modifier: Modifier = Modifier) {
// Use the application context: requestProfiling resolves the ProfilingManager
// system service from it, so there's no reason to hand it a short-lived Activity.
val appContext = LocalContext.current.applicationContext
val scope = rememberCoroutineScope()
Button(
onClick = {
// Run the orchestration off the main thread. Profiling a heavy operation
// on the UI thread would freeze the UI (ANR) and distort the very metrics
// you're trying to capture.
//
// Note: this scope is tied to composition. If the user leaves this screen
// mid-session, the coroutine is cancelled and stopSignal.cancel() might not
// run, but setDurationMs() acts as a safety net and ends the trace.
scope.launch(Dispatchers.Default) {
val callbackExecutor = Dispatchers.IO.asExecutor()
val resultCallback = Consumer<ProfilingResult> { profilingResult ->
if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
Log.d("ProfileTest", "Result file: ${profilingResult.resultFilePath}")
} else {
// errorMessage explains the failure (e.g., rate limiting); keep it.
Log.e(
"ProfileTest",
"Profiling failed errorCode=${profilingResult.errorCode} " +
"errorMessage=${profilingResult.errorMessage}"
)
}
}
val stopSignal = CancellationSignal()
val requestBuilder = SystemTraceRequestBuilder().apply {
setCancellationSignal(stopSignal)
setTag("FOO") // Caller-supplied tag for identification.
setDurationMs(60000) // Hard cap: ends the session if cancel() never fires.
setBufferFillPolicy(BufferFillPolicy.RING_BUFFER)
setBufferSizeKb(32768)
}
// 1. Start the session. This is asynchronous system IPC. The tracing
// engine takes a moment to start and allocate buffers.
requestProfiling(appContext, requestBuilder.build(), callbackExecutor, resultCallback)
// 2. The API exposes no "profiling started" signal, so pad with a short,
// best-effort delay before running the code you care about. This is
// approximate. Increase it on slower or heavily loaded devices.
delay(STARTUP_PADDING_MS)
// 3. The session is already recording every thread in your app. This slice
// doesn't scope what's captured. It just labels this region of the
// timeline so heavyOperation() is easier to find. trace { } closes the
// section even if the block throws.
trace("MyApp:HeavyOperation") {
heavyOperation()
}
// 4. Stop recording. Until this fires or the setDurationMs() cap is
// reached (whichever comes first), the session keeps capturing app-wide
// activity.
stopSignal.cancel()
}
}
) {
Text("Run & Profile Heavy Operation")
}
}
// Best-effort wait for the system trace engine to initialize before profiling.
// There is no deterministic start callback; tune this for your target devices.
private const val STARTUP_PADDING_MS = 100L
fun heavyOperation() {
// Background computations 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(32768);
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();
}
샘플 코드는 다음 단계를 거쳐 프로파일링 세션을 설정하고 관리합니다.
실행기를 설정합니다. 프로파일링 결과를 수신할 스레드를 정의하는
Executor를 만듭니다. 프로파일링은 백그라운드에서 실행됩니다. UI 스레드가 아닌 실행자를 사용하면 나중에 콜백에 더 많은 처리를 추가하는 경우 애플리케이션 응답 없음 (ANR) 오류를 방지하는 데 도움이 됩니다.프로파일링 결과 처리
Consumer<ProfilingResult>객체를 만듭니다. 시스템은 이 객체를 사용하여ProfilingManager의 프로파일링 결과를 앱으로 다시 전송합니다.프로파일링 요청을 빌드합니다.
SystemTraceRequestBuilder를 만들어 프로파일링 세션을 설정합니다. 이 빌더를 사용하면ProfilingManagertrace 설정을 맞춤설정할 수 있습니다. 빌더 맞춤설정은 선택사항입니다. 맞춤설정하지 않으면 시스템에서 기본 설정을 사용합니다.- 태그를 정의합니다.
setTag()를 사용하여 trace 이름에 태그를 추가합니다. 이 태그는 trace를 식별하는 데 도움이 됩니다. - 선택사항: 기간을 설정합니다.
setDurationMs()를 사용하여 프로파일링할 시간을 밀리초 단위로 지정합니다. 예를 들어60000는 60초 trace를 설정합니다. 그 전에CancellationSignal가 트리거되지 않으면 지정된 기간이 지난 후 추적이 자동으로 종료됩니다. - 버퍼 정책을 선택합니다.
setBufferFillPolicy()를 사용하여 trace 데이터가 저장되는 방식을 정의합니다.BufferFillPolicy.RING_BUFFER은 버퍼가 가득 차면 새 데이터가 가장 오래된 데이터를 덮어쓰므로 최근 활동의 연속적인 기록을 유지한다는 의미입니다. - 버퍼 크기를 설정합니다.
setBufferSizeKb()를 사용하여 출력 트레이스 파일의 크기를 제어하는 데 사용할 수 있는 트레이스 버퍼 크기를 지정합니다.
- 태그를 정의합니다.
선택사항: 세션 수명 주기를 관리합니다.
CancellationSignal를 만듭니다. 이 객체를 사용하면 원할 때 언제든지 프로파일링 세션을 중지할 수 있으므로 세션 길이를 정밀하게 제어할 수 있습니다.시작 및 결과 수신
requestProfiling()를 호출하면ProfilingManager가 백그라운드에서 프로파일링 세션을 시작합니다. 프로파일링이 완료되면ProfilingResult를resultCallback#accept메서드로 전송합니다. 프로파일링이 성공적으로 완료되면ProfilingResult는ProfilingResult#getResultFilePath를 통해 트레이스가 기기에 저장된 경로를 제공합니다. 이 파일은 프로그래매틱 방식으로 가져오거나 로컬 프로파일링의 경우 컴퓨터에서adb pull <trace_path>를 실행하여 가져올 수 있습니다.커스텀 trace 지점을 추가합니다. 앱 코드에 커스텀 trace 지점을 추가할 수 있습니다. 이전 코드 예시에서
trace("MyApp:HeavyOperation") { ... }블록은 생성된 프로필에 맞춤 슬라이스를 만듭니다.