15 poin oleh darjeeling 22 hari lalu | Belum ada komentar. | Bagikan ke WhatsApp

Pencapaian utama

Platform Peningkatan performa JIT (vs interpreter tail-calling)
macOS AArch64 +11~12%
x86_64 Linux +5~6%

Cakupan benchmark: bervariasi dari kasus yang 20% lebih lambat hingga lebih dari 100% lebih cepat (unpack_sequence microbenchmark dikecualikan)

  • Target tercapai: target 3.15 (peningkatan 5%) tercapai lebih dari 1 tahun lebih awal
  • Dukungan free-threading: masih belum selesai, sedang dikerjakan dengan target 3.15/3.16

Pelajaran utama

  1. Sponsor pergi = krisis → beralih menjadi dipimpin komunitas
    Meskipun sponsor utama tim Faster CPython mundur pada 2025, kontribusi sukarela dari komunitas justru menambah jumlah kontributor dan menghasilkan capaian ini.

  2. Pecah masalah kompleks menjadi bagian-bagian kecil
    Bahkan proyek dengan hambatan masuk tinggi seperti JIT pun bisa menerima kontribusi dari programmer C nonspesialis lewat pemecahan pekerjaan menjadi unit-unit kecil ditambah panduan yang jelas.

  3. Penurunan bus factor adalah indikator proyek yang sehat
    Jumlah kontributor untuk tahap tengah (optimizer) meningkat dari 2 orang menjadi 4 orang, dan pengembang non-core pun tumbuh menjadi kontributor utama.

  4. Infrastruktur pengukuran mengubah kecepatan pengembangan
    Sistem yang melaporkan performa JIT setiap hari (doesjitgobrrr.com) sangat menentukan baik untuk mendeteksi regression lebih awal maupun menjaga motivasi.

  5. Pertukaran antarkomunitas meningkatkan kemampuan teknis
    Interaksi dengan tim PyPy dan obrolan informal dengan para pengembang compiler berujung pada kemajuan teknis yang nyata.


Latar belakang dan capaian

[IMG] Grafik performa JIT (per 17 Maret 2026, semakin rendah semakin cepat dibanding interpreter)
(Performa JIT per 17 Maret 2026. Semakin rendah, semakin cepat dibanding interpreter. Sumber gambar: doesjitgobrrr.com)

Ini kabar baik. Di macOS AArch64, target performa (yang sangat sederhana) untuk CPython JIT tercapai lebih dari 1 tahun lebih awal, dan di x86_64 Linux tercapai beberapa bulan lebih awal. JIT alfa 3.15 sekitar 11~12% lebih cepat daripada interpreter tail-calling di macOS AArch64, dan 5~6% lebih cepat daripada interpreter standar di x86_64 Linux. Angka-angka ini adalah geometric mean dan masih bersifat awal. Rentang nyata bervariasi dari 20% lebih lambat hingga lebih dari 100% lebih cepat (unpack_sequence microbenchmark dikecualikan). Dukungan free-threading yang benar-benar memadai memang belum ada, tetapi itu menjadi target untuk 3.15/3.16. Kini JIT kembali ke jalurnya.

Sulitnya proses ini tidak bisa dilebih-lebihkan. Ada masa ketika saya benar-benar ragu apakah proyek JIT bisa menghasilkan peningkatan kecepatan yang berarti. Kalau dilihat kembali, CPython JIT versi awal nyaris tidak memberi peningkatan kecepatan sama sekali. Delapan bulan lalu, saya menulis refleksi tentang JIT yang menunjukkan bahwa CPython JIT asli di 3.13 dan 3.14 justru sering lebih lambat daripada interpreter. Pada saat itu juga, tim Faster CPython kehilangan dukungan dari sponsor utamanya. Saya sendiri relawan jadi tidak terdampak langsung, tetapi rekan-rekan yang bekerja di sana terdampak, dan sempat ada masa depan JIT terlihat tidak pasti.

Lalu apa yang berbeda dibanding 3.13 dan 3.14? Saya tidak akan menyusun kisah heroik tentang bagaimana kami dengan kecerdikan kami menyelamatkan JIT dari ancaman kegagalan. Sejujurnya saya merasa sebagian besar keberhasilan saat ini datang dari keberuntungan. Waktu yang tepat, tempat yang tepat, orang yang tepat, pilihan yang tepat. Saya sungguh merasa ini tidak akan mungkin terjadi jika salah satu dari kontributor inti JIT Savannah Ostrowski, Mark Shannon, Diego Russo, Brandt Bucher, atau saya sendiri tidak terlibat. Agar tidak melewatkan kontributor JIT aktif lainnya, saya juga ingin menyebut beberapa nama lagi: Hai Zhu, Zheaoli, Tomas Roun, Reiden Ong, Donghee Na, dan mungkin masih ada yang terlewat.

Saya ingin membahas hal yang jarang disorot dalam JIT, yaitu orang-orang dan sedikit keberuntungan. Jika Anda ingin detail teknisnya, lihat di sini.


Bagian 1: JIT yang dipimpin komunitas

Tim Faster CPython kehilangan sponsor utamanya pada 2025. Saya segera mengusulkan gagasan pengelolaan yang dipimpin komunitas. Saat itu cukup tidak pasti apakah ini akan berhasil. Proyek JIT dikenal bukan area yang ramah bagi kontributor baru. Secara historis, proyek ini membutuhkan banyak pengetahuan khusus sejak awal.

Di core sprint CPython di Cambridge, tim inti JIT bertemu dan menyusun rencana untuk JIT yang 5% lebih cepat pada 3.15, JIT yang 10% lebih cepat pada 3.16, serta dukungan free-threading. Ada satu hal yang kurang mendapat sorotan tetapi sangat penting bagi kesehatan proyek, yaitu mengurangi bus factor. Kami ingin ada lebih dari 2 maintainer aktif di ketiga tahap JIT: region selector di frontend, optimizer di middle-end, dan code generator di backend.

Sebelumnya, middle-end JIT hanya memiliki 2 kontributor berulang yang aktif. Sekarang middle-end JIT memiliki 4 kontributor berulang yang aktif, dan 2 pengembang non-core (Hai Zhu dan Reiden) telah berkembang menjadi anggota yang kompeten dan sangat berharga.

Hal yang efektif untuk menarik orang masuk ternyata adalah praktik software engineering yang umum: memecah masalah kompleks menjadi bagian yang bisa dikelola. Brandt mulai melakukannya lebih dulu di 3.14 dengan membuka beberapa mega issue yang membagi optimisasi JIT menjadi tugas-tugas sederhana. Misalnya, "coba optimalkan satu instruksi di JIT." Saya meneruskan ide Brandt dan menerapkannya lagi di 3.15. Untungnya, saya menangani tugas yang lebih mudah, yaitu issue untuk mengubah instruksi interpreter menjadi bentuk yang mudah dioptimalkan. Untuk mendorong kontributor baru, saya segera menyusun petunjuk yang sangat rinci agar bisa langsung dikerjakan. Saya juga memisahkan unit pekerjaannya dengan jelas. Sepertinya ini membantu. Termasuk saya, ada 11 kontributor yang mengerjakan issue tersebut dan mengubah hampir seluruh interpreter menjadi bentuk yang ramah terhadap optimizer JIT. Intinya, JIT dipecah dari sesuatu yang terasa buram dan tertutup menjadi sesuatu yang bisa dikontribusikan oleh programmer C tanpa pengalaman JIT.

Cara efektif lainnya: mendorong orang dan merayakan pencapaian besar maupun kecil. Setiap PR JIT punya hasil yang jelas, dan saya rasa itu membantu memberi orang rasa arah.

Upaya optimisasi komunitas membuahkan hasil. JIT berkembang dari 1% lebih cepat menjadi 3~4% lebih cepat di x86_64 Linux (lihat garis biru di bawah):

[IMG] Performa JIT vs interpreter selama periode optimisasi komunitas
(Sumber gambar: doesjitgobrrr.com)


Bagian 2: Pilihan-pilihan yang beruntung

Trace Recording

Sekali lagi, saya rasa sebagian besar ini terjadi karena keberuntungan. Di CPython core sprint Cambridge, Brandt meyakinkan saya untuk menulis ulang frontend JIT dengan pendekatan tracing. Awalnya saya tidak suka ide itu, tetapi dengan semacam rasa keras kepala saya berpikir, mari kita tulis ulang "untuk membuktikan bahwa ini tidak akan berhasil."

Prototype awal sudah berjalan dalam 3 hari, tetapi butuh sebulan untuk membuatnya benar-benar melakukan JIT sambil tetap lolos test suite. Hasil awalnya buruk. Di x86_64 Linux, performanya sekitar 6% lebih lambat. Tepat ketika saya hendak menyerah, terjadi kecelakaan yang beruntung: saya salah memahami saran Mark.

