Design: Panggilan balik JS API sinkron untuk pertumbuhan memori?

Dibuat pada 29 Agu 2019  ·  37Komentar  ·  Sumber: WebAssembly/design

Latar belakang: https://github.com/WebAssembly/WASI/issues/82

Singkatnya, JavaScript perlu tahu kapan memori wasm tumbuh, karena perlu memperbarui tampilan array yang diketik JS. Di emscripten kami memiliki hal-hal yang diatur di sbrk dll. untuk memanggil ke JS untuk melakukan itu ketika memori bertambah. Namun, dalam wasi pendekatan saat ini adalah dengan memanggil instruksi wasm tumbuh memori di dalam modul wasm, jadi JS tidak diperbarui.

JS dapat memeriksa apakah memori bertambah setiap kali kode wasm dijalankan (tiba di JS, atau kembali dari wasm, dll.). Emscripten melakukan sesuatu yang serupa untuk pthreads+pertumbuhan memori, tetapi itu tidak menyenangkan, menambah overhead, dan rawan kesalahan.

Pilihan lain adalah menambahkan API di wasi untuk memperbarui sistem pada pertumbuhan memori.

Namun opsi lain adalah memperluas JS wasm API untuk mendapatkan panggilan balik saat terjadi pertumbuhan memori. Itulah yang dimaksud dengan masalah ini.

Mungkin terlihat seperti ini:

memory.addGrowCallback(() => {
  console.log("wasm memory grew!");
  updateAllJSViewsRightNow();
});

Panggilan balik akan sinkron , yaitu, ketika memori wasm bertambah, semua panggilan balik tersebut segera dieksekusi, sementara wasm masih di tumpukan dll. Ini diperlukan karena jika itu adalah peristiwa yang terjadi di loop peristiwa JS berikutnya maka itu adalah terlambat - kami dapat mengeksekusi JS sebelum itu, dan itu akan menggunakan tampilan lama yang sudah usang.

Pikiran?

Komentar yang paling membantu

Terima kasih, sekarang saya mengerti! Ya, jika realokasi dilakukan secara otomatis, sehingga ArrayBuffers dan tampilan secara otomatis bertambah dengan memori wasm, maka itu akan menyelesaikan masalah di sini.

Mungkinkah ini juga terjadi dengan SharedArrayBuffers, jadi JS diperbarui di seluruh utas? Itu akan memecahkan masalah yang sangat besar juga (saat ini kita harus melakukan polling secara manual jika memori bertambah di JS).

Semua 37 komentar

Berikut dua utas yang ada tentang masalah ini: https://github.com/WebAssembly/design/issues/1271 dan https://github.com/WebAssembly/design/issues/1210. Mereka tampaknya membahas proposal yang setara dan beberapa lainnya.

Terima kasih @Macil!

Yang pertama adalah masalah pthreads+pertumbuhan, yang sangat terkait, tetapi berbeda. (Khususnya peristiwa sinkron tidak cukup di sana. seperti yang Anda sebutkan di sana, tetapi itu akan cukup di sini.)

Yang kedua memang sepertinya sampai pada proposal ini, jadi sayang sekali saya tidak menemukannya ketika saya mencari sebelumnya ... tetapi diskusi di sana tampaknya terhenti, dan proposal tidak secara jelas fokus pada sinkronisasi yang diperlukan aspek. Jadi saya sarankan agar masalah ini tetap terbuka untuk didiskusikan?

Menambahkan metode baca/tulis pada memori wasm (sebagai pengganti tampilan ArrayBuffer) dapat melayani kasus penggunaan ini juga, tetapi masih berarti bahwa tampilan arraybuffer tidak akan pernah dapat digunakan secara andal pada memori wasm, yang akan menjadi kutil yang tidak menguntungkan.

