2 poin oleh GN⁺ 2023-07-13 | 1 komentar | Bagikan ke WhatsApp
  • Prototipe peminjaman region di Vale untuk pertama kalinya berhasil dikompilasi, sehingga pendekatan keamanan memori yang menggabungkan referensi generasional dan region kini bisa divalidasi pada program nyata
  • Pengembang dapat menulis kode dengan gaya yang mendekati C/C++, lalu menerapkan pure dan peminjaman region hanya di bagian yang diperlukan untuk mengurangi overhead pemeriksaan generasi
  • Program Vale zero-check pertama adalah contoh Cellular Automata untuk pembuatan level roguelike, dan assembly hasilnya hampir setara dengan mode unsafe_with_bounds
  • Dalam benchmark, safe_fastest tidak menunjukkan slowdown yang teramati dibanding unsafe_with_bounds, sementara unsafe_no_bounds 1.18 ± 0.01 kali lebih cepat daripada kedua mode tersebut
  • Ini belum merupakan perbandingan langsung dengan C/Rust, dan masih ada pekerjaan tersisa terkait noise optimisasi LLVM, kematangan prototipe, tidak adanya dukungan inline data, serta perapian fitur region dan pre-optimizer khusus Vale

Menggabungkan referensi generasional dan peminjaman region

  • Pendekatan keamanan memori Vale bertujuan untuk tidak menggunakan reference counting, tracing garbage collection, maupun borrow checking
  • Struktur dasarnya adalah pengembang menulis program dengan gaya yang mendekati C atau C++, lalu generational references milik Vale menjaga keamanan memori
  • Setelah itu, dengan menerapkan pure dan region borrowing, sebagian besar overhead pemeriksaan generasi dapat dihilangkan
  • Jika ditambah linear style, pemeriksaan generasi dalam kode Vale diyakini bisa diturunkan hingga zero
  • Peminjaman region sepenuhnya bersifat opt-in, jadi kode bisa ditulis dengan nyaman terlebih dahulu lalu ditambahkan nanti hanya pada bagian yang perlu dioptimalkan
  • Tujuannya adalah struktur yang memungkinkan, bahkan dalam program yang sama, sebagian bagian fleksibel seperti Java, sebagian cepat seperti Rust, atau berada di titik mana pun di antaranya

Pekerjaan yang diperlukan untuk membuat prototipe

  • Selama beberapa tahun terakhir, fondasi kompiler dibangun agar bisa mendukung sistem peminjaman berbasis region bersama dengan generational references
  • Selain sistem peminjamannya sendiri kompleks, juga dibutuhkan full generics yang lebih kuat daripada template sebelumnya
  • Agar region dan referensi generasional bisa bekerja bersama secara alami, tahap baru dalam kompiler juga diperlukan
    • Secara internal, region direduksi menjadi bilangan bulat “pure height”
    • Generic parameter region direpresentasikan sebagai nilai negatif, region default sebagai 0, dan setiap pure block sebagai nilai positif yang meningkat
  • Beberapa bulan lalu, prototipe region selesai dibuat, dan walaupun masih kasar di beberapa bagian, untuk pertama kalinya sesuatu berhasil dikompilasi
  • Hasilnya adalah program Vale zero-check pertama
    • Dengan flag kompiler --print_mem_overhead true, jumlah pemeriksaan generasi dalam program dapat dihitung

Program zero-check pertama dan perbandingan assembly

  • Program pertama itu adalah contoh Cellular Automata untuk menghasilkan level game roguelike
  • Kesalahan kecil dalam kode kompiler pun bisa menambahkan instruksi ekstra ke assembly hasil, sehingga menciptakan overhead buatan pada program akhir
  • Untuk melacak masalah tersebut, assembly hasil terus dibandingkan dengan mode unsafe milik Vale
    • unsafe_no_bounds: seperti C, semua perlindungan keamanan memori dimatikan, dan raw pointer digunakan sebagai pengganti generational references
    • unsafe_with_bounds: seperti Rust, bounds checking ditambahkan pada akses array
  • Setelah berbulan-bulan melacak perbedaannya, assembly hasil akhirnya menjadi hampir sama dengan mode unsafe_with_bounds
  • Satu-satunya perbedaan yang diperkirakan adalah penambahan generation number pseudo-random di bagian atas setiap allocation, dan itu tidak pernah dibaca oleh pemeriksaan generasi yang sebenarnya
    • Secara internal, register yang meningkat secara monoton digunakan agar tetap cepat
    • Jika isolates atau unique references ditambahkan, perbedaan ini dapat dihilangkan

