Mengelompokkan performa build

Laporkan masalah Lihat sumber

Bazel bersifat kompleks dan melakukan banyak hal yang berbeda selama build, beberapa di antaranya dapat berdampak pada performa build. Halaman ini mencoba memetakan beberapa konsep Bazel ini ke implikasinya terhadap performa build. Meskipun tidak banyak, kami telah menyertakan beberapa contoh cara mendeteksi masalah performa build melalui mengekstrak metrik dan tindakan yang dapat Anda lakukan untuk memperbaikinya. Dengan demikian, kami harap Anda dapat menerapkan konsep tersebut saat menyelidiki regresi performa build.

Build Bersih vs Inkremental

Clean build adalah build yang membangun semuanya dari awal, sedangkan build inkremental menggunakan kembali beberapa tugas yang sudah selesai.

Sebaiknya lihat build bersih dan inkremental secara terpisah, terutama saat Anda mengumpulkan / menggabungkan metrik yang bergantung pada status cache Bazel (misalnya metrik ukuran permintaan build ). Keduanya juga mewakili dua pengalaman pengguna yang berbeda. Dibandingkan dengan memulai build bersih dari awal (yang memerlukan waktu lebih lama karena cold cache), build inkremental terjadi jauh lebih sering saat developer melakukan iterasi kode (biasanya lebih cepat karena cache biasanya sudah warm).

Anda dapat menggunakan kolom CumulativeMetrics.num_analyses di BEP untuk mengklasifikasi build. Jika num_analyses <= 1, berarti build bersih; jika tidak, kita dapat mengategorikannya secara luas sebagai build inkremental - pengguna dapat beralih ke flag atau target yang berbeda, sehingga menghasilkan clean build yang efektif. Definisi inkrementalitas yang lebih ketat kemungkinan harus berbentuk heuristik, misalnya dengan melihat jumlah paket yang dimuat (PackageMetrics.packages_loaded).

Metrik build deterministik sebagai proxy untuk performa build

Mengukur performa build bisa jadi sulit diukur karena sifatnya yang tidak deterministik dari metrik tertentu (misalnya waktu CPU Bazel atau waktu antrean di cluster jarak jauh). Oleh karena itu, sebaiknya gunakan metrik deterministik sebagai proxy untuk jumlah pekerjaan yang dilakukan oleh Bazel, yang kemudian memengaruhi performanya.

Ukuran permintaan build dapat memiliki implikasi yang signifikan terhadap performa build. Build yang lebih besar dapat merepresentasikan lebih banyak pekerjaan dalam menganalisis dan membuat grafik build. Pertumbuhan build organik secara alami mengikuti pengembangan, seiring bertambahnya dependensi yang ditambahkan/dibuat, sehingga makin kompleks dan membutuhkan biaya lebih mahal untuk di-build.

Kita dapat membagi masalah ini ke dalam berbagai fase build, dan menggunakan metrik berikut sebagai metrik proxy untuk pekerjaan yang dilakukan di setiap fase:

  1. PackageMetrics.packages_loaded: jumlah paket yang berhasil dimuat. Regresi di sini menunjukkan lebih banyak pekerjaan yang perlu dilakukan untuk membaca dan mengurai setiap file BUILD tambahan dalam fase pemuatan.

    • Hal ini sering kali disebabkan oleh penambahan dependensi dan keharusan memuat penutupan transitifnya.
    • Gunakan query / cquery untuk menemukan lokasi dependensi baru yang mungkin telah ditambahkan.
  2. TargetMetrics.targets_configured: mewakili jumlah target dan aspek yang dikonfigurasi dalam build. Regresi mewakili lebih banyak pekerjaan dalam membuat dan menjelajahi grafik target yang dikonfigurasi.

    • Hal ini sering kali disebabkan oleh penambahan dependensi dan keharusan untuk membuat grafik penutupan transitifnya.
    • Gunakan cquery untuk menemukan tempat dependensi baru mungkin ditambahkan.
  3. ActionSummary.actions_created: mewakili tindakan yang dibuat dalam build, dan regresi menunjukkan lebih banyak pekerjaan dalam membuat grafik tindakan. Perlu diketahui bahwa ini juga mencakup tindakan tidak terpakai yang mungkin belum dieksekusi.

  4. ActionSummary.actions_executed: jumlah tindakan yang dieksekusi, regresi secara langsung mewakili lebih banyak pekerjaan dalam menjalankan tindakan ini.

    • BEP menulis statistik tindakan ActionData yang menunjukkan jenis tindakan yang paling banyak dijalankan. Secara default, class ini mengumpulkan 20 jenis tindakan teratas, tetapi Anda dapat meneruskan --experimental_record_metrics_for_all_mnemonics untuk mengumpulkan data ini untuk semua jenis tindakan yang dijalankan.
    • Informasi ini akan membantu Anda mengetahui jenis tindakan yang dijalankan (juga).
  5. BuildGraphSummary.outputArtifactCount: jumlah artefak yang dibuat oleh tindakan yang dieksekusi.

    • Jika jumlah tindakan yang dieksekusi tidak meningkat, kemungkinan penerapan aturan telah diubah.

Semua metrik ini dipengaruhi oleh status cache lokal. Oleh karena itu, Anda harus memastikan bahwa build yang Anda ekstrak metrik ini adalah build bersih.

Kami telah menemukan bahwa regresi dalam salah satu metrik ini dapat disertai dengan regresi waktu dinding, waktu CPU, dan penggunaan memori.

Penggunaan resource lokal

Bazel menggunakan berbagai resource di mesin lokal Anda (untuk menganalisis grafik build dan menggerakkan eksekusi, serta untuk menjalankan tindakan lokal), hal ini dapat memengaruhi performa / ketersediaan mesin Anda dalam menjalankan build, dan juga tugas lainnya.

Waktu yang dihabiskan

Mungkin metrik yang paling rentan terhadap derau (dan dapat sangat bervariasi dari build hingga build) adalah waktu; khususnya - waktu dinding, waktu CPU, dan waktu sistem. Anda dapat menggunakan bazel-bench untuk mendapatkan tolok ukur untuk metrik ini, dan dengan jumlah --runs yang memadai, Anda dapat meningkatkan data statistik yang signifikan dari pengukuran Anda.

  • Wall time adalah waktu dunia nyata yang berlalu.

    • Jika hanya terjadi regresi waktu dinding, sebaiknya kumpulkan profil rekaman aktivitas JSON dan cari perbedaannya. Jika tidak, akan lebih efisien untuk menyelidiki metrik lain yang mengalami regresi karena dapat memengaruhi waktu proses.
  • Waktu CPU adalah waktu yang dihabiskan oleh CPU untuk mengeksekusi kode pengguna.

    • Jika waktu CPU mengalami regresi di dua commit project, sebaiknya kumpulkan profil CPU Starlark. Anda mungkin juga harus menggunakan --nobuild untuk membatasi build ke fase analisis karena di situlah sebagian besar pekerjaan berat CPU dilakukan.
  • Waktu sistem adalah waktu yang dihabiskan oleh CPU di dalam {i>kernel<i}.

    • Jika waktu sistem menurun, sebagian besar masalah terkait dengan I/O saat Bazel membaca file dari sistem file Anda.

Pembuatan profil beban di seluruh sistem

Dengan menggunakan flag --experimental_collect_load_average_in_profiler yang diperkenalkan di Bazel 6.0, profiler pelacakan JSON mengumpulkan rata-rata pemuatan sistem selama pemanggilan.

Profil yang menyertakan beban sistem rata-rata

Gambar 1. Profil yang menyertakan rata-rata beban sistem.

Beban tinggi selama pemanggilan Bazel dapat menjadi indikasi bahwa Bazel menjadwalkan terlalu banyak tindakan lokal secara paralel untuk mesin Anda. Sebaiknya pertimbangkan untuk menyesuaikan --local_cpu_resources dan --local_ram_resources, terutama di lingkungan penampung (setidaknya hingga #16512 digabungkan).

Memantau penggunaan memori Bazel

Ada dua sumber utama untuk mendapatkan penggunaan memori Bazel, info Bazel dan BEP.

  • bazel info used-heap-size-after-gc: Jumlah memori yang digunakan dalam byte setelah panggilan ke System.gc().

    • Bazel bench juga menyediakan tolok ukur untuk metrik ini.
    • Selain itu, ada peak-heap-size, max-heap-size, used-heap-size, dan committed-heap-size (lihat dokumentasi), tetapi kurang relevan.
  • MemoryMetrics.peak_post_gc_heap_size BEP: Ukuran ukuran heap JVM puncak dalam byte pasca GC (memerlukan setelan --memory_profile yang mencoba memaksa GC penuh).

Regresi dalam penggunaan memori biasanya akibat dari regresi dalam metrik ukuran permintaan build, yang sering kali disebabkan oleh penambahan dependensi atau perubahan dalam implementasi aturan.

Untuk menganalisis jejak memori Bazel pada tingkat yang lebih terperinci, sebaiknya gunakan profiler memori bawaan untuk aturan.

Pembuatan profil memori pekerja persisten

Meskipun pekerja persisten dapat membantu mempercepat build secara signifikan (terutama untuk bahasa yang ditafsirkan), jejak memori mereka dapat menjadi masalah. Bazel mengumpulkan metrik pada pekerjanya, khususnya, kolom WorkerMetrics.WorkerStats.worker_memory_in_kb memberi tahu berapa banyak memori yang digunakan pekerja (dengan mnemonic).

Profiler pelacakan JSON juga mengumpulkan penggunaan memori pekerja persisten selama pemanggilan dengan meneruskan flag --experimental_collect_system_network_usage (baru di Bazel 6.0).

Profil yang menyertakan penggunaan memori pekerja

Gambar 2. Profil yang menyertakan penggunaan memori pekerja.

Menurunkan nilai --worker_max_instances (default 4) dapat membantu mengurangi jumlah memori yang digunakan oleh pekerja persisten. Kami secara aktif berupaya untuk membuat resource manager dan penjadwal Bazel menjadi lebih cerdas, sehingga penyesuaian semacam itu akan lebih jarang diperlukan di masa mendatang.

Memantau traffic jaringan untuk build jarak jauh

Dalam eksekusi jarak jauh, Bazel mendownload artefak yang dibuat sebagai hasil dari tindakan eksekusi. Dengan demikian, bandwidth jaringan Anda dapat memengaruhi performa build.

Jika menggunakan eksekusi jarak jauh untuk build Anda, sebaiknya pertimbangkan untuk memantau traffic jaringan selama pemanggilan menggunakan proto NetworkMetrics.SystemNetworkStats dari BEP (memerlukan penerusan --experimental_collect_system_network_usage).

Selain itu, profil rekaman aktivitas JSON memungkinkan Anda melihat penggunaan jaringan seluruh sistem selama proses build dengan meneruskan flag --experimental_collect_system_network_usage (baru di Bazel 6.0).

Profil yang menyertakan penggunaan jaringan di seluruh sistem

Gambar 3. Profil yang mencakup penggunaan jaringan di seluruh sistem.

Penggunaan jaringan yang tinggi tetapi rata saat menggunakan eksekusi jarak jauh dapat menunjukkan bahwa jaringan merupakan bottleneck dalam build Anda. Jika Anda belum menggunakannya, pertimbangkan untuk mengaktifkan Build tanpa Byte dengan meneruskan --remote_download_minimal. Tindakan ini akan mempercepat build dengan menghindari download artefak perantara yang tidak diperlukan.

Opsi lainnya adalah mengonfigurasi cache disk lokal untuk menghemat bandwidth download.