Sử dụng tính năng tối ưu hoá theo hướng dẫn của hồ sơ

Hệ thống xây dựng Android cho Android 13 trở xuống hỗ trợ sử dụng tính năng tối ưu hoá theo hướng dẫn của hồ sơ (PGO) của Clang trên các mô-đun Android gốc có quy tắc bản dựng blueprint. Trang này mô tả Clang PGO, cách liên tục tạo và cập nhật hồ sơ dùng cho PGO, cũng như cách tích hợp PGO với hệ thống xây dựng (có trường hợp sử dụng).

Lưu ý: Tài liệu này mô tả cách sử dụng PGO trong nền tảng Android. Để tìm hiểu cách sử dụng PGO từ một ứng dụng Android, hãy truy cập vào trang này.

Giới thiệu về Clang PGO

Clang có thể thực hiện tính năng tối ưu hoá theo hướng dẫn của hồ sơ bằng hai loại hồ sơ:

  • Hồ sơ dựa trên khả năng đo lường được tạo từ một chương trình mục tiêu được đo lường. Các hồ sơ này rất chi tiết và gây ra mức hao tổn thời gian chạy cao.
  • Hồ sơ dựa trên hoạt động lấy mẫu thường do các bộ đếm phần cứng lấy mẫu tạo ra. Các chỉ số này gây ra mức hao tổn thời gian chạy thấp và có thể được thu thập mà không cần đo lường hoặc sửa đổi tệp nhị phân. Các hồ sơ này ít chi tiết hơn so với hồ sơ dựa trên khả năng đo lường.

Tất cả hồ sơ phải được tạo từ một mức tải đại diện thực hiện hành vi thông thường của ứng dụng. Mặc dù Clang hỗ trợ cả dựa trên AST (-fprofile-instr-generate) và dựa trên LLVM IR (-fprofile-generate), nhưng Android chỉ hỗ trợ dựa trên LLVM IR cho PGO dựa trên đo lường.

Bạn cần có các cờ sau để tạo bản dựng cho tính năng thu thập hồ sơ:

  • -fprofile-generate cho thiết bị đo lường dựa trên hồng ngoại. Với tuỳ chọn này, phần phụ trợ sử dụng phương pháp cây lấp kín tối thiểu có trọng số để giảm số lượng điểm đo lường và tối ưu hoá vị trí của các điểm đo lường đó cho các cạnh có trọng số thấp (cũng sử dụng tuỳ chọn này cho bước liên kết). Trình điều khiển Clang tự động truyền thời gian chạy phân tích tài nguyên (libclang_rt.profile-arch-android.a) đến trình liên kết. Thư viện này chứa các quy trình để ghi hồ sơ vào ổ đĩa khi thoát chương trình.
  • -gline-tables-only để thu thập hồ sơ dựa trên hoạt động lấy mẫu nhằm tạo ra thông tin gỡ lỗi tối thiểu.

Bạn có thể sử dụng hồ sơ cho PGO bằng cách sử dụng -fprofile-use=pathname hoặc -fprofile-sample-use=pathname cho hồ sơ dựa trên đo lường và hồ sơ dựa trên lấy mẫu tương ứng.

Lưu ý: Khi bạn thực hiện các thay đổi đối với mã, nếu Clang không thể sử dụng dữ liệu hồ sơ nữa, thì mã này sẽ tạo ra cảnh báo -Wprofile-instr-out-of-date.

Sử dụng PGO

Quá trình sử dụng PGO bao gồm các bước sau:

  1. Tạo thư viện/tệp thực thi có khả năng đo lường bằng cách truyền -fprofile-generate cho trình biên dịch và trình liên kết.
  2. Thu thập hồ sơ bằng cách chạy một khối lượng công việc tiêu biểu trên tệp nhị phân được đo lường.
  3. Hậu xử lý hồ sơ bằng tiện ích llvm-profdata (để biết thông tin chi tiết, hãy xem phần Xử lý tệp hồ sơ LLVM).
  4. Sử dụng các cấu hình để áp dụng PGO bằng cách truyền -fprofile-use=<>.profdata cho trình biên dịch và trình liên kết.

Đối với PGO trong Android, bạn nên thu thập hồ sơ ngoại tuyến và kiểm tra cùng với mã để đảm bảo các bản dựng có thể tái tạo. Bạn có thể sử dụng cấu hình khi mã phát triển, nhưng phải tạo lại định kỳ (hoặc bất cứ khi nào Clang cảnh báo rằng cấu hình đã lỗi thời).

Thu thập hồ sơ

Clang có thể sử dụng các hồ sơ được thu thập bằng cách chạy phép đo điểm chuẩn bằng một bản dựng được đo lường của thư viện hoặc bằng cách lấy mẫu bộ đếm phần cứng khi chạy phép đo điểm chuẩn. Hiện tại, Android không hỗ trợ việc sử dụng tính năng thu thập hồ sơ dựa trên hoạt động lấy mẫu, vì vậy, bạn phải thu thập hồ sơ bằng một bản dựng được đo lường:

  1. Xác định một điểm chuẩn và tập hợp các thư viện do điểm chuẩn đó thực thi chung.
  2. Thêm các thuộc tính pgo vào điểm chuẩn và thư viện (thông tin chi tiết bên dưới).
  3. Tạo một bản dựng Android có bản sao được đo lường của các thư viện này bằng cách sử dụng:
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark là phần giữ chỗ xác định bộ sưu tập thư viện được đo lường trong quá trình xây dựng. Dữ liệu đầu vào đại diện thực tế (và có thể là một tệp thực thi khác liên kết với thư viện đang được đo điểm chuẩn) không dành riêng cho PGO và nằm ngoài phạm vi của tài liệu này.

  1. Truyền nhanh hoặc đồng bộ hoá bản dựng được đo lường trên một thiết bị.
  2. Chạy phép đo điểm chuẩn để thu thập hồ sơ.
  3. Sử dụng công cụ llvm-profdata (xem phần thảo luận bên dưới) để xử lý sau các hồ sơ và chuẩn bị để kiểm tra các hồ sơ đó vào cây nguồn.

Sử dụng hồ sơ trong quá trình tạo bản dựng

Kiểm tra các hồ sơ vào toolchain/pgo-profiles trong cây Android. Tên phải khớp với tên được chỉ định trong thuộc tính phụ profile_file của thuộc tính pgo cho thư viện. Hệ thống xây dựng sẽ tự động chuyển tệp hồ sơ đến Clang khi tạo thư viện. Bạn có thể đặt biến môi trường ANDROID_PGO_DISABLE_PROFILE_USE thành true để tạm thời tắt PGO và đo lường lợi ích về hiệu suất của PGO.

Để chỉ định các thư mục hồ sơ bổ sung theo sản phẩm, hãy thêm các thư mục đó vào biến tạo PGO_ADDITIONAL_PROFILE_DIRECTORIES trong BoardConfig.mk. Nếu bạn chỉ định các đường dẫn bổ sung, thì các hồ sơ trong các đường dẫn này sẽ ghi đè các hồ sơ trong toolchain/pgo-profiles.

Khi tạo hình ảnh phát hành bằng cách sử dụng mục tiêu dist cho make, hệ thống xây dựng sẽ ghi tên của các tệp hồ sơ bị thiếu vào $DIST_DIR/pgo_profile_file_missing.txt. Bạn có thể kiểm tra tệp này để xem những tệp hồ sơ nào đã bị vô tình xoá (tắt PGO một cách thầm lặng).

Bật PGO trong tệp Android.bp

Để bật PGO trong tệp Android.bp cho các mô-đun gốc, bạn chỉ cần chỉ định thuộc tính pgo. Thuộc tính này có các thuộc tính phụ sau:

Thuộc tính Nội dung mô tả
instrumentation Đặt thành true cho PGO bằng cách sử dụng tính năng đo lường. Giá trị mặc định là false.
sampling Đặt thành true cho PGO bằng cách sử dụng tính năng lấy mẫu. Giá trị mặc định là false.
benchmarks Danh sách chuỗi. Mô-đun này được tạo để lập hồ sơ nếu có điểm chuẩn nào trong danh sách được chỉ định trong tuỳ chọn bản dựng ANDROID_PGO_INSTRUMENT.
profile_file Tệp hồ sơ (so với toolchain/pgo-profile) để sử dụng với PGO. Bản dựng sẽ cảnh báo rằng tệp này không tồn tại bằng cách thêm tệp này vào $DIST_DIR/pgo_profile_file_missing.txt trừ phi thuộc tính enable_profile_use được đặt thành false HOẶC biến bản dựng ANDROID_PGO_NO_PROFILE_USE được đặt thành true.
enable_profile_use Đặt thành false nếu không nên sử dụng hồ sơ trong quá trình tạo bản dựng. Có thể dùng trong quá trình khởi động để bật tính năng thu thập hồ sơ hoặc để tạm thời tắt PGO. Giá trị mặc định là true.
cflags Danh sách các cờ bổ sung để sử dụng trong bản dựng được đo lường.

Ví dụ về mô-đun có PGO:

cc_library {
    name: "libexample",
    srcs: [
        "src1.cpp",
        "src2.cpp",
    ],
    static: [
        "libstatic1",
        "libstatic2",
    ],
    shared: [
        "libshared1",
    ]
    pgo: {
        instrumentation: true,
        benchmarks: [
            "benchmark1",
            "benchmark2",
        ],
        profile_file: "example.profdata",
    }
}

Nếu điểm chuẩn benchmark1benchmark2 thực hiện hành vi đại diện cho các thư viện libstatic1, libstatic2 hoặc libshared1, thì thuộc tính pgo của các thư viện này cũng có thể bao gồm các điểm chuẩn. Mô-đun defaults trong Android.bp có thể bao gồm một thông số kỹ thuật pgo chung cho một nhóm thư viện để tránh lặp lại cùng một quy tắc bản dựng cho một số mô-đun.

Để chọn các tệp cấu hình khác nhau hoặc tắt PGO một cách có chọn lọc cho một cấu trúc, hãy chỉ định các thuộc tính profile_file, enable_profile_usecflags cho mỗi cấu trúc. Ví dụ (với mục tiêu cấu trúc được in nổi):

cc_library {
    name: "libexample",
    srcs: [
          "src1.cpp",
          "src2.cpp",
    ],
    static: [
          "libstatic1",
          "libstatic2",
    ],
    shared: [
          "libshared1",
    ],
    pgo: {
         instrumentation: true,
         benchmarks: [
              "benchmark1",
              "benchmark2",
         ],
    }

    target: {
         android_arm: {
              pgo: {
                   profile_file: "example_arm.profdata",
              }
         },
         android_arm64: {
              pgo: {
                   profile_file: "example_arm64.profdata",
              }
         }
    }
}

Để phân giải các tệp tham chiếu đến thư viện thời gian chạy phân tích tài nguyên trong quá trình phân tích tài nguyên dựa trên đo lường, hãy truyền cờ bản dựng -fprofile-generate đến trình liên kết. Thư viện tĩnh được đo lường bằng PGO, tất cả thư viện dùng chung và mọi tệp nhị phân trực tiếp phụ thuộc vào thư viện tĩnh cũng phải được đo lường cho PGO. Tuy nhiên, các thư viện hoặc tệp thực thi dùng chung như vậy không cần sử dụng hồ sơ PGO và bạn có thể đặt thuộc tính enable_profile_use của các thư viện đó thành false. Ngoài quy định hạn chế này, bạn có thể áp dụng PGO cho mọi thư viện tĩnh, thư viện dùng chung hoặc tệp thực thi.

Xử lý tệp hồ sơ LLVM

Việc thực thi một thư viện được đo lường hoặc tệp thực thi sẽ tạo ra một tệp cấu hình có tên là default_unique_id_0.profraw trong /data/local/tmp (trong đó unique_id là một hàm băm số chỉ dành riêng cho thư viện này). Nếu tệp này đã tồn tại, thời gian chạy phân tích tài nguyên sẽ hợp nhất hồ sơ mới với hồ sơ cũ trong khi ghi hồ sơ. Xin lưu ý rằng nhà phát triển ứng dụng không thể truy cập vào /data/local/tmp; thay vào đó, họ nên sử dụng một nơi nào đó như /storage/emulated/0/Android/data/packagename/files. Để thay đổi vị trí của tệp cấu hình, hãy đặt biến môi trường LLVM_PROFILE_FILE trong thời gian chạy.

Sau đó, tiện ích llvm-profdata được dùng để chuyển đổi tệp .profraw (và có thể hợp nhất nhiều tệp .profraw) thành tệp .profdata:

  llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>

Sau đó, bạn có thể kiểm tra profile.profdata vào cây nguồn để sử dụng trong quá trình xây dựng.

Nếu nhiều tệp nhị phân/thư viện được đo lường được tải trong quá trình đo điểm chuẩn, thì mỗi thư viện sẽ tạo một tệp .profraw riêng biệt với một mã nhận dạng duy nhất riêng biệt. Thông thường, tất cả các tệp này có thể được hợp nhất thành một tệp .profdata duy nhất và được dùng cho bản dựng PGO. Trong trường hợp một thư viện được thực thi bằng một điểm chuẩn khác, thư viện đó phải được tối ưu hoá bằng cách sử dụng hồ sơ của cả hai điểm chuẩn. Trong trường hợp này, tuỳ chọn show của llvm-profdata sẽ hữu ích:

  llvm-profdata merge -output=default_unique_id.profdata default_unique_id_0.profraw
llvm-profdata show -all-functions default_unique_id.profdata

Để liên kết unique_id với từng thư viện, hãy tìm tên hàm duy nhất của thư viện trong kết quả show cho mỗi unique_id.

Nghiên cứu điển hình: PGO cho ART

Nghiên cứu điển hình này trình bày ART dưới dạng một ví dụ có thể liên tưởng; tuy nhiên, đây không phải là mô tả chính xác về tập hợp thư viện thực tế được lập hồ sơ cho ART hoặc các mối tương quan phụ thuộc lẫn nhau của chúng.

Trình biên dịch trước thời gian dex2oat trong ART phụ thuộc vào libart-compiler.so, rồi phụ thuộc vào libart.so. Thời gian chạy ART chủ yếu được triển khai trong libart.so. Các điểm chuẩn cho trình biên dịch và thời gian chạy sẽ khác nhau:

Điểm chuẩn Thư viện được phân tích tài nguyên
dex2oat dex2oat (có thể thực thi), libart-compiler.so, libart.so
art_runtime libart.so
  1. Thêm thuộc tính pgo sau vào dex2oat, libart-compiler.so:
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. Thêm thuộc tính pgo sau vào libart.so:
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. Tạo bản dựng được đo lường cho điểm chuẩn dex2oatart_runtime bằng cách sử dụng:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. Ngoài ra, hãy tạo một bản dựng được đo lường duy nhất với tất cả thư viện được đo lường bằng cách sử dụng:

        make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime
        (or)
        make ANDROID_PGO_INSTRUMENT=ALL

    Lệnh thứ hai tạo tất cả mô-đun hỗ trợ PGO để phân tích tài nguyên.

  5. Chạy phép đo điểm chuẩn thực thi dex2oatart_runtime để lấy:
    • Ba tệp .profraw từ dex2oat (dex2oat_exe.profdata, dex2oat_libart-compiler.profdatadexeoat_libart.profdata), được xác định bằng phương thức được mô tả trong phần Xử lý tệp hồ sơ LLVM.
    • Một art_runtime_libart.profdata.
  6. Tạo một tệp profdata chung cho dex2oat có thể thực thi và libart-compiler.so bằng cách sử dụng:
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. Lấy hồ sơ cho libart.so bằng cách hợp nhất các hồ sơ từ hai điểm chuẩn:
    llvm-profdata merge -output=libart.profdata \
        dex2oat_libart.profdata art_runtime_libart.profdata

    Số lượng thô của libart.so từ hai hồ sơ có thể khác nhau vì các điểm chuẩn khác nhau về số lượng trường hợp kiểm thử và thời lượng chạy. Trong trường hợp này, bạn có thể sử dụng tính năng hợp nhất có trọng số:

    llvm-profdata merge -output=libart.profdata \
        -weighted-input=2,dex2oat_libart.profdata \
        -weighted-input=1,art_runtime_libart.profdata

    Lệnh trên gán trọng số gấp đôi cho hồ sơ từ dex2oat. Trọng số thực tế phải được xác định dựa trên kiến thức về miền hoặc thử nghiệm.

  8. Kiểm tra các tệp cấu hình dex2oat.profdatalibart.profdata vào toolchain/pgo-profiles để sử dụng trong quá trình xây dựng.