Hasil benchmark dan kondisi pengukuran

  • Ringkasan benchmark adalah sebagai berikut
Summary
  './build_unsafe_no_bounds/main' ran
    1.18 ± 0.01 times faster than './build_unsafe_with_bounds/main'
    1.18 ± 0.01 times faster than './build_safe_fastest/main'
  • safe_fastest, yaitu normal mode Vale, tidak menunjukkan slowdown dibanding mode yang hanya memiliki bounds checking
  • Dalam pengukuran tersebut, pendekatan ini tidak memiliki overhead yang teramati
  • Untuk mencobanya sendiri, Anda bisa membangun regions branch, melihat benchmarking scripts, dan bertanya di discord server
  • Kondisi pengukuran memiliki batasan yang jelas
    • Ini bukan benchmark yang membandingkan langsung dengan bahasa seperti C atau Rust
    • Kompiler-kompiler tersebut memiliki optimisasi tersendiri yang telah berkembang selama bertahun-tahun dan dapat mengaburkan variabel eksperimen
    • Untuk mengisolasi perbedaan pendekatan keamanan memori, perbandingan dilakukan dengan unsafe_no_bounds dan unsafe_with_bounds
    • Lingkungan pengujian adalah Razer Blade 15" 2018 dengan SSD 512GB yang menjalankan Ubuntu 22.04
    • Alat pengukurannya adalah hyperfine dan dijalankan di dalam cset shield

Noise optimisasi yang terlihat pada program besar

  • Pada program yang lebih besar, cukup banyak optimizer noise yang teramati
    • Ini berbeda dari benchmark noise, karena konfigurasi pengukuran menunjukkan waktu eksekusi yang sangat konsisten seperti ± 0.01
    • Perubahan kecil di satu area bisa menggoyangkan hasil pengukuran ke satu sisi
  • Ada juga kasus ketika ukuran generation number diubah dan hasilnya secara konsisten menunjukkan negative overhead sebesar 1.13 ± 0.01
    • Ini hasil yang aneh karena program tersebut tidak memiliki banyak generation number
    • Bisa jadi perubahan register allocation mengalahkan perbedaan performa yang berasal dari perbedaan semantik
  • Dalam program yang lebih besar, yaitu game roguelike kecil, optimizer gagal menggabungkan dua branch identik di dalam pernyataan if, dan juga melewatkan optimisasi lain yang jelas
  • Belum jelas dampak dari keberadaan integer yang tidak dibaca itu, dan ada kemungkinan ini merupakan bug LLVM
  • Hasil ini mengisyaratkan bahwa Vale mungkin memerlukan pre-optimizer khusus, mirip MIR di Rust
    • LLVM lebih dirancang dengan mempertimbangkan C
    • Jika LLVM menganggap generational references sebagai pola yang mengakses memori yang sengaja sudah dibebaskan, itu bisa diperlakukan sebagai undefined behavior

