Design: Bisakah WebAssembly.Instance mengkompilasi ulang Modul yang sudah dikompilasi?

Dibuat pada 27 Okt 2016  ·  94Komentar  ·  Sumber: WebAssembly/design

Katakanlah saya punya kode ini:

let descriptor = /* ... */;
let memories = Array.apply(null, {length: 1024}).map(() => new WebAssembly.Memory(descriptor));
let instance = fetch('foo.wasm')
  .then(response => response.arrayBuffer())
  .then(buffer => WebAssembly.compile(buffer))
  .then(module => new WebAssembly.Instance(module, { memory: memories[1023] }));

Apakah WebAssembly.Instance diizinkan untuk memblokir untuk waktu yang cukup lama. Bisakah misalnya mengkompilasi ulang WebAssembly.Module ?

Dalam kebanyakan kasus saya akan mengatakan tidak, tetapi bagaimana jika kode yang sudah dikompilasi tidak terlalu menyukai memori yang diterimanya? Katakanlah, karena memori itu adalah memori mode lambat dan kodenya dikompilasi dengan asumsi mode cepat? mungkin memories[0] adalah memori mode cepat, tetapi memories[1023] tentu saja tidak.

Bagaimana dengan kode ini sebagai gantinya:

let instances = [0,1,2,3,4,5,6,7].map(v => fetch(`foo${v}.wasm`)
  .then(response => response.arrayBuffer())
  .then(buffer => WebAssembly.compile(buffer))
  .then(module => new WebAssembly.Instance(module)));

Apakah panggilan ke WebAssembly.Instance diizinkan untuk menyebabkan kompilasi ulang?

Dengan asumsi di atas masuk akal, berikut adalah beberapa pertanyaan terkait:

  • Apakah kita menginginkan fungsi async yang mengembalikan janji yang dapat mengkompilasi _and_ instantiate? Saya tidak mengatakan bahwa kita harus membuang salah satu API sinkron dan asinkron yang sudah kita miliki, saya mengusulkan API asinkron baru.
  • Bagaimana browser mengekspos kode yang dikompilasi dalam WebAssembly.Module cepat, dan bahwa instance WebAssembly.Memory cocok untuk kode secepat itu? Saat ini jawabannya sepertinya "cobalah dan lihat apakah Anda dapat memperhatikan".
  • Bagaimana pengguna mengetahui berapa banyak instance WebAssembly.Memory diizinkan sebelum mereka mendapatkan kode lambat (menghitung yang implisit, misalnya seperti yang dibuat oleh contoh kedua)?
JS embedding

Komentar yang paling membantu

@kgryte Saya seharusnya mengklarifikasi bahwa komentar saya terutama berkaitan dengan browser sebagai konteks eksekusi. Kami telah mendarat di permukaan API yang masih mengekspos API sinkron. Browser dapat menerapkan batas ukuran pada modul yang diteruskan ke API sinkron (Chrome sudah melakukannya, misalnya), tetapi batas tersebut dapat dikonfigurasi oleh penyemat dan tidak perlu diterapkan ke Node.js.

Semua 94 komentar

Akan lebih baik jika WebAssembly.Instance terkadang menyebabkan kompilasi ulang, dengan cara ini vars global yang tidak dapat diubah dapat dilipat secara konstan dalam kode yang dihasilkan. Misalnya, Emscripten menghasilkan kode yang dapat dipindahkan dengan mengimbangi semua pointer ke data statis. Offset dilewatkan sebagai var global yang tidak dapat diubah saat modul dipakai. Jika WebAssembly.Instance dapat dikompilasi ulang, itu bisa mengkhususkan kode yang dihasilkan.

Spesifikasi tidak mendefinisikan apa itu "kompilasi", juga tidak akan membuat
masuk akal untuk melakukannya, karena pendekatan implementasi mungkin sangat berbeda
(termasuk penerjemah). Jadi tidak ada kata normatif tentang ini
baik cara. Yang terbaik yang bisa kami lakukan adalah menambahkan catatan bahwa
WebAssembly.Instance diharapkan "cepat".

Pada 27 Oktober 2016 pukul 03:24, Michael Bebenita [email protected]
menulis:

Akan lebih baik untuk WebAssembly.Instance terkadang menyebabkan kompilasi ulang,
dengan cara ini vars global yang tidak dapat diubah dapat dilipat secara konstan di yang dihasilkan
kode. Misalnya, Emscripten menghasilkan kode yang dapat dipindahkan dengan mengimbangi semua
pointer ke data statis. Offset dilewatkan sebagai var global yang tidak dapat diubah
ketika modul dipakai. Jika WebAssembly.Instance dapat dikompilasi ulang,
itu bisa mengkhususkan kode yang dihasilkan.


Anda menerima ini karena Anda berlangganan utas ini.
Balas email ini secara langsung, lihat di GitHub
https://github.com/WebAssembly/design/issues/838#issuecomment -256522163,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AEDOO9sJPgujK3k0f6P7laYV_zaJxES5ks5q3_1LgaJpZM4Kh1gM
.

Setuju ini akan menjadi catatan non-normatif paling banyak.

Di SM, kami saat ini juga bermaksud untuk instantiasi untuk tidak pernah mengkompilasi ulang sehingga ada model biaya kompilasi yang dapat diprediksi untuk pengembang (khususnya, sehingga pengembang dapat menggunakan WebAssembly.compile dan IDB untuk mengontrol kapan mereka menerima kompilasi hit) . Kompilasi ulang waktu instantiasi dari dalam konstruktor Instance sinkron pasti akan merusak model biaya itu dan dapat menyebabkan jank besar.

