Runtime: Memperkenalkan JIT berjenjang

Dibuat pada 14 Apr 2016  ·  63Komentar  ·  Sumber: dotnet/runtime

Mengapa .NET JIT tidak berjenjang?

JIT memiliki dua tujuan desain utama: Waktu startup yang cepat dan throughput kondisi mapan yang tinggi.

Pada awalnya, tujuan-tujuan ini tampak bertentangan. Tetapi dengan desain JIT dua tingkat, keduanya dapat dicapai:

  1. Semua kode mulai ditafsirkan. Ini menghasilkan waktu startup yang sangat cepat (lebih cepat dari RyuJIT). Contoh: Metode Main hampir selalu dingin dan hanya membuang-buang waktu.
  2. Kode yang sering berjalan di-jit menggunakan generator kode berkualitas sangat tinggi. Sangat sedikit metode yang akan menjadi panas (1%?). Oleh karena itu, throughput dari JIT berkualitas tinggi tidak terlalu menjadi masalah. Itu dapat menghabiskan waktu sebanyak yang dihabiskan kompiler C untuk menghasilkan kode yang sangat bagus. Juga, dapat _menganggap_ bahwa kode tersebut panas. Itu bisa sebaris seperti loop gila dan membuka gulungan. Ukuran kode tidak menjadi perhatian.

Mencapai arsitektur ini tampaknya tidak terlalu mahal:

  1. Menulis juru bahasa tampaknya murah dibandingkan dengan JIT.
  2. Generator kode berkualitas tinggi harus dibuat. Ini bisa berupa VC, atau proyek LLILC.
  3. Harus dimungkinkan untuk mentransisikan kode yang dijalankan yang ditafsirkan ke kode yang dikompilasi. Ini mungkin; JVM melakukannya. Ini disebut penggantian tumpukan (OSR).

Apakah ide ini sedang dikejar oleh tim JIT?

.NET berjalan di 100-an juta server. Saya merasa banyak kinerja yang tersisa di atas meja dan jutaan server terbuang sia-sia untuk pelanggan karena gen kode yang kurang optimal.

kategori: throughput
tema:pertaruhan besar
tingkat keterampilan: ahli
biaya: ekstra besar

area-CodeGen-coreclr enhancement optimization tenet-performance

Komentar yang paling membantu

Dengan PR terbaru (https://github.com/dotnet/coreclr/pull/17840, https://github.com/dotnet/sdk/pull/2201) Anda juga memiliki kemampuan untuk menentukan kompilasi berjenjang sebagai runtimeconfig. properti json atau properti proyek msbuild. Menggunakan fungsi ini akan mengharuskan Anda untuk menggunakan versi terbaru sedangkan variabel lingkungan telah ada untuk sementara waktu.

Semua 63 komentar

@GSPP Tiering adalah topik konstan dalam merencanakan percakapan. Kesan saya adalah bahwa ini masalah _kapan_, bukan _jika_, jika itu memberikan pelipur lara. Untuk _why_ itu belum ada, saya pikir itu karena, secara historis, potensi keuntungan yang dirasakan tidak membenarkan sumber daya pengembangan tambahan yang diperlukan untuk mengelola peningkatan kompleksitas dan risiko beberapa mode codegen. Saya harus benar-benar membiarkan para ahli berbicara tentang ini, jadi saya akan menambahkannya.

/cc @dotnet/jit-contrib @russellhadley

Entah kenapa saya ragu ini masih relevan di dunia crossgen/ngen, Ready to Run dan corert.

Tak satu pun dari ini memberikan throughput kondisi mapan yang tinggi saat ini yang penting bagi sebagian besar aplikasi web. Jika mereka pernah melakukannya, saya senang dengan itu karena saya pribadi tidak peduli dengan waktu startup.

Namun sejauh ini semua pembuat kode untuk .NET telah mencoba membuat tindakan penyeimbangan yang mustahil antara dua tujuan, tidak memenuhi keduanya dengan baik. Mari singkirkan tindakan penyeimbangan itu sehingga kita dapat mengubah pengoptimalan menjadi 11.

Namun sejauh ini semua pembuat kode untuk .NET telah mencoba membuat tindakan penyeimbangan yang mustahil antara dua tujuan, tidak memenuhi keduanya dengan baik. Mari singkirkan tindakan penyeimbangan itu sehingga kita dapat mengubah pengoptimalan menjadi 11.

Saya setuju tetapi memperbaiki ini tidak memerlukan hal-hal seperti juru bahasa. Hanya kompiler crossgen yang bagus, baik itu RyuJIT atau LLILC yang lebih baik.

Saya pikir keuntungan terbesar adalah untuk aplikasi yang perlu menghasilkan kode saat runtime. Ini termasuk bahasa dinamis dan wadah server.

Memang benar bahwa kode yang dihasilkan secara dinamis adalah salah satu motivasi - tetapi juga benar bahwa kompiler statis tidak akan pernah memiliki akses ke semua informasi yang tersedia saat runtime. Tidak hanya itu, bahkan ketika berspekulasi (misalnya berdasarkan informasi profil), jauh lebih sulit bagi kompiler statis untuk melakukannya dengan adanya modal atau perilaku yang bergantung pada konteks eksternal.

Aplikasi web seharusnya tidak memerlukan pemrosesan gaya ngen. Itu tidak cocok dengan baik ke dalam pipa penyebaran. Dibutuhkan banyak waktu untuk ngen biner besar (walaupun hampir semua kode mati secara dinamis atau dingin).

Juga, saat men-debug dan menguji aplikasi web, Anda tidak dapat mengandalkan ngen untuk memberikan kinerja yang realistis.

Selanjutnya, poin I 2nd Carol menggunakan informasi dinamis. Tingkat interpretasi dapat memprofilkan kode (cabang, jumlah perjalanan berulang, target pengiriman dinamis). Ini pertandingan yang sempurna! Kumpulkan dulu profilnya, lalu optimalkan.

Tiering menyelesaikan segalanya dalam setiap skenario selamanya. Kira-kira berbicara :) Ini benar-benar dapat membawa kita ke janji JIT: Mencapai kinerja _melampaui apa yang dapat dilakukan oleh kompiler C.

Implementasi RyuJIT saat ini seperti sekarang cukup baik untuk Tier 1... Pertanyaannya adalah: Apakah masuk akal untuk memiliki JIT optimasi ekstrim Tier 2 untuk hot path yang dapat dijalankan setelah fakta? Pada dasarnya ketika kami mendeteksi atau memiliki informasi runtime yang cukup untuk mengetahui bahwa ada sesuatu yang panas atau ketika diminta untuk menggunakannya dari awal.

