Seperti disebutkan dalam komentar, tidak terlalu tepat untuk menyatakan "tanaman kompiler saat ini (Bigloo, SBCL, Gambit, Chicken, dll) 20-50 kali lebih lambat daripada kode C yang setara", tanpa kualifikasi bagaimana Anda menguji dan apa kamu diuji.
Untuk penggunaan saya , saya menemukan bahwa untuk banyak hal Gambit dan Chicken Scheme cukup dekat dengan kode 'C' yang setara dalam kecepatan, dengan versi Gambit saat ini (4.7.3) umumnya lebih cepat daripada Chicken (4.9.0.1) tetapi lebih awal Mengoptimalkankode 'C' keluaran (membuat asumsi tentang jumlah register yang tersedia - mengasumsikan x686 - dan memaksa penggunaan memori tumpukan untuk setiap persyaratan memori tambahan, yang keputusannya harus diserahkan kepada kompiler 'C' seperti halnya Chicken, yang seringkali menghilangkan persyaratan untuk register tambahan dan menggabungkan langkah-langkah pemrosesan) untuk mencegah kompiler 'C' melakukan optimasi sendiri menghasilkan loop kecil sangat ketat hingga sekitar dua kali lebih lambat dari loop kecil ketat yang sama di 'C' (atau Ayam ); Ayam hanya mendefinisikan banyak variabel lokal ke fungsi yang diberikan sesuai keinginan (sebagian besar digunakan secara tidak langsung) dan kemudian tergantung pada kompiler untuk mengoptimalkan sebagian besar dari mereka yang jauh. Ayam tidak
EDIT_ADD: Saya telah melakukan penelitian lebih lanjut tentang versi Skema Ayam dan Gambit-C dan telah menemukan yang berikut:
Ayam lebih cepat daripada Gambit untuk loop ketat kecil karena alasan di atas (lebih tergantung pada kompiler 'C' untuk optimasi tanpa melakukan sebanyak itu sendiri dan dengan demikian mengambil keuntungan lebih baik dari register tambahan x86-64), tetapi juga karena itu tidak termasuk pemeriksaan pemeliharaan tumpukan "POLL" di dalam loop, sedangkan Gambit menyertakan pemeriksaan "POLL" di dalam loop. Bahkan ketika ini tidak dipicu (kasus biasa), akan diperlukan beberapa siklus jam CPU untuk menentukan bahwa tidak ada yang diperlukan (sekitar 6 siklus). Kompiler yang lebih pintar di masa depan mungkin melihat bahwa tidak perlu melakukan pemeriksaan tumpukan ketika berada di dalam loop ketat dan tidak melakukan operasi pembuatan tumpukan, melakukannya hanya sebelum atau setelah loop dan menghemat waktu ini.
Makro 'C' Gambit melakukan terlalu banyak pekerjaan, seperti yang dikatakan, dalam mendefinisikan secara tepat bagaimana operasi harus dilakukan, terutama termasuk operasi ukuran tumpukan tetap, dan ini kemungkinan lebih sulit untuk dioptimalkan oleh kompiler 'C'; menggunakan register secara lebih efektif dapat mengurangi waktu putaran ketat mungkin 4 siklus, yang dikombinasikan dengan yang di atas akan memasukkannya ke dalam Chicken Ballpark.
Baik output "baca / modifikasi / tulis" optimisasi untuk mengatakan operasi vektor yang memodifikasi di tempat dan jangan output kode sehingga kompiler melakukannya. Backend yang lebih cerdas seperti LLVM saat digunakan dengan Haskell melakukan hal semacam ini. Ini akan mengurangi penggunaan register oleh satu dan waktu pelaksanaan dalam menggunakan hanya satu instruksi daripada membaca terpisah, perhitungan modifikasi, dan menulis ke lokasi yang sama; ini akan menjadi hanya perhitungan modifikasi (katakan sedikit atau), dan kemudian baca modifikasi (| =) tulis instruksi tunggal. Ini mungkin membuat kecepatan lebih cepat dengan satu siklus atau lebih
Keduanya diketik secara dinamis dan memproses data "tag" bit sebagai bagian dari data mereka. Tidak ada yang cukup pintar untuk loop ketat untuk mengurangi tag, melakukan loop "tag-less", kemudian menambahkan tag kembali untuk setiap hasil dari loop, juga tidak menghasilkan kode di mana kompiler 'C' dapat melihat untuk melakukan ini walaupun itu menggabungkan operasi ini untuk beberapa kasus. Optimalisasi di sini dapat mengurangi waktu loop oleh beberapa siklus CPU atau lebih, tergantung pada loop.
Loop 'C' yang sangat ketat dapat memakan waktu sekitar 3,5 siklus clock CPU per loop pada CPU yang cepat yang kecepatan akses cache memory tidak dibatasi (seperti AMD Bulldozer, yang sekitar dua kali lebih lambat); loop yang sama di Chicken saat ini membutuhkan waktu sekitar 6 siklus dan Gambit membutuhkan sekitar 16,9 siklus. Dengan semua optimasi seperti di atas, tidak ada alasan bahwa implementasi Skema ini tidak dapat melakukan itu, namun beberapa pekerjaan diperlukan:
Dalam kasus Gambit, pekerjaan yang lebih sulit mungkin adalah meningkatkan analisis aliran untuk mengenali ketika tidak ada tes "POLL" yang perlu dimasukkan (mis. Bisakah ini didorong oleh interupsi, meskipun kompiler memungkinkan interupsi dimatikan untuk beberapa penggunaan? ); perbaikan yang lebih mudah adalah dengan hanya menerapkan penggunaan register yang lebih baik (mis. mengenali register x86-64 lebih baik daripada arsitektur x686 default). Untuk keduanya, analisis aliran yang lebih baik untuk mengenali bahwa mereka dapat "membatalkan" data, terutama "fixnum", "flonum", dan vektor, data sehingga operasi ini tidak diperlukan di dalam loop ketat dan menggabungkan instruksi baca / modifikasi / tulis. Kedua tujuan ini dapat dicapai dengan menggunakan backend yang lebih baik seperti LLVM (bukan jumlah pekerjaan sepele, tetapi keduanya sudah sebagian ada di sana).
Kesimpulan: Ayam saat ini sekitar 50% lebih lambat dari 'C' pada CPU tercepat (bukan Bulldozer saya, di mana kecepatannya hampir sama karena pembatasan cache kode 'C') dan Gambit sekitar 400% lebih lambat (hanya sekitar 125% lebih lambat pada Bulldozer saya yang lambat). Namun, perbaikan di masa depan untuk kompiler dapat mengurangi ini sehingga salah satu kode tidak lebih lambat dari 'C' atau dalam margin yang ditentukan OP.
Bahasa yang lebih kompleks seperti Haskell, ketika menggunakan backend LLVM, memperhatikan dengan seksama penggunaan yang ketat (bukan masalah dengan skema yang selalu ingin secara default), dan menggunakan struktur data yang sesuai (ST array tanpa kotak daripada daftar untuk loop ketat; agak berlaku untuk Skema menggunakan vektor), berjalan pada kecepatan yang sama seperti 'C' jika backend LLVM digunakan dengan optimisasi penuh. Jika dapat melakukan ini, begitu juga Skema dengan peningkatan kompiler di atas.
LAGI, tidak ada cara yang salah satu dari ini adalah 20 sampai 50 kali lebih lambat bila digunakan dengan flag optimasi yang tepat. END_EDIT_ADD
Tentu saja, semua tolok ukur tidak valid jika seseorang tidak menggunakan pengaturan optimasi yang sesuai untuk masing-masing seperti yang akan dilakukan dalam lingkungan produksi ...
Saya akan berpikir bahwa kompiler Chez Scheme komersial akan berada di stadion baseball untuk menghasilkan output kinerja tinggi seperti halnya Gambit dan Chicken, sebagai komersial itu pasti memiliki "waktu dan uang yang serius diinvestasikan ke dalamnya".
Satu-satunya cara saya dapat membuat Gambit atau Chicken berjalan selambatnya "20 hingga 50 kali lebih lambat dari 'C'" adalah dengan tidak menggunakan pengaturan pengoptimalan, dalam hal ini mereka sering tidak berjalan lebih cepat daripada yang ditafsirkan dalam REPL mereka - 10 kali lebih lambat daripada menggunakan pengaturan itu dengan benar.
Apakah mungkin OP belum diuji menggunakan pengaturan ini dengan benar?
Jika OP ingin memperjelas prosedur pengujiannya, saya dengan senang hati akan mengedit jawaban ini untuk menunjukkan bahwa setidaknya Gambit dan Chicken tidak harus selambat itu.
(declare (optimize ...))
,(declare (<type> <var))
dan(the <type> <expr>)
dalam fungsi Anda? Kalau tidak, ini bukan perbandingan yang adil :)