Skip to content

Instantly share code, notes, and snippets.

@uupaa
Last active August 29, 2015 14:21
Show Gist options
  • Select an option

  • Save uupaa/bb81ccf31e25868ce8f7 to your computer and use it in GitHub Desktop.

Select an option

Save uupaa/bb81ccf31e25868ce8f7 to your computer and use it in GitHub Desktop.
Optimize a variable using a reference to the TypedArray.

ES5 + TypedArray 環境において、Hash 生成関数のように、大量のデータをループで処理する場合は、TypedArray を使った変数の参照を作成することで、さらなる最適化を期待できる場合があります。

function Adler32(source, // @arg Uint8Array|String
                 hex,    // @arg Boolean = false
                 seed) { // @arg Integer = 1 - seed
                         // @ret UINT32|HexString - 0x00000000 or "00000000"
                         // @desc http://en.wikipedia.org/wiki/Adler-32
    seed = seed === undefined ? 1 : seed;

    var MOD_ADLER    = 65521;
    var MAGIC_NUMBER = 5550;

    var source_ = typeof source === "string" ? _toUint8Array(source) : source;
    var a =  seed         & 0xffff;
    var b = (seed >>> 16) & 0xffff;

    var len = source_.length;
    var i = 0;

    while (len > 0) {
        var tlen = len > MAGIC_NUMBER ? MAGIC_NUMBER : len;

        len -= tlen;

        do {
            a += source_[i++];
            b += a;
        } while (--tlen);

        a %= MOD_ADLER;
        b %= MOD_ADLER;
    }

    var u32 = ((b << 16) | a) >>> 0;

    return hex ? _toHexString(u32) : u32;
}

上記のコードの a, b, len, i, tlen を Uint32Array を使った参照にすることで、変数を UINT32 として JIT に認識させ、より最適化を促す事ができます。

function Adler32_2(source, // @arg Uint8Array|String
                 hex,    // @arg Boolean = false
                 seed) { // @arg Integer = 1 - seed
                         // @ret UINT32|HexString - 0x00000000 or "00000000"
                         // @desc http://en.wikipedia.org/wiki/Adler-32
    seed = seed === undefined ? 1 : seed;

    var source_ = typeof source === "string" ? _toUint8Array(source) : source;
    // optimization
    var u32 = new Uint32Array([
                        seed         & 0xffff,  // a
                       (seed >>> 16) & 0xffff,  // b
                        source_.length,         // len
                        0,                      // i
                        0,                      // tlen
                        65521,                  // MOD_ADLER
                        5550,                   // MAGIC_NUMBER
                        0                       // pad (reserved)
                    ]);

    var a            = u32[0];
    var b            = u32[1];
    var len          = u32[2];
    var i            = u32[3];
    var tlen         = u32[4];
    var MOD_ADLER    = u32[5];
    var MAGIC_NUMBER = u32[6];

    while (len > 0) {
        tlen = len > MAGIC_NUMBER ? MAGIC_NUMBER : len;
        len -= tlen;

        do {
            a += source_[i++];
            b += a;
        } while (--tlen);

        a %= MOD_ADLER;
        b %= MOD_ADLER;
    }

    var result = ((b << 16) | a) >>> 0; // to uint32

    return hex ? _toHexString(result) : result;
}

これらのベンチマークを取ると、以下のようになります。
Adler32の場合は 20〜25% ほど改善されたようです。

DataSize:  102400
Adler32: 2.059999998891726
Adler32(optim): 1.6369999793823808  // Adler32_2 のスコア
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment