Ingatlah bahwa yang berikut ini hanya membandingkan perbedaan antara kompilasi asli dan JIT, dan tidak mencakup spesifikasi bahasa atau kerangka kerja tertentu. Mungkin ada alasan yang sah untuk memilih platform tertentu di luar ini.
Ketika kami mengklaim bahwa kode asli lebih cepat, kita berbicara tentang kasus penggunaan khas dari kode yang dikompilasi secara native versus kode yang dikompilasi JIT, di mana penggunaan khas dari aplikasi yang dikompilasi JIT akan dijalankan oleh pengguna, dengan hasil langsung (misalnya, tidak ada tunggu dulu kompiler). Dalam hal ini, saya tidak berpikir siapa pun dapat mengklaim dengan wajah lurus, bahwa kode yang dikompilasi JIT dapat cocok atau mengalahkan kode asli.
Mari kita asumsikan kita memiliki program yang ditulis dalam beberapa bahasa X, dan kita dapat mengkompilasinya dengan kompiler asli, dan lagi dengan kompiler JIT. Setiap alur kerja memiliki tahapan yang sama, yang dapat digeneralisasi sebagai (Kode -> Representasi Menengah -> Kode Mesin -> Eksekusi). Perbedaan besar antara dua adalah tahapan mana yang dilihat oleh pengguna dan mana yang dilihat oleh programmer. Dengan kompilasi asli, programmer melihat semua kecuali tahap eksekusi, tetapi dengan solusi JIT, kompilasi ke kode mesin dilihat oleh pengguna, di samping eksekusi.
Klaim bahwa A lebih cepat dari B mengacu pada waktu yang dibutuhkan untuk menjalankan program, seperti yang terlihat oleh pengguna . Jika kita mengasumsikan bahwa kedua keping kode bekerja secara identik dalam tahap Eksekusi, kita harus mengasumsikan bahwa alur kerja JIT lebih lambat untuk pengguna, karena ia juga harus melihat waktu T dari kompilasi ke kode mesin, di mana T> 0. Jadi , untuk setiap kemungkinan alur kerja JIT untuk melakukan hal yang sama seperti alur kerja asli, kepada pengguna, kita harus mengurangi waktu Eksekusi kode, sehingga Eksekusi + Kompilasi ke kode mesin, lebih rendah daripada hanya tahap Eksekusi dari alur kerja asli. Ini berarti kita harus mengoptimalkan kode lebih baik dalam kompilasi JIT daripada dalam kompilasi asli.
Namun, ini agak tidak layak, karena untuk melakukan optimasi yang diperlukan untuk mempercepat Eksekusi, kita harus menghabiskan lebih banyak waktu dalam mengkompilasi ke tahap kode mesin, dan dengan demikian, setiap kali kita menyimpan karena kode yang dioptimalkan benar-benar hilang, karena kami menambahkannya ke kompilasi. Dengan kata lain, "kelambatan" dari solusi berbasis JIT bukan hanya karena waktu tambahan untuk kompilasi JIT, tetapi kode yang dihasilkan oleh kompilasi tersebut bekerja lebih lambat daripada solusi asli.
Saya akan menggunakan contoh: Daftar alokasi. Karena akses memori beberapa ribu kali lebih lambat daripada akses register, idealnya kami ingin menggunakan register sedapat mungkin dan memiliki akses memori sesedikit mungkin, tetapi kami memiliki jumlah register yang terbatas, dan kami harus menumpahkan keadaan ke dalam memori ketika kami membutuhkan sebuah register. Jika kita menggunakan algoritma alokasi register yang membutuhkan 200ms untuk menghitung, dan sebagai hasilnya kita menghemat waktu eksekusi 2ms - kita tidak memanfaatkan waktu terbaik untuk kompiler JIT. Solusi seperti algoritma Chaitin, yang dapat menghasilkan kode yang sangat optimal tidak cocok.
Peran kompiler JIT adalah untuk mencapai keseimbangan terbaik antara waktu kompilasi dan kualitas kode yang dihasilkan, namun, dengan bias besar pada waktu kompilasi yang cepat, karena Anda tidak ingin membiarkan pengguna menunggu. Kinerja kode yang dieksekusi lebih lambat dalam kasus JIT, karena kompiler asli tidak terikat (banyak) berdasarkan waktu dalam mengoptimalkan kode, jadi bebas menggunakan algoritma terbaik. Kemungkinan keseluruhan kompilasi + eksekusi untuk kompiler JIT hanya dapat mengalahkan waktu eksekusi untuk kode yang dikompilasi secara asli adalah 0
Tetapi VM kami tidak hanya terbatas pada kompilasi JIT. Mereka menggunakan teknik kompilasi sebelumnya, caching, hot swapping, dan optimisasi adaptif. Jadi mari kita modifikasi klaim kami bahwa kinerja adalah apa yang dilihat pengguna, dan batasi sampai waktu yang diperlukan untuk pelaksanaan program (anggap kami telah mengkompilasi AOT). Kita dapat secara efektif membuat kode eksekusi setara dengan kompiler asli (atau mungkin lebih baik?). Klaim besar untuk VM adalah bahwa mereka mungkin dapat menghasilkan kode kualitas yang lebih baik daripada kompiler asli, karena ia memiliki akses ke lebih banyak informasi - bahwa dari proses yang berjalan, seperti seberapa sering fungsi tertentu dapat dieksekusi. VM kemudian dapat menerapkan optimasi adaptif ke kode yang paling penting melalui hot swapping.
Ada masalah dengan argumen ini - ia mengasumsikan bahwa optimasi yang dipandu profil dan sejenisnya adalah sesuatu yang unik untuk VM, yang tidak benar. Kita juga dapat menerapkannya pada kompilasi asli - dengan mengkompilasi aplikasi kita dengan profiling diaktifkan, merekam informasi, dan kemudian mengkompilasi ulang aplikasi dengan profil itu. Mungkin juga patut menunjukkan bahwa hot swapping kode bukanlah sesuatu yang hanya dapat dilakukan oleh kompiler JIT, kita dapat melakukannya untuk kode asli - meskipun solusi berbasis JIT untuk melakukan ini lebih mudah tersedia, dan jauh lebih mudah bagi pengembang. Jadi pertanyaan besarnya adalah: Dapatkah seorang VM menawarkan kami beberapa informasi yang tidak dapat dikompilasi oleh native, yang dapat meningkatkan kinerja kode kami?
Saya tidak bisa melihatnya sendiri. Kami dapat menerapkan sebagian besar teknik VM khas untuk kode asli juga - meskipun prosesnya lebih terlibat. Demikian pula, kita dapat menerapkan optimasi apa pun dari kompiler asli kembali ke VM yang menggunakan kompilasi AOT atau optimisasi adaptif. Kenyataannya adalah bahwa perbedaan antara kode asli yang dijalankan, dan yang dijalankan dalam VM tidak sebesar yang kami yakini. Mereka pada akhirnya mengarah pada hasil yang sama, tetapi mereka mengambil pendekatan yang berbeda untuk sampai ke sana. VM menggunakan pendekatan berulang untuk menghasilkan kode yang dioptimalkan, di mana kompiler asli mengharapkannya dari awal (dan dapat ditingkatkan dengan pendekatan berulang).
Seorang programmer C ++ mungkin berpendapat bahwa ia membutuhkan optimisasi sejak awal, dan seharusnya tidak menunggu seorang VM untuk mengetahui bagaimana melakukannya, jika memang ada. Ini mungkin titik yang valid dengan teknologi kami saat ini, karena tingkat optimisasi saat ini di VM kami lebih rendah daripada yang ditawarkan kompiler asli - tetapi itu tidak selalu menjadi masalah jika solusi AOT di VM kami meningkat, dll.