Чтобы посмотреть, как это работает, я написал очень короткий модуль asm.js вручную, который имитирует двумерное волновое уравнение с использованием 32-битной целочисленной математики и типизированных массивов (Int32Array). У меня есть три версии этого, все как можно более близкая:Почему asm.js ухудшает производительность?
- обыкновенные (т.е. разборчивый, хотя C-стиль) JavaScript
- То же, что 1, с asm.js аннотации добавили так, что она проходит валидатор, в соответствии с Firefox и другими инструментами
- То же, что и 2, кроме как без использования asm; директива в верхней части
Я оставил демонстрационную версию на http://jsfiddle.net/jtiscione/xj0x0qk3/, которая позволяет переключаться между модулями, чтобы увидеть эффекты использования каждого из них. Все три работают, но с разной скоростью. Это точка доступа (с asm.js аннотациями):
for (i = 0; ~~i < ~~h; i = (1 + i)|0) {
for (j = 0; ~~j < ~~w; j = (1 + j)|0) {
if (~~i == 0) {
index = (1 + index) | 0;
continue;
}
if (~~(i + 1) == ~~h) {
index = (1 + index) | 0;
continue;
}
if (~~j == 0) {
index = (1 + index) | 0;
continue;
}
if (~~(j + 1) == ~~w) {
index = (1 + index) | 0;
continue;
}
uCen = signedHeap [((u0_offset + index) << 2) >> 2] | 0;
uNorth = signedHeap[((u0_offset + index - w) << 2) >> 2] | 0;
uSouth = signedHeap[((u0_offset + index + w) << 2) >> 2] | 0;
uWest = signedHeap [((u0_offset + index - 1) << 2) >> 2] | 0;
uEast = signedHeap [((u0_offset + index + 1) << 2) >> 2] | 0;
uxx = (((uWest + uEast) >> 1) - uCen) | 0;
uyy = (((uNorth + uSouth) >> 1) - uCen) | 0;
vel = signedHeap[((vel_offset + index) << 2) >> 2] | 0;
vel = vel + (uxx >> 1) | 0;
vel = applyCap(vel) | 0;
vel = vel + (uyy >> 1) | 0;
vel = applyCap(vel) | 0;
force = signedHeap[((force_offset + index) << 2) >> 2] | 0;
signedHeap[((u1_offset + index) << 2) >> 2] = applyCap(((applyCap((uCen + vel) | 0) | 0) + force) | 0) | 0;
force = force - (force >> forceDampingBitShift) | 0;
signedHeap[((force_offset + index) << 2) >> 2] = force;
vel = vel - (vel >> velocityDampingBitShift) | 0;
signedHeap[((vel_offset + index) << 2) >> 2] = vel;
index = (index + 1)|0;
}
}
версия «обычный JavaScript» структурировано как указано выше, но без битовых операторов, asm.js требуется (например, «х | 0», «~ ~ x "," arr [(x < < 2) >> 2] »и т. д.)
Это результаты для всех трех модулей на моей машине с использованием Firefox (версия для разработчиков версии 41) и Chrome (версия 44), в миллисекундах на итерацию:
- FIREFOX (версия 41): 20 мс, 35 мс, 60 мс.
- ХРОМ (версия 44): 25 мс, 150 мс, 75 мс.
Так что обычный JavaScript выигрывает в обоих браузерах. Наличие аннотаций, требуемых asm.js, ухудшает производительность в 3 раза в обоих случаях. Кроме того, наличие «использования asm»; директива имеет очевидный эффект - она немного помогает Firefox, и Chrome на коленях!
Кажется странным, что просто добавление побитовых операторов должно вносить трехкратное ухудшение производительности, которое невозможно преодолеть, сообщив браузеру использовать asm.js. Кроме того, почему использование браузера для использования asm.js незначительно влияет на Firefox и полностью обходит Chrome?
Для начала я запустил тест [«Massive»] (https://kripken.github.io/Massive/) в Chrome 44 и FF 39 (Win XP, 32 бит), вот мои результаты для [Chrome ] (http://pastebin.com/fZQYzWKs) и [Firefox] (http://pastebin.com/brtZHecb) (копирование и сбрасывание в поле «введите данные, скопированные из другого запуска» на тестовой странице - да, это работает с фактическим HTML). За исключением одного пункта («poppler-cold-preparation»), Chrome был медленнее везде, в крайнем случае в 24,6 раза медленнее FF. Похоже, что Chrome в настоящее время просто не способен обрабатывать asm.js разумно. – Siguza
просто идея, вы «сравнили» последующие/повторные вызовы, так как asm будет использовать больше времени на этапах компиляции/выбора (я полагаю)? – birdspider
@birdspider Ты хочешь сказать, что несколько раз тестировал бенчмарк? Нет, я просто взял то, что было там ... текущий интерфейс, похоже, требует перезагрузки страницы для повторного запуска теста, что, скорее всего, требует компиляции/оптимизации кода снова. Но весь тест занял около 15 минут, чтобы закончить для меня, поэтому я думаю, что время компиляции не является существенным фактором. Если Chrome действительно забирает так много времени, чтобы скомпилировать его, это меня озадачивает, что код даже запускается * вообще *. – Siguza