2017-09-20 20 views
3

広い質問のお詫び!私はWASMを学んだし、Cでマンデルブロアルゴリズムを作成しました:WebAssemblyの機能がJavaScriptの機能よりも遅いのはなぜですか?

int iterateEquation(float x0, float y0, int maxiterations) { 
    float a = 0, b = 0, rx = 0, ry = 0; 
    int iterations = 0; 
    while (iterations < maxiterations && (rx * rx + ry * ry <= 4.0)) { 
    rx = a * a - b * b + x0; 
    ry = 2.0 * a * b + y0; 
    a = rx; 
    b = ry; 
    iterations++; 
    } 
    return iterations; 
} 

void mandelbrot(int *buf, float width, float height) { 
    for(float x = 0.0; x < width; x++) { 
    for(float y = 0.0; y < height; y++) { 
     // map to mandelbrot coordinates 
     float cx = (x - 150.0)/100.0; 
     float cy = (y - 75.0)/100.0; 
     int iterations = iterateEquation(cx, cy, 1000); 
     int loc = ((x + y * width) * 4); 
     // set the red and alpha components 
     *(buf + loc) = iterations > 100 ? 255 : 0; 
     *(buf + (loc+3)) = 255; 
    } 
    } 
} 

(明確にするために省略ファイル名入力/出力)を次のように私はWASMにコンパイルしてい

clang -emit-llvm -O3 --target=wasm32 ... 
llc -march=wasm32 -filetype=asm ... 
s2wasm --initial-memory 6553600 ... 
wat2wasm ... 

を私はロードしています

instance.exports.mandelbrot(0, 300, 150) 

出力がキャンバスにコピーされているため、正しく実行されていることを確認できます。私のコンピュータ上では、上記の機能は約120msかかる。

しかし、ここでは、JavaScriptのと同等です:

const iterateEquation = (x0, y0, maxiterations) => { 
    let a = 0, b = 0, rx = 0, ry = 0; 
    let iterations = 0; 
    while (iterations < maxiterations && (rx * rx + ry * ry <= 4)) { 
    rx = a * a - b * b + x0; 
    ry = 2 * a * b + y0; 
    a = rx; 
    b = ry; 
    iterations++; 
    } 
    return iterations; 
} 

const mandelbrot = (data) => { 
    for (var x = 0; x < 300; x++) { 
    for (var y = 0; y < 150; y++) { 
     const cx = (x - 150)/100; 
     const cy = (y - 75)/100; 
     const res = iterateEquation(cx, cy, 1000); 
     const idx = (x + y * 300) * 4; 
     data[idx] = res > 100 ? 255 : 0; 
     data[idx+3] = 255; 
    } 
    } 
} 

のみ〜実行する62msかかります。

今私はWebAssemblyが非常に新しく、ひどく最適化されていないことを知っています。しかし、私はそれがこれより速くなければならないと感じるのを助けることができません!

私は見逃したかもしれない何かを明白に見つけられますか?

また、私のCコードは '0'から始まるメモリに直接書き込みます - これが安全かどうか疑問に思っていますか?スタックはページ・リニア・メモリにどこに格納されていますか?私はそれを上書きする危険性がありますか?ここで

を説明するためのフィドルです:

https://wasdk.github.io/WasmFiddle/?jvoh5

を実行すると、それは(そしてWASM JavaScriptの)2つの等価な実装のタイミングを記録します

+0

jsfiddleのリンクのようなものを試してみることはできますか?どのブラウザでテストしていますか?あなたのスタックに関する質問はこちら(https://stackoverflow.com/a/43644387/3983557)、WebAssemblyでは0を使用しても安全ですが、WebAssemblyにコンパイルするとC++は不幸になることがあります。 –

+0

私はWasmFiddleでこれを動作させることに縛りつけています。私が管理するとすぐに質問を更新します。ブラウザはChrome 61です。スタック回答へのリンクをありがとう。 – ColinE

+0

@JFBastien - 私はフィドルを追加しました:-) – ColinE

答えて

2

一般

通常、あなたがに望むことができます最適化されたJSと比較して、重い計算で10%の向上が得られます。

  • wasm利益
  • /アウトメモリコピーexpences:それは構成されています。

注意、Uint8Arrayのコピーは、クロムでかなり遅いです(FFのok)。 rgbaデータを扱うときは、基礎となるバッファをUint32Arrayにリキャストする方が良いです。.set()を使用してください。

wasmのワード(rgba)でピクセルを読み書きしようとすると、読み取り/書き込みバイト(r、g、b、a)と同じ速度で動作します。私は違いが見つかりませんでした。

開発のためにnode.jsを使用する場合、私はJSベンチマークのために8.2.1に留まる価値があります。次のバージョンでは、v8をv6.0にアップグレードし、そのような数学に重大な速度回帰を導入しました。 8.2.1では、const,=>などの最新のES6機能を使用しないでください。代わりにES5を使用してください。 v8 v6.2の次のバージョンではこれらの問題が修正される予定です。clang -O3後いつか役立つかもしれ

サンプルコメント

  1. 使用wasm-opt -O3、。
  2. 固定メモリサイズをハードコードする代わりにs2wasm --import-memoryを使用してください。
  3. wasdkサイトのコードでは、グローバル変数を使用しないでください。それらが存在するとき、コンパイラは未知のブロックをメモリ開始時にグローバルに割り当て、間違ってそれらを上書きすることができます。
  4. おそらく、正しいコードは適切な場所からメモリコピーを追加する必要があり、それはベンチマークに含める必要があります。あなたのサンプルは完全ではなく、wasdkのIMHOコードは正しく動作しません。
  5. benchmark.jsを使用すると、より正確です。
  6. 要するに

:前にクリーンアップ物事にそれは価値がある、継続します。

https://github.com/nodeca/multimathソースを検索するか、実験で使用すると便利でしょう。私は小さなCPUを集中的に使用するために特別に作成し、適切なモジュールinit、メモリ管理、jsフォールバックなどの問題を単純化しました。これには、例とベンチマークとしての「アンシャープマスク」実装が含まれています。そこにコードを採用するのは難しいことではありません。

+0

多くの優れたヒントありがとう - 本当に有益 – ColinE

+1

正直言って、テキストのすべての詳細を説明するのは難しいです。マルチマスsrcを検査する方がずっと便利です。それらは小さく、戦闘テストされ、よくコメントされています。しかし、SOのルールは、単一のリンクで返信を禁止しています:) – Vitaly

関連する問題