由应用驱动的性能分析

本页介绍了如何使用 ProfilingManager API 记录系统跟踪记录。

ProfilingManager 还可以记录其他配置文件类型。此过程与记录系统跟踪记录类似,但每种类型都使用不同的构建器。支持的配置文件及其构建器如下:

添加依赖项

为了获得最佳 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.
}

Java

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();
}

示例代码通过执行以下步骤来设置和管理性能分析会话:

  1. 设置执行器。创建一个 Executor 以定义将接收性能分析结果的线程。性能分析在后台进行。如果您稍后向回调添加更多处理,使用非界面线程执行器有助于防止应用无响应 (ANR) 错误。

  2. 处理性能分析结果。创建一个 Consumer<ProfilingResult> 对象。 系统使用此对象将 ProfilingManager 中的性能分析结果发送回您的应用。

  3. 构建性能分析请求。创建一个 SystemTraceRequestBuilder 以设置性能分析会话。借助此构建器,您可以自定义 ProfilingManager 跟踪记录设置。自定义构建器是可选的;如果您不自定义,系统将使用默认设置。

    • 定义标记。使用 setTag() 向跟踪记录名称添加标记。此标记有助于您识别跟踪记录。
    • 可选:设置时长。使用 setDurationMs() 以毫秒为单位指定性能分析时长。例如,60000 会设置 60 秒的跟踪记录。如果在指定时长之前未触发 CancellationSignal,跟踪记录会在指定时长后自动结束。
    • 选择缓冲区政策。使用 setBufferFillPolicy() 定义跟踪记录数据的存储方式。BufferFillPolicy.RING_BUFFER 表示当缓冲区已满时,新数据会覆盖最旧的数据,从而持续记录近期活动。
    • 设置缓冲区大小。使用 setBufferSizeKb() 为跟踪记录指定缓冲区空间,您可以使用该大小来控制输出跟踪记录文件的大小。
  4. 可选:管理会话生命周期。创建一个 CancellationSignal。 借助此对象,您可以随时停止性能分析会话,从而精确控制会话时长。

  5. 启动并接收结果。当您调用 requestProfiling() 时,ProfilingManager 会在后台启动性能分析会话。性能分析完成后,它会将 ProfilingResult 发送到 resultCallback#accept 方法。如果性能分析成功完成, ProfilingResult 会通过 ProfilingResult#getResultFilePath 提供跟踪记录在设备上的保存路径 。您可以通过编程方式获取此文件 ,也可以在本地进行性能分析时,通过在计算机上运行 adb pull <trace_path> 来获取此文件。

  6. 添加自定义跟踪点。您可以在应用的代码中添加自定义跟踪点。在前面的代码示例中, trace("MyApp:HeavyOperation") { ... } 块会在 生成的配置文件中创建一个自定义切片。