Kemungkinan penerapan dan pekerjaan berikutnya

  • Referensi generasional dan region, ketika digabungkan, dapat menghasilkan pendekatan keamanan memori yang sangat cepat
  • Domain perangkat lunak yang mungkin cocok untuk pendekatan ini memiliki kondisi berikut
    • Menginginkan latency yang lebih dapat diprediksi daripada tracing garbage collection
    • Menginginkan performa dan cache friendliness yang lebih baik daripada reference counting
    • Ingin melakukan prototyping dan iterasi dengan lebih mudah daripada borrow checking
  • Sebelum Vale bisa dibandingkan secara langsung dengan C atau C++, masih ada pekerjaan yang tersisa
    • LLVM optimizer mengalami kesulitan dalam menurunkan generation dan immutability, sehingga diperlukan pre-optimizer khusus Vale
    • Vale saat ini perlu mendukung inline data alih-alih solusi sementara yang menempatkan semua struct di heap
    • Benchmark di atas tidak menggunakan struct, sehingga ketiadaan dukungan inline data tidak memengaruhi hasil tersebut
    • Fitur region masih berada pada tahap prototipe, jadi bagian-bagian yang kasar perlu dirapikan dan utang teknis dikurangi sebelum digabungkan ke main branch
  • Setelah penggabungan, rencananya standard library akan dibuat menggunakan region agar kode program utama pengguna bisa memperoleh manfaatnya tanpa harus langsung memakai region
  • Pengukuran saat ini menunjukkan bahwa program zero-check memang memungkinkan dan dapat mencapai kecepatan yang diharapkan

1 komentar

 
GN⁺ 2023-07-13
Komentar Hacker News
  • Saya mengunduh Vale dan mencobanya, tetapi kesan pertama saya buruk karena saat pertama kali menjalankan compiler valec tanpa argumen, ia langsung menampilkan "(panic)"
    panic adalah istilah yang sangat kuat, dan menurut saya sebaiknya dihindari dalam situasi penanganan error yang normal. Ketika sebuah program mengeluarkan panic, rasanya seperti terjadi situasi yang tidak terkendali, jadi meninggalkan kesan yang kurang enak
    Lalu saya mencoba melihat bantuan argumen baris perintah, tetapi saat ini praktis tidak ada. Setelah menyimpan contoh Hello World dari situs web ke hello.vl lalu menjalankan valec hello.vl, yang muncul adalah Unknown subcommand
    Jadi saya menjalankan valec build hello.vl, lalu muncul Unrecognized input: hello.vl diikuti (panic) lagi. valec help juga tidak membantu, jadi saya akhirnya menyerah. Saya tidak tahu cara memakai ini

    • Maaf. Sepertinya file bantuan sudah tidak ditampilkan dengan benar lagi. Jika Anda menjalankan cat langsung pada valec-help-build.txt yang disertakan dalam unduhan, isinya menjelaskan apa yang Anda cari
      Compiler-nya saat ini masih sangat kasar di bagian tepiannya. Dari Agustus sampai Mei saya 100% fokus pada pembuatan prototipe region, dan yang Anda alami sekarang adalah utang teknis yang menumpuk selama proses itu. Termasuk tidak adanya integration test untuk sistem bantuan
      Selama 1~2 bulan terakhir saya sedang melunasi utang itu, tetapi masih belum kembali ke tingkat kualitas saat rilis 0.2. Jika butuh bantuan lebih lanjut, beri tahu saya atau datang ke server Discord; banyak orang di sana yang bisa membantu
    • Saya rasa Vale pada dasarnya masih berada di tahap R&D. Ekspektasinya lebih seperti hanya commit tertentu di branch tertentu yang akan berfungsi, bukan tahap di mana siapa pun bisa mengunduh compiler dan mulai membuat sesuatu
      Hanya saja README di GitHub tidak cukup jelas menyampaikan hal ini karena tertulis “Try Vale”, jadi terasa agak ambigu. Meski begitu, saat ini tampaknya lebih dekat ke R&D/proof of concept
    • Ini terasa lebih seperti masalah antarmuka pengguna daripada bug. Kalau memang sesuatu masih eksperimental, saya rasa masih masuk akal untuk memberi toleransi tertentu bahkan pada bug yang nyata
      Bahkan dari sisi antarmuka pengguna atau bug, pengalaman men-debug C++ berusia 40 tahun dengan gdb berusia 35 tahun cukup mampu menandingi bahasa eksperimental mana pun. Misalnya, output funcname()::staticvarname adalah antarmuka yang aneh dan gagal kira-kira separuh waktu. Belum lagi sistem build C++
      Jika teknologinya eksperimental, konsepnya boleh dikritik, tetapi antarmuka pengguna yang kasar masih bisa dimaklumi sampai batas tertentu
    • Cara memakai compiler dijelaskan di README GitHub
      https://github.com/ValeLang/Vale#building-a-vale-program
    • Untuk software yang masih alpha, ini kurang lebih sesuai ekspektasi
  • Latensinya lebih dapat diprediksi daripada tracing garbage collection, performa dan cache-friendliness-nya lebih baik daripada reference counting, dan prototyping serta iterasinya lebih mudah daripada borrow checker—ini membuat saya bukan sekadar penasaran, tapi benar-benar tertarik
    Saya bahkan mulai berlangganan feed RSS-nya: https://verdagon.dev/rss.xml

    • Akhirnya ada ide baru untuk bahasa AOT-compiled yang tidak berujung pada “ya sudah, biarkan saja sesekali muncul bug memori
  • Vale butuh lebih banyak sponsor
    https://github.com/sponsors/ValeLang
    Saya berharap selama tulisan ini masih ada di halaman depan, proyek ini bisa dibantu mencapai target 3.000 dolar per bulan
    Saya ingin membantu Evan agar bisa mengerjakan ini secara penuh waktu. Saya sendiri juga sponsor. Bahasa yang cepat, aman, dan tetap menyenangkan untuk prototyping layak didukung

    • Saya penasaran bagaimana pembagian pendapatan antara sponsor GitHub dan sponsor Patreon
  • “Optimizer pra-backend khusus Vale, mirip Cranelift di Rust” tampaknya merujuk ke MIR, yaitu medium-level intermediate representation. Ada tulisan blog yang bagus terkait ini: https://blog.rust-lang.org/2016/04/19/MIR.html
    Cranelift terutama adalah backend compiler yang berfokus pada JIT, tetapi secara teori juga bisa menggantikan LLVM. Pekerjaan backend alternatif juga sedang berlangsung, meski ada keterbatasan: https://github.com/bjorn3/rustc_codegen_cranelift

    • Sepertinya benar. Cranelift saya anggap sebagai optimizer Rust untuk WebAssembly
  • Pendekatan yang memungkinkan kita tidak perlu memikirkan manajemen memori di sebagian besar kode, tetapi tetap memberi opsi untuk mengoptimalkan hanya jalur kode panas dengan abstraksi tanpa biaya, terdengar seperti mengambil kelebihan dari kedua sisi
    Terutama jika demi kenyamanan, yang dipertukarkan hanyalah performa dan bukan keamanan

    • Saya hanya memakai C++ tetapi sama sekali tidak mengkhawatirkan manajemen memori
      Shared ownership adalah konsep yang buruk, jadi saya juga tidak memakai smart pointer
      Saya menganggap masalah manajemen memori pada umumnya sepele
  • Saya terus penasaran apa yang dimaksud dengan aman dalam konteks referensi generasional (generational references)
    Kalau saya memahaminya dengan benar, apakah itu berarti mencegah use-after-free dan double-free? Jika begitu, program masih bisa gagal saat mengakses memori ketika generasi yang diharapkan dan generasi yang sebenarnya tidak cocok
    Dalam hal itu, ini tampak kurang aman dibanding reference counting, garbage collection pelacakan, atau borrow checker

    • double-free dicegah oleh kepemilikan tunggal Vale, yaitu kepemilikan tunggal dalam arti C++, dan referensi generasional memungkinkan deteksi use-after-free secara aman
      Jika mencoba mengakses memori yang sudah dibebaskan lewat referensi, hasilnya seharusnya berupa segmentation fault atau assertion failure yang dapat diprediksi dan aman. Ke depannya ada harapan peningkatan dengan memetakan ulang ruang alamat virtual sehingga segmentation fault pun bisa dihilangkan
    • Aman dalam arti menghasilkan segmentation fault alih-alih membiarkan dangling pointer membaca atau menulis memori sembarang
      Namun kalau ini indeks generasional, seharusnya runtime juga bisa memeriksa apakah akses valid sebelum benar-benar mencoba mengaksesnya. Saya tidak tahu apakah itu mungkin di Vale
    • Ini kurang aman dibanding GC, borrow checker, atau reference counting. Meski begitu, tetap lebih aman daripada malloc/free, dan juga punya kelebihan lain
    • Saya juga penasaran. Saya tidak paham bagaimana ini mencegah use-after-free dan double-free
      Fungsi check memerlukan nomor generasi dari alokasi, jadi ia mengakses alokasi tersebut. Artinya, untuk memeriksa apakah referensi bisa mengakses alokasi itu, pertama-tama ia harus mengakses alokasi itu dulu
      Tentu saja, jika alokasi itu sudah dibebaskan, maka mengakses alokasi itu maupun nomor generasinya sendiri sudah merupakan undefined behavior, jadi ini tidak akan berhasil
      Ini terasa terlalu jelas, jadi saya tidak tahu apakah saya melewatkan sesuatu yang besar, atau apakah “keamanan memori” yang dimaksud di sini punya arti yang sama sekali berbeda
    • Jika ditanya apakah ini kurang aman daripada definisi “aman” yang ia tetapkan secara terbatas, mungkin iya
  • Vale bukanlah bahasa seperti V. V pernah mendapat ulasan yang sangat kritis di https://mawfig.github.io/2022/06/18/v-lang-in-2022.html, dan saya salah mengingatnya sebagai Vale karena namanya mirip
    Saya tinggalkan catatan ini kalau-kalau ada orang lain yang melakukan kekeliruan yang sama

    • “Ulasan yang sangat kritis” itu hanyalah daftar bug kecil yang sudah diperbaiki setahun lalu
      Isi tulisannya sekarang sudah tidak relevan lagi, tetapi tetap dibiarkan ada, dan itu juga satu-satunya tulisan di blog tersebut
    • “Ulasan kritis” itu tampak lebih seperti spam lama yang terus dipakai para penentang atau troll. Itu “ulasan” atas versi alfa bahasa tersebut, pada dasarnya tulisan yang menyerang, jadi tampaknya tidak punya nilai lain
      Sekarang sudah tahun 2023 dan V juga sudah beta (0.4). Selain itu, orang yang membuat tulisan itu memakai akun GitHub sekali pakai untuk mengunggah ulasan/serangan, memicu kontroversi, lalu menghilang
      Satu-satunya tulisan di blog itu juga hanya serangan terhadap V, tidak ada ulasan lain. Bagian yang memang punya substansi praktis sudah diperbaiki[1]
      Jika mencari mawfig.github, akan terlihat juga bahwa itu berulang kali disebarkan di HN dan biasanya dipakai untuk menjelekkan
      [1]: https://github.com/vlang/v/issues/14803
      [1]: https://github.com/vlang/v/issues/14787
      [1]: https://github.com/vlang/v/issues/14786
  • Selamat kepada Evan atas tercapainya tonggak ini. Saya tidak punya pengalaman dalam desain bahasa pemrograman atau compiler, tetapi saya menikmati membaca tulisan-tulisan Vale

    • Saya juga mirip, tetapi saya berharap namanya berbeda
      Sekarang ada Vale milik Evan dan juga Val dari Adobe Software Technology Lab, jadi mencari materi terkait tampaknya akan jadi cukup sulit
      https://www.val-lang.dev
    • Saya juga tidak punya latar belakang untuk memahami tulisannya dalam banyak kasus, tetapi tetap menarik
    • Saya juga merasa tulisannya sangat bagus dan menantikan masa depan Vale
  • “Vale cepat: Vale dikompilasi AOT dengan LLVM, menggunakan tipe statis, memakai teknik baru referensi generasional untuk keamanan memori yang cepat dan fleksibel, dan sebentar lagi akan mengadopsi pemeriksaan peminjaman berbasis region agar menjadi lebih cepat lagi”
    https://vale.dev/

  • Rasanya seperti menguping perdebatan dua orang yang sudah berlangsung selama 5 tahun
    Adakah yang bisa menjelaskan apa yang sedang terjadi di sini? Tulisan ini terlalu sulit dipahami