Mark menyarankan agar dispatch table di-thread ke interpreter sehingga interpreter memiliki dua dispatch table, satu untuk interpreter biasa dan satu untuk tracing. Tetapi saya salah paham dan justru membuat versi yang lebih ekstrem: alih-alih punya versi tracing untuk instruksi normal, saya hanya menyisakan satu instruksi yang menangani tracing dan membuat semua instruksi di tabel kedua menunjuk ke instruksi itu. Ternyata ini pilihan yang sangat bagus. Pendekatan dua tabel awal membuat ukuran interpreter menjadi dua kali lipat, menyebabkan code bloat dan perlambatan alami sehingga jauh lebih lambat. Dengan memakai hanya satu instruksi dan dua tabel, ukuran interpreter hanya bertambah setara 1 instruksi, dan interpreter dasar bisa tetap sangat cepat. Mekanisme ini kami sebut dengan penuh kasih dual dispatch.

Angka yang menunjukkan betapa pentingnya trace recording: code coverage JIT meningkat 50%. Artinya, semua optimisasi di masa depan akan menjadi (secara sederhana) 50% kurang efektif jika ini tidak ada.

Terima kasih kepada Brandt dan Mark karena telah membawa kami menemukan solusi keren ini secara tidak sengaja.

Eliminasi reference count

Pilihan beruntung lain adalah mencoba eliminasi reference count. Awalnya ini adalah pekerjaan Matt Page di bytecode optimizer CPython. Saya menemukan bahwa meskipun sudah ada pekerjaan pada bytecode optimizer, kode hasil JIT masih menyisakan satu branch untuk setiap reference count decrement. Saya berpikir, "bagaimana kalau branch ini dihilangkan," tanpa tahu seberapa besar dampaknya. Ternyata satu branch saja cukup mahal, dan jika setiap instruksi Python memiliki satu atau lebih branch seperti ini, biayanya akan menumpuk.

Keberuntungan lain adalah betapa mudahnya pekerjaan ini diparalelkan dan betapa bagusnya ia menjadi alat untuk mengajarkan interpreter dan JIT kepada orang-orang. Inilah optimisasi utama yang kami gunakan untuk membagikan pekerjaan di Python 3.15 JIT. Sebagian besar berupa proses refactoring manual, tetapi memberi orang kesempatan belajar tanpa membuat mereka kewalahan dengan bagian inti JIT yang paling rumit.


Bagian 3: Tim yang hebat

Kami memiliki tim infrastruktur yang hebat. Sebenarnya ini hanya satu orang. Faktanya, "tim" kami saat ini adalah 4 mesin yang berjalan di lemari Savannah. Meski begitu, Savannah telah melakukan pekerjaan setara satu tim infrastruktur penuh untuk JIT. Tanpa cara untuk melaporkan angka performa, JIT tidak mungkin maju secepat ini. Hasil eksekusi JIT harian menjadi pengubah permainan dalam feedback loop. Itu membantu menangkap regression performa dan membuat kami bisa memastikan optimisasi kami benar-benar bekerja.

Mark sangat luar biasa secara teknis. Saya tidak akan berkata lebih banyak karena internet rasanya sudah memberinya terlalu banyak pujian :).

Diego juga luar biasa. Ia menangani JIT di hardware ARM, dan belakangan mulai mengerjakan agar JIT lebih ramah untuk profiler. Sulitnya masalah ini juga tidak bisa dilebih-lebihkan.

Brandt meletakkan fondasi awal backend machine code. Tanpa itu, kontributor baru harus menulis assembler, dan kemungkinan besar itu akan membuat lebih banyak orang menjauh.


Bagian 4: Berbicara dengan orang lain

Saya ingin menekankan nilai dari berbicara dengan orang lain dan berbagi ide.

Terima kasih kepada CF Bolz-Tereick yang banyak mengajari saya tentang PyPy. Saya menghabiskan beberapa bulan mempelajari source code PyPy, dan saya rasa itu membuat saya menjadi pengembang JIT yang lebih baik secara keseluruhan. CF juga sangat baik membantu ketika saya membutuhkan bantuan.

Saya ikut obrolan compiler santai bersama Max Bernstein, dan tanpa itu saya mungkin sudah kehilangan motivasi sejak lama. Max adalah penulis yang produktif dan pakar compiler yang ramah.

Ide tidak hidup di ruang yang terisolasi. Saya rasa bergaul dengan para pengembang compiler selama beberapa waktu membuat saya lebih terampil dalam menulis JIT. Paling tidak, melihat PyPy telah memperluas wawasan saya!


Kesimpulan

Orang-orang itu penting. Dan dengan sedikit keberuntungan, JIT go brrr.

Belum ada komentar.

Belum ada komentar.