این صفحه نحوه ضبط ردگیری سیستم را بااستفاده از ProfilingManager API نشان میدهد.
ProfilingManager میتواند انواع دیگر نمایه را نیز ضبط کند. این فرایند مشابه
ضبط ردگیری سیستم است، اما هر نوع از سازنده متفاوتی استفاده میکند. نمایههای پشتیبانیشده و سازندگان آنها عبارتاند از:
ردگیریهای سیستم: بااستفاده از
SystemTraceRequestBuilderضبط شده است که برای تحلیل تأخیر و اشکالزدایی عملکرد کلی مفید است.رونوشتهای پشته: بااستفاده از
JavaHeapDumpRequestBuilderضبط شدهاند که برای تشخیص نشت حافظه و بهینهسازی مفید هستند.نمایههای پشته: بااستفاده از
HeapProfileRequestBuilderضبط شدهاند که برای بهینهسازی حافظه مفید هستند.نمایههای پشته فراخوانی: بااستفاده از
StackSamplingRequestBuilderضبط شدهاند، که برای درک اجرای کد و تحلیل تأخیر مفید هستند.
افزودن وابستگیها
برای داشتن بهترین تجربه با ProfilingManager API، کتابخانههای Jetpack زیر را به فایل build.gradle.kts خود اضافه کنید.
کاتلین
dependencies { implementation("androidx.tracing:tracing-ktx:2.0.5") implementation("androidx.core:core:1.19.1") }
شیک
dependencies { implementation 'androidx.tracing:tracing:2.0.5' implementation 'androidx.core:core:1.19.1' }
ضبط ردیابی سیستم
پساز افزودن وابستگیهای لازم، از کد زیر برای ضبط ردگیری سیستم استفاده کنید. این مثال نشان میدهد که چگونه میتوان یک جلسه نمایهسازی را از یک composable شروع کرد و درعینحال عملیات سنگین را بهطور ایمن خارج از رشته اصلی مدیریت کرد.
کاتلین
@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ایجاد کنید تا رشتهای را که نتایج نمایهسازی را دریافت خواهد کرد تعریف کنید. نمایهسازی در پسزمینه انجام میشود. استفاده از اجراکننده رشته غیرمیانای کاربر به جلوگیری از خطاهای «برنامه پاسخ نمیدهد» (ANR) کمک میکند اگر بعداً پردازش بیشتری به callback اضافه کنید.نتایج نمایهسازی را مدیریت کنید. یک شیء
Consumer<ProfilingResult>ایجاد کنید. سیستم از این شیء برای ارسال نتایج نمایهسازی ازProfilingManagerبه برنامه شما استفاده میکند.درخواست نمایهسازی را بسازید. برای راهاندازی جلسه نمایهسازی،
SystemTraceRequestBuilderایجاد کنید. این سازنده به شما امکان میدهد تنظیمات ردیابیProfilingManagerرا سفارشیسازی کنید. سفارشیسازی سازنده اختیاری است؛ اگر این کار را نکنید، سیستم از تنظیمات پیشفرض استفاده میکند.- برچسبی را تعریف کنید. از
setTag()برای افزودن برچسب به نام ردگیری استفاده کنید. این برچسب به شما کمک میکند ردیابی را شناسایی کنید. - اختیاری: مدت زمان را تنظیم کنید. از
setDurationMs()برای مشخص کردن مدت زمان نمایهسازی برحسب میلیثانیه استفاده کنید. برای مثال،60000ردیابی ۶۰ ثانیهای تنظیم میکند. اگرCancellationSignalقبلاز آن راهاندازی نشود، ردیابی بهطور خودکار پساز مدت مشخصشده بهپایان میرسد. - یک خطمشی بافر انتخاب کنید. از
setBufferFillPolicy()برای تعریف نحوه ذخیره دادههای ردیابی استفاده کنید.BufferFillPolicy.RING_BUFFERیعنی وقتی میانگیر پر میشود، دادههای جدید روی قدیمیترین دادهها بازنویسی میشود و سابقه پیوستهای از فعالیتهای اخیر حفظ میشود. - اندازه میانگیر را تنظیم کنید. از
setBufferSizeKb()برای مشخص کردن اندازه میانگیر برای ردیابی استفاده کنید که میتوانید از آن برای کنترل اندازه فایل ردیابی خروجی استفاده کنید.
- برچسبی را تعریف کنید. از
اختیاری: چرخه حیات جلسه را مدیریت کنید.
CancellationSignalایجاد کنید. این شیء به شما امکان میدهد جلسه نمایهسازی را هر زمان که خواستید متوقف کنید و کنترل دقیقی بر طول آن داشته باشید.شروع کنید و نتایج را دریافت کنید. وقتی با
requestProfiling()تماس میگیرید،ProfilingManagerجلسه نمایهسازی را در پسزمینه شروع میکند. وقتی نمایهسازی انجام شد،ProfilingResultرا به روشresultCallback#acceptشما ارسال میکند. اگر نمایهسازی باموفقیت بهپایان برسد،ProfilingResultمسیری را که ردگیری در آن در دستگاهتان ذخیره شده است ازطریقProfilingResult#getResultFilePathارائه میدهد. میتوانید این فایل را بهصورت برنامهنویسیشده یا برای نمایهسازی محلی با اجرایadb pull <trace_path>از رایانهتان دریافت کنید.افزودن نقاط ردیابی سفارشی. میتوانید نقاط ردیابی سفارشی را در کد برنامهتان اضافه کنید. در نمونه کد قبلی، بلوک
trace("MyApp:HeavyOperation") { ... }یک برش سفارشی در نمایه تولیدشده ایجاد میکند.