RyuJIT sejauh ini cukup baik untuk menjadi tingkat 1. Masalahnya adalah bahwa seorang juru bahasa akan memiliki _jauh_ waktu startup lebih cepat (menurut perkiraan saya). Masalah kedua adalah untuk maju ke tier 2 keadaan lokal yang mengeksekusi kode tier 1 harus dapat ditransfer ke kode tier 2 (OSR) yang baru. Itu membutuhkan perubahan RyuJIT. Menambahkan juru bahasa, menurut saya, akan menjadi jalur yang lebih murah dengan latensi startup yang lebih baik pada saat yang bersamaan.

Varian yang lebih murah adalah tidak mengganti kode yang sedang berjalan dengan kode tingkat 2. Sebagai gantinya, tunggu sampai kode tingkat 1 kembali secara alami. Ini bisa menjadi masalah jika kode masuk ke loop panas yang berjalan lama. Itu tidak akan pernah sampai pada kinerja tingkat 2 seperti itu.

Saya pikir itu tidak terlalu buruk dan bisa digunakan sebagai strategi v1. Ide-ide mitigasi tersedia seperti atribut yang menandai metode sebagai hot (ini harus tetap ada bahkan dengan strategi JIT saat ini).

@GSPP Itu benar, tetapi itu tidak berarti Anda tidak akan tahu itu pada putaran berikutnya. Jika kode & instrumentasi Jitted menjadi persisten, maka eksekusi kedua Anda masih akan mendapatkan kode Tier 2 (dengan mengorbankan beberapa waktu startup) --- yang untuk sekali ini saya pribadi tidak peduli karena saya menulis sebagian besar kode server.

Menulis juru bahasa tampaknya murah dibandingkan dengan JIT.

Alih-alih menulis penerjemah baru, apakah masuk akal untuk menjalankan RyuJIT dengan pengoptimalan dinonaktifkan? Apakah itu cukup meningkatkan waktu startup?

Generator kode berkualitas tinggi harus dibuat. Ini bisa jadi VC

Apakah Anda berbicara tentang C2, backend Visual C++? Itu bukan lintas platform dan bukan open source. Saya ragu bahwa memperbaiki keduanya akan terjadi dalam waktu dekat.

Ide bagus dengan menonaktifkan pengoptimalan. Masalah OSR tetap ada. Tidak yakin betapa sulitnya menghasilkan kode yang memungkinkan runtime untuk mendapatkan status arsitektur IL (lokal dan tumpukan) saat runtime di titik aman, salin itu ke kode jitted tingkat 2 dan lanjutkan fungsi tengah eksekusi tingkat 2. JVM melakukannya tetapi siapa yang tahu berapa banyak waktu yang dibutuhkan untuk mengimplementasikannya.

Ya, saya sedang berbicara tentang C2. Saya pikir saya ingat bahwa setidaknya satu dari JIT Desktop didasarkan pada kode C2. Mungkin tidak berfungsi untuk CoreCLR tetapi mungkin untuk Desktop. Saya yakin Microsoft tertarik untuk menyelaraskan basis kode jadi itu mungkin memang keluar. LLVM tampaknya menjadi pilihan yang bagus. Saya percaya banyak bahasa saat ini tertarik untuk membuat LLVM berfungsi dengan GC dan dengan runtime terkelola secara umum.

LLVM tampaknya menjadi pilihan yang bagus. Saya percaya banyak bahasa saat ini tertarik untuk membuat LLVM berfungsi dengan GC dan dengan runtime terkelola secara umum.

Artikel menarik tentang topik ini: Apple baru-baru ini memindahkan tingkat terakhir JIT JavaScript mereka dari LLVM: https://webkit.org/blog/5852/introducing-the-b3-jit-compiler/ . Kami kemungkinan akan menghadapi masalah serupa dengan apa yang mereka temui: waktu kompilasi yang lambat dan kurangnya pengetahuan LLVM tentang bahasa sumber.

10x lebih lambat dari RyuJIT akan benar-benar dapat diterima untuk tingkat ke-2.

Saya tidak berpikir bahwa kurangnya pengetahuan tentang bahasa sumber (yang merupakan masalah sebenarnya) melekat pada arsitektur LLVM. Saya percaya banyak tim sibuk memindahkan LLVM ke keadaan di mana pengetahuan bahasa sumber dapat digunakan dengan lebih mudah. _Semua_ bahasa tingkat tinggi non-C memiliki masalah ini saat kompilasi di LLVM.

Proyek WebKIT FTL/B3 berada dalam posisi yang lebih sulit untuk berhasil daripada .NET karena mereka harus unggul saat menjalankan kode yang _dalam total_ menghabiskan beberapa ratus milidetik waktu dan kemudian keluar. Ini adalah sifat beban kerja JavaScript yang mendorong halaman web. .NET tidak di tempat itu.

@GSPP Saya yakin Anda mungkin tahu tentang LLILC . Jika tidak, lihatlah.

Kami telah bekerja untuk sementara waktu pada dukungan LLVM untuk konsep CLR dan telah berinvestasi dalam peningkatan EH dan GC. Masih sedikit lagi yang harus dilakukan pada keduanya. Di luar itu, ada sejumlah pekerjaan yang tidak diketahui agar pengoptimalan berfungsi dengan baik dengan adanya GC.

LLILC tampaknya terhenti. Apakah itu?
Pada 18 Apr 2016 19:32, "Andy Ayers" [email protected] menulis:

@GSPP https://github.com/GSPP Saya yakin Anda mungkin tahu tentang LLILC
https://github.com/dotnet/llilc. Jika tidak, lihatlah.

Kami telah bekerja untuk sementara waktu pada dukungan LLVM untuk konsep CLR dan telah
diinvestasikan dalam perbaikan EH dan GC. Masih sedikit lagi yang harus dilakukan
keduanya. Di luar itu beberapa ada jumlah pekerjaan yang tidak diketahui untuk mendapatkan optimasi
bekerja dengan baik di hadapan GC.


Anda menerima ini karena Anda berkomentar.
Balas email ini secara langsung atau lihat di GitHub
https://github.com/dotnet/coreclr/issues/4331#issuecomment -211630483

@drbo - LLILC berada di belakang burner untuk saat ini - tim MS telah berfokus untuk mendapatkan lebih banyak target yang diangkat di RyuJIT serta memperbaiki masalah yang muncul saat CoreCLR mendorong untuk dirilis dan itu menghabiskan hampir seluruh waktu kita. Ada dalam daftar TODO saya (di waktu luang saya yang berlimpah) untuk menulis posting pelajaran berdasarkan seberapa jauh kami (saat ini) telah mencapai LLILC, tetapi saya belum melakukannya.
Pada tiering, topik ini telah menghasilkan banyak diskusi selama bertahun-tahun. Saya pikir mengingat beberapa beban kerja baru, serta tambahan baru dari gambar siap pakai versi yang dapat dijalankan, kami akan melihat lebih segar tentang bagaimana dan di mana harus tier.

@russellhadley apakah Anda punya waktu luang untuk menulis posting?

Saya berhipotesis, seharusnya ada sesuatu tentang slot tumpukan yang tidak dipromosikan dan gcroot yang melanggar optimasi dan waktu jitting yang lambat... Sebaiknya saya melihat kode proyek.

Saya juga bertanya-tanya apakah mungkin dan menguntungkan untuk langsung masuk ke SelectionDAG dan melakukan bagian dari backend LLVM. Setidaknya beberapa lubang intip dan perbanyakan salinan... jika misalnya promosi gcroot ke register didukung di LLILC

Saya ingin tahu tentang status LLILC termasuk kemacetan saat ini dan bagaimana tarifnya terhadap RyuJIT. LLVM sebagai kompiler "kekuatan industri" yang lengkap harus memiliki banyak pengoptimalan yang tersedia untuk OSS. Ada beberapa pembicaraan tentang serialisasi/deserialisasi format bitcode yang lebih efisien dan lebih cepat di milis; Saya bertanya-tanya apakah ini hal yang berguna untuk LLILC.

Apakah ada pemikiran lain tentang ini? @russellhadley CoreCLR telah dirilis dan RyuJIT telah di-porting ke (setidaknya) x86 – apa rencana selanjutnya?

Lihat dotnet/coreclr#10478 untuk permulaan pengerjaan ini.

Juga dotnet/coreclr#12193

@noahfalk , dapatkah Anda memberikan cara untuk memberi tahu runtime untuk memaksa kompilasi tingkat 2 langsung dari kode yang dikelola itu sendiri? Kompilasi berjenjang adalah ide yang sangat bagus untuk sebagian besar kasus penggunaan, tetapi saya sedang mengerjakan proyek di mana waktu startup tidak relevan tetapi throughput dan latensi yang stabil sangat penting.

Dari atas kepala saya, ini bisa jadi:

  • pengaturan baru di file konfigurasi, sakelar seperti <gcServer enabled="true" /> untuk memaksa JIT agar selalu melewati tingkat 1
  • atau sesuatu seperti RuntimeHelpers.PrepareMethod , yang akan dipanggil oleh kode pada semua metode yang merupakan bagian dari hot path (kami menggunakan ini untuk pra-JIT kode kami saat startup). Ini memiliki keuntungan memberikan tingkat kebebasan yang lebih besar kepada pengembang yang seharusnya mengetahui apa itu hot path. Kelebihan tambahan dari metode ini akan baik-baik saja.

Memang, beberapa proyek akan mendapat manfaat dari ini, tetapi saya agak khawatir dengan optimasi yang melewatkan JIT secara default, dan saya tidak dapat mengatakannya, saya lebih suka itu mengoptimalkan kode saya sebagai gantinya.

Saya tahu Anda menulis yang berikut ini di dokumen desain:

Tambahkan tahap pipeline build baru yang dapat diakses dari API kode terkelola untuk melakukan modifikasi sendiri kode.

Kedengarannya sangat menarik 😁 tapi saya tidak yakin itu mencakup apa yang saya tanyakan di sini.


Juga pertanyaan terkait: kapan operan JIT kedua akan dimulai? Kapan suatu metode akan dipanggil untuk ke- n kalinya? Akankah JIT terjadi pada utas metode yang seharusnya dijalankan? Jika demikian, itu akan menyebabkan penundaan sebelum pemanggilan metode. Jika Anda menerapkan pengoptimalan yang lebih agresif, penundaan ini akan lebih lama dari waktu JIT saat ini, yang dapat menjadi masalah.

Itu harus terjadi ketika metode ini dipanggil cukup kali, atau jika loop
mengeksekusi iterasi yang cukup (penggantian di atas panggung). Itu harus terjadi
secara asinkron pada utas latar belakang.

Pada 29 Jun 2017 19:01, "Lucas Trzesniewski" [email protected]
menulis:

@noahfalk https://github.com/noahfalk , bisa tolong berikan caranya
untuk memberi tahu runtime untuk memaksa kompilasi tingkat 2 segera dari
kode yang dikelola itu sendiri? Kompilasi berjenjang adalah ide yang sangat bagus untuk sebagian besar
kasus penggunaan, tetapi saya sedang mengerjakan proyek di mana waktu startup tidak relevan
tetapi throughput dan latensi yang stabil sangat penting.

Dari atas kepala saya, ini bisa jadi:

  • pengaturan baru di file konfigurasi, sakelar seperti diaktifkan="true" /> untuk memaksa JIT untuk selalu melewati tingkat 1
  • atau sesuatu seperti RuntimeHelpers.PrepareMethod, yang akan menjadi
    dipanggil oleh kode pada semua metode yang merupakan bagian dari hot path (kami
    menggunakan ini untuk pra-JIT kode kami saat startup). Ini memiliki keuntungan dari
    memberikan tingkat kebebasan yang lebih besar kepada pengembang yang seharusnya tahu apa
    jalur panas adalah. Kelebihan tambahan dari metode ini akan baik-baik saja.

Memang, beberapa proyek akan mendapat manfaat dari ini, tetapi saya agak khawatir dengan
optimasi lompatan JIT secara default, dan saya tidak bisa mengatakannya
Saya lebih suka itu mengoptimalkan kode saya sebagai gantinya .

Saya tahu Anda menulis yang berikut ini di dokumen desain:

Tambahkan tahap pipeline build baru yang dapat diakses dari API kode terkelola untuk dilakukan
kode modifikasi diri.

Kedengarannya sangat menarik 😁 tapi saya tidak yakin itu mencakup apa

Saya bertanya di sini.

Juga pertanyaan terkait: kapan operan JIT kedua akan dimulai? Ketika sebuah
metode akan dipanggil untuk ke- n kalinya? Akankah JIT terjadi pada
utas tempat metode itu seharusnya dijalankan? Jika demikian, itu akan memperkenalkan
delay sebelum pemanggilan metode. Jika Anda menerapkan lebih agresif
optimasi penundaan ini akan lebih lama dari waktu JIT saat ini, yang
mungkin menjadi isu.


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/dotnet/coreclr/issues/4331#issuecomment-312130920 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AGGWB2WbZ2qVBjRIQWS86MStTSa1ODfoks5sJCzOgaJpZM4IHWs8
.

@ltrzesniewski - Terima kasih atas umpan baliknya! Tentu saja saya berharap kompilasi berjenjang berguna untuk sebagian besar proyek tetapi pengorbanannya mungkin tidak ideal untuk setiap proyek. Saya telah berspekulasi kami akan meninggalkan variabel lingkungan di tempat untuk menonaktifkan jitting berjenjang, dalam hal ini Anda menjaga perilaku runtime yang Anda miliki sekarang dengan kualitas yang lebih tinggi (tetapi lebih lambat untuk menghasilkan) jitting di depan. Apakah menyetel variabel lingkungan adalah sesuatu yang wajar untuk dilakukan aplikasi Anda? Opsi lain juga dimungkinkan, saya hanya tertarik pada variabel lingkungan karena ini adalah salah satu opsi konfigurasi paling sederhana yang dapat kita gunakan.

Juga pertanyaan terkait: kapan operan JIT kedua akan dimulai?

Ini adalah kebijakan yang sangat mungkin berkembang dari waktu ke waktu. Implementasi prototipe saat ini menggunakan kebijakan sederhana: "Apakah metode telah dipanggil >= 30 kali"
https://github.com/dotnet/coreclr/blob/master/src/vm/tieredcompilation.cpp#L89
https://github.com/dotnet/coreclr/blob/master/src/vm/tieredcompilation.cpp#L122

Dengan mudah kebijakan yang sangat sederhana ini menyarankan peningkatan kinerja yang bagus pada mesin saya, meskipun itu hanya tebakan. Untuk membuat kebijakan yang lebih baik, kita perlu mendapatkan umpan balik penggunaan dunia nyata, dan mendapatkan umpan balik itu akan mengharuskan mekanik inti cukup kuat dalam berbagai skenario. Jadi rencana saya adalah meningkatkan ketahanan/kompat terlebih dahulu dan kemudian melakukan lebih banyak eksplorasi untuk kebijakan penyetelan.

@DemiMarie - Kami tidak memiliki apa pun yang melacak iterasi loop sebagai bagian dari kebijakan sekarang, tetapi ini merupakan prospek yang menarik untuk masa depan.

Apakah ada pemikiran tentang pembuatan profil, pengoptimalan spekulatif, dan
deoptimasi? JVM melakukan semua ini.

Pada 29 Jun 2017 20:58, "Noah Falk" [email protected] menulis:

@ltrzesniewski https://github.com/ltrzesniewski - Terima kasih atas
masukan! Tentunya semoga kompilasi berjenjang ini bermanfaat bagi yang luas
sebagian besar proyek tetapi pengorbanannya mungkin tidak ideal untuk setiap proyek.
Saya telah berspekulasi kami akan meninggalkan variabel lingkungan di tempat untuk
nonaktifkan jitting berjenjang, dalam hal ini Anda menjaga perilaku runtime Anda
miliki sekarang dengan kualitas yang lebih tinggi (tetapi lebih lambat untuk menghasilkan) jitting di depan. Adalah
menyetel variabel lingkungan sesuatu yang masuk akal untuk dilakukan aplikasi Anda?
Pilihan lain juga dimungkinkan, saya hanya tertarik pada lingkungan
variabel karena ini adalah salah satu opsi konfigurasi paling sederhana yang dapat kita gunakan.

Juga pertanyaan terkait: kapan operan JIT kedua akan dimulai?

Ini adalah kebijakan yang sangat mungkin berkembang dari waktu ke waktu. Sekarang
implementasi prototipe menggunakan kebijakan sederhana: "Apakah metodenya telah
dipanggil >= 30 kali"
https://github.com/dotnet/coreclr/blob/master/src/vm/
tieredcompilation.cpp#L89
https://github.com/dotnet/coreclr/blob/master/src/vm/
tieredcompilation.cpp#L122

Mudahnya, kebijakan yang sangat sederhana ini menyarankan peningkatan kinerja yang bagus pada
mesin saya, meskipun itu hanya tebakan. Untuk membuat kebijakan yang lebih baik
kita perlu mendapatkan umpan balik penggunaan dunia nyata, dan mendapatkan umpan balik itu
akan membutuhkan mekanika inti yang cukup kuat dalam berbagai
skenario. Jadi rencana saya adalah meningkatkan ketahanan/kompat terlebih dahulu dan kemudian melakukannya
eksplorasi lebih lanjut untuk kebijakan penyetelan.

@DemiMarie https://github.com/demimarie - Kami tidak memiliki apa pun yang
melacak iterasi loop sebagai bagian dari kebijakan sekarang, tetapi ini menarik
prospek untuk masa depan.


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/dotnet/coreclr/issues/4331#issuecomment-312146470 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AGGWB5m2qCnOKJsaXFCFigI3J6Ql8PMQks5sJEgZgaJpZM4IHWs8
.

@noahfalk Variabel lingkungan jelas bukan solusi yang memungkinkan Anda mengontrol aplikasi ini dengan aplikasi. Untuk aplikasi server/layanan, Anda biasanya tidak peduli berapa banyak waktu yang dibutuhkan aplikasi untuk memulai (saya tahu kami tidak peduli dengan mengorbankan kinerja). Mengembangkan mesin basis data, saya dapat memberi tahu Anda secara langsung, kami membutuhkannya untuk bekerja secepat mungkin sejak awal dan bahkan di jalur atau tolok ukur yang tidak biasa yang dilakukan oleh klien baru yang potensial.

Di sisi lain, mengingat bahwa pada lingkungan tipikal uptime dapat diukur dalam hitungan minggu, kami tidak peduli jika dibutuhkan bahkan 30 detik; apa yang kami pedulikan adalah memaksa pengguna untuk mengeluarkan sakelar umum (semua atau tidak sama sekali) atau bahkan membuat pengguna harus mempedulikannya (seperti yang disetel secara default dari file konfigurasi) adalah 10 langkah mundur.

Jangan salah paham Saya melihat lebih dari ke depan untuk JIT Berjenjang karena membuka jalur kinerja tinggi membutuhkan waktu sebanyak yang Anda butuhkan codepath untuk optimasi di tingkat JIT. Saya bahkan menyarankan itu sendiri sejak lama dalam pembicaraan informal dengan beberapa insinyur JIT, dan Anda sudah mengetahuinya. Tetapi cara untuk menyesuaikan aplikasi perilaku secara luas (bukan di seluruh sistem) adalah (setidaknya bagi kami) indikator kualitas penting untuk fitur khusus ini.

EDIT: Beberapa masalah gaya.

@redknightlois - Terima kasih atas tindak lanjutnya

Variabel lingkungan jelas bukan solusi yang memungkinkan Anda mengontrol aplikasi ini dengan aplikasi.

Sedikit bingung di bagian ini... variabel lingkungan memiliki per-proses daripada per-perincian sistem, setidaknya di platform yang saya ketahui. Misalnya hari ini untuk mengaktifkan kompilasi berjenjang untuk pengujian hanya dalam satu aplikasi yang saya jalankan:

set COMPLUS_EXPERIMENTAL_TieredCompilation=1
MyApp.exe
set COMPLUS_EXPERIMENTAL_TieredCompilation=0

yang kami pedulikan adalah [kami tidak] memaksa pengguna ... untuk peduli tentang itu

Saya kira Anda menginginkan pengaturan konfigurasi yang dapat ditentukan oleh pengembang aplikasi, bukan oleh orang yang menjalankan aplikasi? Satu kemungkinan dengan env var adalah membuat aplikasi pengguna meluncurkan pembungkus sepele (seperti skrip batch) yang meluncurkan aplikasi coreclr meskipun saya akui tampaknya agak tidak elegan. Saya terbuka untuk alternatif dan tidak diatur pada env var. Hanya untuk menetapkan harapan, ini bukan area yang akan saya habiskan dalam upaya desain aktif dalam waktu dekat, tetapi saya setuju bahwa memiliki konfigurasi yang tepat penting untuk dicapai.

Juga sebagai peringatan - dengan asumsi kami melanjutkan jalur kompilasi berjenjang dengan cara yang layak, saya dapat dengan mudah membayangkan kami mencapai titik di mana mengaktifkan kompilasi berjenjang tidak hanya startup tercepat, tetapi juga mengalahkan kinerja kondisi mapan saat ini. Saat ini startup perf adalah target saya, tetapi itu bukan batasan dari apa yang dapat kami lakukan dengannya :)

Apakah ada pemikiran tentang pembuatan profil, pengoptimalan spekulatif, dan
deoptimasi?

@DemiMarie - Mereka pasti muncul dalam percakapan dan saya pikir banyak orang senang kompilasi berjenjang membuka kemungkinan ini. Berbicara hanya untuk diri saya sendiri, saya mencoba untuk tetap fokus dalam memberikan kemampuan kompilasi berjenjang dasar sebelum menetapkan pandangan saya lebih tinggi. Orang lain di komunitas kami mungkin sudah memimpin saya di aplikasi lain.

@noahfalk Ya, menjadi tidak elegan juga berarti bahwa proses biasa untuk menjalankannya dapat (dan kemungkinan besar akan) menjadi rawan kesalahan dan pada dasarnya itulah masalahnya (satu-satunya cara untuk benar-benar yakin tidak ada yang akan mengacaukannya adalah melakukannya di seluruh sistem). Alternatif yang kami tahu cara kerjanya adalah dengan cara yang sama Anda dapat mengkonfigurasi jika Anda akan menggunakan server GC dengan entri di app.config Anda dapat melakukan hal yang sama dengan kompilasi berjenjang (setidaknya sampai berjenjang dapat secara konsisten mengalahkan kinerja kondisi mapan). Menjadi JIT, Anda juga dapat melakukannya per perakitan menggunakan assembly.config dan akan memberikan tingkat kemampuan yang saat ini tidak ada jika kenop lain dapat dipilih dengan cara itu juga.

Variabel lingkungan sering ditetapkan per pengguna atau per sistem, yang memiliki potensi efek negatif yang memengaruhi semua proses tersebut, di beberapa versi runtime. File konfigurasi per-aplikasi sepertinya merupakan solusi yang jauh lebih baik (bahkan jika per-pengguna/per-sistem juga tersedia) -- sesuatu seperti nilai konfigurasi desktop yang dapat diatur di app.config, tetapi juga menggunakan env vars atau registry .

Saya pikir kita akan mengimplementasikan jalur paling umum yaitu per-aplikasi. Pengaturan seluruh sistem juga mungkin berguna, tetapi saya tidak berpikir kita harus memikirkannya sebelum fitur diimplementasikan.

Harap perhatikan bahwa kami belum menentukan secara rinci apa yang harus dilakukan jit tingkat kedua untuk pengoptimalan, meskipun kami memiliki beberapa ide. Itu mungkin hanya melakukan apa yang dilakukan jit hari ini, tetapi kemungkinan besar itu akan melakukan lebih banyak.

Jadi izinkan saya menunjukkan beberapa komplikasi potensial....

Ada kemungkinan bahwa jit tingkat kedua akan melakukan bootstrap sendiri di atas pengamatan yang dilakukan pada perilaku kode yang dibuat oleh jit tingkat pertama. Jadi, melewati jit tingkat pertama dan meminta jit tingkat kedua secara langsung mungkin tidak berhasil sama sekali, atau mungkin tidak berfungsi dengan baik, karena membiarkan tiering berjalan dengan sendirinya. Mungkin opsi "bypass tiering", bagaimanapun diterapkan, akan berakhir dengan memberikan kode seperti kode yang dihasilkan jit secara default hari ini, bukan kode yang dapat dihasilkan oleh jit tingkat kedua.

Jit tingkat kedua dapat disetel sedemikian rupa sehingga menjalankannya pada kumpulan metode yang besar menyebabkan waktu jit yang relatif lambat (karena harapan kami adalah bahwa metode yang relatif sedikit akan berakhir dengan jit tingkat kedua, dan kami berharap jit tingkat kedua akan melakukan optimasi yang lebih menyeluruh). Kami belum tahu pengorbanan yang tepat di sini.

Yang telah dibilang...

Saya pikir atribut metode "pengoptimalan agresif" masuk akal - yang meminta jit untuk berperilaku agak seperti jit tingkat kedua mungkin berperilaku untuk metode tertentu, dan mungkin melewatkan metode ini selama prajit (karena kode yang dibuat sebelumnya berjalan lebih lambat daripada kode yang dibuat, khusus untuk R2R). Tetapi menerapkan gagasan ini ke seluruh majelis atau ke semua rakitan dalam aplikasi tampaknya tidak menarik.

Jika Anda mengambil apa yang terjadi di compiler asli sebagai analogi yang sesuai, kinerja vs kompilasi waktu/ukuran kode tradeoff bisa menjadi sangat buruk pada tingkat optimasi yang lebih tinggi, misalnya kompilasi 10x lebih lama untuk peningkatan agregat 1-2% dalam kinerja. Kunci dari teka-teki ini adalah mengetahui metode mana yang penting, dan satu-satunya cara untuk melakukannya adalah agar programmer mengetahuinya atau agar sistem mengetahuinya sendiri.

@AndyAyersMS Saya pikir Anda berhasil. Atribut "pengoptimalan agresif" yang menangani JIT mungkin akan menyelesaikan sebagian besar masalah karena tidak dapat memiliki informasi yang cukup bagi JIT untuk menghasilkan kode isolasi yang lebih baik tanpa jit tingkat pertama memiliki waktu untuk memberikan umpan balik itu.

Atribut @redknightlois tidak akan berfungsi jika kita menginginkan lebih banyak tiering: - T3 JIT, T4 JIT, ... Saya tidak yakin apakah dua level tidak cukup, tetapi setidaknya kita harus mempertimbangkan kemungkinan ini.

Akan sangat bagus untuk dapat menggunakan sesuatu yang mirip dengan MPGO untuk mulai berjalan dengan kode jitted tingkat kedua. Maju cepat tingkat pertama alih-alih melewatinya sepenuhnya.

@AndyAyersMS , apakah fakta bahwa Azul telah menerapkan JIT terkelola untuk JVM menggunakan LLVM membuatnya lebih mudah untuk mengintegrasikan LLVM di CLR? Rupanya perubahan didorong ke hulu ke LLVM dalam prosesnya.

Sekadar informasi, saya membuat sejumlah item pekerjaan untuk beberapa pekerjaan tertentu yang perlu kita lakukan untuk mendapatkan jitting berjenjang dari tanah (#12609, dotnet/coreclr#12610, dotnet/coreclr#12611, dotnet/coreclr#12612, dotnet/coreclr #12617). Jika minat Anda berhubungan langsung dengan salah satu dari mereka, jangan ragu untuk menambahkan komentar Anda kepada mereka. Untuk topik lain, saya berasumsi diskusi akan tetap ada di sini, atau siapa pun dapat membuat masalah untuk sub-topik tertentu jika ada cukup minat untuk membaginya sendiri.

@MendelMonteiro Membuat data umpan balik gaya MPGO tersedia saat jitting tentu saja merupakan opsi (saat ini kami hanya dapat membaca data ini kembali saat melakukan prejitting). Ada berbagai batasan untuk apa yang dapat diinstrumentasi, jadi tidak semua metode dapat ditangani dengan cara ini, ada batasan lain yang perlu kita lihat (misalnya, tidak ada data umpan balik yang tersedia untuk inline), instrumentasi dan pelatihan yang diperlukan untuk membuat data MPGO adalah penghalang bagi banyak pengguna, dan data MPGO mungkin cocok atau tidak dengan apa yang kita miliki saat melakukan bootstrap dari tingkat pertama, tetapi ide tersebut tentu saja bermanfaat.

Sejauh tingkat atas berbasis LLVM -- jelas kami telah melihat hal ini sampai batas tertentu dengan LLILC, dan pada saat kami sering berhubungan dengan orang-orang Azul, jadi kami mengetahui banyak hal yang mereka lakukan di LLVM untuk membuatnya lebih dapat menerima kompilasi bahasa dengan GC yang tepat.

Ada (dan kemungkinan besar masih) perbedaan signifikan dalam dukungan LLVM yang diperlukan untuk CLR versus apa yang dibutuhkan untuk Java, baik di GC maupun di EH, dan dalam batasan yang harus diterapkan pada pengoptimal. Untuk mengutip hanya satu contoh: GC CLR saat ini tidak dapat mentolerir pointer terkelola yang mengarah ke ujung objek. Java menangani ini melalui mekanisme pelaporan berpasangan dasar/turunan. Kami perlu memberikan dukungan untuk jenis pelaporan berpasangan ini ke dalam CLR atau membatasi pass pengoptimal LLVM untuk tidak pernah membuat pointer semacam ini. Selain itu, jit LLILC lambat dan kami tidak yakin pada akhirnya kualitas kode seperti apa yang mungkin dihasilkannya.

Jadi, mencari tahu bagaimana LLILC mungkin cocok dengan pendekatan multi-tingkat potensial yang belum ada tampaknya (dan tampaknya masih) prematur. Idenya untuk saat ini adalah memasukkan tiering ke dalam framework dan menggunakan RyuJit untuk jit tingkat kedua. Saat kita belajar lebih banyak, kita mungkin menemukan bahwa memang ada ruang untuk tingkat yang lebih tinggi, atau, setidaknya, lebih memahami apa lagi yang perlu kita lakukan sebelum hal-hal seperti itu masuk akal.

@AndyAyersMS Mungkin Anda dapat memperkenalkan perubahan yang diperlukan di LLVM juga daripada mengatasi keterbatasannya.

Apakah Multicore JIT dan Pengoptimalan Profilnya berfungsi dengan coreclr?

@benaadams - Ya multicore JIT berfungsi. Saya tidak ingat skenario mana (jika ada) yang mengaktifkannya secara default, tetapi Anda dapat mengubahnya melalui konfigurasi: https://github.com/dotnet/coreclr/blob/master/src/inc/clrconfigvalues.h# L548

Saya menulis kompiler setengah mainan dan saya perhatikan bahwa sebagian besar waktu optimasi yang sulit dapat dilakukan dengan cukup baik pada infrastruktur yang sama dan sangat sedikit hal yang dapat dilakukan di pengoptimal tingkat yang lebih tinggi.

Maksud saya adalah ini: jika suatu fungsi dipukul berkali-kali, parameternya sebagai:

  • tingkatkan jumlah instruksi sebaris
  • gunakan pengalokasi register yang lebih "maju" (pewarna mundur seperti LLVM atau pewarna penuh)
  • lakukan lebih banyak optimasi, mungkin beberapa khusus dengan pengetahuan lokal. Misalnya: izinkan penggantian alokasi objek penuh menjadi alokasi tumpukan jika objek dideklarasikan dalam metode dan tidak ditetapkan dalam badan fungsi sebaris yang lebih besar.
  • gunakan PIC untuk sebagian besar objek hit di mana CHA tidak memungkinkan. Bahkan StringBuilder misalnya sangat mungkin tidak ditimpa, kode dapat jika ditandai sebagai setiap kali dipukul dengan StringBuilder, semua metode yang dipanggil di dalam dapat dengan aman didevirtualisasi dan tipe-penjaga diatur di depan akses SB.

Ini juga akan sangat bagus, tapi mungkin ini adalah mimpi saya, bahwa CompilerServices menawarkan "kompiler lanjutan" untuk diekspos agar dapat diakses melalui kode atau metadata, sehingga tempat-tempat seperti game atau platform perdagangan dapat mengambil manfaat dengan memulai kompilasi sebelumnya kelas dan metode mana yang harus "dikompilasi lebih dalam". Ini bukan NGen, tetapi jika kompiler non-tier belum tentu memungkinkan (diinginkan), setidaknya dimungkinkan untuk menggunakan kode optimal yang lebih berat untuk bagian-bagian penting yang membutuhkan kinerja ekstra ini. Tentu saja, jika sebuah platform tidak menawarkan optimasi berat (katakanlah Mono), panggilan API pada dasarnya adalah NO-OP.

Kami memiliki dasar yang kuat untuk tiering sekarang berkat kerja keras dari @noahfalk , @kouvel dan lainnya.

Saya menyarankan agar kita menutup masalah ini dan membuka masalah "bagaimana kita bisa membuat jitting berjenjang lebih baik". Saya mendorong siapa pun yang tertarik dengan topik tersebut untuk mencoba tingkatan saat ini untuk mendapatkan ide di mana keadaan saat ini. Kami akan senang untuk mendapatkan umpan balik tentang perilaku yang sebenarnya, apakah baik atau buruk.

Apakah perilaku saat ini dijelaskan di suatu tempat? Saya hanya menemukan ini tetapi ini lebih tentang detail implementasi daripada tiering secara khusus.

Saya yakin kita akan segera memiliki semacam penulisan ringkasan, dengan beberapa data yang telah kita kumpulkan.

Tiering dapat diaktifkan di 2.1 dengan menyetel COMPlus_TieredCompilation=1 . Jika Anda mencobanya, tolong laporkan kembali apa yang Anda temukan ....

Dengan PR terbaru (https://github.com/dotnet/coreclr/pull/17840, https://github.com/dotnet/sdk/pull/2201) Anda juga memiliki kemampuan untuk menentukan kompilasi berjenjang sebagai runtimeconfig. properti json atau properti proyek msbuild. Menggunakan fungsi ini akan mengharuskan Anda untuk menggunakan versi terbaru sedangkan variabel lingkungan telah ada untuk sementara waktu.

Seperti yang telah kita bahas sebelumnya dengan @jkotas Tiered JIT dapat meningkatkan waktu startup. Apakah ini berfungsi saat kita menggunakan gambar asli?
Kami telah melakukan pengukuran untuk beberapa aplikasi di ponsel Tizen dan inilah hasilnya:

DLL Sistem|DLL Aplikasi|Bertingkat|waktu, s
-----------|--------|------|--------
R2R |R2R |tidak |2,68
R2R |R2R |ya |2,61 (-3%)
R2R |tidak |tidak |4,40
R2R |tidak |ya |3,63 (-17%)

Kami akan memeriksa mode FNV juga, tetapi tampaknya berfungsi dengan baik ketika tidak ada gambar.

cc @gbalykov @nkaretnikov2

FYI, kompilasi berjenjang sekarang menjadi default untuk .NET Core: https://github.com/dotnet/coreclr/pull/19525

@alpencolt , peningkatan waktu startup mungkin lebih sedikit saat menggunakan kompilasi AOT seperti R2R. Peningkatan waktu startup saat ini berasal dari jitting lebih cepat dengan lebih sedikit optimasi, dan saat menggunakan kompilasi AOT akan ada lebih sedikit JIT. Beberapa metode tidak dibuat sebelumnya, seperti beberapa generik, stub IL, dan metode dinamis lainnya. Beberapa obat generik mungkin mendapat manfaat dari tiering selama startup bahkan saat menggunakan kompilasi AOT.

Saya akan melanjutkan untuk menutup masalah ini, karena dengan komitmen @kouvel saya pikir telah mencapai permintaan dalam judul : D Orang-orang dipersilakan untuk melanjutkan diskusi dan/atau membuka masalah baru tentang topik yang lebih spesifik seperti peningkatan yang diminta, pertanyaan, atau penyelidikan tertentu. Jika ada yang berpikir itu ditutup sebelum waktunya tentu saja beri tahu kami.

@kouvel Maaf untuk mengomentari masalah yang ditutup. Saya bertanya-tanya ketika menggunakan kompilasi AOT seperti crossgen, apakah aplikasi masih akan mendapat manfaat dari kompilasi tingkat kedua untuk jalur kode hot-spot?

@daxian-dbw ya sangat banyak; saat runtime, Jit dapat melakukan inlining lintas-perakitan (antara dll); penghapusan cabang berdasarkan konstanta runtime ( readonly static ); dll

@benaadams Dan kompiler AOT yang dirancang dengan baik tidak bisa?

Saya menemukan beberapa informasi tentang ini di https://blogs.msdn.microsoft.com/dotnet/2018/08/02/tiered-compilation-preview-in-net-core-2-1/ :

gambar yang telah dikompilasi sebelumnya memiliki batasan versi dan batasan instruksi CPU yang melarang beberapa jenis optimasi. Untuk metode apa pun dalam gambar ini yang sering disebut Kompilasi Berjenjang meminta JIT untuk membuat kode yang dioptimalkan pada utas latar belakang yang akan menggantikan versi yang telah dikompilasi sebelumnya.

Ya, itu contoh "bukan AOT yang dirancang dengan baik." 😛.

gambar yang telah dikompilasi sebelumnya memiliki batasan versi dan batasan instruksi CPU yang melarang beberapa jenis optimasi.

Salah satu contohnya adalah metode yang menggunakan hardware intrinsik. Compiler AOT (crossgen) hanya mengasumsikan SSE2 sebagai target codegen pada x86/x64, sehingga semua metode yang menggunakan hardware intrinsik akan ditolak oleh crossgen dan dikompilasi oleh JIT yang mengetahui informasi hardware yang mendasarinya.

Dan kompiler AOT yang dirancang dengan baik tidak bisa?

Kompiler AOT memerlukan optimasi link-time (untuk cross-assembly inlining) dan optimasi yang dipandu profil (untuk konstanta runtime). Sementara itu, kompiler AOT memerlukan info perangkat keras "garis bawah" (seperti -mavx2 di gcc/dentang) pada waktu pembuatan untuk kode SIMD.

Salah satu contohnya adalah metode yang menggunakan hardware intrinsik. Compiler AOT (crossgen) hanya mengasumsikan SSE2 sebagai target codegen pada x86/x64, sehingga semua metode yang menggunakan hardware intrinsik akan ditolak oleh crossgen dan dikompilasi oleh JIT yang mengetahui informasi hardware yang mendasarinya.

Tunggu apa? Saya tidak cukup mengikuti di sini. Mengapa kompiler AOT menolak intrinsik?

Dan kompiler AOT yang dirancang dengan baik tidak bisa?

Kompiler AOT memerlukan optimasi link-time (untuk cross-assembly inlining) dan optimasi yang dipandu profil (untuk konstanta runtime). Sementara itu, kompiler AOT memerlukan info perangkat keras "garis bawah" (seperti -mavx2 di gcc/dentang) pada waktu pembuatan untuk kode SIMD.

Ya, seperti yang saya katakan, "kompiler AOT yang dirancang dengan baik." 😁

@masonwheeler skenario yang berbeda; crossgen adalah AoT yang bekerja dengan Jit dan memungkinkan servis/penambalan dll tanpa memerlukan kompilasi ulang dan redistribusi aplikasi penuh. Ini menawarkan gen kode yang lebih baik daripada Tier0 dengan start-up yang lebih cepat daripada Tier1; tetapi tidak platform netral.

Tier0, crossgen, dan Tier1 semuanya bekerja bersama sebagai model kohesif di coreclr

Untuk cross-assembly inline (non-Jit) itu akan memerlukan kompilasi dari file tunggal yang terhubung secara statis yang dapat dieksekusi dan memerlukan kompilasi ulang penuh dan distribusi ulang aplikasi untuk menambal perpustakaan apa pun yang digunakannya serta menargetkan platform tertentu (versi apa SSE, Avx dll untuk digunakan; umum terendah atau menghasilkan versi untuk semua?).

corert akan mendukung gaya aplikasi ini.

Namun; melakukan jenis eliminasi cabang tertentu yang dapat dilakukan oleh Jit akan membutuhkan sejumlah besar generasi asm ekstra untuk jalur alternatif; dan tambalan runtime dari pohon yang benar

misalnya kode apa pun yang menggunakan metode seperti (di mana Tier1 Jit akan menghapus semua if s)

readonly static _numProcs = Environment.ProcessorCount;

public void DoThing()
{
    if (_numProcs == 1) 
    {
       // Single proc path
    }
    else if (_numProcs == 2) 
    {
       // Two proc path
    }
    else
    {
       // Multi proc path
    }
}

@benaadams

Untuk cross-assembly inline (non-Jit) itu akan memerlukan kompilasi dari file tunggal yang terhubung secara statis yang dapat dieksekusi dan memerlukan kompilasi ulang penuh dan distribusi ulang aplikasi untuk menambal perpustakaan apa pun yang digunakannya serta menargetkan platform tertentu (versi apa SSE, Avx dll untuk digunakan; umum terendah atau menghasilkan versi untuk semua?).

Seharusnya tidak memerlukan redistribusi penuh dari aplikasi. Lihatlah sistem kompilasi ART Android: Anda mendistribusikan aplikasi sebagai kode terkelola (Java dalam kasus mereka, tetapi prinsip yang sama berlaku) dan kompiler, yang hidup di sistem lokal, AOT mengkompilasi kode terkelola menjadi executable asli yang sangat dioptimalkan.

Jika Anda mengubah beberapa perpustakaan kecil, semua kode yang dikelola masih ada dan Anda tidak perlu mendistribusikan ulang semuanya, cukup dengan patch, dan kemudian AOT dapat dijalankan kembali untuk menghasilkan executable baru. (Jelas di sinilah analogi Android rusak, karena model distribusi aplikasi APK Android, tetapi itu tidak berlaku untuk pengembangan desktop/server.)

dan kompiler, yang hidup di sistem lokal, AOT mengkompilasi kode terkelola...

Itu model NGen sebelumnya yang menggunakan full framework; meskipun tidak berpikir itu membuat satu Majelis yang memasukkan kode kerangka kerja ke dalam kode aplikasi juga? Perbedaan antara dua pendekatan disorot dalam Bing.com berjalan di .NET Core 2.1! posting blog

Gambar ReadyToRun

Aplikasi yang dikelola seringkali memiliki kinerja startup yang buruk karena metode pertama-tama harus dikompilasi JIT ke kode mesin. .NET Framework memiliki teknologi prakompilasi, NGEN. Namun, NGEN memerlukan langkah prakompilasi yang terjadi pada mesin tempat kode akan dieksekusi. Untuk Bing, itu berarti NGENing pada ribuan mesin. Ini ditambah dengan siklus penerapan yang agresif akan menghasilkan pengurangan kapasitas penyajian yang signifikan karena aplikasi telah dikompilasi sebelumnya pada mesin web-serving. Selain itu, menjalankan NGEN memerlukan hak administratif, yang seringkali tidak tersedia atau sangat diteliti dalam pengaturan pusat data. Pada .NET Core, alat crossgen memungkinkan kode untuk dikompilasi sebelumnya sebagai langkah pra-penerapan, seperti di lab build, dan gambar yang disebarkan ke produksi Siap Dijalankan!

@masonwheeler AOT menghadapi tantangan dalam .Net penuh karena sifat dinamis dari proses .Net. Misalnya badan metode di .Net dapat dimodifikasi melalui profiler kapan saja, kelas dapat dimuat atau dibuat melalui refleksi, dan kode baru dapat dibuat oleh runtime sesuai kebutuhan untuk hal-hal seperti interop -- jadi informasi analisis antarprosedural paling mencerminkan keadaan sementara proses yang sedang berjalan. Analisis atau optimasi antarprosedural (termasuk inlining) di .Net harus tidak dapat dibatalkan saat runtime.

AOT bekerja paling baik ketika sekumpulan hal yang dapat berubah antara waktu AOT dan runtime kecil dan dampak dari perubahan tersebut terlokalisasi, sehingga cakupan luas yang tersedia untuk pengoptimalan AOT sebagian besar mencerminkan hal-hal yang harus selalu benar (atau mungkin sedikit sejumlah alternatif).

Jika Anda dapat membangun mekanisme untuk mengatasi atau membatasi sifat dinamis dari proses .Net maka AOT murni dapat melakukannya dengan cukup baik -- misalnya .Net Native mempertimbangkan dampak refleksi dan interop, dan melarang pemuatan perakitan, pancaran pantulan, dan ( Saya kira) melampirkan profil. Tapi itu tidak sederhana.

Ada beberapa pekerjaan yang sedang berlangsung untuk memungkinkan kami memperluas cakupan crossgen ke beberapa rakitan sehingga kami dapat mengkompilasi AOT semua kerangka kerja inti (atau semua rakitan asp.net) sebagai satu bundel. Tapi itu hanya layak karena kami memiliki jit sebagai cadangan untuk mengulang codegen ketika ada perubahan.

@AndyAyersMS Saya tidak pernah percaya bahwa solusi .NET AOT harus menjadi solusi "hanya AOT murni", untuk alasan yang Anda jelaskan di sini. Memiliki JIT untuk membuat kode baru sesuai kebutuhan sangat penting. Tetapi situasi di mana itu dibutuhkan sangat sedikit, dan oleh karena itu saya pikir aturan Anders Hejlsberg untuk sistem tipe dapat diterapkan secara menguntungkan di sini:

Statis bila memungkinkan, dinamis bila perlu.

Dari System.Linq.Expressions
Kompilasi TDelegate publik (interpretasi preferensi bool);

Apakah kompilasi berjenjang terus berfungsi jika preferInterpretation benar?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat