Menggunakan pengoptimalan yang dipandu profil

Sistem build Android untuk Android 13 dan yang lebih rendah mendukung penggunaan pengoptimalan terpandu profil (PGO) Clang pada modul Android native yang memiliki aturan build blueprint. Halaman ini menjelaskan Clang PGO, cara terus membuat dan memperbarui profil yang digunakan untuk PGO, dan cara mengintegrasikan PGO dengan sistem build (dengan kasus penggunaan).

Catatan: Dokumen ini menjelaskan penggunaan PGO di platform Android. Untuk mempelajari cara menggunakan PGO dari aplikasi Android, buka halaman ini.

Tentang Clang PGO

Clang dapat melakukan pengoptimalan yang dipandu profil menggunakan dua jenis profil:

  • Profil berbasis instrumentasi dibuat dari program target berinstrumen. Profil ini mendetail dan menimbulkan overhead runtime yang tinggi.
  • Profil berbasis sampling biasanya dihasilkan oleh sampler penghitung hardware. Pengukuran ini menimbulkan overhead runtime yang rendah, dan dapat dikumpulkan tanpa instrumentasi atau modifikasi apa pun pada biner. Profil ini kurang mendetail dibandingkan profil berbasis instrumentasi.

Semua profil harus dibuat dari beban kerja perwakilan yang menjalankan perilaku umum aplikasi. Meskipun Clang mendukung berbasis AST (-fprofile-instr-generate) dan berbasis LLVM IR (-fprofile-generate), Android hanya mendukung berbasis LLVM IR untuk PGO berbasis instrumentasi.

Flag berikut diperlukan untuk membuat koleksi profil:

  • -fprofile-generate untuk instrumentasi berbasis IR. Dengan opsi ini, backend menggunakan pendekatan weighted minimal spanning tree untuk mengurangi jumlah titik instrumentasi dan mengoptimalkan penempatannya ke tepi berbobot rendah (gunakan juga opsi ini untuk langkah penautan). Driver Clang secara otomatis meneruskan runtime pembuatan profil (libclang_rt.profile-arch-android.a) ke penaut. Library ini berisi rutinitas untuk menulis profil ke disk saat program keluar.
  • -gline-tables-only untuk pengumpulan profil berbasis sampling guna menghasilkan informasi debug minimal.

Profil dapat digunakan untuk PGO menggunakan -fprofile-use=pathname atau -fprofile-sample-use=pathname untuk profil berbasis instrumentasi dan berbasis sampling.

Catatan: Saat perubahan dilakukan pada kode, jika Clang tidak dapat lagi menggunakan data profil, kode tersebut akan menghasilkan peringatan -Wprofile-instr-out-of-date.

Menggunakan PGO

Penggunaan PGO melibatkan langkah-langkah berikut:

  1. Build library/file yang dapat dieksekusi dengan instrumentasi dengan meneruskan -fprofile-generate ke compiler dan penaut.
  2. Kumpulkan profil dengan menjalankan beban kerja representatif pada biner berinstrumen.
  3. Lanjutkan pemrosesan profil menggunakan utilitas llvm-profdata (untuk mengetahui detailnya, lihat Menangani file profil LLVM).
  4. Gunakan profil untuk menerapkan PGO dengan meneruskan -fprofile-use=<>.profdata ke compiler dan linker.

Untuk PGO di Android, profil harus dikumpulkan secara offline dan diperiksa bersama kode untuk memastikan build yang dapat direproduksi. Profil dapat digunakan saat kode berkembang, tetapi harus dibuat ulang secara berkala (atau setiap kali Clang memperingatkan bahwa profil sudah tidak berlaku).

Mengumpulkan profil

Clang dapat menggunakan profil yang dikumpulkan dengan menjalankan benchmark menggunakan build berinstrumen library atau dengan mengambil sampel penghitung hardware saat benchmark dijalankan. Saat ini, Android tidak mendukung penggunaan pengumpulan profil berbasis sampling, sehingga Anda harus mengumpulkan profil menggunakan build berinstrumen:

  1. Identifikasi benchmark dan kumpulan library yang secara kolektif digunakan oleh benchmark tersebut.
  2. Tambahkan properti pgo ke benchmark dan library (detail di bawah).
  3. Buat build Android dengan salinan berinstrumen dari library ini menggunakan:
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark adalah placeholder yang mengidentifikasi kumpulan library yang diinstrumentasi selama build. Input perwakilan yang sebenarnya (dan mungkin file yang dapat dieksekusi lainnya yang ditautkan ke library yang diukur) tidak khusus untuk PGO dan berada di luar cakupan dokumen ini.

  1. Flash atau sinkronkan build berinstrumen di perangkat.
  2. Jalankan benchmark untuk mengumpulkan profil.
  3. Gunakan alat llvm-profdata (dibahas di bawah) untuk memproses ulang profil dan membuatnya siap untuk diperiksa ke dalam hierarki sumber.

Menggunakan profil selama build

Periksa profil ke toolchain/pgo-profiles dalam hierarki Android. Nama harus cocok dengan yang ditentukan dalam sub-properti profile_file dari properti pgo untuk library. Sistem build otomatis meneruskan file profil ke Clang saat mem-build library. Variabel lingkungan ANDROID_PGO_DISABLE_PROFILE_USE dapat ditetapkan ke true untuk menonaktifkan PGO untuk sementara dan mengukur manfaat performanya.

Untuk menentukan direktori profil khusus produk tambahan, tambahkan direktori tersebut ke variabel pembuatan PGO_ADDITIONAL_PROFILE_DIRECTORIES di BoardConfig.mk. Jika jalur tambahan ditentukan, profil di jalur ini akan menggantikan profil di toolchain/pgo-profiles.

Saat membuat image rilis menggunakan target dist ke make, sistem build akan menulis nama file profil yang hilang ke $DIST_DIR/pgo_profile_file_missing.txt. Anda dapat memeriksa file ini untuk melihat file profil yang tidak sengaja dihapus (yang secara senyap menonaktifkan PGO).

Mengaktifkan PGO dalam file Android.bp

Untuk mengaktifkan PGO dalam file Android.bp untuk modul native, cukup tentukan properti pgo. Properti ini memiliki sub-properti berikut:

Properti Deskripsi
instrumentation Tetapkan ke true untuk PGO menggunakan instrumentasi. Default-nya adalah false.
sampling Tetapkan ke true untuk PGO menggunakan sampling. Default-nya adalah false.
benchmarks Daftar string. Modul ini dibuat untuk pembuatan profil jika benchmark dalam daftar ditentukan dalam opsi build ANDROID_PGO_INSTRUMENT.
profile_file File profil (relatif terhadap toolchain/pgo-profile) untuk digunakan dengan PGO. Build memperingatkan bahwa file ini tidak ada dengan menambahkan file ini ke $DIST_DIR/pgo_profile_file_missing.txt kecuali properti enable_profile_use ditetapkan ke false ATAU variabel build ANDROID_PGO_NO_PROFILE_USE ditetapkan ke true.
enable_profile_use Tetapkan ke false jika profil tidak boleh digunakan selama build. Dapat digunakan selama bootstrap untuk mengaktifkan pengumpulan profil atau untuk menonaktifkan PGO untuk sementara. Default-nya adalah true.
cflags Daftar flag tambahan yang akan digunakan selama build berinstrumen.

Contoh modul dengan 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",
    }
}

Jika benchmark benchmark1 dan benchmark2 menjalankan perilaku perwakilan untuk library libstatic1, libstatic2, atau libshared1, properti pgo library ini juga dapat menyertakan benchmark. Modul defaults di Android.bp dapat menyertakan spesifikasi pgo umum untuk sekumpulan library guna menghindari pengulangan aturan build yang sama untuk beberapa modul.

Untuk memilih file profil yang berbeda atau menonaktifkan PGO secara selektif untuk arsitektur, tentukan properti profile_file, enable_profile_use, dan cflags per arsitektur. Contoh (dengan target arsitektur dalam cetak tebal):

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

Untuk me-resolve referensi ke library runtime pembuatan profil selama pembuatan profil berbasis instrumentasi, teruskan flag build -fprofile-generate ke penaut. Library statis yang diinstrumentasikan dengan PGO, semua library bersama, dan biner apa pun yang secara langsung bergantung pada library statis juga harus diinstrumentasikan untuk PGO. Namun, library bersama atau file yang dapat dieksekusi tersebut tidak perlu menggunakan profil PGO, dan properti enable_profile_use-nya dapat ditetapkan ke false. Di luar batasan ini, Anda dapat menerapkan PGO ke library statis, library bersama, atau file yang dapat dieksekusi.

Menangani file profil LLVM

Menjalankan library berinstrumen atau file yang dapat dieksekusi akan menghasilkan file profil bernama default_unique_id_0.profraw di /data/local/tmp (dengan unique_id adalah hash numerik yang unik untuk library ini). Jika file ini sudah ada, runtime pembuatan profil akan menggabungkan profil baru dengan profil lama saat menulis profil. Perhatikan bahwa /data/local/tmp tidak dapat diakses oleh developer aplikasi; mereka harus menggunakan tempat seperti /storage/emulated/0/Android/data/packagename/files. Untuk mengubah lokasi file profil, tetapkan variabel lingkungan LLVM_PROFILE_FILE saat runtime.

Utilitas llvm-profdata kemudian digunakan untuk mengonversi file .profraw (dan mungkin menggabungkan beberapa file .profraw) ke file .profdata:

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

profile.profdata kemudian dapat diperiksa ke dalam hierarki sumber untuk digunakan selama build.

Jika beberapa biner/library berinstrumen dimuat selama benchmark, setiap library akan menghasilkan file .profraw terpisah dengan ID unik terpisah. Biasanya, semua file ini dapat digabungkan ke dalam satu file .profdata dan digunakan untuk build PGO. Jika library dijalankan oleh benchmark lain, library tersebut harus dioptimalkan menggunakan profil dari kedua benchmark. Dalam situasi ini, opsi show dari llvm-profdata berguna:

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

Untuk memetakan unique_id ke setiap library, telusuri output show untuk setiap unique_id guna menemukan nama fungsi yang unik untuk library.

Studi kasus: PGO untuk ART

Studi kasus ini menyajikan ART sebagai contoh yang relevan; namun, studi kasus ini bukan deskripsi akurat dari kumpulan library sebenarnya yang dibuat profilnya untuk ART atau interdependensi library tersebut.

Compiler ahead-of-time dex2oat di ART bergantung pada libart-compiler.so, yang kemudian bergantung pada libart.so. Runtime ART diimplementasikan terutama di libart.so. Benchmark untuk compiler dan runtime akan berbeda:

Benchmark Library yang dibuat profilnya
dex2oat dex2oat (dapat dieksekusi), libart-compiler.so, libart.so
art_runtime libart.so
  1. Tambahkan properti pgo berikut ke dex2oat, libart-compiler.so:
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. Tambahkan properti pgo berikut ke libart.so:
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. Buat build berinstrumen untuk benchmark dex2oat dan art_runtime menggunakan:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. Atau, buat satu build berinstrumen dengan semua library yang diinstrumentasikan menggunakan:

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

    Perintah kedua mem-build semua modul yang mengaktifkan PGO untuk pembuatan profil.

  5. Jalankan benchmark yang menggunakan dex2oat dan art_runtime untuk mendapatkan:
    • Tiga file .profraw dari dex2oat (dex2oat_exe.profdata, dex2oat_libart-compiler.profdata, dan dexeoat_libart.profdata), diidentifikasi menggunakan metode yang dijelaskan dalam Menangani file profil LLVM.
    • Satu art_runtime_libart.profdata.
  6. Buat file profdata umum untuk dex2oat yang dapat dieksekusi dan libart-compiler.so menggunakan:
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. Dapatkan profil untuk libart.so dengan menggabungkan profil dari dua benchmark:
    llvm-profdata merge -output=libart.profdata \
        dex2oat_libart.profdata art_runtime_libart.profdata

    Jumlah mentah untuk libart.so dari kedua profil mungkin berbeda karena benchmark berbeda dalam jumlah kasus pengujian dan durasi yang dijalankan. Dalam hal ini, Anda dapat menggunakan penggabungan berbobot:

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

    Perintah di atas menetapkan bobot dua kali lipat ke profil dari dex2oat. Bobot sebenarnya harus ditentukan berdasarkan pengetahuan atau eksperimen domain.

  8. Periksa file profil dex2oat.profdata dan libart.profdata ke dalam toolchain/pgo-profiles untuk digunakan selama build.