Apa yang sebenarnya terjadi sekarang (atau seharusnya terjadi) jika utas Javascript mengambil referensi ke ArrayBuffer memori WASM dan membaca/menulisnya sementara utas WASM yang terpisah menumbuhkan memori? Saya berasumsi salah satu dari dua hal ini terjadi:

  1. Javascript selesai secara normal. Untuk run event loop saat ini, Javascript selalu melihat properti buffer memori WASM sama dengan nilai yang sama, dan panjangnya tidak berubah. Hanya setelah loop peristiwa saat ini berjalan, properti buffer memori WASM menunjuk ke nilai baru, dan ArrayBuffer yang ada menjadi tidak valid.
  2. ArrayBuffer menjadi tidak valid pada saat yang sewenang-wenang dalam eksekusi Javascript, dan pembacaan/penulisan pergi ke salinan memori yang tidak aktif dan penulisannya hilang, atau terjadi pengecualian.

Jika 1, maka sepertinya panggilan balik JS API sinkron untuk pertumbuhan memori akan baik-baik saja. Panggilan balik tidak akan benar-benar terjadi secara sinkron dengan panggilan tumbuh (yang terjadi di utas lain), tetapi itu akan terjadi secara sinkron dengan titik waktu di mana ArrayBuffer yang ada menjadi tidak valid dalam konteks JS saat ini.

IIRC, yang seharusnya terjadi adalah seperti (1). Sebuah thread memperoleh nilai memory.buffer. Ini memiliki bidang panjang yang tidak pernah berubah. Utas akan dapat menulis ke buffer hingga panjang itu, bahkan jika utas lain menumbuhkan memori secara bersamaan. Nilai buffer yang diekstraksi _tetap valid tanpa batas_, tetapi jika utas membaca memory.buffer lagi (bahkan selama giliran yang sama) ia mungkin mengamati bahwa panjangnya telah berubah dan dengan menggunakan buffer ini ia dapat menulis hingga panjang yang baru.

Ada perkembangan baru di sini?

@kripken Ini semua tampaknya paling rapi diselesaikan dengan memastikan kemampuan ArrayBuffer , SharedArrayBuffer , dan WebAssembly.Memory tetap sinkron. Intinya, saya akan dengan senang hati menghidupkan kembali bagian realloc dari https://github.com/domenic/proposal-arraybuffer-transfer/ (yang tampaknya saya sudah menjadi juara) untuk memungkinkan pengubahan ukuran AB dan SAB dengan pembatasan serupa seperti yang dikemukakan oleh wasm, sambil menjaga identitas JS mereka. WDYT?

@syg

Tergantung apa yang Anda maksud dengan "ini" - maksud Anda seluruh masalah? Maka IIUC .realloc() akan membantu tetapi tidak cukup. Jika wasm memanggil memory.grow internal, kita memerlukan buffer JS dan tampilan untuk diperbarui. Bahkan jika kita memiliki metode .realloc() yang dapat kita gunakan dari JS, kita masih memerlukan JS untuk dipanggil agar kita dapat melakukannya (atau, kita memerlukan buffer dan tampilan diperbarui secara otomatis).

maksudmu seluruh masalah?

Ya, maksud saya seluruh masalah.

Jika wasm memanggil memory.grow secara internal, kita membutuhkan buffer JS dan tampilan untuk diperbarui. Bahkan jika kita memiliki metode .realloc() yang dapat kita gunakan dari JS, kita masih perlu memanggil JS agar kita dapat melakukannya (atau, kita memerlukan buffer dan tampilan diperbarui secara otomatis).

Itulah yang saya usulkan untuk realloc , bahwa itu adalah operasi destruktif yang menjaga identitas ArrayBuffer .

Mungkin saya salah paham dengan Anda, tetapi saya pikir realloc membantu kami melakukan sesuatu yang lebih bersih di JS ketika terjadi pertumbuhan, tetapi kami masih perlu diberi tahu, jadi kami bahkan mendapat kesempatan untuk melakukan apa pun di JS sama sekali ?

Jika saya kehilangan sesuatu, apa yang akan memanggil JS yang memanggil realloc ?

Mungkin saya salah paham dengan Anda, tetapi saya pikir realoc membantu kami melakukan sesuatu yang lebih bersih di JS ketika pertumbuhan terjadi, tetapi kami masih perlu diberi tahu, jadi kami bahkan mendapat kesempatan untuk melakukan apa pun di JS sama sekali?

Jika saya kehilangan sesuatu, apa yang akan memanggil JS yang memanggil realoc?

memory.grow wasm akan dijelaskan dalam istilah realoc. Jika ArrayBuffers dapat diubah ukurannya, tidak perlu melakukan pekerjaan manual untuk memperbarui tampilan IIUC. Secara teknis ini adalah perubahan yang melanggar mundur, karena hasil dari pertumbuhan memori tidak akan lagi menghasilkan ArrayBuffers yang berbeda di sisi JS, tetapi saya merasa itu tidak akan benar-benar merusak apa pun.

Terima kasih, sekarang saya mengerti! Ya, jika realokasi dilakukan secara otomatis, sehingga ArrayBuffers dan tampilan secara otomatis bertambah dengan memori wasm, maka itu akan menyelesaikan masalah di sini.

Mungkinkah ini juga terjadi dengan SharedArrayBuffers, jadi JS diperbarui di seluruh utas? Itu akan memecahkan masalah yang sangat besar juga (saat ini kita harus melakukan polling secara manual jika memori bertambah di JS).

Bagaimana kami berencana menangani pertumbuhan SAB di seluruh utas? Apakah kita mengharapkan SAB dan WebAssembly.memory diperbarui secara atomik bersama-sama? Mungkin sangat sulit untuk memastikan bahwa setiap utas JS melihat ukuran memori yang konsisten antara WASM dan JS. misalnya WASM a = memory.grow(0) * 64 * KB (dapatkan ukuran memori dalam byte) segera diikuti oleh SAB b = buffer.byteLength dapat menghasilkan a > b , yang mungkin menyebabkan bug aneh...

Apakah harapan bahwa pertumbuhan memori di WASM akan menangguhkan semua utas dan memperbarui buffernya secara atom? Jika demikian, itu bisa mahal tergantung seberapa sering orang ingin menumbuhkan memori. Mungkin ini tidak masalah dalam praktiknya.

Kami menentukan selama diskusi sebelumnya bahwa penyebaran pembaruan batas antara utas Wasm sebagai hasil dari memory.grow perlu mengikuti semantik yang santai. Saat ini, tidak ada jaminan dalam model memori bahwa pertumbuhan dalam satu utas akan terlihat oleh utas lain tanpa sinkronisasi eksplisit (baik melalui operasi atom, atau permintaan eksplisit memory.size , atau dengan melakukan pertumbuhan sendiri) .

Masih dijamin bahwa pembaruan panjang dari pertumbuhan akan menjadi "penghitung atom", sehingga utas lain tidak akan pernah melihat tampilan memori yang benar-benar tidak konsisten, mereka hanya tidak akan memiliki memori yang baru tumbuh dapat diakses dengan andal kecuali jika mereka menyinkronkan dengan utas yang tumbuh terbaru.

Saya berharap JavaScript dapat menggunakan semantik yang sama, selama realloc benar-benar hanya akan memungkinkan memori untuk tumbuh, dan tidak menyusut.

EDIT: mungkin, analog dengan memory.size , membaca buffer.byteLength dalam JavaScript dapat dihitung sebagai sinkronisasi eksplisit (dengan pertumbuhan terakhir)? Ini berpotensi membutuhkan penghalang dalam beberapa implementasi.

Dari obrolan singkat saya dengan @binji tentang masalah ini, memori bersama akan memiliki batasan realokasi yang berbeda dari memori yang tidak dibagikan, dan saya tidak benar-benar melihat cara lain selain mengikuti apa yang sudah dilakukan wasm.

Intinya, tampaknya sangat, sangat bermasalah untuk mengecilkan SAB di tempat. Tampaknya tidak terlalu buruk untuk mengecilkan AB di tempatnya?

mungkin, analog dengan memory.size, membaca buffer.byteLength dalam JavaScript dapat dihitung sebagai sinkronisasi eksplisit (dengan pertumbuhan terakhir)? Ini berpotensi membutuhkan penghalang dalam beberapa implementasi.

Sepertinya itu mungkin diinginkan. Bahkan jika itu menyebabkan beberapa sakit kepala kinerja ...

Sepertinya itu mungkin diinginkan. Bahkan jika itu menyebabkan beberapa sakit kepala kinerja ...

Tampaknya cukup masuk akal bagi saya untuk mengatakan bahwa banyak utas yang menyaksikan panjangnya disinkronkan.

Pembatasan lain termasuk bahwa agar SAB dapat diubah ukurannya sama sekali, konstruktor SharedArrayBuffer diperluas untuk menyertakan gagasan tentang ukuran maksimum, seperti WebAssembly.Memory .

Tampaknya cukup masuk akal bagi saya untuk mengatakan bahwa banyak utas yang menyaksikan panjangnya disinkronkan.

Saya belum memiliki banyak pendapat tentang banyak utas tetapi dalam satu utas itu mungkin harus disinkronkan. Jika tidak, Anda memiliki masalah di mana panjang Anda menyusut secara ajaib jika Anda meminta API yang berbeda karena nomor tersebut disimpan di alamat yang berbeda di VM.

Dalam satu utas semantik Anda dibatasi oleh urutan agen (atau urutan program seperti yang biasanya dikenal), yang lebih kuat daripada menyinkronkan acara seqcst.

Itu hanya benar jika semua slot internal yang berbeda dan apa pun yang digunakan WASM adalah sama. Dengan asumsi slot berbeda maka mereka akan secara efektif santai, bukan?

Saya pikir saya harus melihat contoh khusus yang Anda pikirkan. Saya tidak tahu apa artinya menyinkronkan akses dalam satu utas. Dalam pikiran saya seharusnya tidak ada masalah basi intra-utas karena alasan yang sama AB.byteLength tidak akan pernah menjadi utas intra-utas meskipun itu adalah akses yang tidak berurutan.

Saat ini, jika SAB didukung oleh memori Wasm yang dikembangkan, SAB tetap terpasang, tetapi dengan panjang asli yang sama (sehingga memori yang baru dikembangkan tidak dapat diakses, karena pemeriksaan batas JS). Jadi saya pikir @kmiller68 memikirkan berbagai hal melalui lensa ini, di mana "panjang" SAB adalah bidang yang berbeda pada objek yang tidak harus selalu sinkron dengan panjang memori yang mendasarinya (yang bisa saja tumbuh secara bersamaan di Wasm).

Jika saya membaca https://github.com/WebAssembly/design/issues/1296#issuecomment -644778006 dengan benar, @kripken melakukan rooting untuk perubahan ini, sehingga pertumbuhan SAB dalam satu utas (baik melalui Wasm memory.grow atau JS realloc ) berarti panjang semua SAB yang didukung oleh buffer yang sama akan diperbarui.

EDIT: komentar saya https://github.com/WebAssembly/design/issues/1296#issuecomment -644962043 ditulis dengan asumsi bahwa perubahan ini akan dicapai dengan membuat SAB bertindak persis seperti memori Wasm kelas satu, jadi pemeriksaan batas/panjang adalah tidak lagi melawan bidang "panjang" utas/objek-lokal yang berbeda, tetapi diimplementasikan dengan cara yang sama seperti Wasm.

@conrad-watt Ya, itu mungkin cara yang paling masuk akal untuk menentukannya. yaitu sesuatu seperti, jika objek JS SAB atau AB didukung oleh wasm, maka jangkau memori wasm namun menyimpan panjangnya dan kembalikan nilai itu (dikalikan ukuran halaman WASM dalam byte, saya kira). Dengan begitu, Anda tidak memiliki dua tempat independen yang menahan panjangnya.

Atau, kita bisa pergi ke arah lain juga. Di mana WASM mendapatkan panjangnya dari JS tetapi itu kemungkinan lebih sulit karena spesifikasi inti wasm tidak memiliki konsep nyata dari kait host saat ini, IIRC.

Aku mengerti. Maksud Anda "menyinkronkan" dalam arti panjang AB/SAB vs panjang penyimpanan cadangan tidak sinkron.

Saya setuju dengan asumsi @conrad-watt: bahwa kami bekerja di luar backing store. Itu satu-satunya hal yang masuk akal untuk dilakukan IMO, jika tidak, kita harus terus-menerus menyinkronkan panjang pembungkus per-SAB dengan toko dukungan tunggal, yang cukup aneh.

Menemukan kembali masalah yang muncul pertama kali seperti ini dibicarakan di Mozilla dengan asm.js: growable ArrayBuffer s sayangnya tidak cukup. Berbagai panjang tampilan TypedArray juga perlu diperbarui secara otomatis. Itu sangat disayangkan untuk implementasi dan untuk kompleksitas bahasa. Untuk implementasi, buffer harus melacak semua pandangan mereka buruk. Untuk bahasa, tidak semua tampilan TypedArray harus diperbarui secara otomatis. Misalnya, jika tampilan dibuat dengan offset dan panjang eksplisit, seharusnya tidak demikian.

Hmm...

FWIW, ide ini telah dibahas sebelumnya dalam edisi ini juga: https://github.com/WebAssembly/design/issues/1210

Dengan peristiwa sinkron, kode apa pun yang berpotensi mengalokasikan (dan karenanya berpotensi menumbuhkan memori) berpotensi menjalankan JS, yang pada dasarnya dapat melakukan apa saja, termasuk memasukkan kembali Wasm lagi. Sebagian besar kode yang memanggil malloc tidak disiapkan untuk ini. Saya pikir ini menambahkan senjata kaki baru, dan merasa agak mengkhawatirkan.

Dengan lem JS wasm-bindgen dihasilkan, kami memeriksa apakah tampilan telah dibatalkan oleh pertumbuhan memori, dan membuat ulang tampilan jika perlu. Pada dasarnya semua kode yang menggunakan tampilan melewati jalur kode tunggal yang menangani ini. Saya menduga pemeriksaan ini secara keseluruhan lebih sedikit daripada (atau setidaknya setara dengan) VM yang mempertahankan set yang tepat dari semua tampilan aktif yang perlu diperbarui ketika memori bertambah.

Apakah pendekatan ini tidak dapat dipertahankan untuk orang lain?

Dengan peristiwa sinkron, kode apa pun yang berpotensi mengalokasikan (dan karenanya berpotensi menumbuhkan memori) berpotensi menjalankan JS, yang pada dasarnya dapat melakukan apa saja, termasuk memasukkan kembali Wasm lagi. Sebagian besar kode yang memanggil malloc tidak disiapkan untuk ini. Saya pikir ini menambahkan senjata kaki baru, dan merasa agak mengkhawatirkan.

Ya, ini adalah perhatian saya yang sebenarnya untuk panggilan balik sinkron.

Ah, saya secara naif berpikir bahwa array yang diketik juga dapat diubah untuk menentukan panjangnya dalam hal buffer yang mendasarinya, tapi ya, setidaknya itu tidak mencakup kasus di mana panjangnya secara eksplisit diperbaiki.

Melihat kembali melalui diskusi yang ditautkan sebelumnya, ada saran di sini untuk hanya mengekspos akses gaya Wasm di JS melalui objek memori Wasm: https://Gist.github.com/kripken/949eab99b7bc34f67c12140814d2b595

Apakah ini akan menyelesaikan masalah?

Apakah ini akan menyelesaikan masalah?

Saya pikir itu akan untuk kasus penggunaan wasm tetapi menetapkan preseden yang tidak diinginkan. Ini akan mendorong perbedaan lebih lanjut antara wasm dan JS dalam mengakses buffer. Saya masih mencari cerita antarmuka wasm-JS yang lebih terintegrasi.

Dengan lem JS yang dihasilkan wasm-bindgen, kami memeriksa apakah tampilan telah dibatalkan oleh pertumbuhan memori, dan membuat ulang tampilan jika perlu. Pada dasarnya semua kode yang menggunakan tampilan melewati jalur kode tunggal yang menangani ini. Saya menduga pemeriksaan ini secara keseluruhan lebih sedikit daripada (atau setidaknya setara dengan) VM yang mempertahankan set yang tepat dari semua tampilan aktif yang perlu diperbarui ketika memori bertambah. Apakah pendekatan ini tidak dapat dipertahankan untuk orang lain?

Saya pikir itu kemungkinan, ya. Namun, saya pikir itu akan terasa lebih lambat dalam beberapa kasus: Anda pada dasarnya perlu polling di JS apakah memori berubah setiap kali Anda melewati batas wasm/js. Jika Anda memanggil pengambil kecil berulang kali itu bisa menyakitkan. Lebih cepat untuk menghindari polling dan mendapatkan pemberitahuan saat terjadi pertumbuhan, yang merupakan peristiwa langka.

Dengan peristiwa sinkron, kode apa pun yang berpotensi mengalokasikan (dan karenanya berpotensi menumbuhkan memori) berpotensi menjalankan JS, yang pada dasarnya dapat melakukan apa saja, termasuk memasukkan kembali Wasm lagi.

Saya pikir saya tidak mengerti kekhawatiran di sini. Ya, secara teori kode seperti itu bisa melakukan hal-hal yang mengerikan. Tetapi satu-satunya hal yang kita perlukan untuk dilakukan kode itu adalah membuat ulang tampilan dengan tepat, dan tidak lebih. Itu adalah operasi yang sangat sederhana - hanya beberapa baris JS, pada dasarnya beberapa viewX = new XArray(memory.buffer); yang aman dan tidak memiliki entri ulang.

Jika toolchain menyalahgunakan panggilan balik ini untuk melakukan hal-hal aneh, itu akan menjadi bug di sana - tetapi mekanisme apa pun dapat disalahgunakan?

Jika toolchain menyalahgunakan panggilan balik ini untuk melakukan hal-hal aneh, itu akan menjadi bug di sana - tetapi mekanisme apa pun dapat disalahgunakan?

Bagian dari perhatian saya adalah poin re-entrancy implisit secara umum adalah kotak pandora, bahkan jika kasus penggunaan yang dimaksudkan dipahami dengan baik dan sederhana. Ini baunya seperti penangan sinyal.

Ini baunya seperti penangan sinyal.

Tepat.

Oh, ya, saya setuju di sana. Ini benar-benar penangan sinyal, dan itu juga terasa agak aneh bagi saya. Saya khawatir tentang ini sebelum membuka masalah ini, pada kenyataannya, tetapi beberapa orang berpikir itu dapat diterima, lihat alasan mereka di sana.

@fitzgen

Saya menulis beberapa tolok ukur untuk memeriksa ukuran overhead polling. Itu bisa setinggi 50% dalam beberapa kasus yang saya lihat, tetapi itu pasti sangat bervariasi dan tergantung pada VM! Salah satu contohnya adalah

  for (var i = 0; i < 500 * 1000 * 1000;) {
    // poll to see if the heap grew, and if so, realloc the view
    if (module.HEAP8.length > 20000000) {
      module.HEAP8 = new Int8Array(module.buffer);
    }
    // wasm function that just returns the input
    result = result | module.copy(i++);
    // ..4 more unrolled copies..
    // ..it may also be good to read from HEAP8 here for realism..
    if (i == 1000) {
      // will force one realloc in the next polling check
      module.HEAP8 = new Int8Array(20000000 + 1);
    }
  }

Untuk melihat overhead paling banyak, unroll membantu menghindari loop overhead, dan setidaknya pada beberapa VM, 4 baris terakhir membuat perbedaan besar (mereka memaksa salah satu pemeriksaan polling untuk benar-benar benar untuk sekali, tetapi kemudian mereka kembali menjadi salah lagi).

50% mungkin merupakan jumlah overhead yang tidak mungkin, tetapi mudah untuk melihat 10% atau lebih. OTOH, mungkin tidak umum bagi orang untuk memanggil getter kecil melintasi batas js/wasm (tapi saya telah melihat banyak contoh orang yang melakukannya). Bagaimanapun, polling secara manual di JS memang menambahkan beberapa overhead yang dapat dihindari oleh pendekatan non-polling.

Saya pikir akan lebih baik untuk menghindari overhead itu, tetapi saya pasti setuju dengan Anda dan orang lain baik di sini maupun di masalah lain bahwa solusi yang mungkin juga memiliki kelemahan. Saya dapat mencoba meringkasnya:

  1. sbrk() (atau memori apa pun yang bertambah) dapat memanggil JS untuk memberi tahunya untuk memperbarui tampilan. Inilah yang dilakukan Emscripten ketika memancarkan wasm dan JS (sebagai lawan memancarkan wasm mandiri yang kompatibel dengan WASI tanpa JS).
  2. Khususnya untuk WASI, yang mengasumsikan tidak ada JS, kami dapat menambahkan API WASI untuk menambah memori atau untuk mendapatkan pemberitahuan saat memori bertambah, https://github.com/WebAssembly/WASI/issues/82 tetapi tampaknya tidak ada minat di sana, dan sebenarnya mereka menyarankan opsi berikutnya, 3.
  3. Seperti yang diusulkan dalam masalah ini, JS API dapat memberi kami panggilan balik. Ini masuk akal karena masalahnya ada di sisi JS sih , tapi ya, panggilan balik sinkronisasi terasa aneh, saya setuju dengan @syg
  4. Kami dapat melakukan polling secara manual di JS setiap kali kami melewati batas JS/wasm, yang menambahkan beberapa overhead dalam beberapa kasus, tetapi mungkin dalam banyak kasus baik-baik saja.
  5. Secara terpisah dari ini, ada overhead polling yang jauh lebih buruk dari pertumbuhan + utas, di mana kita perlu melakukan polling terus-menerus bahkan dalam loop tanpa panggilan ke wasm (karena utas lain dapat menumbuhkan memori kapan saja :scream: ). Saya yakin tidak ada solusi yang disebutkan sejauh ini yang dapat membantu, kecuali opsi VM yang secara otomatis menangani pertumbuhan tampilan untuk kami, secara transparan. Itu akan menyelesaikan banyak hal, tetapi sepertinya sisi VM mengalami masalah seperti yang disebutkan @syg ...

Saya sendiri tidak punya ide bagus untuk maju di sini, mengingat keberatan (sangat masuk akal). Kita mungkin berakhir dengan status quo, yaitu, rantai alat juga bisa

  • Selalu polling untuk pertumbuhan memori dalam lem JS, menerima overhead.
  • Miliki build terpisah untuk Web (dan Node.js) dan untuk lingkungan non-JS, untuk menghindari overhead polling di Web (seperti yang dilakukan emscripten sekarang). Ini lebih optimal, tetapi 2 build adalah fragmentasi yang mengganggu - saya harap kita bisa menghindari itu yang menjadi alasan saya membuka https://github.com/WebAssembly/WASI/issues/82 dan kemudian masalah ini. Tapi saya kira mungkin kita tidak bisa menghindarinya.

(Secara terpisah, di kedua opsi, pertumbuhan + pthreads membutuhkan polling yang tidak dapat dihindari.)

Penasaran apakah bisa

  1. Buat WebAssembly.Memory({initial: 1, maximum: 8000, shared: true})
  2. Tulis langsung (setelah mengekspor jika perlu) ke alokasi memori tunggal dalam skrip shell, misalnya bash stdout
  3. Baca memori tertulis itu dalam JavaScript

?

Singkatnya, JavaScript perlu tahu kapan memori wasm tumbuh, karena perlu memperbarui tampilan array yang diketik JS.

Mungkin terlihat seperti ini:

memory.addGrowCallback(() => {
  console.log("wasm memory grew!");
  updateAllJSViewsRightNow();
});

Setelah bereksperimen dengan pertumbuhan memori dinamis dalam acara AudioWorkletGlobalScope mungkin tidak berguna sama sekali. AudioWorkletProcessor.process() dapat dipanggil antara 344 dan 384 kali per detik. Memori dapat bertambah di antara panggilan ke process() mana tujuannya adalah pemrosesan audio "waktu nyata" dengan batasan pada proses lain dalam cakupan.

Jika sebuah event terjadi di antara panggilan process() haruskah event handler didahulukan daripada panggilan process() tertunda?

Saat acara sinkron, pengguna masih dapat mendefinisikan handler sebagai fungsi asinkron, atau memanggil queueMicrotask() di dalam handler; apakah operasi potensial tersebut akan memengaruhi panggilan process() ?

Dalam konteks pemrosesan audio pada saat pengendali peristiwa diaktifkan, waktu antara membaca informasi pertumbuhan memori itu dan peristiwa pemrosesan audio berikutnya dapat membuat pemberitahuan peristiwa dapat diperdebatkan, karena kode telah melanjutkan dengan operasi berikutnya.

console.log() sebelum dan sesudah grow() dipanggil dalam konteks pemberitahuan yang cukup di sini

          this.initial = (384 * 512) / 65536; // 1 second
          this.maximum = (384 * 512 * 60 * 60) / 65536; // 1 hour
          this.byteSize = this.maximum * 65536;
          this.memory = new WebAssembly.Memory({
            initial: this.initial,
            maximum: this.maximum,
            shared: true,
          });
            write: (value, controller) => {
              if (
                this.totalBytes + value.byteLength >
                  this.memory.buffer.byteLength &&
                this.totalBytes + value.buffer.byteLength < this.byteSize
              ) {
                console.log('before grow', this.memory.buffer.byteLength);
                this.memory.grow(1);
                console.log('after grow', this.memory.buffer.byteLength);
              }

untuk pertumbuhan memori dinamis yang dilakukan dalam konteks JavaScript untuk pemrosesan audio, di sini, untuk menghindari kondisi balapan.

Melacak offset tulis dan baca offset

                for (
                  let i = 0;
                  i < value.buffer.byteLength;
                  i++, this.readOffset++
                ) {
                  uint8_sab[this.readOffset] = value[i];
                }
       const uint8 = new Uint8Array(512);
          const uint8_sab = new Uint8Array(
            this.memory.buffer,
            this.writeOffset,
            512
          ); 

          try {
            for (let i = 0; i < 512; i++, this.writeOffset++) {
              if (this.writeOffset === this.byteSize) {
                break;
              }
              uint8[i] = uint8_sab[this.writeOffset];
            }

Untuk pertumbuhan memori dinamis dalam kode WASM, salinan dangkal dari instance memori itu hanya memperlihatkan jumlah halaman yang saat ini ditetapkan sebagai properti hanya-baca pada objek, bagi pengguna untuk mendapatkan ukuran halaman saat ini.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

badumt55 picture badumt55  ·  8Komentar

beriberikix picture beriberikix  ·  7Komentar

ghost picture ghost  ·  7Komentar

JimmyVV picture JimmyVV  ·  4Komentar

nikhedonia picture nikhedonia  ·  7Komentar