Ghi lại chỉ số Macrobenchmark

Chỉ số là loại thông tin chính được lấy từ các điểm chuẩn của bạn. Các chỉ số này được chuyển đến hàm measureRepeated dưới dạng List, cho phép bạn chỉ định nhiều chỉ số được đo lường cùng một lúc. Cần có ít nhất một loại chỉ số để chạy điểm chuẩn.

Đoạn mã sau đây chỉ ra thời gian kết xuất khung hình và chỉ số của mục dấu vết tuỳ chỉnh:

Kotlin

benchmarkRule.measureRepeated(
    packageName = TARGET_PACKAGE,
    metrics = listOf(
        FrameTimingMetric(),
        TraceSectionMetric("RV CreateView"),
        TraceSectionMetric("RV OnBindView"),
    ),
    iterations = 5,
    // ...
)

Java

benchmarkRule.measureRepeated(
    TARGET_PACKAGE,     // packageName
    Arrays.asList(      // metrics
        new StartupTimingMetric(),
        new TraceSectionMetric("RV CreateView"),
        new TraceSectionMetric("RV OnBindView"),
    ),
    5,                  // Iterations
    // ...
);

Trong ví dụ này, RV CreateViewRV OnBindView là mã nhận dạng của các khối có thể theo dõi được xác định trong RecyclerView. Mã nguồn cho phương thức createViewHolder() là một ví dụ về cách bạn có thể xác định các khối có thể theo dõi trong mã của riêng mình.

StartupTimingMetric, TraceSectionMetric, FrameTimingMetricPowerMetric được đề cập chi tiết ở phần sau của tài liệu này.

Kết quả đo điểm chuẩn được xuất sang Android Studio, như minh hoạ trong hình 1. Nếu bạn xác định nhiều chỉ số, thì tất cả các chỉ số đó sẽ được kết hợp với nhau trong dữ liệu đầu ra.

Kết quả của TraceSectionMetric và FrameTimingMetric.
Hình 1. Kết quả của TraceSectionMetricFrameTimingMetric.

StartupTimingMetric

StartupTimingMetric thu thập các chỉ số về thời gian khởi động ứng dụng bằng các giá trị sau:

  • timeToInitialDisplayMs: Khoảng thời gian từ khi hệ thống nhận được ý định khởi động cho đến khi kết xuất khung hình đầu tiên của Activity đích.
  • timeToFullDisplayMs: Khoảng thời gian từ khi hệ thống nhận được ý định khởi động cho đến khi ứng dụng báo cáo là đã hiển thị đầy đủ bằng phương thức reportFullyDrawn(). Quá trình đo lường sẽ dừng khi hoàn tất quá trình kết xuất khung đầu tiên sau (hoặc có chứa) lệnh gọi reportFullyDrawn(). Thông tin đo lường này có thể không có trên Android 10 (API cấp 29) trở xuống.

StartupTimingMetric cho ra các giá trị tối thiểu, trung bình và tối đa từ các vòng lặp khởi động. Để đánh giá mức độ cải thiện khi khởi động, bạn nên tập trung vào các giá trị trung vị, vì các giá trị này cung cấp số liệu ước tính chính xác nhất về thời gian khởi động thông thường. Để biết thêm thông tin về những yếu tố cấu thành thời gian khởi động ứng dụng, hãy xem bài viết Thời gian khởi động ứng dụng.

Kết quả của StartupTimingMetric
Hình 2. Kết quả StartupTimingMetric.

Cải thiện độ chính xác về thời gian khởi động

Hai chỉ số chính giúp đo lường thời gian khởi động ứng dụng là thời gian hiển thị khung hình đầu tiên (TTID)thời gian hiển thị khung hình đầu tiên với nội dung đầy đủ (TTFD). TTID là thời gian cần thiết để hiển thị khung hình đầu tiên trên giao diện người dùng của ứng dụng. TTFD cũng bao gồm thời gian để hiển thị mọi nội dung tải không đồng bộ sau khi khung hình đầu tiên hiển thị.

TTFD được báo cáo sau khi phương thức reportFullyDrawn() của ComponentActivity được gọi. Nếu reportFullyDrawn() không được gọi, thì TTID sẽ được báo cáo. Bạn có thể cần phải trì hoãn thời điểm reportFullyDrawn() được gọi cho đến khi quá trình tải không đồng bộ hoàn tất. Ví dụ: nếu giao diện người dùng chứa một danh sách động, chẳng hạn như danh sách RecyclerView hoặc danh sách lazy, thì có thể danh sách này sẽ được điền bằng một tác vụ trong nền (hoàn tất sau khi danh sách này hiển thị lần đầu và do đó, chính là thời điểm sau khi giao diện người dùng được đánh dấu là đã được vẽ đầy đủ). Trong những trường hợp như vậy, hoạt động điền danh sách không được đưa vào quy trình đo điểm chuẩn.

Để đưa hoạt động điền danh sách vào khoảng thời gian đo điểm chuẩn, hãy lấy FullyDrawnReporter bằng cách sử dụng getFullyDrawnReporter() và thêm một trình báo cáo vào đó trong mã ứng dụng của bạn. Bạn phải loại bỏ trình báo cáo khi tác vụ trong nền hoàn tất hoạt động điền danh sách.

FullyDrawnReporter sẽ không gọi phương thức reportFullyDrawn()cho đến khi mọi trình báo cáo đã thêm được loại bỏ. Nếu bạn thêm một trình báo cáo cho đến khi tiến trình nền hoàn tất, thời gian này cũng sẽ bao gồm cả khoảng thời gian cần thiết để điền danh sách trong dữ liệu về thời gian khởi động. Điều này không làm thay đổi hành vi của ứng dụng đối với người dùng nhưng cho phép dữ liệu về thời gian khởi động bao gồm cả thời gian cần thiết để điền danh sách.

Ví dụ sau cho thấy cách bạn có thể chạy đồng thời nhiều tác vụ trong nền, trong đó mỗi tác vụ đăng ký một công cụ báo cáo riêng:

Kotlin

class MainActivity : ComponentActivity() {

    sealed interface ActivityState {
        data object LOADING : ActivityState
        data object LOADED : ActivityState
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            var activityState by remember {
                mutableStateOf(ActivityState.LOADING as ActivityState)
            }
            fullyDrawnReporter.addOnReportDrawnListener {
                activityState = ActivityState.LOADED
            }
            ReportFullyDrawnTheme {
                when(activityState) {
                    is ActivityState.LOADING -> {
                        // Display the loading UI.
                    }
                    is ActivityState.LOADED -> {
                        // Display the full UI.
                    }
                }
            }
            SideEffect {
                lifecycleScope.launch(Dispatchers.IO) {
                    fullyDrawnReporter.addReporter()

                    // Perform the background operation.

                    fullyDrawnReporter.removeReporter()
                }
                lifecycleScope.launch(Dispatchers.IO) {
                    fullyDrawnReporter.addReporter()

                    // Perform the background operation.

                    fullyDrawnReporter.removeReporter()
                }
            }
        }
    }
}

Java

public class MainActivity extends ComponentActivity {
    private FullyDrawnReporter fullyDrawnReporter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        fullyDrawnReporter = getFullyDrawnReporter();
        fullyDrawnReporter.addOnReportDrawnListener(() -> {
            // Trigger the UI update.
            return Unit.INSTANCE;
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                fullyDrawnReporter.addReporter();

                // Do the background work.

               fullyDrawnReporter.removeReporter();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                fullyDrawnReporter.addReporter();

                // Do the background work.

                fullyDrawnReporter.removeReporter();
            }
        }).start();
    }
}

reportFullyDrawn() không được gọi cho đến khi hoàn tất tất cả các tác vụ, bất kể thứ tự.

Nếu ứng dụng của bạn dùng Jetpack Compose, thì bạn có thể sử dụng các API sau để biểu thị trạng thái đã hiển thị đầy đủ:

  • ReportDrawn: cho biết thành phần kết hợp của bạn đã sẵn sàng tương tác ngay lập tức.
  • ReportDrawnWhen: sử dụng một thuộc tính, chẳng hạn như list.count > 0, để cho biết thời điểm thành phần kết hợp của bạn đã sẵn sàng tương tác.
  • ReportDrawnAfter: sử dụng phương thức tạm ngưng sau khi hoàn tất để cho biết thành phần kết hợp đã sẵn sàng tương tác.

FrameTimingMetric

FrameTimingMetric ghi lại thông tin thời gian từ các khung do một điểm chuẩn tạo ra, chẳng hạn như thao tác cuộn hoặc ảnh động, đồng thời cho ra các giá trị sau:

  • frameOverrunMs: khoảng thời gian lỡ thời hạn của một khung hình cụ thể. Số dương cho biết khung hình bị rớt và có hiện tượng giật hoặc kết xuất gián đoạn quan sát được. Số âm cho biết một khung hình nhanh hơn thời hạn bao nhiêu. Lưu ý: Giá trị này chỉ có trên Android 12 (API cấp 31) trở lên.
  • frameDurationCpuMs: khoảng thời gian cần thiết để tạo khung hình trên CPU ở cả luồng giao diện người dùng và RenderThread.

Các thông tin đo lường này được thu thập trong phạm vi phân phối: phân vị thứ 50, 90, 95 và 99.

Để biết thêm thông tin về cách xác định và cải thiện khung hình chậm, hãy xem phần Kết xuất chậm.

Kết quả FrameTimingMetric
Hình 3. Kết quả FrameTimingMetric.

TraceSectionMetric

TraceSectionMetric thu thập số lần một phần dấu vết khớp với các sectionName được cung cấp và khoảng thời gian cần thiết. Đối với thời gian, công cụ này sẽ xuất ra thời gian tối thiểu, trung bình và tối đa tính bằng mili giây. Phần dấu vết được xác định bằng lệnh gọi hàm trace(sectionName) hoặc mã giữa Trace.beginSection(sectionName)Trace.endSection() hay các biến thể không đồng bộ của chúng. Thuộc tính này luôn chọn bản sao đầu tiên của phần dấu vết được thu thập trong quá trình đo lường. Theo mặc định, tệp này chỉ đưa ra các phần dấu vết từ gói; bao gồm các quy trình bên ngoài gói của bạn, hãy đặt targetPackageOnly = false.

Để biết thêm thông tin về tính năng theo dõi, hãy xem bài viết Tổng quan về tính năng theo dõi hệ thốngXác định sự kiện tuỳ chỉnh.

TraceSectionMetric
Hình 4. Kết quả TraceSectionMetric.

PowerMetric

PowerMetric ghi lại sự thay đổi về điện năng hoặc năng lượng trong khoảng thời gian kiểm thử đối với danh mục công suất được cung cấp. Mỗi danh mục đã chọn được chia nhỏ thành các thành phần con có thể đo lường, còn các danh mục không được chọn sẽ được thêm vào chỉ số "unselected" (bỏ chọn).

Các chỉ số này đo lường mức tiêu thụ trên toàn hệ thống, chứ không phải mức tiêu thụ trên cơ sở từng ứng dụng, đồng thời chỉ áp dụng cho Pixel 6, Pixel 6 Pro và các thiết bị mới hơn:

  • power<category>Uw: mức tiêu thụ điện năng trong khoảng thời gian kiểm thử theo danh mục này.
  • energy<category>Uws: mức năng lượng được truyền trên mỗi đơn vị thời gian trong khoảng thời gian kiểm thử theo danh mục này.

Có các danh mục sau:

  • CPU
  • DISPLAY
  • GPU
  • GPS
  • MEMORY
  • MACHINE_LEARNING
  • NETWORK
  • UNCATEGORIZED

Với một số danh mục, như CPU, bạn có thể khó tách riêng công việc do các quy trình khác thực hiện khỏi công việc do ứng dụng của bạn thực hiện. Để giảm thiểu khả năng gây nhiễu này, hãy xoá hoặc hạn chế các ứng dụng và tài khoản không cần thiết.

Kết quả PowerMetric
Hình 5. Kết quả PowerMetric.