Почему доступ к typedArrays в Chrome на порядок медленнее, чем в Firefox?

Я написал базовую демонстрацию Game of Life, чтобы узнать немного о ES6 / typedArray. С полем 600×600 (на моем Macbook Air) я получаю ~ 57 кадров в секунду в Firefox Nightly (согласно about:config >layers.acceleration.draw-fps), что вполне приемлемо. Однако в Chrome у меня в среднем 3,5 кадра в секунду (измерено с помощью счетчика частоты кадров инструментов разработчика).

Путем некоторой отладки (см. коммиты в репозитории) я сузил медленный код до раздела, который создает несколько активных соседей для каждой ячейки. Вычисление всего поля занимает где-то около 18-19 мс в Firefox (что соответствует производительности около 60 кадров в секунду), но 175-185 мс в Chrome. Комментирование следующего кода, очевидно, ломает демонстрацию, но выравнивает производительность остальных кодов (т. е. медленная часть — это не рендеринг холста).

liveNeighbours = liveNeighbours + field[index - width - 1]
  + field[index - width]
  + field[index - width + 1]
  + field[index - 1]
  + field[index + 1]
  + field[index + width - 1]
  + field[index + width]
  + field[index + width + 1];

Чтобы вы могли увидеть проблему, я поместил код в CodePen: http://codepen.io/anon/pen/aNdzPP

Может ли кто-нибудь указать, что я делаю неправильно, или Chrome просто патологически медленный с этим JS? Если это так, я зарегистрирую ошибку, но я хотел убедиться, что не делаю глупостей.


person Robin Whittleton    schedule 06.03.2016    source источник
comment
Джейк (stackoverflow.com/users/123395/jaffa-the-cake) сообщил об ошибке в V8. для этого (bugs.chromium.org/p/v8/issues/detail ?id=4816)   -  person Robin Whittleton    schedule 07.03.2016


Ответы (1)


Проблема в доступе за границу. Например. для индекса == 0 вы обращаетесь к полю [-width-1], полю [-width] и так далее. V8 не оптимизирован для доступа за пределами границ, потому что они в любом случае обычно являются ошибками. То же самое и здесь: чтение за пределами возвращает «неопределенное», которое приводится к NaN при добавлении к другим числам, поэтому для любого поля на краю поля liveNeighbours всегда NaN, поэтому ни одно из сравнений никогда не будет возвращает true, поэтому fieldBuffer всегда будет оставаться нулевым по этому индексу. Простой способ решить проблему — обернуть доступ к массиву во вспомогательную функцию:

function get(array, index) {
  if (index < 0 || index >= array.length) return 0;
  return array[index];
}

liveNeighbours = get(field, index - width - 1) + get(field, index - width) + ...
person jmrk    schedule 08.03.2016
comment
Спасибо, это имеет смысл. Chrome по-прежнему меньше половины скорости Firefox на моем компьютере (23 кадра в секунду против 57 кадров в секунду), но, по крайней мере, он больше не непригоден для использования. - person Robin Whittleton; 12.03.2016