取消边界检查时,V8 TypedArray的性能出现悬崖吗?

时间:2018-10-14 11:23:41

标签: performance v8

仅出于背景考虑,我正在用JavaScript编写bzip2解压缩库,但我不明白是什么导致游程长度解码步骤中的性能下降。 最终,它需要用恒定值填充数组的一部分:

function fill(buf, from, to, val) {
    for (var i = from; i < to; ++i)
        buf[i] = val;
}

仅使用单一类型的数组调用该函数,而其他参数始终在范围之内。仅此代码就相当于C代码,每秒执行数亿个数组访问,一切都很好。正如预期的那样,涡轮风扇会注入边界检查以确保索引保持在有效范围内。

但是当我将这些绑定检查明确添加到函数中时:

function fill(buf, from, to, val) {
    if (from < 0 || to < from || buf.length < to)
        throw new Error();
    for (var i = from; i < to; ++i)
        buf[i] = val;
}

突然使用通用KEYED_STORE_IC完成数组写入,从而将执行速度降低了 50

这是我的测试设置(100万次通话,约40亿次写入):

var b = new Int32Array(10000);
for (var j = 0; j < 999999; ++j) {
    fill(b, j & 0xFFF, 6000 + (j % 0xFF), j);
}

该库在浏览器和节点8.x / 10.x上应表现良好。该测试是使用v8.10(V8版本6.2.414.50)完成的。

1 个答案:

答案 0 :(得分:2)

V8开发人员在这里。您如何衡量这种差异?我无法复制它。

我已将您的代码复制粘贴到squarefree.com/shell/shell.html中,对其中一个函数进行模运算重命名:

function fill(buf, from, to, val) {
    for (var i = from; i < to; ++i)
        buf[i] = val;
}
function fill2(buf, from, to, val) {
    if (from < 0 || to < from || buf.length < to)
        throw new Error();
    for (var i = from; i < to; ++i)
        buf[i] = val;
}
var b = new Int32Array(10000);
var t1 = Date.now();
for (var j = 0; j < 999999; ++j) {
    fill(b, j & 0xFFF, 6000 + (j % 0xFF), j);
}
var t2 = Date.now();
for (var j = 0; j < 999999; ++j) {
    fill2(b, j & 0xFFF, 6000 + (j % 0xFF), j);
}
var t3 = Date.now();

执行该操作(当前的Chrome Canary)后,我得到:

> t2 - t1
< 5820
> t3 - t2
< 5887

因此,手动边界检查增加了非常小的性能损失,这似乎是合理的。

我的猜测是,您暂时在索引计算中遇到了一个错误,并最终无法进行越界访问。那可以解释为什么使用通用IC,以及为什么观察到严重的速度下降。