หน้านี้แสดงวิธีบันทึกการติดตามระบบโดยใช้ ProfilingManager API
ProfilingManager ยังบันทึกโปรไฟล์ประเภทอื่นๆ ได้ด้วย กระบวนการนี้คล้ายกับการบันทึกการติดตามของระบบ แต่การติดตามแต่ละประเภทจะใช้เครื่องมือสร้างที่แตกต่างกัน โปรไฟล์ที่รองรับและผู้สร้างโปรไฟล์มีดังนี้
การติดตามระบบ: บันทึกโดยใช้
SystemTraceRequestBuilderซึ่งมีประโยชน์สำหรับการวิเคราะห์เวลาในการตอบสนองและการแก้ไขข้อบกพร่องด้านประสิทธิภาพทั่วไปฮีปดัมป์: บันทึกโดยใช้
JavaHeapDumpRequestBuilderซึ่งมีประโยชน์ในการตรวจหาและเพิ่มประสิทธิภาพหน่วยความจำรั่วไหลโปรไฟล์ฮีป: บันทึกโดยใช้
HeapProfileRequestBuilderซึ่งมีประโยชน์สำหรับการเพิ่มประสิทธิภาพหน่วยความจำโปรไฟล์สแต็กการเรียกใช้: บันทึกโดยใช้
StackSamplingRequestBuilderซึ่งมีประโยชน์ในการทำความเข้าใจการเรียกใช้โค้ดและการวิเคราะห์เวลาในการตอบสนอง
เพิ่มทรัพยากร Dependency
หากต้องการประสบการณ์การใช้งาน ProfilingManager API ที่ดีที่สุด ให้เพิ่มไลบรารี Jetpack ต่อไปนี้ลงในไฟล์ build.gradle.kts
Kotlin
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.2") implementation("androidx.core:core:1.19.0") }
ดึงดูด
dependencies { implementation 'androidx.tracing:tracing:2.0.2' implementation 'androidx.core:core:1.19.0' }
บันทึกการติดตามของระบบ
หลังจากเพิ่มการขึ้นต่อกันที่จำเป็นแล้ว ให้ใช้โค้ดต่อไปนี้เพื่อบันทึกการติดตามระบบ ตัวอย่างนี้แสดงวิธีเริ่มเซสชันการทำโปรไฟล์จาก Composable ขณะจัดการการดำเนินการหนักๆ นอกเทรดหลักอย่างปลอดภัย
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();
}
โค้ดตัวอย่างจะตั้งค่าและจัดการเซสชันการทำโปรไฟล์โดยทำตาม ขั้นตอนต่อไปนี้
ตั้งค่าผู้ดำเนินการ สร้าง
Executorเพื่อกำหนดเธรดที่จะ รับผลลัพธ์การทำโปรไฟล์ การทำโปรไฟล์จะเกิดขึ้นในเบื้องหลัง การใช้ ตัวเรียกใช้เธรดที่ไม่ใช่ UI จะช่วยป้องกันข้อผิดพลาดแอปพลิเคชันไม่ตอบสนอง (ANR) หากคุณเพิ่มการประมวลผลลงใน Callback ในภายหลังจัดการผลการทำโปรไฟล์ สร้างออบเจ็กต์
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") { ... }จะสร้างชิ้นที่กำหนดเองใน โปรไฟล์ที่สร้างขึ้น