Tetapi saya menghargai bahwa kompilasi terpisah pada dasarnya bertentangan dengan berbagai optimasi yang mungkin ingin dilakukan untuk mengkhususkan kode yang dihasilkan ke parameter ambient. Menggabungkan kompilasi dan instantiasi menjadi satu operasi async masuk akal dan merupakan sesuatu yang telah kami pertimbangkan di masa lalu. Kelemahannya, tentu saja, adalah bahwa ini menghambat caching eksplisit (tidak ada Module ), jadi pengembang harus melakukan tradeoff yang tidak menyenangkan. Beberapa opsi:

  • Impl dapat melakukan caching beralamat konten implisit (yang dapat menyertakan parameter ambien dalam kunci), seperti yang kami lakukan dengan asm.js yang saat ini ada di FF. Ini akan sedikit merepotkan dan memiliki semua masalah prediktabilitas/heuristik dari cache implisit apa pun.
  • Kita dapat membuat cara baru (misalnya, API WebAssembly.Cache tempat Anda memasukkan bytecode dan parameter instantiasi dan mendapatkan kembali Promise<Instance> .

Yang terakhir membuat saya penasaran dan dapat memberikan pengalaman pengembang yang jauh lebih baik daripada menggunakan IDB dan mungkin kesempatan untuk lebih mengoptimalkan caching (karena cache dikhususkan untuk tujuan tertentu), tetapi ini tentu saja merupakan fitur besar dan sesuatu yang kami ingin luangkan waktu. mempertimbangkan.

@rossberg-chromium Sepertinya saya telah menjelaskan tujuan saya dengan buruk: Saya tidak ingin berdalih tentang apa yang dikatakan oleh spesifikasi. Saya mencoba menunjukkan apa yang tampak seperti kejutan serius bagi pengembang, bersembunyi di bawah API. Pengembang tidak akan mengharapkan hasil .compile dikompilasi ulang. Itu sepertinya cacat desain bagi saya.

@lukewagner bahkan dengan caching implisit atau eksplisit, kami mungkin memiliki masalah yang sama: berapa banyak WebAssembly.Memory dapat dibuat di ruang alamat/asal yang sama adalah batasan browser. Saya suka apa yang Anda sarankan, tetapi saya pikir itu ortogonal untuk masalah ini. Beri tahu saya jika saya salah memahami apa yang Anda sarankan.

Mungkin .compile dan Module dapat diberikan Memory , dan Instance memiliki properti .memory yang dapat diteruskan ke kompilasi / instantiasi lain ?

Saya tidak mencoba menghilangkan kemungkinan kompilasi ulang, saya pikir kami lebih menginginkan penggunaan API idiomatik umum yang memiliki informasi sempurna dengan Memory pada waktu kompilasi pertama (atau pada waktu pengambilan cache) jadi bahwa kompilasi mengeluarkan pemeriksaan batas atau tidak jika diperlukan.

@jfbastien Dengan caching implisit/eksplisit yang disediakan parameter instantiasi tertentu (jadi Memory ), saya tidak melihat bagaimana akan ada kebutuhan untuk kompilasi ulang.

@jfbastien Dengan caching implisit/eksplisit yang disediakan parameter instantiasi tertentu (jadi Memory ), saya tidak melihat bagaimana akan ada kebutuhan untuk kompilasi ulang.

Mungkin disana:

  1. Buat banyak Memory s.
  2. Kompilasi kode, dengan pemeriksaan batas eksplisit (lambat) karena terlalu banyak Memory .
  3. Cache kode itu.
  4. Tinggalkan halaman.
  5. Muat halaman lagi.
  6. Alokasikan hanya satu Memory , yang mendapatkan versi cepat.
  7. Dapatkan dari cache.
  8. Terima kode lambat Instance .

Pada titik ini saya setuju Anda tidak _perlu_ kompilasi ulang, tetapi kami agak konyol karena kami melakukan pemeriksaan batas lambat ketika kami tidak perlu.

Seperti yang saya katakan: Saya suka API Cache Anda usulkan, saya pikir itu membuat WebAssembly lebih bermanfaat, tapi saya pikir masalahnya masih ada. 😢

Nah, itulah poin saya tentang memiliki cache yang ditingkatkan yang menerima parameter instantiasi dan bytecode: cache bebas untuk dikompilasi ulang jika apa yang telah di-cache tidak cocok dengan parameter instantiasi. Jadi langkah-langkahnya adalah:

  1. buat banyak Memory s
  2. meminta Instance dari cache, melewati salah satu dari itu (lambat) Memory s
  3. kode lambat dikompilasi, di-cache dan dikembalikan sebagai Instance
  4. tinggalkan halaman
  5. muat halaman lagi
  6. alokasikan hanya satu Memory
  7. meminta Instance dari cache, meneruskan Memory
  8. kode cepat dikompilasi, di-cache dan dikembalikan sebagai Instance

dan setelah langkah 8, semua pemuatan halaman berikutnya akan di-cache kode cepat atau lambat.

@lukewagner Pertama-tama, Anda mengusulkan mitigasi yang bertentangan dengan tujuan yang dinyatakan dari WebAssembly yang memberikan kinerja deterministik. Perbedaan antara lambat dan cepat terakhir dikutip sekitar 20%, jadi akan sangat buruk jika spesifikasi yang dengan susah payah bertujuan untuk kinerja deterministik menjatuhkannya ke lantai karena kekhasan API. Saya tidak percaya bahwa browser yang memiliki cache yang dialamatkan konten adalah solusi yang tepat, karena spesifikasi sudah mengalami banyak masalah di tempat lain untuk meniadakan kebutuhan untuk optimasi cache-recompile-profil. Misalnya, kami menjanjikan kompilasi dengan tepat sehingga aplikasi bisa mendapatkan perilaku yang wajar meskipun kode tidak di-cache. Jika cara ini ditentukan mengharuskan kita semua untuk mengimplementasikan cache atau mitigasi lainnya, maka kita akan gagal mencapai tujuan kita untuk memberikan model biaya yang cukup portabel kepada orang-orang.

Bagi saya masalahnya hanya ini: salah satu optimasi yang kita semua harus lakukan secara efektif untuk alasan kompetitif (pemeriksaan batas memori virtual 4GB, yang saya sebut saja peretasan 4GB) tidak dapat dilakukan dalam spesifikasi saat ini tanpa mengorbankan salah satu dari hal-hal ini:

  • Anda dapat melakukannya jika Anda selalu mengalokasikan memori virtual 4GB untuk memori wasm apa pun. Ini akan mencegah orang menggunakan WebAssembly untuk modul kecil, karena Anda akan mencapai batas alokasi memori virtual, fragmentasi memori virtual, atau masalah lain jika Anda mengalokasikan banyak dari ini. Saya juga khawatir jika Anda mengizinkan mengalokasikan banyak dari mereka maka Anda akan mengurangi kemanjuran mitigasi keamanan seperti ASLR. Perhatikan bahwa API yang ada tidak berbagi bahaya ini, karena mereka melakukan memori yang mereka alokasikan dan mereka akan OOM atau macet sebelum membiarkan Anda mengalokasikan lebih dari yang diizinkan oleh memori fisik.
  • Anda dapat melakukannya jika Anda mengizinkan kompilasi ulang ketika Anda menemukan ketidakcocokan selama instantiasi (kode yang dikompilasi menginginkan peretasan 4GB tetapi memori tidak memiliki alokasi memori virtual). Anda juga bisa lolos jika instantiasi memindahkan memori ke wilayah 4GB, tetapi lihat poin sebelumnya. Jadi, mungkin setiap kali ini terjadi, itu akan menjadi bug P1 untuk browser yang menemukannya.

Saya pikir ini berarti bahwa spesifikasi akan mendorong vendor untuk berkumpul untuk hanya mengizinkan reservasi 4GB kapan saja memori wasm dialokasikan, atau memiliki optimasi cache/kompilasi-malas/profil untuk mendeteksi ini.

Akhirnya, saya tidak mengerti maksud dari membuat semua ini non-normatif. Ini bisa menjadi normatif, karena kita bisa membuat API menghalangi kemungkinan browser harus mengkompilasi sesuatu tanpa mengetahui jenis memori apa yang akan dimilikinya. Saya membayangkan bahwa ada banyak cara untuk melakukan ini. Misalnya, instantiating dapat mengembalikan janji dan kami dapat menghapus langkah kompilasi yang terpisah. Ini akan memperjelas bahwa instantiasi adalah langkah yang bisa memakan waktu cukup lama, yang secara kuat menyiratkan kepada klien bahwa ini adalah langkah yang melakukan kompilasi. Dalam API seperti itu, kompiler selalu tahu apakah memori yang dikompilasi memiliki peretasan 4GB atau tidak.

Sangat menyedihkan bahwa kami baru menyadarinya sekarang, tetapi saya terkejut bahwa kalian tidak melihat ini adalah masalah yang lebih besar. Apakah ada beberapa mitigasi selain caching yang saya abaikan?

@jfbastien dalam skenario motivasi Anda, Anda menunjukkan bahwa modul ini ditulis untuk memilih memori yang cepat. Saya berasumsi Anda terutama mengejar mengaktifkan pengoptimalan memori cepat ketika modul tertentu menginginkannya, dan mungkin baik-baik saja dengan tidak melakukannya ketika modul tidak menginginkannya (tidak ada yang buruk dengan secara oportunistik tersandung dalam kasus itu, juga , hanya mencoba untuk memisahkan prioritas).

Jika demikian, bagaimana perasaan alternatif untuk caching atau async Instantiate ini:

  1. Pembuat modul harus membutuhkan 4GB sebagai memori min/maks
  2. Varian kompilasi (setidaknya async, mungkin juga sinkronisasi) yang menghasilkan instance yang hanya menerima memori cepat.

Untuk masalah "retas 4GB" dan ketidakcocokan antara memori yang menggunakannya dan kode yang mengharapkannya, apakah masuk akal untuk kompilasi untuk memancarkan dua versi kode secara internal? (Jelas ini akan menggunakan lebih banyak memori, yang menyedihkan, tetapi semoga waktu kompilasi tidak akan jauh lebih buruk, penulis dapat menghasilkan keduanya sekaligus?)

@mtrofin Saya rasa tidak masuk akal untuk meminta 4GiB jika Anda tidak berniat menggunakannya. Alokasi virtual terpisah dari maksud penggunaan, jadi saya pikir kita perlu memisahkan keduanya.

Pada 2.: masih tidak terlalu membantu pengembang: jika mereka menggunakan varian itu dan gagal, lalu apa?

@kripken Saya tidak berpikir kompilasi ganda adalah ide yang bagus.

@kripken Saya pikir itulah yang akan kami lakukan tanpa resolusi lain untuk masalah ini.

Saya ingin WebAssembly menjadi hebat dalam hal penjelajahan biasa: Anda memberi tahu saya tentang sesuatu yang keren, kirimi saya URL, saya klik, dan saya menghibur diri selama beberapa menit. Itulah yang membuat web menjadi keren. Tapi itu berarti banyak kompilasi akan berupa kode yang tidak di-cache, jadi waktu kompilasi akan memainkan peran besar dalam masa pakai baterai pengguna. Jadi, kompilasi ganda membuat saya sedih.

@mtrofin

Pembuat modul harus membutuhkan 4GB sebagai memori min/maks

Itu tidak terlalu praktis, karena banyak perangkat tidak memiliki memori fisik 4GB. Juga, itu sulit untuk ditentukan.

Varian kompilasi (setidaknya async, mungkin juga sinkronisasi) yang menghasilkan instance yang hanya menerima memori cepat.

Saya tidak berpikir kita ingin kompilasi ganda.

@pizlonator Sejauh ini, kami belum mempertimbangkan desain yang memerlukan mode codegen yang berbeda: kami selalu mengalokasikan wilayah 4gb pada 64-bit dan mengamati ini berhasil untuk ribuan memori di Linux, OSX dan Windows. Kami memiliki batas atas konservatif untuk mencegah kelelahan total sepele ruang alamat yang tersedia yang saya harapkan akan cukup untuk mendukung kasus penggunaan banyak-perpustakaan kecil. Jadi saya pikir kendala baru yang kami bahas di sini adalah bahwa iOS memiliki beberapa batasan ruang alamat virtual yang dapat mengurangi jumlah alokasi 4gb.

Jadi satu pengamatan adalah bahwa sebagian besar penghapusan batas-cek yang diizinkan oleh peretasan 4gb dapat dihindari hanya dengan memiliki wilayah penjaga kecil di akhir memori wasm. Eksperimen awal kami menunjukkan bahwa analisis dasar (tidak ada hubungannya dengan loop, hanya menghilangkan pemeriksaan pada beban/penyimpanan dengan penunjuk dasar yang sama) sudah dapat menghilangkan kira-kira setengah dari pemeriksaan batas. Dan mungkin ini bisa menjadi lebih baik. Jadi peretasan 4gb akan menjadi percepatan yang lebih sederhana, dan kurang perlu.

Ide lain yang saya miliki sebelumnya adalah mengkompilasi kode secara pesimis dengan pemeriksaan batas (menggunakan eliminasi berdasarkan halaman penjaga) dan kemudian menghapusnya saat membuat instance dengan memori mode cepat. Gabungan, overhead bisa sangat kecil dibandingkan dengan kode mode cepat ideal.

@lukewagner

Sejauh ini, kami belum mempertimbangkan desain yang memerlukan mode codegen yang berbeda: kami hanya selalu mengalokasikan wilayah 4gb pada 64-bit dan mengamati ini berhasil untuk ribuan memori di Linux, OSX dan Windows. Kami memiliki jumlah total konservatif untuk mencegah kelelahan total sepele ruang alamat yang tersedia yang saya harapkan akan cukup untuk mendukung kasus penggunaan banyak-perpustakaan kecil. Jadi saya pikir kendala baru yang kami bahas di sini adalah bahwa iOS memiliki beberapa batasan ruang alamat virtual yang dapat mengurangi jumlah alokasi 4gb.

Ini bukan masalah khusus iOS. Masalahnya adalah jika Anda mengizinkan banyak alokasi seperti itu, maka itu menimbulkan risiko keamanan karena setiap alokasi tersebut mengurangi kemanjuran ASLR. Jadi, saya pikir VM harus memiliki opsi untuk menetapkan batas yang sangat rendah untuk jumlah ruang 4GB yang dialokasikannya, tetapi itu menyiratkan bahwa jalur mundur tidak boleh terlalu mahal (yaitu tidak memerlukan kompilasi ulang).

Berapa batasan jumlah memori 4GB yang akan Anda alokasikan? Apa yang Anda lakukan ketika Anda mencapai batas ini - menyerah sepenuhnya, atau mengkompilasi ulang pada instantiasi?

Jadi satu pengamatan adalah bahwa sebagian besar penghapusan batas-cek yang diizinkan oleh peretasan 4gb dapat dihindari hanya dengan memiliki wilayah penjaga kecil di akhir memori wasm. Eksperimen awal kami menunjukkan bahwa analisis dasar (tidak ada hubungannya dengan loop, hanya menghilangkan pemeriksaan pada beban/penyimpanan dengan penunjuk dasar yang sama) sudah dapat menghilangkan kira-kira setengah dari pemeriksaan batas. Dan mungkin ini bisa menjadi lebih baik. Jadi peretasan 4gb akan menjadi percepatan yang lebih sederhana, dan kurang perlu.

Saya setuju bahwa analisis memungkinkan kami untuk menghilangkan lebih banyak pemeriksaan, tetapi peretasan 4GB adalah cara yang harus dilakukan jika Anda menginginkan kinerja puncak. Semua orang menginginkan kinerja puncak, dan saya pikir akan sangat bagus jika memungkinkan untuk mendapatkan kinerja puncak tanpa juga menyebabkan masalah keamanan, masalah sumber daya, dan kompilasi ulang yang tidak terduga.

Ide lain yang saya miliki sebelumnya adalah mengkompilasi kode secara pesimis dengan pemeriksaan batas (menggunakan eliminasi berdasarkan halaman penjaga) dan kemudian menghapusnya saat membuat instance dengan memori mode cepat. Gabungan, overhead bisa sangat kecil dibandingkan dengan kode mode cepat ideal.

Kode yang memiliki pemeriksaan batas sebaiknya menyematkan register untuk ukuran memori dan menyematkan register untuk basis memori.

Kode yang menggunakan peretasan 4GB hanya perlu menyematkan register untuk basis memori.

Jadi, ini bukan solusi yang bagus.

Selain gangguan karena harus memperdebatkan spesifikasi dan implementasi, apa kerugian dari menggabungkan kompilasi dan instantiasi menjadi satu tindakan yang dijanjikan?

Masalahnya adalah jika Anda mengizinkan banyak alokasi seperti itu, maka itu menimbulkan risiko keamanan karena masing-masing alokasi tersebut
alokasi mengurangi kemanjuran ASLR.

Saya bukan ahli ASLR tetapi, iiuc, bahkan jika kami tidak memiliki batasan konservatif (yaitu, jika kami mengizinkan Anda untuk terus mengalokasikan hingga mmap gagal karena kernel mencapai jumlah-of- rentang alamat maks), hanya sebagian kecil dari seluruh ruang beralamat 47-bit yang akan digunakan sehingga penempatan kode akan terus menjadi sangat acak pada ruang 47-bit ini. IIUC, penempatan kode ASLR juga tidak sepenuhnya acak; cukup untuk membuatnya sulit untuk memprediksi di mana sesuatu akan berada.

Berapa batasan jumlah memori 4GB yang akan Anda alokasikan? Apa yang kamu kerjakan
ketika Anda mencapai batas ini - menyerah sepenuhnya, atau kompilasi ulang pada instantiasi?

Nah, karena dari hari asm.js, hanya 1000. Lalu alokasi memorinya dibuang begitu saja. Mungkin kita perlu mengatasi ini, tetapi bahkan dengan banyak aplikasi super-modularized (dengan banyak modul wasm terpisah masing-masing) berbagi proses yang sama, saya tidak bisa membayangkan kita membutuhkan lebih banyak lagi. Saya pikir Memory berbeda dari ArrayBuffer s lama biasa di aplikasi yang secara alami tidak ingin membuat ribuan.

Selain kesal karena harus memperdebatkan spesifikasi dan implementasi, apa kerugiannya?
menggabungkan kompilasi dan instantiasi menjadi satu tindakan yang dijanjikan?

Seperti yang saya sebutkan di atas, menambahkan Promise<Instance> eval(bytecode, importObj) API baik-baik saja, tetapi sekarang menempatkan pengembang di tempat yang sulit karena sekarang mereka harus memilih antara peningkatan kinerja pada beberapa platform vs. semua platform. Sepertinya kita membutuhkan solusi yang terintegrasi dengan caching dan itulah yang saya curahkan di atas dengan Cache API eksplisit.

Ide baru: bagaimana jika kita menambahkan versi async dari new Instance , katakanlah WebAssembly.instantiate dan, seperti halnya WebAssembly.compile , kita katakan bahwa setiap orang seharusnya menggunakan versi async? Ini adalah sesuatu yang saya pertimbangkan _anyway_ karena instantiasi dapat memakan waktu beberapa ms jika patching digunakan. Kemudian kami mengatakan dalam spesifikasi bahwa mesin dapat melakukan pekerjaan yang mahal baik dalam compile atau instantiate (atau tidak keduanya, jika mesin melakukan validasi/kompilasi yang lambat!).

Itu masih menyisakan pertanyaan tentang apa yang harus dilakukan ketika compile d Module disimpan di IDB, tetapi itu hanya pertanyaan sulit ketika ada beberapa mode codegen _anyway_. Satu ide adalah bahwa Module s yang disimpan-ke atau diambil-dari IDB memegang pegangan ke entri IDB mereka dan mereka menambahkan kode kompilasi baru ke entri ini. Dengan cara itu, entri IDB akan dengan malas mengakumulasi satu atau lebih versi terkompilasi dari modulnya dan dapat menyediakan mana saja yang diperlukan selama instantiasi.

Bagian IDB sedikit lebih banyak pekerjaan, tetapi tampaknya cukup dekat dengan ideal, dari segi kinerja. WDYT?

Saya pikir menambahkan async instantiate masuk akal, tetapi saya juga menambahkan parameter Memory ke compile . Jika meneruskan memori yang berbeda ke instantiate maka Anda bisa dikompilasi ulang, jika tidak, Anda sudah "mengikat" memori saat kompilasi.

Saya belum memikirkan caching yang cukup untuk memiliki pendapat yang terbentuk sepenuhnya.

@lukewagner

Saya bukan ahli dalam ASLR tetapi, iiuc, bahkan jika kami tidak memiliki batasan konservatif (yaitu, jika kami mengizinkan Anda untuk terus mengalokasikan hingga mmap gagal karena kernel mencapai jumlah maksimum rentang alamat) , hanya sebagian kecil dari seluruh ruang beralamat 47-bit yang akan digunakan sehingga penempatan kode akan terus menjadi sangat acak pada ruang 47-bit ini. IIUC, penempatan kode ASLR juga tidak sepenuhnya acak; cukup untuk membuatnya sulit untuk memprediksi di mana sesuatu akan berada.

ASLR mempengaruhi kode dan data. Intinya adalah untuk membuatnya lebih mahal bagi penyerang untuk masuk ke struktur data tanpa mengejar pointer ke sana. Jika penyerang dapat menghabiskan memori, dia pasti memiliki lebih banyak daya ungkit.

Nah, karena dari hari asm.js, hanya 1000. Lalu alokasi memorinya dibuang begitu saja. Mungkin kita perlu mengatasi ini, tetapi bahkan dengan banyak aplikasi super-modularized (dengan banyak modul wasm terpisah masing-masing) berbagi proses yang sama, saya tidak bisa membayangkan kita membutuhkan lebih banyak lagi. Saya pikir Memory berbeda dari ArrayBuffers lama biasa di aplikasi yang secara alami tidak ingin membuat ribuan.

1000 sepertinya batas yang masuk akal. Aku akan bertanya-tanya dengan orang-orang keamanan.

Seperti yang saya sebutkan di atas, menambahkan Janjieval(bytecode, importObj) API baik-baik saja, tetapi sekarang menempatkan pengembang di tempat yang sulit karena sekarang mereka harus memilih antara peningkatan kinerja pada beberapa platform vs. kemampuan untuk menyimpan kode yang dikompilasi di semua platform. Sepertinya kita membutuhkan solusi yang terintegrasi dengan caching dan itulah yang saya curahkan di atas dengan Cache API eksplisit.

Benar. Saya dapat melihat beberapa cara agar API semacam itu dapat berfungsi. API yang murahan tapi praktis akan membebani eval:

  1. instancePromise = eval(bytecode, importObj)
  2. instancePromise = eval(modul, importObj)

dan kemudian Instance memiliki pengambil:

modul = instance.modul

Di mana modul adalah struktur yang dapat dikloning.

Apa pendapatmu tentang ini?

Ide baru: bagaimana jika kita menambahkan versi async dari Instance baru, misalnya WebAssembly.instantiate dan, seperti halnya WebAssembly.compile, kita mengatakan bahwa setiap orang seharusnya menggunakan versi async? Ini adalah sesuatu yang telah saya pertimbangkan sejak instantiasi dapat memakan waktu beberapa ms jika patching digunakan. Kemudian kami mengatakan dalam spesifikasi bahwa mesin dapat melakukan pekerjaan mahal baik dalam kompilasi atau instantiate (atau tidak keduanya, jika mesin melakukan validasi/kompilasi malas!).

Itu masih menyisakan pertanyaan tentang apa yang harus dilakukan ketika Modul yang dikompilasi disimpan di IDB, tetapi itu hanya pertanyaan sulit ketika ada beberapa mode codegen. Satu ide adalah bahwa Modul yang disimpan-ke atau diambil-dari IDB memegang pegangan ke entri IDB mereka dan mereka menambahkan kode kompilasi baru ke entri ini. Dengan cara itu, entri IDB akan dengan malas mengakumulasi satu atau lebih versi terkompilasi dari modulnya dan dapat menyediakan mana saja yang diperlukan selama instantiasi.

Bagian IDB sedikit lebih banyak pekerjaan, tetapi tampaknya cukup dekat dengan ideal, dari segi kinerja. WDYT?

Membuat penasaran. Sehubungan dengan ide saya di atas:

Pro: milik Anda adalah abstraksi yang mudah dipahami yang secara konseptual mirip dengan apa yang kami katakan sekarang.
Con: milik Anda tidak menghasilkan banyak sinergi antara apa yang dilakukan pengguna dan apa yang dilakukan mesin seperti yang diizinkan oleh proposal saya.

Ada tiga area di mana proposal Anda tidak memberikan kontrol sebanyak milik saya kepada pengguna:

  1. Pekerjaan yang mahal dapat terjadi di salah satu dari dua tempat, sehingga pengguna harus merencanakan salah satu dari mereka menjadi mahal. Kami mungkin akan memiliki konten web yang berperilaku buruk jika salah satunya mahal, karena disesuaikan untuk kasus-kasus di mana harganya murah. Proposal saya memiliki satu tempat di mana hal-hal mahal terjadi, yang mengarah ke lebih banyak keseragaman antara implementasi.
  2. Tidak ada jalur yang dijamin dengan jelas untuk semua versi kode yang dikompilasi untuk di-cache. Di sisi lain, penggunaan threading modul melalui API berarti bahwa VM dapat membangun modul dengan lebih banyak barang setiap kali, sambil tetap mengizinkan pengguna untuk mengelola cache. Jadi, jika pertama kali kita melakukan 4GB maka inilah yang akan kita cache, tetapi jika kita gagal melakukan 4GB untuk kedua kalinya, kita akan berpotensi men-cache keduanya (jika pengguna men-cache instance.module setelah setiap kompilasi).
  3. Kasus sudut yang tidak biasa di browser atau masalah lain terkadang dapat menyebabkan kompilasi ganda dalam skema Anda, karena kami akan mengkompilasi satu hal dalam langkah kompilasi tetapi kemudian menyadari bahwa kami memerlukan hal lain dalam langkah instantiasi. Versi saya tidak pernah membutuhkan kompilasi ganda.

Jadi, saya lebih suka milik saya. Yang mengatakan, saya pikir proposal Anda adalah kemajuan, jadi itu pasti terdengar bagus untuk saya.

Masalah ini bertumpu pada seberapa sering fragmentasi membuat alokasi cepat
memori (btw Anda akan 4GB + offset maksimum yang didukung, atau 8GB) gagal. jika
mungkin kurang dari 1%, maka itu mungkin tidak sepenuhnya tidak masuk akal untuk
memiliki itu menjadi situasi OOM.

Dalam skenario di mana pengguna menjelajahi web dan menggunakan banyak
modul WASM kecil secara berurutan, mungkin tidak semuanya aktif
satu kali. Dalam hal ini, cache kecil dari potongan 4GB yang dicadangkan akan mengurangi
isu.

Strategi lain yang mungkin adalah menghasilkan satu versi kode dengan
pemeriksaan batas, dan jika memori cepat tersedia, timpa saja batasnya
cek dengan nops. Itu jelek, tapi itu jauh lebih cepat daripada
kompilasi ulang, dan lebih sedikit ruang dari dua kompilasi.

Pada Kam, 27 Okt 2016 jam 21:03, pizlonator [email protected]
menulis:

@mtrofin https://github.com/mtrofin

Pembuat modul harus membutuhkan 4GB sebagai memori min/maks

Itu tidak terlalu praktis, karena banyak perangkat tidak memiliki fisik 4GB
Penyimpanan. Juga, itu sulit untuk ditentukan.

Varian kompilasi (setidaknya async, mungkin juga sinkronisasi) yang menghasilkan
contoh hanya menerima memori cepat.

Saya tidak berpikir kita ingin kompilasi ganda.


Anda menerima ini karena Anda berlangganan utas ini.
Balas email ini secara langsung, lihat di GitHub
https://github.com/WebAssembly/design/issues/838#issuecomment -256738329,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/ALnq1F6CYUaq0unla0H6RYivUC8jfxIAks5q4PWIgaJpZM4Kh1gM
.

Bukan hanya ASLR: itu juga polusi pagetable / pengalokasi / dll. Kita semua perlu berbicara dengan orang-orang keamanan kita _dan juga_ orang-orang kernel / sistem. Atau kita dapat memberitahu pengembang tentang batasan yang diterapkan setiap mesin pada "cepat" Memory , dan menjadikannya idiomatis di API sehingga sulit untuk salah menggunakannya.

Ada semua kruk ini yang bisa kita gunakan, seperti kompilasi nop atau ganda, tapi kenapa ada kruk?

@jfbastien Saya tidak berpikir PROT_NONE memori biaya entri tabel halaman; Saya pikir ada struktur data terpisah yang menyimpan pemetaan dari mana tabel halaman diisi dengan malas.

@pizlonator Saya menyukai ide itu, dan saya dapat melihat bahwa itulah yang kami anjurkan untuk digunakan semua orang secara default dalam tutorial, rantai alat, dll. Ini juga lebih ringkas dan lebih mudah untuk diajarkan jika Anda dapat mengabaikan Module . Ini juga dapat mengatasi kekhawatiran @s3ththompson tentang mengecilkan hati penggunaan API sinkronisasi dengan menjadikan API terbaik sebagai yang asinkron.

Namun, saya pikir kita tidak boleh mengambil WebAssembly.compile dan konstruktor Module : Saya membayangkan skenario di mana Anda memiliki "server kode" (menyediakan cache kode lintas-Asal melalui IDB + postMessage ; ini telah dibahas secara khusus dengan beberapa pengguna) yang ingin mengkompilasi dan menyimpan kode tanpa harus "memalsukan" parameter instantiasi. (Mungkin juga ada beberapa overhead yang tidak perlu (sampah, patching, dll) untuk instantiasi yang tidak perlu.) Dan, untuk kasus sudut yang sama yang menginginkan kompilasi sinkron (melalui new Module ), kita perlu menyimpan new Instance .

Jadi jika disepakati, maka intinya adalah proposal tambahan murni dari dua kelebihan WebAssembly.eval Anda sebutkan. Ya?

Satu tweak, meskipun: Saya pikir kita seharusnya tidak memiliki getter module karena ini akan membutuhkan Instance untuk menyimpan beberapa data internal (yaitu, bytecode) selama masa Instance ; sekarang Module biasanya dapat di-GC segera setelah instantiasi. Ini akan menyarankan properti data (yang dapat dihapus pengguna, meskipun mereka mungkin akan lupa), atau mungkin versi ketiga dari eval yang mengembalikan pasangan {instance, module} ...

Memiliki API satu langkah asinkron sebagai kasus yang direkomendasikan untuk aplikasi monolitik tipikal masuk akal sebagai pola yang direkomendasikan.

Setuju dengan @lukewagner bahwa semua kasus sinkronisasi (kompilasi sebaris) yang dicakup oleh Modul baru + Instans baru berguna.
Juga server kompilasi latar belakang (async) dengan instantiate sinkronisasi juga tampaknya berguna.

Menambahkan dua varian eval yang diusulkan tampaknya merupakan cara yang baik untuk memperkenalkan ini.

Namun saya tidak suka namanya, karena itu akan digabungkan dalam pikiran orang (keamanan) dengan js eval (yang menyerupai dalam satu hal, tetapi tidak dalam hal penangkapan ruang lingkup).
Bagaimana dengan WebAssembly.instantiate ?

Hah, poin bagus, eval memang memiliki sedikit perwakilan . +1 ke WebAssembly.instantiate .

Apa yang akan menjadi pedoman bagi pengembang saat menggunakan instantiate async?

@mtrofin Untuk menggunakan WebAssembly.instantiate secara default kecuali mereka memiliki beberapa skema berbagi kode/pemuatan khusus yang memerlukan kompilasi Module secara independen dari penggunaan tertentu.

@lukewagner Ini sepertinya masuk akal.

Hah, poin bagus, eval memang memiliki sedikit perwakilan. +1 ke WebAssembly.instantiate.

Sepakat.

Jadi jika menyetujui itu, maka intinya adalah proposal aditif murni dari dua kelebihan WebAssembly.eval yang Anda sebutkan. Ya?

Seperti itulah kedengarannya.

Saya pikir kita seharusnya tidak memiliki pengambil modul karena ini akan membutuhkan Instance untuk menyimpan beberapa data internal (yaitu, bytecode) selama masa Instans; sekarang Modul biasanya dapat di-GC segera setelah instantiasi. Ini akan menyarankan properti data (yang dapat dihapus pengguna, meskipun mereka mungkin akan lupa), atau mungkin versi ketiga dari eval yang mengembalikan pasangan {instance, module}...

Tentu terasa seperti properti data lebih baik. Atau membuat WebAssembly.instantiate selalu mengembalikan sebuah instance, pasangan modul.

Apakah ini benar: Misalkan Anda WebAssembly.instantiate dengan tujuan mendapatkan varian modul fastmemory. Anda sekarang mendapatkan modul, dan menggandakannya. Sekarang, modul ini pasti perlu dibuat instance-nya dengan Memory -es yang mendukung fastmemory.

@pizlonator Ya, saya bisa bersepeda di kepala saya dengan berbagai cara. Saya pikir saya suka mengembalikan pasangan sedikit lebih baik karena itu mungkin akan menyebabkan lebih sedikit orang yang secara tidak sengaja memasukkan Module .

@mtrofin Kompilasi ulang masih diperlukan saat Anda mencabut Module dari satu panggilan instantiate dan instantiate dengan impor baru; Saya pikir inti dari penambahan API ini adalah bahwa itu tidak akan menjadi kasus umum dan itu hanya akan terjadi ketika itu benar-benar diperlukan (yaitu, Anda memiliki 1 modul yang mengakses dua jenis memori).

Utas ini semakin panjang, sepertinya menyatu tetapi untuk 100% yakin kita perlu menulis kode yang kita harapkan ditulis oleh pengguna yang berbeda:

  1. Instansiasi asinkron dari satu modul.
  2. Instansiasi asinkron dari sebuah modul, dengan berbagi memori dengan modul lain.
  3. Instansiasi sinkron dari satu modul (saya rasa multi-modul sinkron tidak berguna?).
  4. Caching untuk semua ini (baik memasukkan ke dalam cache, serta mengambil dan membuat instance, dengan memori).
  5. Perbarui satu modul .wasm , dan cache banyak modul lainnya.

Ada yang lain? Kedengarannya seperti @lukewagner memiliki ide seputar impor yang tidak sepenuhnya saya pahami.

Itu berarti bahwa penggunaan selanjutnya dari modul ini harus membuat instantiate secara asinkron, atau berisiko memblokir thread UI dengan instantiate sinkron yang sangat panjang.

@jfbastien Saya ingin memahami untuk setiap cuplikan yang kami harapkan ditulis oleh pengembang, apa yang akan memotivasi mereka untuk menempuh jalur tertentu, dan informasi apa yang harus dimiliki pengembang untuk membuat keputusan.

@mtrofin Benar, diberi Module m , Anda akan memanggil WebAssembly.instantiate(m) yang async. Anda _could_ menelepon new Instance(m) dan itu mungkin mahal, tapi itu tidak berbeda dari new Module(m) .

@jfbastien Dengan asumsi ketika Anda mengatakan "instantiasi async" maksud Anda "kompilasi dan instantiasi async", inilah versi singkatnya:

  1. WebAssembly.instantiate(bytecode, imports)
  2. WebAssembly.instantiate(bytecode, imports) , di mana imports menyertakan memori bersama
  3. new Instance(new Module(bytecode), imports)
  4. Dalam semua kasus, Anda bisa mendapatkan Module , lalu Anda put itu dalam IDBObjectStore . Kemudian, Anda get a Module m kembali dan menelepon WebAssembly.instantiate(m, imports) .
  5. Tidak ada yang benar-benar istimewa di sini: Anda WebAssembly.instantiate satu modul dari bytecode dan instantiate sisanya dari Module yang ditarik dari IDB.

Haruskah kami merekomendasikan penggunaan sync instantiate jika Anda merasa dapat menggunakan kompilasi sinkronisasi, dan instantiate async jika Anda merasa harus menggunakan kompilasi async?

Selain itu, saya khawatir pengembang sekarang akan menghadapi sistem yang lebih kompleks: lebih banyak pilihan yang menghasilkan pengoptimalan yang kami rencanakan, dan saya tidak yakin pengembang memiliki informasi yang tepat yang tersedia untuk melakukan pengorbanan. Berpikir dari sudut pandang pengembang, apakah ada kekhawatiran yang lebih kecil yang mereka pedulikan dan akan merasa nyaman untuk diungkapkan? Kami berbicara pada suatu titik tentang pengembang yang memiliki "pengoptimalan dengan mengorbankan titik kegagalan yang tepat" (ini adalah pemeriksaan batas pengangkatan kembali). Akankah alternatif menjadi bendera "optimalkan"?

@mtrofin 99% dari apa yang akan ditulis oleh pengembang (atau telah dibuat untuk mereka oleh rantai alat) adalah WebAssembly.instantiate . Anda hanya akan menggunakan API sinkronisasi untuk "Saya sedang menulis JIT di wasm" dan WebAssembly.compile jika Anda sedang menulis beberapa sistem berbagi kode, jadi saya pikir tutorial "Memulai" akan secara eksklusif mencakup WebAssembly.instantiate .

@lukewagner Saya perhatikan Anda menambahkan impor ke #3 new Module() di atas. Saya pikir ditambah menambahkannya ke WebAssembly.compile adalah ide yang bagus dan melengkapi kemungkinannya.
Dengan begitu jika Anda ingin memberi petunjuk tentang memori pada waktu kompilasi, Anda bisa.
Jika nanti Anda membuat instance lagi dengan impor yang berbeda, terutama secara sinkron, Anda mungkin mengalami cegukan.

Jadi ringkasan perubahan (agar saya jelas):

  • Tambahkan WebAssembly.instantiate(byte, impor) mengembalikan janji {instance:, module:}
  • Tambahkan WebAssembly.instantiate (modul, impor) mengembalikan janji {instance:, module:}
  • Ubah ke Modul baru (byte , impor ) mengembalikan modul
  • Ubah ke WebAssembly.compile(bytes ,import ) mengembalikan janji instance

Nyatakan di suatu tempat harapan bahwa instantiate akan cepat jika impor dari kompilasi cocok dengan instantiate.

WDYT?

Oh oops, saya bermaksud menempatkan impor sebagai arg ke Instance . Saya tidak yakin itu perlu untuk Module atau compile . [Sunting: karena jika Anda memilikinya, Anda cukup menelepon instantiate ]

Jadi itu berarti bahwa untuk kasus async ujung-ke-ujung, Anda dapat mengetahui bahwa Anda akan mengikat memori peretasan 4GB, tetapi tidak untuk kernel filter JIT atau item yang dikompilasi latar belakang (kecuali jika Anda juga membuat lemparan- jauh misalnya)?

+1 pada memfokuskan panduan pada pasangan async dari kompilasi & instantiate - membuat pesan menjadi sederhana dan menyembunyikan kompleksitas masalah keputusan dari pengembang.

Ya, saya pikir kita semua sepakat bahwa kita akan mengarahkan orang-orang pada:
Pertama kali:
WebAssembly.instantiate(byte, impor) -> janji {module, instance} (modul cache ke indexeddb)
Kedua kalinya:
WebAssembly.instantiate(modul, impor) -> janji {module, instance}

Adakah keberatan dengan itu menjadi pola utama?

Saya robek pada impor untuk kompilasi/Modul baru. Sepertinya itu bisa menjadi petunjuk yang berguna.
Padahal, saya akan terbuka untuk menyebutkannya sebagai kemungkinan dan menunda menambahkan arg itu (bisa opsional) ke Post-MVP.

Pikiran?

@mtrofin (Yah, secara teknis, hanya instantiate .)

@lukewagner (saya pikir itulah yang dimaksud @mtrofin )

@lukewagner , @flagxor OK, tapi kami menyimpan API kompilasi async, bukan?

Bagaimana dengan skenario ini: Anda mendapatkan aplikasi seperti PhotoShop dengan banyak plugin. Setiap plugin adalah modul wasm. Anda memulai aplikasi utama dan Anda berhasil mengalokasikan ukuran memori ajaib yang memicu memori cepat (tampaknya masuk akal untuk skenario ini - satu aplikasi, haus memori).

Anda ingin mengkompilasi sejumlah plugin secara paralel sehingga Anda memecat beberapa pekerja untuk melakukannya. Anda tidak dapat melewatkan kompilasi tersebut ke memori aktual yang akan Anda gunakan (benar?). Jadi, tergantung pada default, Anda mendapatkan kompilasi memori lambat untuk plugin, yang kemudian akan diikuti oleh kompilasi ulang asinkron yang mahal untuk memori cepat saat plugin terhubung ke aplikasi.

Jika kita membeli skenario ini, maka rasanya mungkin ada nilai dalam melewatkan beberapa deskriptor memori (untuk lebih jelasnya, tanpa memori pendukung yang sebenarnya) ke kompilasi API.

Ya, seharusnya (bahkan didorong) untuk meneruskan Memory ke kompilasi.

@mtrofin Benar, compile untuk penggunaan tingkat lanjut. Saya kira contoh plugin itu adalah kasus yang valid di mana Anda ingin _compile_, _and_ Anda memiliki Memory , tetapi Anda belum ingin instantiate (belum).

@pizlonator Btw, saya bermaksud bertanya sebelumnya, dengan asumsi peretasan "lempar jika lebih dari 1000 peta 4gb per proses" cukup untuk mengatasi ASLR/masalah keamanan, apakah _masih_ perlu mode lambat/mode cepat karena platform pembatasan kuota alamat virtual? Karena jika tidak ada, tentu bagus jika ini tidak menjadi pertimbangan kinerja bahkan untuk pengguna tingkat lanjut. (API instantiate tampaknya berguna untuk ditambahkan karena alasan lain yang kami sebutkan, tentu saja.)

Ada juga aplikasi yang mungkin mendapat manfaat dari ukuran memori yang merupakan kekuatan dua ditambah area tumpahan, di mana aplikasi sudah menutupi pointer untuk menghilangkan penandaan sehingga dapat menutupi bit tinggi untuk menghindari pemeriksaan batas. Aplikasi ini perlu mempertimbangkan ukuran alokasi memori yang dapat mereka terima sebelum kompilasi, baik dengan memodifikasi konstanta global yang digunakan untuk masking atau untuk memanggang konstanta yang sesuai saat melakukan dekompresi ke wasm.

Ada juga optimasi buffer-at-zero yang mungkin ingin dimanfaatkan oleh beberapa runtime, dan hanya akan ada satu buffer seperti itu per proses.

Itu juga akan membuat platform lebih ramah pengguna jika dapat mempertimbangkan memori yang diperlukan dan memori yang tersedia sebelum mengkompilasi aplikasi. Misalnya, untuk mengizinkan browser atau aplikasi memberi tahu pengguna bahwa mereka perlu menutup beberapa tab untuk menjalankan aplikasi, atau menjalankannya tanpa penurunan kemampuan.

Peramban web mungkin ingin memiliki mode aplikasi khusus yang merupakan opsi bagi pengguna, di mana mereka mungkin berjalan pada perangkat terbatas dan membutuhkan semua memori dan kinerja yang dapat mereka peroleh hanya untuk menjalankan satu aplikasi dengan baik. Untuk itu perlu dapat menalar tentang kebutuhan sejak dini.

Memori tidak perlu dialokasikan sebelum kompilasi, melainkan reservasi yang beralasan dibuat. Pada perangkat yang terbatas, kompilasi saja mungkin menggunakan banyak memori, sehingga alokasi VM yang besar pun dapat menjadi penghambat acara.

Ini bukan masalah baru, telah dibahas selama bertahun-tahun sekarang. Manajemen sumber daya memori diperlukan, dan perlu dikoordinasikan dengan pembuatan kode.

@lukewagner Saya pikir begitu, karena jika kami membatasi hingga 1000 modul, maka saya khawatir toleransinya tidak cukup besar.

  • Saya khawatir tentang serangan ke permukaan yang membutuhkan langit-langit ini untuk turun.
  • Saya khawatir tentang pengoptimalan di tempat lain dalam tumpukan yang mengurangi jumlah ruang alamat virtual yang tersedia bagi kami, yang kemudian mengharuskan kami untuk mengevaluasi kembali apakah batasnya cukup rendah.
  • Saya khawatir tentang mencegah gaya pemrograman yang sengaja membuat 1000 modul. Sebagai contoh, saya tahu bahwa sebagian besar klien kerangka kerja JavaScriptCore membuat VM, melakukan sedikit pekerjaan, dan kemudian menghancurkannya. Jika WebAssembly digunakan dengan cara yang sama dari JS seperti JSC dari Objective-C, maka untuk membuatnya berfungsi pada sistem 64-bit, GC harus tahu bahwa jika Anda mengalokasikan 1000 memori - bahkan jika masing-masing kecil - maka Anda harus GC jika alokasi berikutnya harus berhasil dengan alasan bahwa 1000 memori itu sekarang tidak dapat dijangkau. Kemampuan untuk mengalokasikan memori non-retas 4GB setelah ada, katakanlah, 10 memori peretasan 4GB secara langsung akan berarti bahwa GC tidak perlu terlalu banyak mengubah heuristiknya. Itu tidak perlu melakukan GC ketika Anda mengalokasikan modul 1001 di instantiate->run->die loop Anda. Ini akan bermanfaat bagi pola yang menggunakan memori kecil. Apa pun di bawah 1MB, dan mulai masuk akal untuk memiliki 1000 di antaranya. Saya bisa membayangkan orang melakukan hal-hal yang berguna dalam 64KB.
  • Saya khawatir ini kurang berguna untuk konteks JavaScript lainnya. Saya ingin membiarkan pintu terbuka untuk JSC C API dan klien Objective-C API untuk memiliki akses ke WebAssembly API dari kode JS mereka. Klien tersebut mungkin lebih menyukai batasan kecil pada jumlah memori 4GB yang kami alokasikan. Sangat menggoda untuk membuat kuota itu dapat dikonfigurasi dalam konteks seperti itu.

Saya suka bahwa API yang ditingkatkan menghilangkan kebutuhan untuk memiliki langit-langit buatan pada jumlah memori, atau kebutuhan untuk mengkompilasi ulang, atau hal-hal lain yang tidak diinginkan. Saya tidak suka langit-langit buatan kecuali toleransinya sangat besar, dan saya rasa itu tidak terjadi di sini.

@pizlonator Cukup adil, dan ini adalah API yang lebih bersih/sederhana, jadi saya pikir tidak apa-apa untuk menambahkannya.

Adapun mengapa saya tidak peduli dengan item yang Anda sebutkan (saat ini):

  • Batasnya mungkin perlu dinaikkan; itu mudah.
  • Pada batas wajar apa pun, hanya sebagian kecil dari total ruang alamat 64-bit yang akan digunakan, jadi saya tidak mengetahui vektor serangan apa yang ada di sini; konten yang ditentukan memiliki banyak cara untuk OOM itu sendiri
  • Kami menabrak heuristik GC yang sepadan dengan ukuran reservasi, dan dengan demikian mengaduk-aduk Memory s hanya mengarah ke GC yang lebih agresif. Lebih banyak GC tidak bagus, tapi saya tidak yakin ini akan menjadi pola yang umum.

Tapi siapa yang tahu apa yang akan kita lihat di masa depan, jadi saya kira itu berguna untuk memiliki fleksibilitas yang dibangun sekarang.

Saya pikir itu ide yang buruk untuk mencoba memunculkan terlalu banyak detail implementasi di js API (terutama detail spesifik arsitektur/platform). Saya pikir itu harus cukup untuk implementasi untuk memiliki batas internal mereka sendiri untuk memori cepat.

Memiliki fungsi instantiate async tampaknya masuk akal tetapi saya pikir kita harus menggunakan sesuatu yang lain jika kita ingin menggunakannya untuk memberikan petunjuk kompiler. Misalnya, kita dapat memperluas modul untuk memiliki bagian flag yang meminta pengoptimalan untuk singleton, pengoptimalan untuk banyak instance, pengoptimalan waktu buka, pengoptimalan untuk kinerja yang dapat diprediksi, dll. Tentu saja, apa yang dilakukan engine (jika ada) sepenuhnya bergantung pada implementasi, tetapi ini memberi para pengembang tombol untuk berputar dan persaingan akan membuat vendor browser tetap jujur.

Pada Jum, 28 Okt 2016 jam 02:15, JF Bastien [email protected]
menulis:

Ya, seharusnya (bahkan didorong) untuk meneruskan Memori ke
kompilasi.

Saya pikir itu lebih baik berkecil hati demi tidak
mengimpor/mengekspor memori sama sekali. Lagi pula jika modul tidak diimpor
atau memori ekspor, memori dapat dicadangkan pada waktu kompilasi. aku tahu kita
ingin dapat secara efisien menangani modul-fu canggih yang beberapa
aplikasi ingin melakukannya, tetapi saya berharap aplikasi WASM monolitik akan
menjadi lebih umum daripada yang kita antisipasi. Mungkin aku minoritas di sini, tapi
Saya lebih suka melihat lebih sedikit modul dengan pengikatan yang kurang dinamis.

Anda menerima ini karena Anda berkomentar.
Balas email ini secara langsung, lihat di GitHub
https://github.com/WebAssembly/design/issues/838#issuecomment -25680506,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/ALnq1KXrUWaegRZwEhznmT1YcyI33IN9ks5q4T6TgaJpZM4Kh1gM
.

Saya sepenuhnya setuju dengan Anda, saya pikir aplikasi monolitik akan menjadi kasus penggunaan utama, setidaknya untuk beberapa tahun segera setelah mvp. Khawatir tentang apa yang terjadi ketika Anda memiliki 10-an ribu modul yang dimuat berarti mengasumsikan banyak tentang ekosistem wasm yang belum ada.

Jadi apa yang tersisa untuk dilakukan untuk menyelesaikan masalah ini? Satu hal adalah memperbarui http://webassembly.org/getting-started/js-api , yang bisa saya lakukan. Lain akan untuk binaryen untuk memancarkan ini secara default (kedengarannya bagus @kripken?). @titzer apakah Canary mengimplementasikan WebAssembly.instantiate ?

Ada yang lain?

@lukewagner : tidak yakin apa yang Anda tanyakan, diskusi dalam masalah ini sangat panjang. Maksud Anda mengubah binaryen dari WebAssembly.Instance API sinkronisasi saat ini yang digunakan untuk menggunakan salah satu API berbasis janji baru yang diusulkan di sini? Apakah itu perlu - apakah kita menghapus cara lama?

@kripken Benar, beralih menggunakan WebAssembly.instantiate . Kami tidak menghapus cara lama, tetapi cara baru lebih efisien dan dimaksudkan untuk digunakan secara default.

Kita bisa menggunakan API berbasis janji saat membuat HTML, tetapi banyak pengguna yang menghasilkan JS dan secara otomatis menambahkan langkah-langkah asinkron. Kami dapat mendokumentasikan ini untuk orang-orang. Tapi saya kira kita harus melakukan semua itu hanya setelah ini mendarat di semua browser.

@kripken Saya tidak yakin saya mengerti: pendekatan saat ini adalah tidak menggunakan API async sama sekali?

Ya . Lihat masalah ini untuk menambahkan hal-hal async.

@kripken Node akan memiliki janji yang berfungsi, saya berasumsi. Bahkan shell memiliki cara untuk secara eksplisit menguras antrian janji (dan dengan demikian menjalankan semua resolusi secara sinkron); di SM drainJobQueue() dan di V8 saya mendengar ada %RunMicroTasks() . Sepertinya Anda cukup menampilkan uji WebAssembly.instantiate dan menggunakannya saat ada secara default.

Tentu, tapi pertama-tama, dukungan Promise mungkin ada di node.js terbaru, tetapi tidak dalam versi yang biasa digunakan (versi default di distro linux misalnya). Dan kedua, masalah yang lebih besar adalah ketika kami memancarkan HTML, kami memiliki kendali atas bagaimana halaman dimuat (emcc memancarkan kode pemuatan untuk pengguna) sementara ketika kami memancarkan JS, JS diasumsikan hanya dijalankan secara linier, dan pengguna bergantung pada itu, misalnya mereka dapat memiliki tag skrip lain tepat setelah JS itu. Dalam hal ini pengguna menulis kode pemuatan mereka sendiri.

Sebagai hasil dari keduanya, seperti yang disebutkan sebelumnya, kita dapat menggunakan API Janji saat memancarkan HTML (maka Anda pasti tidak berada di shell, dan memiliki kendali atas pemuatan), tetapi tidak saat memancarkan JS. Di sana kami hanya bisa mendokumentasikannya.

Apakah Node memiliki versi yang mendukung WebAssembly tetapi tidak Promise? Apakah orang Node peduli dengan versi ini?

Saya tidak mengerti hal JS garis lurus. Jika Anda selalu mengembalikan Promise, bukankah itu Just Work (pengguna kode perlu mengonsumsi janji)?

Saya tidak tahu jawaban untuk pertanyaan pertama, tetapi polyfill mungkin membiarkan wasm berjalan pada versi simpul yang tidak memiliki janji. Meskipun, mungkin untuk melakukan polyfill janji juga karena node telah memiliki versi setTimeout untuk sementara waktu sekarang, saya pikir, tetapi tidak yakin tentang itu juga.

Tentang masalah garis lurus: emcc memancarkan JS yang mengatur runtime dan menghubungkan ke kode yang dikompilasi. Beberapa JS dalam tag skrip tepat setelah itu mungkin memanggil kode yang dikompilasi itu, misalnya menggunakan ccall . Dengan kata lain, keluaran JS emcc bukanlah janji, jadi saya tidak yakin apa yang Anda maksud dengan "mengembalikan janji" - siapa yang akan mengembalikannya, dan siapa yang akan menerimanya? Tetapi bagaimanapun juga, seperti yang disebutkan sebelumnya, jalur yang disarankan adalah agar emcc memancarkan HTML, dalam hal ini kita dapat membuat kode pemuatan asinkron. Hanya saja beberapa pengguna lebih memilih untuk mengontrol loading secara lebih langsung. Kita perlu mendorong mereka untuk menggunakan hal-hal async wasm jika lebih baik.

IMO Node dengan WebAssembly tetapi tanpa Janji bukanlah kendala desain yang harus kita khawatirkan. Polyfill ke WebAssembly cukup konyol dalam konteks itu.

Anda menjelaskan apa yang dilakukan kode hari ini. Saya tidak sepenuhnya memahaminya, tetapi saya ingin mencadangkan: Saya ingin kode di halaman web menggunakan Promise API. Emscripten adalah produsen kode tersebut. Saya tidak mengerti apa yang menghalanginya dari memancarkan kode yang menggunakan janji. Saya benar-benar baik-baik saja jika Anda mengatakan "itu pekerjaan yang signifikan karena bukan cara kerjanya hari ini, tetapi kita akan melakukannya". Tapi dari diskusi kita, saya tidak yakin apakah itu yang Anda katakan.

Apakah masalah yang Anda tunjukkan hanya tentang penggunaan async API untuk caching? Itu awal yang saya kira, tetapi kondisi akhir yang ingin saya capai adalah di mana async API digunakan bahkan pada pemuatan pertama.

Mengapa polyfill menjadi konyol di node? Tampaknya masih berguna dalam konteks itu, meskipun kurang dari dalam kasus lain :)

Sekali lagi: Emscripten akan menggunakan API janji ketika memancarkan HTML. Dan itu adalah jalan yang disarankan. Jadi jawaban untuk pertanyaan Anda adalah "ya". Itu bukan pekerjaan yang signifikan. Itu digambarkan dalam masalah itu, yang ya, berfokus pada caching tetapi saya menambahkan catatan dari diskusi offline (lama) bahwa saat melakukan itu kita juga harus melakukan banyak optimasi async lainnya di sana, karena kita bisa dan itu sepele.

Apakah itu mengatasi kekhawatiran Anda?

Yang saya katakan adalah bahwa ketika Emscripten memancarkan JS - jalur yang kurang direkomendasikan - maka jaminan tentang output itu tidak konsisten dengan kode yang melakukan sihir async secara internal. Kami akan melanggar kode orang, yang tidak ingin kami lakukan. Seperti yang saya katakan, seseorang dapat menulis JS yang berjalan secara serempak tepat setelah JS yang menganggapnya sudah siap. Jadi kami tidak akan dapat menggunakan janji dalam kasus itu. Bayangkan ini:

````

````

doSomething membutuhkan Module.my_func untuk eksis. Jika output.js baru saja mengembalikan janji, maka itu belum ada. Jadi ini akan menjadi perubahan yang menghancurkan.

