Kecepatan build Zig makin cepat
(mitchellh.com)- Dengan rilis Zig 0.15.1, kecepatan kompilasi meningkat signifikan dibanding versi sebelumnya
- Hasil pengukuran waktu build nyata pada proyek Ghostty menunjukkan bahwa waktu eksekusi secara keseluruhan menjadi lebih singkat
- Meski masih sebagian menggunakan LLVM, ada ekspektasi tinggi untuk peningkatan kecepatan tambahan saat backend internal diterapkan
- Kompilasi inkremental (incremental compilation) masih belum sepenuhnya diimplementasikan, tetapi keunggulan performa sudah terlihat bahkan pada build parsial
- Ke depannya, ada kemungkinan besar terwujudnya lingkungan build yang lebih cepat dan pengalaman pengembangan yang lebih baik
Ikhtisar
Berawal dari pernyataan Andrew Kelley, "bug muncul karena kompiler terlalu lambat", Zig selama bertahun-tahun telah melakukan berbagai perbaikan struktural dengan tujuan waktu kompilasi yang lebih cepat
- Tim Zig telah berupaya menghapus LLVM, mengembangkan backend pembangkitan kode sendiri, membangun linker mandiri, dan pada akhirnya mewujudkan kompilasi inkremental
- Hasil dari pengembangan jangka panjang ini mulai tampak jelas pada Zig versi 0.15.1, dan perubahan waktu build pada proyek nyata (Ghostty) diukur lalu dibagikan
Kecepatan kompilasi Build Script
- Zig 0.14: 7 detik 167 md
- Zig 0.15: 1 detik 702 md
Ini adalah waktu build untuk skrip build.zig itu sendiri, dan waktu ini merupakan biaya awal yang harus ditanggung setiap kali berada di lingkungan build sumber baru
- Frekuensi rekompilasi skrip build dijaga tetap rendah, tetapi hal ini berdampak langsung pada pengalaman pengguna saat pertama kali membangun proyek sendiri
Build biner penuh tanpa cache (Ghostty)
- Zig 0.14: 41 detik
- Zig 0.15: 32 detik
Ini adalah waktu build biner penuh termasuk waktu build skrip build
- Dengan Zig 0.15, ada tambahan peningkatan kecepatan sekitar 2 detik, dan perbedaan awal juga terlihat jelas berdasarkan waktu nyata di jam dinding
- Backend x86_64 internal masih belum dimanfaatkan sepenuhnya, dan sebagian besar masih terus menggunakan LLVM
- Ke depannya, jika Ghostty dibangun sepenuhnya dengan backend internal, waktunya diperkirakan bisa turun hingga di bawah 25 detik (sekitar setengah dari sebelumnya)
Build inkremental (file eksekusi Ghostty)
- Zig 0.14: 19 detik
- Zig 0.15: 16 detik
Ini adalah waktu yang dibutuhkan untuk membangun ulang setelah perubahan satu baris yang bermakna (menambahkan pemanggilan log pada kode emulasi terminal)
- Ini adalah build parsial ketika skrip build dan graf dependensi sudah berada dalam keadaan cache
- Fitur kompilasi inkremental memang belum diimplementasikan dengan sempurna, tetapi peningkatan performa sudah terlihat jelas
- Jika LLVM yang sedang digunakan dikesampingkan, ada kemungkinan waktu ini dipangkas hingga sekitar 12 detik
- Jika build inkremental yang sesungguhnya terwujud di masa depan, ada harapan build dalam skala milidetik pun menjadi mungkin
Build inkremental (libghostty-vt)
- Zig 0.14: 2 detik 884 md
- Zig 0.15: 975 md
Pengukuran waktu untuk membangun ulang sebagian hanya libghostty-vt setelah perubahan satu baris
libghostty-vtdapat dibangun sepenuhnya dengan backend x86_64 internal, sehingga peningkatan Zig tercermin langsung tanpa pengaruh LLVM- Mencapai waktu build di bawah 1 detik bahkan tanpa kompilasi inkremental merupakan kemajuan yang sangat besar
- Efisiensi meningkat melalui pengalaman umpan balik instan dalam alur kerja pengembang
- Backend x86_64 dan aarch64 makin stabil, dan ada kemungkinan diterapkan ke seluruh Ghostty dalam beberapa bulan ke depan
Posisi terkini peningkatan kecepatan build
- Build Ghostty dengan Zig 0.15.1 kini jelas lebih cepat di semua bagian pengukuran
- Meski backend internal dan kompilasi inkremental masih belum selesai, capaian saat ini saja sudah cukup mengesankan
- Dalam 1–2 tahun ke depan, diharapkan hasil peningkatan kecepatan yang lebih revolusioner lagi
- Dari sudut pandang kecepatan build, memilih Zig terasa sebagai keputusan yang masuk akal
1 komentar
Komentar Hacker News
Saat lulus SMA pada 1995, saya biasa mengompilasi ulang "Borland Pascal versi Turbo Vision for DOS" di Intel 486, dan sekarang akhirnya kembali merasakan kecepatan kompilasi yang sebanding dengan itu
Turbo Vision adalah framework jendela TUI yang digunakan dalam pengembangan IDE Borland Pascal dan C++
Bisa dibilang ini seperti mode karakter yang mewujudkan IDE JetBrains dalam ukuran 10MB alih-alih 1000MB
Wikipedia Turbo Vision
LLVM semacam jebakan
Bootstrap memang sangat cepat dan kita mendapat banyak pass optimisasi serta dukungan berbagai platform secara gratis, tetapi kita kehilangan kemampuan untuk menyetel performa tahap optimisasi akhir atau tahap linking secara detail
Saya pikir Cranelift akan segera diaktifkan di Rust
Namun Rust bisa mencapai posisinya sekarang justru karena sejak awal memilih LLVM
Go sejak lama memutuskan untuk menangani code generation dan linking sendiri tanpa menyerahkannya ke pihak luar, dan sangat diuntungkan oleh pilihan itu
Sulit setuju dengan klaim bahwa LLVM adalah jebakan, dan Rust justru contoh yang baik
Dalam praktiknya, bagian yang menghasilkan kode lewat LLVM hanyalah porsi yang sangat kecil dari compiler, dan jika ingin diganti bisa beralih ke codegen_cranelift atau codegen_gcc
Ketergantungan pada SIMD vendor intrinsic memang masalah "lock-in", tetapi itu adalah masalah struktur bahasa
Bagi kebanyakan bahasa, memulai dengan backend LLVM adalah pilihan yang masuk akal
Untuk bahasa yang mirip C/C++, pipeline bawaan LLVM saja sudah mengoptimalkan dengan baik, tetapi makin berbeda karakteristik bahasanya, makin perlu menulis pipeline optimisasi sendiri
Contoh seperti Go yang sejak awal mengintegrasikan backend sendiri memang terlihat sukses, tetapi itu bukan pembeda yang terlalu istimewa, dan implementasi sendiri membawa opportunity cost yang cukup besar
Compiler Go dan Ocaml memang sangat cepat
Mereka sejak awal membangun library internal dengan benar, dan sekarang praktis tidak dirugikan dari sisi kecepatan
Ke depan saya tidak ingin bekerja di lingkungan kompilasi yang butuh lebih dari 1 menit
Akan bagus kalau setiap proyek punya compiler khusus ‘dev’, lalu hanya build final yang memakai sesuatu yang berat seperti llvm
Jika bahasa berbasis LLVM menargetkan pengganti C++, pada akhirnya ia tetap bergantung pada C++
Sebuah bahasa harus bisa bootstrap dengan dirinya sendiri
Pada tahap awal memang ada alat bantu yang praktis, tetapi itu hanya penghemat waktu dan bukan kebutuhan mutlak
Saya sepenuhnya sependapat dengan pilihan yang diambil tim Go
Saya berharap Cranelift terus berkembang
LLVM saat ini dipenuhi fork dari berbagai vendor CPU, dan masing-masing mengikat peningkatan khusus CPU ke dalam paket tertutup
Jika memakai frontend bahasa lain atau muncul bug compiler, situasinya bisa menjadi sangat berat
Ada yang mempertanyakan: jika bahasa bisa bebas berpindah ke backend lain, bagaimana mungkin itu disebut jebakan?
Jika kecepatan kompilasi menghambat pengembangan, mengapa tidak membuat interpreter?
Kecepatan eksekusi dan kecepatan kompilasi pada dasarnya independen
Dengan interpreter, lebih mudah juga membuat alat pengembangan tambahan seperti instrumentasi kode atau kontrol runtime
Memang ada sedikit kasus yang mengharuskan debugging hanya pada biner RELEASE yang sudah dioptimalkan, tetapi dalam kebanyakan kasus interpreter atau build DEBUG sudah cukup
Saya dengar Rust bisa diklasifikasikan sebagai keselamatan, performa, kegunaan, sedangkan Zig sebagai performa, kegunaan, keselamatan
Dari sudut pandang itu, peningkatan kecepatan build memang masuk akal, tetapi interpreter lebih cocok sebagai alternatif saat kegunaan menjadi prioritas utama
Saya suka pendekatan Julia
Dalam lingkungan yang sepenuhnya interaktif, interpreter sebenarnya mengompilasi kode lalu langsung menjalankannya
Lingkungan Common Lisp seperti SBCL juga demikian
Kalau dilihat secara ekstrem, kecepatan eksekusi dan kecepatan kompilasi memang independen
Di antaranya ada "wilayah kompromi" sehingga compiler bisa dibuat lebih cepat tanpa harus mengorbankan performa executable
Ada yang berpendapat bahwa bidang game bukanlah kasus yang istimewa
Sampai sekarang kecepatan compiler terbaik adalah TCC (karya Fabrice Bellard)
Tanpa multithreading atau optimisasi rumit pun tetap luar biasa cepat
Untuk rilis saya memakai Clang, tetapi performa code generation TCC juga tidak buruk
Saya pikir Delphi menawarkan ekspresivitas dan keamanan yang jauh lebih baik, sambil tetap memberi kecepatan kompilasi yang sangat tinggi
Compiler Go juga cukup cepat
Saya dulu menganggap DMD sebagai "gold standard" karena bisa mengompilasi C dan D sekaligus
Saya berharap TCC mendukung C23
Tidak ada satu pun yang bisa disebut "gold standard" yang sesungguhnya
vlang juga bisa selesai recompile hanya dalam hitungan detik, dan compiler Go juga sangat cepat
Ada juga teknik seperti build caching yang menghindari recompilation sejak awal, jadi ini bukan wilayah eksklusif siapa pun
Saat membangun aplikasi dengan zig, saya sangat puas dengan incremental build-nya
Biner statis tunggal yang memakai berbagai library seperti SQLite dan luau bisa dibangun secepat Go
Hanya saja compiler self-hosted masih memiliki cukup banyak bug
Sebagai contoh, SQLite harus memakai llvm, dan isu terkait bisa dilihat di sini
Saya penasaran apakah Zig bisa terintegrasi dengan baik dengan sistem build seperti Bazel dan Buck2
Build script Zig bersifat Turing-complete, jadi saya khawatir hal itu akan menyulitkan caching dan otomatisasi build dalam sistem semacam ini
Ini sama seperti alasan library Rust yang bisa dipakai tanpa build.rs lebih disukai
Saya juga penasaran apakah library Zig punya banyak custom build
Build script Zig sepenuhnya opsional
Tanpa build.zig pun kita bisa langsung build/menjalankan file sumber individual
Zig bisa diintegrasikan ke alur kerja mana pun yang biasanya melibatkan GCC atau Clang
Sebagai catatan, Zig juga bisa berfungsi sebagai pengganti compiler C
Artikel terkait
Sebagai contoh integrasi Bazel dan Zig, ada rules_zig
Proyek nyata ZML juga memanfaatkannya
Proyek ZML
Saya penasaran bagaimana kompilasi dan code generation Zig dibandingkan dengan TPDE
Katanya 10~20 kali lebih cepat daripada LLVM -O0, tetapi tampaknya tetap ada batasnya
Menurut saya strategi Zig cukup berani
Tetapi saya masih bertanya-tanya apakah tetap menggunakan backend LLVM adalah keputusan yang tepat
LLVM unggul dalam kecepatan kompilasi dan dukungan platform, tetapi untuk menghasilkan machine code terbaik hampir tidak ada tandingannya
Hanya build Release yang memakai backend LLVM, sedangkan build debug pada platform yang didukung menggunakan pendekatan self-hosted sebagai default
Karena build debug diulang berkali-kali selama proses pengujian, pendekatan ini lebih masuk akal
Saya tidak terlalu paham obsesi pada performa compiler
Pada akhirnya ini adalah trade-off antara pass optimisasi seperti inlining, dead code elimination, dan waktu kompilasi
Compiler tanpa optimisasi hanya akan lebih cepat secara linear, dan untuk optimisasi lebih jauh, waktu yang dibutuhkan pada akhirnya memang akan selalu bertambah besar
"Output assembly yang hebat" sebenarnya bukan isu yang terlalu penting
Menurut Proebsting's Law, kemajuan teknologi compiler jauh lebih lambat daripada kenaikan performa mesin
Kesimpulannya, optimisasi yang mudah dan cepat saja sudah cukup secara praktis
LLVM juga bukan optimisasi absolut, dan dibandingkan dengan kecepatan kompilasi pun cepat mencapai batas manfaatnya
Saya sedang membuat library Java yang membungkus library C lewat JNI, dan membangun dynamic library per platform terlalu merepotkan, jadi saya mempertimbangkan Zig untuk build multi-platform
Jika hanya shim sederhana, di Java terbaru mungkin lebih baik memanfaatkan Panama dan jextract
Zig menyertakan header, source libc, dan LLVM-nya sendiri, sehingga cross-compilation benar-benar mudah
Sampai pada titik nyaris tidak perlu memikirkan apa pun
Ada yang bertanya-tanya mengapa Ghostty saat ini tidak bisa dibangun dengan backend self-hosted x86_64
Compiler Zig crash karena bug
Ini masih teknologi baru sehingga cukup rumit, tetapi akan segera diperbaiki
Sebagian besar pengguna Ghostty memakai platform aarch64