이 페이지에서는 ProfilingManager API를 사용하여 시스템 트레이스를 기록하는 방법을 보여줍니다.
ProfilingManager는 다른 프로필 유형도 기록할 수 있습니다. 이 프로세스는 시스템 트레이스를 기록하는 것과 비슷하지만 각 유형은 다른 빌더를 사용합니다. 지원되는 프로필과 빌더는 다음과 같습니다.
시스템 트레이스:
SystemTraceRequestBuilder를 사용하여 기록되며 지연 시간 분석 및 일반적인 성능 디버깅에 유용합니다.힙 덤프:
JavaHeapDumpRequestBuilder를 사용하여 기록되며 메모리 누수 감지 및 최적화에 유용합니다.힙 프로필:
HeapProfileRequestBuilder를 사용하여 기록되며 메모리 최적화에 유용합니다.호출 스택 프로필:
StackSamplingRequestBuilder를 사용하여 기록되며 코드 실행 및 지연 시간 분석을 이해하는 데 유용합니다.
종속 항목 추가
ProfilingManager API를 최대한 활용하려면 다음 Jetpack 라이브러리를 build.gradle.kts 파일에 추가하세요.
Kotlin
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.1") implementation("androidx.core:core:1.19.0") }
Groovy
dependencies { implementation 'androidx.tracing:tracing:2.0.1' implementation 'androidx.core:core:1.19.0' }
시스템 트레이스 기록
필요한 종속 항목을 추가한 후 다음 코드를 사용하여 시스템 트레이스를 기록합니다. 이 예에서는 기본 스레드에서 과도한 작업을 안전하게 관리하면서 구성 가능한 항목에서 프로파일링 세션을 시작하는 방법을 보여줍니다.
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를 만들어 프로파일링 세션을 설정합니다. 이 빌더를 사용하면ProfilingManager트레이스 설정을 맞춤설정할 수 있습니다. 빌더 맞춤설정은 선택사항입니다. 맞춤설정하지 않으면 시스템에서 기본 설정을 사용합니다.- 태그 정의.
setTag()를 사용하여 트레이스 이름에 태그를 추가합니다. 이 태그는 트레이스를 식별하는 데 도움이 됩니다. - 선택사항: 기간 설정.
setDurationMs()를 사용하여 프로파일링할 기간을 밀리초 단위로 지정합니다. 예를 들어60000은 60초 트레이스를 설정합니다. 지정된 기간 전에CancellationSignal이 트리거되지 않으면 지정된 기간이 지난 후 트레이스가 자동으로 종료됩니다. - 버퍼 정책 선택.
setBufferFillPolicy()를 사용하여 트레이스 데이터가 저장되는 방식을 정의합니다.BufferFillPolicy.RING_BUFFER는 버퍼가 가득 차면 새 데이터가 가장 오래된 데이터를 덮어쓰고 최근 활동의 연속 기록을 유지한다는 의미입니다. - 버퍼 크기 설정.
setBufferSizeKb()를 사용하여 트레이스 버퍼 사이즈를 지정합니다. 이 버퍼 사이즈를 사용하여 출력 트레이스 파일의 크기를 제어할 수 있습니다.
- 태그 정의.
선택사항: 세션 수명 주기 관리.
CancellationSignal을 만듭니다. 이 객체를 사용하면 원하는 때 언제든지 프로파일링 세션을 중지하여 길이를 정확하게 제어할 수 있습니다.결과 시작 및 수신.
requestProfiling()을 호출하면ProfilingManager가 백그라운드에서 프로파일링 세션을 시작합니다. 프로파일링이 완료되면ProfilingResult를resultCallback#accept메서드로 보냅니다. 프로파일링이 완료되면ProfilingResult는 기기에 트레이스가 저장된 경로를 를 통해ProfilingResult#getResultFilePath제공합니다. 이 파일은 프로그래매틱 방식으로 가져오거나 로컬 프로파일링의 경우 컴퓨터에서adb pull <trace_path>을(를) 실행하여 가져올 수 있습니다.커스텀 트레이스 포인트 추가. 앱의 코드에 커스텀 트레이스 포인트를 추가할 수 있습니다. 이전 코드 예에서
trace("MyApp:HeavyOperation") { ... }블록은 생성된 프로필에 커스텀 슬라이스를 만듭니다.