- Proyek CPython baru-baru ini memperkenalkan strategi implementasi baru untuk interpreter bytecode. Hasil awal menunjukkan peningkatan performa rata-rata 10-15% di berbagai platform
- Namun, peningkatan performa ini terutama merupakan hasil dari upaya menghindari masalah regresi pada LLVM 19. Jika dibandingkan dengan tolok ukur yang lebih baik (misalnya GCC, clang-18, LLVM 19 dengan flag tuning tertentu), peningkatan performanya turun menjadi 1-5%
Hasil performa
- Beberapa build interpreter CPython dibenchmark menggunakan berbagai compiler dan opsi konfigurasi. Pengujian dilakukan pada server Intel dan Apple M1 Macbook Air.
- Semua build menggunakan LTO dan PGO. Dengan
clang18 sebagai acuan, digunakan rata-rata yang dilaporkan oleh pypeformance/pyperf compare_to.
- Perbandingan performa compiler
- Apple M1 Macbook Air :
- clang18: acuan
- clang19: 1,12x lebih lambat
- clang19.taildup: 1,02x lebih lambat
- clang19.tc: 1,00x lebih lambat
- gcc: N/A
- Interpreter tail-call masih menunjukkan peningkatan kecepatan dibandingkan clang-18, tetapi penurunan kecepatan saat beralih ke clang-19 jauh lebih drastis.
Regresi LLVM
Latar belakang singkat
- Interpreter bytecode tradisional tersusun dari pernyataan
switch di dalam loop while. Sebagian besar compiler mengompilasi switch menjadi tabel lompatan.
- Compiler C modern mendukung pola mengambil alamat label dan menggunakannya sebagai "computed goto". CPython menggunakan pola ini sampai pekerjaan tail-call dilakukan.
Regresi LLVM 19
- LLVM 19 membatasi pass tail-duplication, sehingga duplikasi dihentikan ketika ukuran IR melebihi ambang tertentu. Akibatnya, di CPython semua lompatan dispatch digabungkan, sehingga tujuan dari implementasi berbasis computed
goto sepenuhnya batal.
Keanehan tambahan
- Ada keyakinan bahwa perubahan pada logika duplikasi tail-call menyebabkan regresi, tetapi besarnya regresi itu tidak bisa dijelaskan sepenuhnya.
- Pada prosesor modern, peningkatan kecepatan 2-4% lebih umum terjadi.
Apakah computed goto diperlukan?
- Benchmark
clang19.nocg diklaim lebih cepat daripada clang19. Ini menunjukkan bahwa compiler dapat melakukan optimisasi yang sama dengan menggunakan interpreter berbasis switch.
Perbaikan
- Pull request LLVM 114990 telah memperbaiki regresi tersebut. Perbaikan ini memulihkan performa yang diharapkan.
Refleksi
Tentang benchmarking
- Saat mengoptimalkan sistem, benchmark dan metodologi benchmarking disusun untuk mengevaluasi perubahan yang diusulkan.
- Benchmark membutuhkan lebih banyak asumsi dan keyakinan agar satu titik data tertentu bisa digeneralisasi.
Baseline
- Saat mengusulkan solusi atau metode baru, praktik umum adalah membandingkannya dengan "pendekatan terbaik yang diketahui saat ini".
Tentang rekayasa perangkat lunak
- Sistem perangkat lunak itu kompleks, saling terhubung, dan berubah dengan cepat.
- Compiler pengoptimal berada dalam ketegangan antara menghormati niat programmer dan tetap mengoptimalkan kode.
Compiler pengoptimal
- Atribut
musttail mewakili jenis baru fitur compiler yang berkaitan dengan optimisasi. Ini dapat menyediakan gaya yang lebih kuat untuk menulis kode yang sensitif terhadap performa.
Satu hal lagi tentang nix
nix sangat berguna dalam proyek ini. Ini sangat membantu untuk mengelola dan membangun beberapa versi interpreter Python.
1 komentar
Opini Hacker News
Halo. Saya adalah penulis PR yang memperkenalkan interpreter tail-calling ke CPython
Benchmarking memang pekerjaan yang sangat sulit dilakukan dengan baik
Saya memuji penulis yang berhasil mengungkap kebenaran masalah ini
Ini adalah contoh yang baik bahwa C bukan bahasa yang "dekat dengan mesin"
switch()yang "naif"Dengan menyesuaikan cara compiler mengatur loop, interpreter tail-call tidak seefektif yang diumumkan
Menilai performa build Python sangatlah sulit
Diskusi terkait:
Artikel yang luar biasa
Baru-baru ini saya melakukan benchmarking dari Python 3.9 hingga 3.13
Saya penasaran bagaimana optimisasi seperti ini berkaitan dengan tail-call optimization