Apakah itu masuk akal sekarang?

Mengapa polyfill menjadi konyol di node? Tampaknya masih berguna dalam konteks itu, meskipun kurang dari dalam kasus lain :)

Sebuah polyfill untuk wasm tidak konyol. Melayani instalasi Node yang tidak memiliki wasm, polyfill, dan tidak punya janji tetapi tidak polyfill itu, konyol. Ini setengah-setengah. Mereka harus mendapatkan separuh pantat lainnya 😁

Sekali lagi: Emscripten akan menggunakan API janji ketika memancarkan HTML. Dan itu adalah jalan yang disarankan. Jadi jawaban untuk pertanyaan Anda adalah "ya". Itu bukan pekerjaan yang signifikan. Itu digambarkan dalam masalah itu, yang ya, berfokus pada caching tetapi saya menambahkan catatan dari diskusi offline (lama) bahwa saat melakukan itu kita juga harus melakukan banyak optimasi async lainnya di sana, karena kita bisa dan itu sepele.

Apakah itu mengatasi kekhawatiran Anda?

OK itu bagus! Selama sebagian besar halaman web menggunakan API janji, saya senang.

[menggunting]

Apakah itu masuk akal sekarang?

Ya. Terima kasih telah menjelaskan.

Dari POV saya, Emscripten tidak hanya dalam bisnis memancarkan JS lagi! Contoh Anda masuk akal untuk Ye Olden Codes, tetapi hal-hal baru harus mengasumsikan janji IMO.

Btw, saya melihat beralih webassembly.org/demo untuk menggunakan instantiate dan itu agak rumit karena new Instance sinkron saat ini terjadi dalam konteks yang menginginkan hasil yang sinkron. Jadi setelah kami memperbarui Binaryen untuk mengeluarkan instantiate secara default, alangkah baiknya untuk membangun kembali demo AngryBots dari awal.

Ya, tetapi perhatikan bahwa membangun kembali dari awal mungkin tidak cukup - saya percaya Unity menggunakan pemuatan dan kode HTML-nya sendiri. Jadi kita perlu mendokumentasikan dan mengomunikasikan masalah ini seperti yang disebutkan sebelumnya sehingga mereka dapat melakukan hal-hal yang diperlukan (atau mungkin kita bisa membuat mereka membiarkan emcc memancarkan html, tapi saya tidak tahu apakah itu layak untuk mereka).

Ya, tetapi perhatikan bahwa membangun kembali dari awal mungkin tidak cukup - saya percaya Unity menggunakan pemuatan dan kode HTML-nya sendiri. Jadi kita perlu mendokumentasikan dan mengomunikasikan masalah ini seperti yang disebutkan sebelumnya sehingga mereka dapat melakukan hal-hal yang diperlukan (atau mungkin kita bisa membuat mereka membiarkan emcc memancarkan html, tapi saya tidak tahu apakah itu layak untuk mereka).

Mengingat potensi kerugian dari tidak menggunakan WebAssembly.instantiate API, saya pikir ada baiknya meminta mereka untuk mempertimbangkan menggunakannya.

Apakah kerugian tersebut didokumentasikan? Panduan yang jelas tentang ini di situs web wasm utama atau halaman wiki wasm emscripten akan menjadi hal yang nyaman untuk mengarahkan orang.

Saya sendiri baru saja membaca sepintas masalah panjang ini, dan saya belum mengetahui kerugiannya, jadi saya ingin membacanya juga :)

@kripken Tantangan dengan kode saat ini adalah bahwa binaryen/emscripten hanya menyediakan impor yang diperlukan (diperlukan sebagai argumen ke instantiate ) pada saat yang sama dengan ekspor yang diperlukan secara sinkron. Jika impor dapat disediakan "di depan", maka cukup sepele untuk menempelkan WebAssembly.instantiate ke bagian belakang async XHR (seperti yang telah saya lakukan dalam demo saat ini dengan async compile ). Jadi saya tidak berpikir ini akan membutuhkan banyak pekerjaan di pihak Unity. Juga, dari apa yang saya lihat , build wasm AngryBots kami saat ini kurang optimal dan tetap perlu disegarkan.

Oh, saya tidak mengerti bahwa memiliki impor yang tersedia bahkan sebelum wasm XHR dimulai adalah kuncinya di sini. Itu jauh lebih rumit kalau begitu. Jadi sebagian besar dari apa yang saya katakan sebelumnya salah.

Agar kami dapat mengimpor, kami harus mengunduh, menguraikan, dan menjalankan semua lem JS. Jika kita melakukan semua itu bahkan sebelum wasm XHR dimulai, maka ini adalah skema pemuatan dan serangkaian pengorbanan yang sangat berbeda dari yang kita miliki sekarang. Khususnya, untuk proyek kecil hingga menengah, mungkin ini bahkan tidak akan menjadi percepatan, saya kira kita harus mengukur ini - jika kita belum melakukannya?

Ini bukan sesuatu yang sederhana untuk dilakukan Unity. Ini akan membutuhkan perubahan signifikan pada kode yang dipancarkan emcc, sehingga lem JS dapat dijalankan sebelum kode yang dikompilasi siap.

Mungkin kita ingin mempertimbangkan model baru JS yang dipancarkan, satu file JS untuk impor, satu file JS untuk sisanya? Dan itu akan menjadi pilihan, jadi kami tidak akan merusak siapa pun. Bagaimanapun, ada banyak pertimbangan, dan tanpa pengukuran sulit untuk menebak apa yang optimal.

@kripken Bukan sebelum XHR tetapi setelah selesai, dan beberapa saat sebelum kita mulai menjalankan skrip yang ingin akses sinkron ke objek ekspor. Saya berharap itu bisa sesederhana meletakkan kode yang menggunakan ekspor itu di beberapa panggilan balik yang dipanggil ketika instantiasi selesai.

Hmm, saya kira saya masih belum sepenuhnya memahami ini, maaf (khususnya, saya tidak mengerti mengapa asinkron berinteraksi dengan mendapatkan impor - dapatkah manfaat dari impor tidak berfungsi secara sinkron?). Tapi sepertinya masalah yang saya sebutkan di atas masih relevan meskipun ini setelah XHR selesai - yaitu, kami sekarang memiliki satu skrip yang menghasilkan impor dan juga menerima ekspor. Memisahkan itu dapat menyebabkan pengorbanan - kita hanya perlu mengukur kapan kita punya waktu.

Tentang menempatkan kode yang menggunakan ekspor dalam panggilan balik, sayangnya itu tidak hanya berfungsi karena alasan yang disebutkan sebelumnya, tetapi kami dapat menyelidiki sebagai bagian dari pengukuran tersebut dengan menambahkan beberapa mode kompilasi baru.

