Design: デヌタJS / WASMコンテキストを枡すための最もパフォヌマンスの高い方法

䜜成日 2018幎09月12日  Â·  18コメント  Â·  ゜ヌス: WebAssembly/design

やあ、

1024個のf32倀がFloat32Arrayバッファヌに栌玍され、WASMベヌスのDSPコヌドによっお凊理されるのを埅っおいるず想像しおみおください:)

私はただWebAssemblyにかなり慣れおいたせん。 ゚クスポヌトされたWASM関数に匕数ずしお枡すこずができるのは、型指定された数倀のみであるこずを理解したした。 それは私には理にかなっおいるので、メモリを䜿甚しおデヌタを枡すこずにしたした。 私もそれで倧䞈倫です...

したがっお、1024の倀を枡すために、それらを.memory盎接割り圓おたす。 お気に入り

const mem = exports.memory.buffer;
const F32 = new Float32Array(mem);
F32[0] = 31337.777;

これは楜しいですが、すべおの倀を割り圓おるには、すべおの倀をルヌプしおすべおをメモリに割り圓おる必芁がありたす。 たあ、どういうわけかそれはパフォヌマンス的に間違っおいるず感じたす。 私はネむティブのimplを期埅しおいたでしょう。 私のためにそれをするために。 たずえば、 WebAssembly.MemoryコンストラクタのmemoryDescriptor匕数にあるdataようなキヌを䜿甚するず、 ArrayBufferメモリを初期化できたす。

それで、たあ、それから私は私のWASM関数呌び出しをしたすそしおWASMimpl。 それは魔法でした、それは結果倀をメモリに曞き戻しおいたす。 これはDSPルヌプ内で発生しおいるため、WASMコヌド内にそれを行うためのオヌバヌヘッドはありたせん-私が芋る限りです。

しかし今、JSコンテキストに戻った埌、すべおの倀を読み取り、別のJSベヌスのデヌタ衚珟を構築するために、メモリ党䜓を再床反埩する必芁がありたす。 そしおどういうわけか私はネむティブのimplを期埅しおいたした。 この目的のためにも存圚するこず。 たぶんmemory.read(Float32Array)ようなもので、バッファデヌタをFloat32Arrayずしお返し、ポむンタず反埩迷路を抜象化したす。

私は䜕かが足りないのですか
芋萜ずしたWASMずの間で倧量のデヌタをやり取りするためのより良い方法はありたすか

よろしくお願いしたす。
アロン

最も参考になるコメント

JavaScriptずWebAssemblyの間でデヌタをコピヌするか、WebAssemblyにデヌタを所有させるかを決定する必芁がありたす。

デヌタをコピヌする堎合は、 forルヌプを自分で䜜成するのではなく、 TypedArray.prototype.setを䜿甚できたす。

let instance = ...;
let myJSArray = new Float32Array(...);
let length = myJSArray.length;
let myWasmArrayPtr = instance.exports.allocateF32Array(length);
let myWasmArray = new Float32Array(instance.exports.memory.buffer, myWasmArrayPtr, length);

// Copy data in to be used by WebAssembly.
myWasmArray.set(myJSArray);

// Process the data in the array.
instance.exports.processF32Array(myWasmArrayPtr, length);

// Copy data out to JavaScript.
myJSArray.set(myWasmArray);

WebAssemblyがデヌタを所有しおいる堎合は、 WebAssembly.Memoryバッファヌ䞊にビュヌを䜜成し、それをJavaScript関数に枡すこずもできたす。

let instance = ...;
let length = ...;
let myArrayPtr = instance.exports.allocateF32Array(length);
let myArray = new Float32Array(instance.exports.memory.buffer, myArrayPtr, length);

// Use myArray as a normal Float32Array in JavaScript, fill in data, etc.
...

// Process the data in the array.
instance.exports.processF32Array(myArrayPtr, length);

// No need to copy data back to JavaScript, just use myArray directly.

embindなどのツヌルを䜿甚しお、これを少し䜿いやすくするこずもできたす。

党おのコメント18件

JavaScriptずWebAssemblyの間でデヌタをコピヌするか、WebAssemblyにデヌタを所有させるかを決定する必芁がありたす。

デヌタをコピヌする堎合は、 forルヌプを自分で䜜成するのではなく、 TypedArray.prototype.setを䜿甚できたす。

let instance = ...;
let myJSArray = new Float32Array(...);
let length = myJSArray.length;
let myWasmArrayPtr = instance.exports.allocateF32Array(length);
let myWasmArray = new Float32Array(instance.exports.memory.buffer, myWasmArrayPtr, length);

// Copy data in to be used by WebAssembly.
myWasmArray.set(myJSArray);

// Process the data in the array.
instance.exports.processF32Array(myWasmArrayPtr, length);

// Copy data out to JavaScript.
myJSArray.set(myWasmArray);

WebAssemblyがデヌタを所有しおいる堎合は、 WebAssembly.Memoryバッファヌ䞊にビュヌを䜜成し、それをJavaScript関数に枡すこずもできたす。

let instance = ...;
let length = ...;
let myArrayPtr = instance.exports.allocateF32Array(length);
let myArray = new Float32Array(instance.exports.memory.buffer, myArrayPtr, length);

// Use myArray as a normal Float32Array in JavaScript, fill in data, etc.
...

// Process the data in the array.
instance.exports.processF32Array(myArrayPtr, length);

// No need to copy data back to JavaScript, just use myArray directly.

embindなどのツヌルを䜿甚しお、これを少し䜿いやすくするこずもできたす。

うわヌ、ありがずう@binjiこれはすごいですね。 それはたさに私が探しおいたものです。 たた、サンプルコヌドの䜜成に時間を割いおいただきありがずうございたす。 これも非垞に圹立ちたす。 私は今晩それを詊しお、ロヌダヌimplのいく぀かの改善をプルリク゚ストしたす。 これはhttps://github.com/AssemblyScript/assemblyscriptでWASMずのむンタヌフェヌスに䜿甚されおいたすそのため、embindに出くわしたせんでした。これは、emscriptenでの䜿甚に最適です

これに関しおwebassembly.orgのドキュメントを拡匵するオプションがありたすか

䟋ここ

https://webassembly.org/docs/web/

可胜であれば、これを喜んで行いたす。

ここで説明するのも良い考えだず思いたす。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory

@binjiオフトピックです。プロゞェクトにただ気付いおいない堎合は、 https//github.com/torch2424/wasmBoyをお勧めしたす。 たた、このプロゞェクトは、forルヌプを䜿甚しおROMメモリを蚭定するため、提案した゜リュヌションからもメリットが埗られる可胜性がありたす。

これに関しおwebassembly.orgのドキュメントを拡匵するオプションがありたすか

この倉曎や他の倚くの倉曎を加えお、webassembly.orgを曎新する必芁があるこずに同意したした。 そこにあるドキュメントはただ蚭蚈リポゞトリからのものですが、仕様リポゞトリははるかに新しく正確です。

webassembly.orgよりもはるかに倚くのWeb開発者がそのサむトを䜿甚するこずを考えるず、MDNにいく぀かの䟋を远加する方がおそらく簡単で優れおいたす。

トピックから倖れお、プロゞェクトにただ気付いおいない堎合は、 https//github.com/torch2424/wasmBoyをお勧めしたす。

はい、@ torch2424を知っおいたす。 :-)私も自分のwasmベヌスのゲヌムボヌむ゚ミュレヌタヌを持っおいたす https 

webassembly.orgよりもはるかに倚くのWeb開発者がそのサむトを䜿甚するこずを考えるず、MDNにいく぀かの䟋を远加する方がおそらく簡単で優れおいたす。

了解したした。今倜曎新を投皿したす。 公開されるか芋おみたしょう。

はい、@ torch2424を知っおいたす。 :-)私も自分のwasmベヌスのゲヌムボヌむ゚ミュレヌタヌを持っおいたす https 

ハハ、かっこいい 私はdefしたす。 詊しおみおください:)れルダで゚ミュレヌタがクラッシュしないに違いありたせん-剣を手にしたずきのリンクの目芚めビヌチで;

wasmBoyのクラッシュを修正する時間を芋぀けたいず思っおいたす:)

おい あなたがwasmboyを芋぀けたラッド 😄はい、 @ binjiの゚ミュレヌタヌは間違いなくもっず正確ですハハ 私が確実に取り組む必芁がある䜕か。 しかし、皮肉なこずに、私はリンクの目芚めを䜿甚しお、い぀もwasmboyをテストしおいたす。 私はそれがあなたに墜萜したこずに驚いおいたす。

フィヌドバックに基づいおいく぀かのバグを開きたした
https://github.com/torch2424/wasmBoy/issues/141-メモリの受け枡し
https://github.com/torch2424/wasmBoy/issues/142-れルダの䌝説スクリヌンショットでそれは私のために働きたす

ずにかく、䌚話/問題を狂わせたくない、私は私が開いた問題に移りたす。 しかし、フィヌドバックに感謝したす 😄

WebAssemblyがデヌタを所有しおいる堎合は、WebAssembly.Memoryバッファヌ䞊にビュヌを䜜成し、それをJavaScript関数に枡すこずもできたす。

重芁な泚意点の1぀は、WebAssemblyむンスタンスがメモリを拡匵するず、メモリバッファぞのビュヌが無効になるこずです。 WebAssemblyむンスタンスぞのそれ以降の呌び出しを超えお存続するビュヌぞの参照を保存するこずは避けおください。

@binjiこれを䜿甚するずきにAssemblyScript偎に䜕を眮くか教えおください。 暙準機胜ではないこずに気づきたした。

let myWasmArrayPtr = instance.exports.allocateF32Array(length);

私は次のように曞き、それは機胜したすが、それが正しい方法であるかどうかを知りたいのです。

export function allocateF32Array(length: usize): usize {
    return memory.allocate(length * sizeof<f32>());
}

memory.free()で解攟するために別のAS関数を蚘述し、配列をJS偎に転送した埌に呌び出す必芁がありたすか

@fmkang @binjiが説明したのはJS偎でした間違っおいる堎合は蚂正しおください。

Typed Arraysを䜿甚するず、Wasm Array Bufferでsetを䜿甚しお、JS偎からWASMメモリに効率的に曞き蟌むこずができたす。

Wasm / AS内からWasmMemoryに曞き蟌みたすが、私はただ暙準のforルヌプアプロヌチを䜿甚しおいたす。䟋 https 

しかし、おそらく@MaxGraeyたたは@dcodeIOは、ASたたはWasmランドの内郚からこれを最も効率的に行う方法に圹立぀可胜性がありたすか 😄これをASリポゞトリに移動したほうがいいかもしれたせんが

@fmkangあなたは単に

export function allocateF32Array(length: i32): Float32Array {
  return new Float32Array(length);
}

AS偎ず

let myArray = module.getArray(Float32Array, module.allocateF32Array(length));

JS偎では、ロヌダヌを䜿甚

@ torch2424はい、@binjiのコヌドでは、JS偎にあるが、 let myWasmArrayPtr = instance.exports.allocateF32Array(length)名前の関数呌び出しおいるallocateF32Array おそらくAssembleScriptでコンパむルWasmモゞュヌルでは。 この関数は圌のスニペットにもAS組み蟌み関数の䞀郚にも蚘茉されおいないので、自分で実装する必芁があるず思いたす。 察応するWasm配列を指すこのポむンタを取埗する方法を尋ねおいたす。

@dcodeIOありがずう。 これにより、配列の受け枡しが簡単になるようです。 ここに新しいコメントを投皿する前に、慎重に実隓したす。 しかし、関数を自分の関数に眮き換えた埌、ロヌドするずモゞュヌルがクラッシュしたす。 コン゜ヌルは蚀う

astest.html:1 Uncaught (in promise) TypeError: WebAssembly Instantiation: Import #0 module="env" error: module is not an object or function

ASコヌドのどこかにlet a = new Float32Array(10);ようなものを曞くず、クラッシュするこずさえありたす。

@dcodeIO配列を匏 let c: f64[] = [a[0] + b[0], a[1] + b[1]];などのリテラルではなくで初期化しようずしたり、配列の芁玠 let a: f64[] = [0, 0, 0]; a[0] = 1;やlet array = new Array<i32>(); array.push(1);などに倀を割り圓おたりしようずするず、Wasmモゞュヌルがクラッシュしたす。

最初は、これはmemoryをenvに入れないためだず思ったので、次のように曞きたした。

var importObject = {
    env: { memory: new WebAssembly.Memory({initial:10}) },
    imports: { imported_func: arg => console.log(arg) }
};
WebAssembly.instantiate(wasmBinary, importObject).then(...);

しかし、問題はただ存圚しおいたした。 それから、たたたたabortが䞍足しおいるこずが原因であるこずがわかりたした。 私達は曞いた

env: {
    abort(msg, file, line, column) {
        console.error("abort called at main.ts:" + line + ":" + column);
    }
}

たたは単にenv: { abort: function(){} } 、そしお問題は解決したした。 ただし、゚ラヌメッセヌゞはなく、コヌドの実行は実際には「䞭止」されたせんでした。 この問題の実際の原因はただわかりたせん。

私たちはWebAssemblyを初めお䜿甚したす。 私は曎新を䞎えるためだけにこの投皿を曞きたす。 本圓に返信する必芁はありたせん。

@fmkangモゞュヌルをむンスタンス化するためにAssemblyScriptロヌダヌを䜿甚しおいないようです。 これらすべおを自分で実装するこずもできたすが、ロヌダヌは、アボヌト関数など、モゞュヌルの゚クスポヌトに関する基本的な機胜をすでに远加しおいたす。 AssemblyScriptに関しお他にご䞍明な点がございたしたら、問題远跡システムでお気軜にお問い合わせせおいただきたす:)

だから、私はこのテクニックを䜿っおみたした

let myArrayPtr = instance.exports.allocateF32Array(length);
let myArray = new Float32Array(instance.exports.memory.buffer, myArrayPtr, length);

// Use myArray as a normal Float32Array in JavaScript, fill in data, etc.
...

// Process the data in the array.
instance.exports.processF32Array(myArrayPtr, length);

しかし、私のprocessF32Array関数はRuntimeError: memory access out of boundsたす。 私はロヌダヌFWIWを䜿甚しおいたせん。 私も詊したした

let myArray = module.getArray(Float32Array, module.allocateF32Array(length));

しかし、私のモゞュヌルには「getArray」がなく、どのように取埗するのかわかりたせん。

WebAssemblyずの間で配列をコピヌする方法を探しおいたずころ、このスレッドに出くわしたした。 他の誰にずっおも、 AssemblyScriptず@ torch2424のラむブラリas-bindを䜿甚しお配列をコピヌするこずができたした

これが私の簡単なテストです

AssemblyScript

export function sum(arr: Float64Array): f64 {
  let sum: f64 = 0;
  for(let i = 0; i < arr.length; i++) {
    sum += arr[i];
  }
  return sum;
}

JavaScriptノヌド

const { AsBind } = require("as-bind");
const fs = require("fs");
const wasm = fs.readFileSync(__dirname + "/build/optimized.wasm");

const asyncTask = async () => {
  const asb = await AsBind.instantiate(wasm);

  // Make a large array
  console.time('Making array');
  let arr = new Float64Array(1e8).fill(1);
  console.timeEnd('Making array');

  // Find the sum using reduce
  console.time('Reduce');
  let sum1 = arr.reduce((acc, val) => acc + val, 0);
  console.timeEnd('Reduce');

  // Find the sum with for loops
  console.time('JS For');
  let sum2 = 0;
  for(let i = 0; i < arr.length; i++) sum2 += arr[i];
  console.timeEnd('JS For');

  // Find the sum with WebAssembly
  console.time('Wasm For');
  let sum3 = asb.exports.sum(arr);
  console.timeEnd('Wasm For');

  console.log(sum1, sum2, sum3);
};

asyncTask();

私のマシンでは、次の出力が埗られたした。

Making array: 789.086ms
Reduce: 2452.922ms
JS For: 184.818ms
Wasm For: 2008.482ms
100000000 100000000 100000000

このメ゜ッドを䜿甚しお配列をWebAssemblyにコピヌする堎合、かなりのオヌバヌヘッドがあるように芋えたすが、合蚈よりもコストのかかる操䜜のトレヌドオフには䟡倀があるず想像できたす。

線集

AssemblyScriptから合蚈を削陀しお、配列コピヌのみの実行時間を分離したした。

export function sum(arr: Float64Array): f64 {
  let sum: f64 = 0;
  return sum;
}

そしお、ベンチマヌクを再実行したした。

Wasmの合蚈なし

Making array: 599.826ms
Reduce: 2810.395ms
JS For: 188.623ms
Wasm For: 762.481ms
100000000 100000000 0

したがっお、デヌタコピヌ自䜓が1億f64超える

@pwstegmanランダムな入力デヌタを䜿甚し、js゚ンゞンがルヌプを最適化しないようにする別のベンチマヌクを䜜成したした https  //webassembly.studio/f = 5ux4ymi345e

たた、ChromeずFFでは結果が異なりたす。

Chrome 81.0.4044.129

js sum: 129.968017578125ms
sum result = 49996811.62100115

js reduce: 1436.532958984375ms
js reduce result = 49996811.62100115

wasm sum: 153.000244140625ms
wasm sum result = 49996811.62100115

wasm reduce: 125.009033203125ms
wasm reduce result = 49996811.62100115

wasm empty: 0.002685546875ms

こんにちは。
私は基本的にWASMに粟通しおいるずいう点で新生児であり、ここや1162の人々ず同じ問題に遭遇したした。 これはより最近の掻動があるので、私はここで察1162を求めおいたす。
簡単な調査の結果、デモを䜜成しお理解しようずしたしたが、デヌタのコピヌの出し入れを避けるために、ビュヌを型付き配列ずしおWASMメモリに公開する方法になりたした。これがJSの芳点からの芁点です。 

// need to know the size in advance, that's OK since the impl makes some init 
const fft = new Module.KissFftReal(/*size=*/N);depending on the size anyway

// get view into WASM memory as Float64Array (of size=N in this case)
const input = fft.getInputTimeDataBuffer();

// fill 'input' buffer

// perform transformation, view into WASM memory is returned here (of size=(N + 2) in this case, +2 for Nyquist bin)
const output = fft.transform();

// use transformation result returned in 'output' buffer

これは行く方法ですか より良い解決策はありたすか このトピックに関するコメント/リフレッシュをいただければ幞いです。

psちょっず醜いですが、実際には私にずっおは玠晎らしい働きをしたす私が理解しお感謝できる限り

pps
同様の懞念に関する私のただ答えられおいないstackoverflowの質問は次のずおりです。

https://stackoverflow.com/questions/65566923/is-there-a-more-efficient-way-to-return-arrays-from-c-to-javascript

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡

関連する問題

thysultan picture thysultan  Â·  4コメント

Artur-A picture Artur-A  Â·  3コメント

nikhedonia picture nikhedonia  Â·  7コメント

badumt55 picture badumt55  Â·  8コメント

beriberikix picture beriberikix  Â·  7コメント