Ninja: Opsi untuk menggunakan karakteristik file alih-alih cap waktu

Dibuat pada 14 Agu 2018  ·  15Komentar  ·  Sumber: ninja-build/ninja

Seperti disebutkan dalam masalah lain, menggunakan stempel waktu untuk menentukan apakah akan membangun kembali sesuatu bisa menjadi masalah. Sementara stempel waktu nyaman dan relatif cepat, seringkali diinginkan untuk membuat keputusan kunci pada beberapa karakteristik intrinsik file itu sendiri, seperti hash isinya.

Saya sering menggunakan git dan itu menjengkelkan karena hanya mengubah cabang memicu pembangunan kembali. Idealnya, saya akan dapat beralih dari cabang kerja saya saat ini ke beberapa cabang lain, tidak menyentuh file apa pun dan kemudian beralih kembali ke cabang asli dan tidak perlu membangun kembali apa pun. Sejauh yang saya tahu itu tidak mungkin jika sistem build menggunakan cap waktu. Menggunakan hash file akan menyelesaikan masalah khusus ini.

Saya mengerti penggunaan hash file atau karakteristik file intrik lainnya dapat memperlambat Ninja sehingga menggunakannya harus menjadi pilihan.

feature

Komentar yang paling membantu

Saya juga menggunakan hashing di tempat kerja, dengan sukses besar. Ini didasarkan pada #929, tetapi dengan banyak tambalan, seperti yang dapat dilihat di https://github.com/moroten/ninja/commits/hashed. hash_input = 1 pada aturan yang dipilih sangat nyaman. Cabang saya masih mengandung bug di mana file stat terlalu sering, O(n^2) bukannya O(n) . Bug ini terkait dengan tepi palsu.

Satu masalah adalah bagaimana menangani tepi palsu. Saya menggunakan tepi palsu untuk mengelompokkan misalnya file header. Oleh karena itu, implementasi saya berulang secara rekursif melalui tepi palsu. Ini juga terkait dengan bug di #1021.

Pikiran lain adalah membuat hashing anggota kelas satu ninja, yaitu memindahkan hash ke dalam log build. Menggunakan SHA256 akan menjadi satu langkah untuk menambahkan dukungan untuk API eksekusi jarak jauh Bazel. Implementasi C++ dapat ditemukan di https://gitlab.com/bloomberg/recc/. Bukankah itu sangat bagus?

Sayangnya, memilah semantik untuk tepi palsu mungkin akan merusak kompatibilitas ke belakang.

Semua 15 komentar

929 memiliki implementasi. Meskipun berhasil digunakan (dalam fork) untuk ribuan build setiap hari, itu tidak dipertimbangkan untuk digabungkan.

929 adalah utas tunggal dan karenanya dapat lebih lambat seperti ccache atau solusi lainnya. Saya juga berpikir bahwa ini seharusnya menjadi flag baris perintah, sehingga tidak memerlukan perubahan pada definisi build.

Itu tidak bisa (atau setidaknya tidak boleh) menjadi bendera baris perintah, karena hashing akan berlaku untuk semua aturan. Hashing misalnya semua masukan dari aturan tautan mahal dan oleh karena itu tidak diinginkan, sedangkan file sumber dan dependensinya yang diketahui adalah kandidat yang baik. Untuk perbedaan itu, itu harus menjadi bagian dari deskripsi build. Selain itu, untuk menggunakan fitur tersebut Anda harus menggunakan flag secara konsisten setiap saat. Tidak hanya kadang-kadang.

Menanggapi argumen utas tunggal: Ya, itu menambahkan instruksi ke loop utas tunggal. Pada kenyataannya itu hanya penting jika satu utas mendapat lebih banyak pekerjaan daripada yang dapat dikerjakan (yaitu lebih banyak aturan yang selesai daripada yang dapat diproses oleh satu utas (depslog+hashlog+...)). Hanya kemudian hashing menyakitkan. Jika tidak, loop utas tunggal tetap menunggu pekerjaan selesai. Kami tidak pernah melihat ninja yang sibuk dengan hashing bahkan dengan eksperimen -j1000. (Dan untuk aturan penyelesaian cepat, hashing tetap tidak menarik untuk waktu yang aman.)

Juga pertimbangkan: hashing dengan murmur hash sangat cepat dan bahkan file sumber besar hanya membutuhkan beberapa milidetik untuk di-hash. Selain itu, hashing terjadi tepat setelah file sumber (dan dependensi) dilihat oleh kompiler. Oleh karena itu mereka biasanya dibaca dari cache sistem file.
Karena hashing terjadi selama build (bersamaan dengan aturan yang dijalankan), waktu build keseluruhan biasanya tidak terpengaruh secara terukur.

