Contents

ConiのネイティブFloat32配列のためのハードコア・カオステスト

ブラウザで高性能なアプリケーションを構築する場合、JavaScriptの汎用的なNumber型では不十分なことがよくあります。連続した生のメモリ配列が必要になるのです。Coni WASMでは、最も数学的に集約的なアプリケーションのために、ネイティブなWebAssemblyのfloat32配列に大きく依存しています。

Float32は実際にConiのどこで使われているのか?

ネイティブのfloat32配列(make-float32-arrayf32-set!f32-get)は、Coniのパフォーマンス・レイヤーの絶対的なバックボーンです。これらは以下のような機能を駆動しています:

  1. WebGLジオメトリ: deep-focus-webglアプリでは、float32配列を使用して80,000頂点のブレイン・マトリックス(240,000個の浮点数!)をネイティブに数学的に形成し、その後js/float32-bufferを介して一撃でGPUに転送します。
  2. ゲームエンジンのパーティクルシステム: flappy-birdneon-boidsのようなゲームでは、並行するfloat32配列が数千のX/Y座標、速度、寿命を、ガベージコレクションの停止を発生させることなく追跡します。
  3. 生(Raw)のDSPオーディオ: 私たちのsound-nodesシンセサイザーは、複雑なインパルス応答とノイズ波形をWebAudioチャンネルにマッピングする前に、float32配列を使用してネイティブに計算します。

バグ:型強制とf64.reinterpret_i64

これらの配列は非常に重要であるため、そこでのバグは壊滅的です。最近、正確な整数(例えば150)をf32-set!に渡すと、なぜか0.0が返ってくるという問題を発見しました。

何が起きていたのでしょうか?以前のバージョンのWASMコンパイラでは、整数を浮動小数点数のセッターに渡すと、コンパイラがビットを解釈するために誤ってf64.reinterpret_i64を使用し、基礎となる値を完全に文字化けさせていたのです。

解決策:Float32カオステスト

私たちはコンパイラにパッチを当て、メモリへの挿入前に整数を正しく浮動小数点数に強制(コアーション)するようにしましたが、二度と退行(リグレッション)しないという保証が欲しかったのです。そこでカオステストの登場です。

新しいfloat32_coercion_test.coniスイートに、ハードコアなカオステストを構築しました。少数のハッピーパス(正常系)の数値をテストするだけでなく、巨大な配列を割り当て、決定論的な擬似ランダムループでそれを激しく叩きます。

(deftest test-f32-chaos
  "float32配列の境界と型強制のためのハードコアなカオステスト"
  (let [size 1000
        arr (make-float32-array size)]
    (loop [i 0]
      (if (< i size)
        (let [
          ;; 極端なエッジケースを混ぜて生成:
          val (if (= (mod i 4) 0) (- 0 i)                   ;; 負の整数
                (if (= (mod i 4) 1) (* i 10000)             ;; 大きな正の整数
                  (if (= (mod i 4) 2) (+ i 0.5)             ;; 正確なfloat32の分数
                    0)))                                    ;; ゼロ(整数)
        ]
          (f32-set! arr i val)
          (recur (+ i 1)))
        nil))
    ;; ... 検証ループ ...

極端な正の整数、負の境界値、純粋なゼロ、そして小数部を持つ浮動小数点数の残酷なミックスを意図的に1,000回f32-set!関数に投げつけることで、WASMのトラップを回避し、型強制が防弾(完璧)であることを保証します。

オーバーヘッドなしでGPUアクセラレーション・アプリケーションや複雑なステートマシンを構築したい場合、メモリプリミティブに対する絶対的な信頼が必要です。カオステストにより、Coniのfloat32配列は今や実戦で鍛え上げられたものとなりました!