Optimasi Tingkat Rendah dan Zig
(alloc.dev)- Optimasi tingkat rendah dapat diterapkan dengan mudah dalam bahasa Zig
- Compiler melakukan optimasi dengan baik dalam sebagian besar situasi, tetapi terkadang kinerja yang lebih baik bisa diperoleh jika niat programmer disampaikan dengan jelas
- Zig mendukung pembuatan kode berperforma tinggi dan metaprogramming yang kuat melalui fitur eksekusi saat kompilasi (comptime)
- Dibandingkan dengan Rust, Zig memungkinkan optimasi yang lebih presisi melalui anotasi dan struktur kode yang eksplisit
- Dalam operasi berulang seperti perbandingan string, comptime dapat dimanfaatkan untuk menghasilkan kode assembly yang lebih unggul daripada fungsi biasa
Optimasi dan Zig
Seperti peringatan terkenal, "Segala sesuatu mungkin dilakukan, tetapi hal yang menarik tidak bisa didapat dengan mudah," optimasi program selalu menjadi perhatian utama para pengembang. Untuk biaya infrastruktur cloud, perbaikan latensi, penyederhanaan sistem, dan sebagainya, optimasi kode mutlak diperlukan. Artikel ini berfokus menjelaskan konsep optimasi tingkat rendah di Zig serta keunggulan Zig.
Bisakah compiler dipercaya?
- Secara umum ada banyak saran untuk "percayalah pada compiler", tetapi dalam praktiknya ada kasus ketika compiler bekerja berbeda dari harapan atau melanggar spesifikasi bahasa
- Bahasa tingkat tinggi memiliki keterbatasan performa karena sulit menyampaikan niat (intent) dengan jelas
- Karena eksplisitas kodenya, bahasa tingkat rendah memungkinkan compiler mengetahui informasi yang dibutuhkan untuk optimasi; misalnya, jika membandingkan fungsi maxArray di JavaScript dan Zig, Zig menyampaikan tipe yang jelas, alignment, ada tidaknya alias, dan sebagainya pada waktu kompilasi, bukan saat runtime
- Jika operasi maxArray yang sama ditulis dalam Zig dan Rust, hasilnya hampir sama berupa kode assembly berperforma tinggi, tetapi semakin baik niat diekspresikan, semakin baik pula hasil optimasinya
- Namun kita tidak bisa selalu percaya pada performa compiler, jadi pada bagian bottleneck kita perlu memeriksa langsung kode dan hasil kompilasinya serta mencari cara optimasi yang tepat
Peran Zig
- Zig dapat menghasilkan kode teroptimasi tanpa informasi abstrak berkat karakteristik seperti eksplisitas yang akurat, fungsi bawaan yang kaya, pointer dan anotasi, comptime, serta Illegal Behavior yang terdefinisi dengan baik
- Rust, berkat memory model-nya, secara default menjamin tidak ada alias pada argumen, tetapi di Zig diperlukan anotasi seperti noalias secara langsung
- Jika hanya berdasarkan LLVM IR, tingkat optimasi Zig juga tinggi
- Yang terpenting, comptime (eksekusi saat kompilasi) di Zig adalah alat optimasi yang sangat kuat
Apa itu comptime?
- comptime di Zig digunakan untuk pembuatan kode, penyematan nilai konstan, pembuatan struct generik berbasis tipe, dan sebagainya, serta berperan penting dalam meningkatkan performa runtime
- Metaprogramming dapat diimplementasikan dengan comptime
- Berbeda dari makro di C/C++ atau sistem macro di Rust, comptime adalah kode biasa, bukan sintaks terpisah
- Kode comptime tidak mengubah AST secara langsung, tetapi dapat memeriksa, merefleksikan, dan menghasilkan sesuatu pada waktu kompilasi untuk semua tipe
- Fleksibilitas comptime juga memengaruhi perbaikan bahasa lain seperti Rust, dan terintegrasi secara alami ke dalam bahasa Zig
Batasan comptime
- Beberapa fitur macro seperti token-pasting tidak dapat digantikan oleh comptime Zig
- Karena Zig menekankan keterbacaan kode, hal seperti membuat variabel di luar scope atau mendefinisikan makro tidak diizinkan
- Sebagai gantinya, Zig comptime memiliki banyak contoh penggunaan metaprogramming yang luas seperti refleksi tipe, implementasi DSL, dan optimasi parsing string
Optimasi perbandingan string dengan comptime
- Fungsi perbandingan string umum dapat diimplementasikan di semua bahasa, tetapi di Zig, ketika salah satu dari dua string adalah konstanta yang diketahui saat comptime, kode assembly yang lebih efisien dapat dihasilkan
- Misalnya, jika satu string selalu bernilai "Hello!\n", optimasi dapat dilakukan dengan membandingkan dalam blok yang lebih besar, bukan per byte
- Untuk itu, dengan menggunakan comptime, kode berperforma tinggi seperti vektor SIMD, pemrosesan blok, dan optimasi byte sisa dapat dihasilkan pada waktu kompilasi
- Melalui pendekatan ini, bukan hanya perbandingan string berulang, tetapi juga berbagai implementasi berorientasi performa seperti mapping berbasis data statis, perfect hash table, parser AST, dan lain-lain dapat dibuat
Kesimpulan
- Zig sangat cocok untuk optimasi tingkat rendah, dan berkat struktur kode yang eksplisit serta fitur comptime yang kuat, performa terbaik dapat diimplementasikan secara langsung
- Dibandingkan dengan bahasa lain seperti Rust, kemampuan pemrograman saat kompilasi dan eksplisitas Zig menjadi keunggulan besar dalam pengembangan perangkat lunak berperforma tinggi
- Kemampuan optimasi Zig akan terus menjadi daya saing yang semakin penting ke depannya
1 komentar
Komentar Hacker News
for(;;);memang harus benar-benar menjadi loop tak hingga, danloop {}di Rust juga seharusnya begitu. Namun para pengembang LLVM kadang tampak lupa bahwa mereka bukan hanya membuat compiler C++, sehingga ketika Rust berkata "tolong buat loop tak hingga", LLVM malah menerapkan "menurut C++ hal seperti itu tidak terjadi, jadi optimalkan saja!" dan timbullah masalah. Jadinya optimisasi yang salah diterapkan pada bahasa yang salahcomptime), melakukan inline dan unroll pada perbandingan string tetap sangat mungkin di C. Contoh terkaiti < x.length, yang justru mudah dioptimalkan JIT. Jadi memang agak nitpick, meskipun tetap ada perbedaan kecilpurchase.calculate_tax().await.map_err(|e| TaxCalculationError { source: e })?;memang penuh dengan intent, tetapi mustahil diprediksi seperti apa machine code yang akan dihasilkannya-march=native, whole-program optimization, dll.). Sebenarnya di C pun petunjuk optimisasi sepertiunreachablebisa dilakukan lewat ekstensi bahasa, dan Clang juga sangat agresif dalam constant folding. Jadi, perbedaan antara comptime di Zig dan codegen C sering kali berasal dari pengaturan optimisasi compiler. TL;DR: kalau C terasa lambat, cek dulu pengaturan compiler-nya. Bagaimanapun, inti optimisasinya tetap LLVMcomptime) serta whole-program compilation daripada yang saya perkirakan dari artikel aslinya. Saya setuju soal itu. Sebagai catatan, Virgil sudah mendukung pemanfaatan seluruh bahasa saat compile-time dan whole-program compilation sejak 2006. Virgil tidak menargetkan LLVM, jadi perbandingan kecepatannya pada akhirnya adalah perbandingan backend. Berkat pendekatan ini, Virgil bisa melakukan optimisasi yang sangat kuat seperti devirtualize pemanggilan method secara statis sejak awal, menghapus field/objek yang tidak dipakai semaksimal mungkin, melakukan constant propagation hingga ke field-heap object, dan spesialisasi secara sempurnafor loopZig terasa terlalu berantakan bagi saya. Harus menaruh dua daftar berdampingan lalu menyelaraskan posisinya; melihatnya saja sudah bikin mata lelah. Menurut saya, bahasa-bahasa belakangan ini keliru karena menuangkan terlalu banyak sintaks 'ajaib' dan simbol khusus. Rasanya sulit menatapnya berjam-jam