Terakhir, implementasi di #929 adalah keikutsertaan dan tidak dikenakan biaya bagi orang yang tidak menggunakan fitur tersebut (selain pernyataan if).

Hashing misalnya semua masukan dari aturan tautan mahal dan oleh karena itu tidak diinginkan, sedangkan file sumber dan dependensinya yang diketahui adalah kandidat yang baik.

Saya akan mengatakan bahwa hashing input ke penaut sangat diinginkan karena sering kali dapat mengakibatkan penautan dilewati sepenuhnya (misalnya untuk perubahan pemformatan atau ketika komentar diubah). Saat kompilasi file objek selesai sepotong demi sepotong, perhitungan hash dapat terjadi saat build sedang berjalan (seperti yang Anda tunjukkan).

Jika benar-benar terlalu lambat (misalnya dengan perpustakaan statis yang besar), kita dapat berpikir untuk mengimplementasikan hash hanya untuk input murni dan bukan file perantara. Itu akan menyelesaikan kasus "beralih cabang Git menyebabkan pembangunan kembali penuh" setidaknya.

Selain itu, untuk menggunakan fitur tersebut Anda harus menggunakan flag secara konsisten setiap saat. Tidak hanya kadang-kadang.

Saya akan mengatakan itu adalah keuntungan: Jika saya sedang mengerjakan satu cabang dan ingin mengulangi dengan cepat, saya tidak akan menggunakan hash. Jika saya membandingkan cabang fitur yang berbeda, saya akan menggunakan hash.

Selain itu, untuk menggunakan fitur tersebut Anda harus menggunakan flag secara konsisten setiap saat. Tidak hanya kadang-kadang.

Saya akan mengatakan itu adalah keuntungan: Jika saya sedang mengerjakan satu cabang dan ingin mengulangi dengan cepat, saya tidak akan menggunakan hash. Jika saya membandingkan cabang fitur yang berbeda, saya akan menggunakan hash.

Tetapi kemudian perlu ada cara untuk beralih dari non-hashing ke hashing, yang berarti bahwa status file saat ini perlu di-hash, sehingga pembangunan kembali berikutnya dapat menggunakan hash (yang mungkin tidak ada atau tidak ada tanggal jika Anda tidak melewati bendera).

Saya kira hashing masih menggunakan stempel waktu terlebih dahulu, sehingga jika stempel waktu cocok, tidak perlu membandingkan hash. Itu berarti, bahwa beberapa build pertama mungkin tidak perlu mengkompilasi ulang beberapa file, tetapi itu seharusnya tidak sering terjadi (sebagian besar waktu heuristik stempel waktu benar).

Saya juga menggunakan hashing di tempat kerja, dengan sukses besar. Ini didasarkan pada #929, tetapi dengan banyak tambalan, seperti yang dapat dilihat di https://github.com/moroten/ninja/commits/hashed. hash_input = 1 pada aturan yang dipilih sangat nyaman. Cabang saya masih mengandung bug di mana file stat terlalu sering, O(n^2) bukannya O(n) . Bug ini terkait dengan tepi palsu.

Satu masalah adalah bagaimana menangani tepi palsu. Saya menggunakan tepi palsu untuk mengelompokkan misalnya file header. Oleh karena itu, implementasi saya berulang secara rekursif melalui tepi palsu. Ini juga terkait dengan bug di #1021.

Pikiran lain adalah membuat hashing anggota kelas satu ninja, yaitu memindahkan hash ke dalam log build. Menggunakan SHA256 akan menjadi satu langkah untuk menambahkan dukungan untuk API eksekusi jarak jauh Bazel. Implementasi C++ dapat ditemukan di https://gitlab.com/bloomberg/recc/. Bukankah itu sangat bagus?

Sayangnya, memilah semantik untuk tepi palsu mungkin akan merusak kompatibilitas ke belakang.

Sementara itu saya telah membuat solusi untuk kasus penggunaan saya berpindah cabang di Chromium (yang sangat menyakitkan); program dan skrip Go kecil yang saya gunakan ada di sini: https://github.com/bromite/mtool

Jangan ragu untuk menyesuaikannya dengan kasus penggunaan Anda, jika berfungsi untuk Chromium, saya yakin itu juga akan berfungsi untuk proyek pembangunan yang lebih kecil (dan butuh waktu yang dapat diabaikan untuk menjalankan saya). Satu-satunya downside adalah bahwa jika Anda menggunakan skrip yang saya terbitkan di sana apa adanya, itu akan mengotori file .mtool di setiap direktori induk repositori git, tetapi tidak ada gitignore global yang tidak dapat disembuhkan.

Menarik untuk dicatat bahwa saya menggunakan output git ls-files --stage untuk kebutuhan hashing; mungkin (tetapi kurang efisien) untuk meminta git untuk hash juga file yang tidak diindeks jika build Anda bergantung pada itu.

Dari segi fitur, diharapkan untuk mengimplementasikan fitur yang sedang dibahas di sini, ninja dapat melakukan hal yang sama secara internal (tanpa bergantung pada git) dan dengan hasil kinerja yang serupa.

Setelah melihat sekilas tambalan ninja tersebut tampaknya tidak meng-hash baris perintah kompiler selain file input. Apakah saya kehilangan sesuatu?

Baris perintah sudah di-hash oleh ninja dan disimpan di log build.

Saya kira hashing masih menggunakan stempel waktu terlebih dahulu, sehingga jika stempel waktu cocok, tidak perlu membandingkan hash. Itu berarti, bahwa beberapa build pertama mungkin tidak perlu mengkompilasi ulang beberapa file, tetapi itu seharusnya tidak sering terjadi (sebagian besar waktu heuristik stempel waktu benar).

Itu akan sangat salah. Membandingkan hash dapat dihilangkan jika stempel waktu tidak cocok; sistem build dapat berasumsi bahwa dependensi telah dimodifikasi, dan jika tidak benar-benar dimodifikasi (hanya disentuh) maka build akan menjadi kurang optimal tetapi benar. Namun jika stempel waktu cocok, masih mungkin bahwa dependensi telah dimodifikasi dan stempel waktunya disetel ulang secara paksa (EDIT: atau target disentuh dan dengan demikian dibuat lebih baru daripada dependensinya). Tanpa pemeriksaan ganda dengan membandingkan hash, ini akan menghasilkan build yang salah.

Saya kira Ninja sudah mengasumsikan dan melewatkan semua pekerjaan ketika stempel waktu cocok. Jadi dalam contoh Anda, ini akan menjadi build yang salah.

Saya tidak mengetahui (mungkin karena ketidaktahuan saya) tentang alat apa pun yang akan menghasilkan keluaran berbeda dan akan mempertahankan stempel waktu sebelumnya. Mengapa seseorang melakukan itu?

IMHO, melewatkan pemeriksaan hash ketika stempel waktu cocok adalah pengoptimalan yang sangat valid.

Pemeriksaan hash hanya akan menghindari beberapa pembangunan kembali "kotor palsu", sambil menjaga semantik yang ada yang sudah disediakan oleh Ninja.

Masalahnya bukan pembangunan kembali yang salah-kotor, ini bukan pembangunan kembali yang salah-bersih. Sebuah git checkout menyentuh semua yang ditimpanya. Itu dapat membuat target lebih baru daripada ketergantungan (ya, orang melakukan kode yang dihasilkan karena berbagai alasan yang valid). Pemeriksaan hash akan mencegah pembersihan palsu non-rebuild dalam kasus ini.

@rulatir Saya pikir saya paling mengerti apa yang Anda katakan :) Saya rasa itulah salah satu alasan mengapa Bazel dan sistem build lainnya berdasarkan pemeriksaan hash benar-benar bertentangan dengan output target in-tree.

Meskipun, tidakkah masalah ini akan terpecahkan jika sistem pembangunan akan memeriksa apakah target lebih baru dari waktu yang diketahui sebelumnya, dan membangun kembali jika perlu?

@rulatir Saya pikir saya paling mengerti apa yang Anda katakan :) Saya rasa itulah salah satu alasan mengapa Bazel dan sistem build lainnya berdasarkan pemeriksaan hash benar-benar bertentangan dengan output target in-tree.

Bagaimana hash bergantung pada di mana file itu berada?

Meskipun, tidakkah masalah ini akan terpecahkan jika sistem pembangunan akan memeriksa apakah target lebih baru dari waktu yang diketahui sebelumnya, dan membangun kembali jika perlu?

Saya mengerti bahwa manfaat utama menggunakan stempel waktu adalah menghindari kebutuhan untuk memelihara database terpisah yang melacak tanda tangan versi "yang sebelumnya diketahui". Jika Anda bersedia melepaskan manfaat itu, mengapa tanda tangan itu tidak menjadi hash?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat