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

Hệ thống xây dựng Android dành cho Android 13 trở xuống hỗ trợ sử dụng tính năng tối ưu hóa theo hướng dẫn hồ sơ (PGO) của Clang trên các mô-đun Android gốc có quy tắc xây dựng bản thiết kế. Trang này mô tả Clang PGO, cách liên tục tạo và cập nhật các cấu hình được 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ả việc sử dụng PGO trong nền tảng Android. Để tìm hiểu về cách sử dụng PGO từ ứng dụng Android, hãy truy cập trang này .

Giới thiệu về Clang PGO

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

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

Tất cả hồ sơ phải được tạo từ khối lượng công việc đại diện để thực hiện hành vi điển hình của ứng dụng. Trong khi Clang hỗ trợ cả dựa trên AST ( -fprofile-instr-generate ) và dựa trên LLVM IR ( -fprofile-generate) , Android chỉ hỗ trợ dựa trên LLVM IR cho PGO dựa trên thiết bị đo đạc.

Cần có các cờ sau để xây dựng bộ sưu tập hồ sơ:

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

Một cấu hình có thể được sử dụng cho PGO bằng cách sử dụng -fprofile-use= pathname hoặc -fprofile-sample-use= pathname cho các cấu hình dựa trên thiết bị đo và lấy mẫu tương ứng.

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

Sử dụng PGO

Sử dụng PGO bao gồm các bước sau:

  1. Xây dựng thư viện/có thể thực thi bằng thiết bị đo bằng cách chuyển -fprofile-generate tới 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 khối lượng công việc đại diện trên tệp nhị phân được đo lường.
  3. Xử lý hậu kỳ các cấu hình bằng tiện ích llvm-profdata (để biết chi tiết, xem 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 chuyển -fprofile-use=<>.profdata đến trình biên dịch và trình liên kết.

Đối với PGO trong Android, hồ sơ phải được thu thập ngoại tuyến và được kiểm tra cùng với mã để đảm bảo các bản dựng có thể tái tạo. Cấu hình có thể được sử dụng khi mã phát triển nhưng phải được 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 đã cũ).

Thu thập hồ sơ

Clang có thể sử dụng các cấu hình được thu thập bằng cách chạy điểm chuẩn bằng cách sử dụng bản dựng thư viện được thiết kế sẵn hoặc bằng cách lấy mẫu bộ đếm phần cứng khi điểm chuẩn được chạy. Tại thời điểm này, Android không hỗ trợ sử dụng bộ sưu tập hồ sơ dựa trên mẫu, do đó bạn phải thu thập hồ sơ bằng cách sử dụng 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 được thực hiện chung theo điểm chuẩn đó.
  2. Thêm thuộc tính pgo vào điểm chuẩn và thư viện (chi tiết bên dưới).
  3. Tạo bản dựng Android bằng bản sao công cụ của các thư viện này bằng cách sử dụng:
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark là một trình giữ chỗ xác định tập hợp các thư viện được thiết kế trong quá trình xây dựng. Các đầ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. Flash hoặc đồng bộ hóa bản dựng thiết bị trên thiết bị.
  2. Chạy điểm chuẩn để thu thập hồ sơ.
  3. Sử dụng công cụ llvm-profdata (được thảo luận bên dưới) để xử lý hậu kỳ các cấu hình và chuẩn bị sẵn sàng để kiểm tra chúng vào cây nguồn.

Sử dụng hồ sơ trong quá trình xây dựng

Kiểm tra các cấu hình trong 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 tự động chuyển tệp hồ sơ cho Clang khi xây dựng thư viện. Biến môi trường ANDROID_PGO_DISABLE_PROFILE_USE có thể được đặt thành true để tạm thời vô hiệu hóa PGO và đo lường lợi ích hiệu suất của nó.

Để chỉ định các thư mục hồ sơ bổ sung dành riêng cho sản phẩm, hãy thêm chúng vào biến tạo PGO_ADDITIONAL_PROFILE_DIRECTORIES trong BoardConfig.mk . Nếu các đường dẫn bổ sung được chỉ định, các cấu hình trong các đường dẫn này sẽ ghi đè các cấu hình 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 tới 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 tệp hồ sơ nào đã vô tình bị đánh rơi (điều này sẽ vô hiệu hóa PGO một cách âm thầm).

Kích hoạt PGO trong tệp Android.bp

Để bật PGO trong tệp Android.bp cho mô-đun gốc, 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:

Tài sản Sự miêu tả
instrumentation Đặt thành true cho PGO sử dụng thiết bị đo. Mặc định là false .
sampling Đặt thành true cho PGO bằng cách lấy mẫu. Mặc định là false .
benchmarks Danh sách các chuỗi. Mô-đun này được xây dựng để lập hồ sơ nếu bất kỳ điểm chuẩn nào trong danh sách được chỉ định trong tùy chọn xây dựng ANDROID_PGO_INSTRUMENT .
profile_file Tệp hồ sơ (liên quan đến toolchain/pgo-profile ) để sử dụng với PGO. Bản dựng 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ừ khi 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 cấu hình không được sử dụng trong quá trình xây dựng. Có thể được sử dụng trong quá trình khởi động để kích hoạt việc thu thập hồ sơ hoặc tạm thời vô hiệu hóa PGO. Mặc định là true .
cflags Danh sách các cờ bổ sung để sử dụng trong quá trình xây dựng công cụ.

Ví dụ về mô-đun với 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 , thuộc tính pgo của các thư viện này cũng có thể bao gồm điểm chuẩn. Mô- defaults trong Android.bp có thể bao gồm đặc tả pgo chung cho một tập hợp thư viện để tránh lặp lại các quy tắc xây dựng giống nhau cho một số mô-đun.

Để chọn các tệp hồ sơ khác nhau hoặc vô hiệu hóa có chọn lọc PGO cho một kiến ​​trúc, hãy chỉ định các thuộc tính profile_file , enable_profile_usecflags cho mỗi kiến ​​trúc. Ví dụ (với mục tiêu kiến ​​trúc được in đậm ):

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",
              }
         }
    }
}

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

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

Việc thực thi một thư viện được điều chỉnh hoặc tệp thực thi sẽ tạo ra một tệp hồ sơ có tên default_ unique_id _0.profraw trong /data/local/tmp (trong đó unique_id là hàm băm số duy nhất cho thư viện này). Nếu tệp này đã tồn tại, thời gian chạy lập hồ sơ sẽ hợp nhất hồ sơ mới với hồ sơ cũ trong khi ghi hồ sơ. Lưu ý rằng nhà phát triển ứng dụng không thể truy cập /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 hồ sơ, hãy đặt biến môi trường LLVM_PROFILE_FILE khi chạy.

Sau đó, tiện ích llvm-profdata được sử 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>

profile.profdata sau đó có thể được kiểm tra trong 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ông cụ đượ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 có một ID 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 sử dụng để xây dựng PGO. Trong trường hợp thư viện được thực hiện theo điểm chuẩn khác, thư viện đó phải được tối ưu hóa bằng cách sử dụng cấu hình từ cả hai điểm chuẩn. Trong tình huống này, tùy chọn show của llvm-profdata rất 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

Để ánh xạ các Unique_id tới các thư viện riêng lẻ, hãy tìm kiếm đầu ra show cho mỗi Unique_id để biết tên hàm duy nhất cho thư viện.

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

Nghiên cứu trường hợp này trình bày ART như một ví dụ dễ hiểu; 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 sự phụ thuộc lẫn nhau của chúng.

Trình biên dịch trước dex2oat trong ART phụ thuộc vào libart-compiler.so , do đó phụ thuộc vào libart.so . Thời gian chạy ART được triển khai chủ yếu trong libart.so . Đ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 hồ sơ
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 các 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ả cá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 xây dựng tất cả các mô-đun hỗ trợ PGO để lập hồ sơ.

  5. Chạy các điểm chuẩn thực hiện dex2oatart_runtime để có được:
    • Ba tệp .profraw từ dex2oat ( dex2oat_exe.profdata , dex2oat_libart-compiler.profdatadexeoat_libart.profdata ), được xác định bằng phương pháp được mô tả trong Xử lý tệp hồ sơ LLVM .
    • Một art_runtime_libart.profdata duy nhất.
  6. Tạo một tệp profdata chung cho tệp thực thi dex2oatlibart-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ô cho libart.so từ hai cấu hình có thể khác nhau do điểm chuẩn khác nhau về số lượng trường hợp thử nghiệm và thời lượng chúng chạy. Trong trường hợp này, bạn có thể sử dụ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 cấu hình từ dex2oat . Trọng lượng thực tế phải được xác định dựa trên kiến ​​thức hoặc thử nghiệm về miền.

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