Tanda tangan dari instantiate adalah WebAssembly.instantiate(bytes, importObj) , jadi untuk menjalankan async compile+instantiate, Anda harus melewati importObj .

Berbicara secara offline, @lukewagner membuat saya terkesan bahwa masalah utama di sini adalah memiliki Memori saat mengkompilasi modul. Secara keseluruhan, tampaknya ada tiga masalah yang terkait dengan betapa mudahnya menggunakan API baru ini dalam praktik:

  1. Menyediakan Memori saat kompilasi.
  2. Menyediakan semua impor saat kompilasi (superset dari sebelumnya).
  3. Melakukan semua ini secara tidak sinkron.

Mengingat cara kerja toolchain saat ini, melakukan 2 + 3 itu sulit, seperti yang dijelaskan di atas, karena akan merusak pengguna yang ada. Kita dapat melakukannya, tetapi mungkin tidak menginginkannya secara default, setidaknya tidak pada awalnya - kita perlu berkonsultasi dengan anggota komunitas, dll. Dan untuk melakukannya dengan sangat baik - tidak ada biaya tambahan baru - akan membutuhkan waktu dan kerja (melakukannya dengan cepat dapat dilakukan dengan menambahkan lapisan tipuan baik pada impor atau ekspor).

Tetapi beberapa opsi lain mudah digunakan:

  • 1 + 3 akan membutuhkan API baru seperti instantiate(bytes, Memory) -> Promise . Alasan mengapa ini mudah digunakan adalah karena Memori dapat dibuat lebih awal (sementara hampir semua impor lainnya adalah fungsi JS, yang tidak dapat kita miliki sejak awal).
  • 2 dengan sendirinya, tanpa 3, yaitu new Instance(bytes, imports) . Artinya, kompilasi sinkron pada data biner + impor. Alasan mengapa ini mudah digunakan adalah karena kode kami saat ini melakukan ini: instance = new WebAssembly.Instance(new WebAssembly.Module(getBinary()), imports) jadi kami hanya akan melipatnya menjadi 1 panggilan API.

Saya pikir opsi terakhir masuk akal. Ini pada dasarnya berarti menambahkan versi sinkronisasi dari API baru, membuat segalanya lebih simetris dengan opsi kompilasi sinkron kami yang ada. Dan saya tidak melihat alasan untuk mengikat pengoptimalan baru mengetahui Memori pada waktu kompilasi ke kompilasi asinkron? (async bagus, tetapi masalah terpisah?)

Saya menyarankan objek meta yang menggambarkan impor (memori) untuk memecahkan batasan bahwa impor perlu dialokasikan sebelum dikompilasi. Kemudian metode instantiate dapat menimbulkan kesalahan jika memori yang diberikan tidak sesuai dengan yang diharapkan dan tidak akan ditunda kompilasi ulang.

Juga akan sangat berguna untuk dapat mengkompilasi sebelum mengalokasikan memori linier pada perangkat yang dibatasi memori, juga untuk dapat mengoptimalkan kompilasi untuk memori yang dialokasikan pada nol di ruang alamat linier, dan mungkin untuk memori dengan zona penjaga, dan untuk mengoptimalkan memori dengan ukuran maksimum tetap yang dapat menjadi kekuatan dua ditambah zona tumpahan. Objek meta ini juga dapat digunakan oleh decoder/penulis ulang pengguna wasm untuk memancarkan kode yang dioptimalkan untuk karakteristik memori yang dinegosiasikan.

Ini adalah sesuatu yang disarankan sebagai kebutuhan sekitar awal proyek ini bertahun-tahun yang lalu sekarang!

@kripken Sementara API sinkronisasi, saya percaya, secara teknis diperlukan, mereka pasti harus menjadi jalur yang tidak direkomendasikan atau kami akan memperkenalkan banyak jank utas utama yang tidak perlu, sebuah regresi dibandingkan dengan asm.js +

Saya bermaksud memberikan contoh yang lebih baik tentang mengapa kita perlu secara eksplisit mencegah (atau, seperti yang saya katakan di masa lalu, bahkan melarang) kompilasi/instantiasi sinkron. Semoga ini memberikan tambahan bahan untuk diskusi.

Mari kita memperkecil dan berbicara tentang pengalaman pengguna sejenak.


Berikut perbandingan antara memuat demo AngryBots secara asinkron (via asm.js), kiri, dan sinkron (via WebAssembly di V8), kanan.

comparison

Kompilasi sinkron memberikan pengalaman pengguna yang buruk dan merusak bilah kemajuan atau indikasi visual lainnya dari pemuatan aplikasi.

Apa pun upayanya, saya pikir kita perlu bekerja sama untuk memastikan bahwa Emscripten, Unity, dan alat lain mengekspor memuat WebAssembly secara asinkron secara default. cc @jechter @juj Tidak hanya itu, saya pikir kita perlu mempersulit pengembang untuk jatuh ke dalam perangkap penulisan kode pemuatan sinkron.

Kita perlu secara eksplisit mendorong WebAssembly.compile & WebAssembly.instantiate dan mencegah new WebAssembly.Module & new WebAssembly.Instance .


Mari selami lebih dalam dan lihat seberapa buruk bilah kemajuan di sebelah kanan, untuk WebAssembly.

Berikut adalah jejak yang ditangkap dengan panel kinerja DevTools:

screen shot 2016-12-28 at 1 26 59 pm

MacBook Air saya membutuhkan waktu 30 detik untuk menampilkan bilah kemajuan apa pun.

Apa yang membutuhkan waktu itu? Mari kita perbesar ~20-an setelah modul wasm diunduh ketika utas utama terkunci sepenuhnya:

screen shot 2016-12-28 at 2 18 36 pm

Kompilasi memakan waktu ~20 detik dan instantiasi membutuhkan waktu ~2 detik.

Perhatikan bahwa dalam kasus ini, pemuat Unity sudah memanggil WebAssembly.compile asinkron jika didukung, jadi 20-an adalah karena V8 masih melakukan kompilasi sinkron di bawah tenda. cc @titzer @flagxor ini adalah sesuatu yang benar-benar perlu diperbaiki oleh V8.

Instansiasi jank 2s disebabkan oleh kode pemuat Unity yang memanggil new WebAssembly.Instance sinkron. Inilah yang benar-benar perlu kita perbaiki dalam kode Unity dan Emscripten.


Saya pikir perlu juga disebutkan bahwa ini bukan _hanya_ risiko pengembang menembak diri mereka sendiri atau tidak. Rata-rata halaman web mencakup lusinan skrip pihak ketiga: skrip tersebut semuanya berpotensi untuk menyertakan WebAssembly janking dokumen teratas.

(Jika Anda ingin menjelajahi jejak lebih detail, Anda dapat melihat garis waktu lengkapnya di sini: https://chromedevtools.github.io/timeline-viewer/?loadTimelineFromURL=https://www.dropbox.com/s/ noqjwql0pq6c1wy/wasm?dl=0)

Saya setuju 100% bahwa async bagus :) Tapi saya katakan itu ortogonal untuk optimasi mendapatkan Memori pada saat yang sama dengan kompilasi Modul. Dan kita tidak bisa secara sepele mendapatkan async+optimasi itu - kita bisa mendapatkan kombo itu, tetapi baik dengan biaya beberapa overhead, atau waktu jika kita memperkenalkan flag baru untuknya dan menemukan cara untuk mengubahnya menjadi default .

Jadi jika kita ingin optimasi Memori/kompilasi itu sekarang, aktif secara default, dan dengan efisiensi penuh, maka mengikatnya menjadi juga async adalah masalah. Tetapi jika itu tidak mendesak, atau kami baik-baik saja dengan itu tidak diaktifkan secara default, atau kami baik-baik saja dengan beberapa overhead baru, maka tidak ada masalah.

Karena pengembang memilih wasm, saya pikir masuk akal untuk mengambil kesempatan untuk sedikit mengubah struktur tingkat atas dengan default baru (dengan cara untuk ikut serta ke perilaku lama jika perlu). Orang yang menggunakan sinkronisasi

@kripken Saya pikir Anda sampai pada kesimpulan yang berbeda dari yang saya, @lukewagner dan @s3ththompson miliki karena bagi Anda bagian terpenting adalah menawarkan transisi yang mulus dari asm.js untuk pengembang yang ada.

Apakah ini benar?

Saya setuju ini adalah kekhawatiran yang valid. Saya menimbangnya lebih rendah karena IMO dengan WebAssembly kami membawa lebih banyak pengembang daripada yang dimiliki asm.js. Saya ingin menghindari pembakaran pengadopsi awal, tetapi pengembang IIUC yang ada cukup fleksibel dan menginginkan kompilasi asinkron.

Jika kita berasumsi bahwa mereka menginginkan kompilasi asinkron, dan bersedia melakukan refactor beberapa untuk mendapatkannya, maka yang tersisa hanyalah memiliki memori pada waktu kompilasi, yang disediakan oleh API ini. Ini sangat diinginkan karena menghindari jebakan.

Sebelumnya Anda menyatakan keprihatinan pada jumlah pekerjaan yang terlibat di pihak Emscripten untuk mendukung ini. Apakah Anda masih berpikir ini adalah masalah?

FWIW, Unity 5.6 akan menggunakan WebAssembly.instantiate.

jonas

Pada 28 Desember 2016, pukul 23.42, Seth Thompson [email protected] menulis:

Saya bermaksud memberikan contoh yang lebih baik tentang mengapa kita perlu secara eksplisit mencegah (atau, seperti yang saya katakan di masa lalu, bahkan melarang) kompilasi/instantiasi sinkron. Semoga ini memberikan tambahan bahan untuk diskusi.

Mari kita memperkecil dan berbicara tentang pengalaman pengguna sejenak.

Berikut perbandingan antara memuat demo AngryBots dengan panggilan asinkron (via asm.js), panggilan kiri, dan panggilan sinkron (implementasi WebAssembly saat ini), kanan.

Kompilasi sinkron memberikan pengalaman pengguna yang buruk dan merusak bilah kemajuan atau indikasi visual lainnya dari pemuatan aplikasi.

Apa pun upayanya, saya pikir kita perlu bekerja sama untuk memastikan bahwa Emscripten, Unity, dan alat lain mengekspor memuat WebAssembly secara asinkron secara default. cc @jechter @juj Tidak hanya itu, saya pikir kita perlu mempersulit pengembang untuk jatuh ke dalam perangkap penulisan kode pemuatan sinkron.

Kita perlu secara eksplisit mendorong WebAssembly.compile & WebAssembly.instantiate dan mencegah WebAssembly.Module baru & WebAssembly.Instance baru.

Mari selami lebih dalam dan lihat seberapa buruk bilah kemajuan di sebelah kanan, untuk WebAssembly.

Berikut adalah jejak yang ditangkap dengan panel kinerja DevTools:

MacBook Air saya membutuhkan waktu 30 detik untuk menampilkan bilah kemajuan apa pun.

Apa yang membutuhkan waktu itu? Mari kita perbesar ~20-an setelah modul wasm diunduh ketika utas utama terkunci sepenuhnya:

Kompilasi memakan waktu ~20 detik dan instantiasi membutuhkan waktu ~2 detik.

Perhatikan bahwa dalam kasus ini, pemuat Unity sudah memanggil WebAssembly.compile asynchronous jika didukung, jadi 20-an adalah karena V8 masih melakukan kompilasi sinkron di bawah tenda. cc @titzer @flagxor ini adalah sesuatu yang benar-benar perlu diperbaiki oleh V8.

Instansiasi jank 2s disebabkan oleh kode pemuat Unity yang memanggil WebAssembly.Instance baru yang sinkron. Inilah yang benar-benar perlu kita perbaiki dalam kode Unity dan Emscripten.

Saya pikir perlu juga disebutkan bahwa ini bukan hanya risiko pengembang menembak diri mereka sendiri atau tidak. Rata-rata halaman web mencakup lusinan skrip pihak ketiga: skrip tersebut semuanya berpotensi untuk menyertakan WebAssembly janking dokumen teratas.

(Jika Anda ingin menjelajahi jejak lebih detail, Anda dapat melihat garis waktu lengkapnya di sini: https://chromedevtools.github.io/timeline-viewer/?loadTimelineFromURL=https://www.dropbox.com/s/ noqjwql0pq6c1wy/wasm?dl=0)


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub, atau matikan utasnya.

@jfbastien Mungkin saya tidak mengerti apa yang Anda maksud dengan "kesimpulan". Saya kebanyakan hanya menyajikan opsi di sini. Saya sendiri tidak punya kesimpulan.

Jika kita ingin memilih Memory-at-Compile-time sekarang, saya mengusulkan beberapa opsi yang dapat memungkinkan kita memilikinya ASAP, dengan mudah memodifikasi kompilasi sinkronisasi kita saat ini.

Atau jika kita ingin memilih itu sekarang dengan cara asinkron, saya mengusulkan opsi ("1 + 3", yaitu, tidak menerima semua impor pada waktu kompilasi, hanya Memori) yang dapat membuat kita memilikinya ASAP juga.

Atau jika kita ingin fokus sekarang pada versi async dari pilihan itu dengan API saat ini (bukan "1 + 3") maka kita bisa mendapatkannya juga, itu hanya akan membutuhkan perencanaan yang matang karena itu akan menjadi perubahan yang merusak. Saya tidak berpikir itu pilihan bagi kami di sini untuk memutuskan untuk menghentikan pengguna yang ada, jadi kami perlu berkonsultasi dengan komunitas. Mungkin akan ada sedikit masalah dan kita hanya bisa melakukannya, dalam hal ini, seberapa banyak usaha tergantung pada berapa banyak overhead yang ingin kita toleransi - jika kita tidak dapat menerima overhead sama sekali, maka itu mungkin banyak. Atau mungkin akan ada kekhawatiran, yang merupakan intuisi pribadi saya - setiap perubahan yang melanggar harus dilakukan secara bertahap - dalam hal ini akan memakan waktu lebih lama, kami mungkin akan mulai dengan opsi baru dan akhirnya berencana untuk menjadikannya default.

Sekali lagi, tidak ada kesimpulan dari saya. Semua di atas adalah pilihan. Itu benar-benar tergantung apa yang lebih Anda pedulikan: Memory-at-Compile-time, atau async, atau keduanya; dan masalah menoleransi overhead baru vs tidak; dan apakah Anda menginginkan ini segera atau dapat menunggu, dll. dll. Saya senang membantu di sisi emscripten dengan salah satu di atas, bagaimanapun orang memutuskan.

Atau jika kita ingin fokus sekarang pada versi async dari pilihan itu dengan API saat ini (bukan "1 + 3") maka kita bisa mendapatkannya juga, itu hanya akan membutuhkan perencanaan yang matang karena itu akan menjadi perubahan yang merusak. Saya tidak berpikir itu pilihan bagi kami di sini untuk memutuskan untuk menghentikan pengguna yang ada, jadi kami perlu berkonsultasi dengan komunitas. Mungkin akan ada sedikit masalah dan kita hanya bisa melakukannya, dalam hal ini, seberapa banyak usaha tergantung pada berapa banyak overhead yang ingin kita toleransi - jika kita tidak dapat menerima overhead sama sekali, maka itu mungkin banyak. Atau mungkin akan ada kekhawatiran, yang merupakan intuisi pribadi saya - setiap perubahan yang melanggar harus dilakukan secara bertahap - dalam hal ini akan memakan waktu lebih lama, kami mungkin akan mulai dengan opsi baru dan akhirnya berencana untuk menjadikannya default.

Yang pasti saya mengerti:

  1. Apa itu overhead?

    • Apakah overhead ini melekat pada Async + Memory-at-compile-time, atau apakah itu kendala implementasi yang dapat diperbaiki nanti? IMO jika mereka melekat pada A+M maka kita harus memperbaiki API ASAP.

    • IIUC overhead adalah hal sementara pada impor atau ekspor, dan tidak melekat pada A+M, apakah itu benar? Bisakah Anda merinci ini sedikit lebih banyak?

  2. Pengguna mana yang sedang kita bicarakan? pengguna asm.js yang ingin kode yang sama juga menargetkan wasm?

Dengan kata lain: apa keadaan akhir yang ideal untuk WebAssembly jika kita memiliki waktu tak terbatas dan tidak ada "warisan"? Saya pikir kami telah merancang untuk keadaan akhir yang ideal itu, dan Anda menunjukkan rintangan di jalan, tetapi saya masih tidak yakin itu masalahnya. Jika demikian, maka saya tidak yakin saya memiliki informasi yang cukup untuk mengetahui apakah WebAssembly memerlukan jeda sementara untuk memudahkan transisi, atau apakah beban sementara dapat diterima untuk sebagian pengguna Emscripten (dan pengguna mana).

Tentang overhead di beberapa opsi: Seperti dijelaskan di atas, hal yang rumit adalah kita harus mengirim impor dan menerima ekspor secara sinkron saat ini, dan bahwa kita tidak memiliki impor JS sampai JS siap (tetapi kita memiliki Memori !). Salah satu cara untuk menyiasatinya adalah dengan menambahkan lapisan tipuan pada impor atau ekspor. Misalnya, kami dapat menyediakan thunks alih-alih impor yang sebenarnya sangat awal (dalam HTML, sebelum JS), jadi kami tampaknya menyediakannya secara sinkron (tetapi itu hanya thunks, yang sepele untuk dibuat bahkan sebelum kami memiliki JS) . Kemudian nanti ketika kita memiliki JS, kita dapat memperbarui thunks untuk menunjuk ke tempat yang tepat. Ini akan menambah overhead panggilan JS lain dan pencarian objek JS untuk setiap panggilan impor. Juga beberapa overhead dalam ukuran kode dan startup.

Tentang melanggar pengguna: Kami ingin pengguna emscripten yang ada dapat membalik bendera dan bekerja wasm . Banyak pengguna dan mitra senang akan hal itu. Ini memungkinkan mereka membandingkan asm.js dan wasm dan memungkinkan proyek yang mereka habiskan untuk porting mendapat manfaat dari wasm tanpa upaya porting baru. Dan itu menghindari risiko bahwa jika mereka juga perlu menyinkronkan kode startup mereka saat porting ke wasm, dan ada yang rusak, mereka mungkin menyalahkan wasm secara tidak perlu.

bahwa kami tidak memiliki impor JS sampai JS siap (tetapi kami memiliki Memori!)

Itu tampaknya tidak disengaja dan bukan sesuatu yang harus kita panggang selamanya dengan API. Selanjutnya, untuk alasan @ s3ththompson menjelaskan, bahkan mengabaikan masalah memori-di-kompilasi-waktu, kita perlu Instansiasi menjadi async pula. Jadi saya setuju dengan @jfbastien bahwa kami memiliki API keadaan akhir ideal kami di sini dan itu tidak boleh kami kompromikan di sini.

Tentang melanggar pengguna: jika kami menawarkan jalur migrasi sederhana (seperti acara/janji "onload"), itu harus mudah bagi pengguna untuk bermigrasi, dengan wortel sebagai pemenang kinerja utama. Saya tidak berpikir kami memiliki bukti bahwa backcompat sumber asm.js yang tepat adalah persyaratan yang sulit untuk konfigurasi default; kami memiliki banyak contoh sebaliknya: pengguna bersedia melakukan apa saja untuk mencapai kinerja optimal karena itu, tentu saja, intinya.

Berbicara dengan @lukewagner offline, kami pikir hal terbaik adalah memulai dengan mengaktifkan instantiate for wasm dalam pengaturan default yang direkomendasikan di emscripten, dengan menambahkan lapisan tipuan (seperti dijelaskan di atas, tetapi pada ekspor). Ini mungkin akan memiliki overhead yang dapat diabaikan untuk sebagian besar kasus penggunaan. Jadi ini memberi kita manfaat yang kita semua inginkan di sini.

Pada akhirnya, kami dapat menghilangkan overhead kecil itu, tetapi itu akan menjadi perubahan besar yang akan membutuhkan lebih banyak perencanaan dan diskusi milis, dll., karena tidak ada cara yang jelas baik/benar untuk melakukannya, kami menyadari. Tapi karena kami pikir overhead lapisan tipuan sangat rendah, bagian ini tidak mendesak.

@kripken hebat! Akan sangat membantu untuk memiliki diagram yang menunjukkan berbagai contoh / JS / impor / ekspor / memori / tabel. Apakah Anda ingin memindahkan diskusi ini ke tempat lain (Emscripten / binaryen repo)? Saya memiliki gambaran mental tentang apa yang menurut saya kode C++ harus diatur, tetapi cukup jelas sekarang bahwa Anda tidak memiliki gambaran yang sama! Anda memiliki lebih banyak pengalaman di sana, jadi saya ingin belajar darinya dan membantu semampu saya.

@jfbastien : tentu. Saya belum jelas tentang apa yang Anda cari dalam diagram, tapi ya, mungkin tempat lain lebih baik. Untuk implementasi ini di emscripten ada masalah yang disebutkan sebelumnya, https://github.com/kripken/emscripten/issues/4711 , juga jangan ragu untuk membuka yang lain jika itu tidak mencakup apa yang Anda inginkan.

IIUC Emscripten menggunakan ini secara default sekarang. Penutupan.

Untuk menindaklanjuti komentar @s3ththompson , perhatikan bahwa kompilasi dan instantiasi sinkron berguna. Khususnya, saya baru-baru ini mengalami situasi di mana saya ingin memuat dan mengkompilasi modul WebAssembly secara serempak di Node.js ( v7.7.2 ). Jika hanya API yang mengembalikan janji yang tersedia, ini berarti saya tidak akan dapat menyediakan ekspor sinkron.

Saat memutuskan apakah akan menyediakan async, sync, atau keduanya API, ingatlah bahwa konteks browser bukan satu-satunya lingkungan di mana orang ingin menggunakan WebAssembly. Sejumlah orang, termasuk saya sendiri, tertarik dengan potensi WebAssembly sebagai target kompilasi yang efisien yang dikombinasikan dengan runtime Node.js, mirip dengan JVM. Sementara impor/ekspor async mungkin mendarat di Node.js, impor dan ekspor sinkron akan tetap menjadi pola dominan di masa mendatang. Dalam hal ini, kemampuan untuk memuat modul WebAssembly dan secara sinkron mengompilasi dan membuat instance modul itu sangat berguna.

@kgryte Saya seharusnya mengklarifikasi bahwa komentar saya terutama berkaitan dengan browser sebagai konteks eksekusi. Kami telah mendarat di permukaan API yang masih mengekspos API sinkron. Browser dapat menerapkan batas ukuran pada modul yang diteruskan ke API sinkron (Chrome sudah melakukannya, misalnya), tetapi batas tersebut dapat dikonfigurasi oleh penyemat dan tidak perlu diterapkan ke Node.js.

@s3ththompson Terima kasih atas klarifikasinya.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

oridb picture oridb  ·  159Komentar

kripken picture kripken  ·  37Komentar

dcodeIO picture dcodeIO  ·  48Komentar

ngzhian picture ngzhian  ·  41Komentar

kripken picture kripken  ·  96Komentar