HTML5 Canvas медленный на Chrome, но быстрый на FireFox - PullRequest
4 голосов
/ 01 ноября 2011

Я тестирую Chrome 15.0.874.106m на двухъядерной системе Pentium Windows 7 с частотой 2,8 ГГц с 4 ГБ ОЗУ (и сильно ускоренной видеокартой с большим объемом памяти) и тестирую FireFox 7.0.1 наОдноядерный 1,6 ГГц ноутбук Athalon с операционной системой Windows Vista и 2 ГБ оперативной памяти.Тем не менее, система FireFox превосходит систему Chrome примерно в 10 раз (по моим визуальным оценкам - в 10 раз больше FPS).

Большинство сообщений, которые я вижу, демонстрируют более низкую производительность при работе FireFox и Chrome, но здесь япохоже, что дело обстоит совершенно иначе.Любые идеи о том, что может быть ответственным за это?Файл HTML (один файл, без зависимостей), который я тестирую, составляет около 33 МБ (16 МБ сжатых) и доступен здесь .

Это продолжение до HTML5производительность холста для маленьких и больших файлов .

Я обнаружил chrome: // трассировка, которая помогла мне получить эти профильные результаты при запуске файла проблемы через профилировщик chrome:

Редактировать: Результаты удалены, я получил несколько новых, гораздо более интересных результатов, которые я опишу в новом разделе (см. Ниже). Конец редактирования

Я также обнаружил --show-fps-counter, который показывал прокрутку со скоростью около 3,5 FPS.Но мне все еще не ясно, в чем проблема.

Я также нашел переключатель --use-gl и попробовал рабочий стол, egl и osmesa.Производительность, казалось, была лучшей с osmesa, но только едва.Я не могу точно сказать, сколько именно, потому что переключатель show-fps-counter явно не работает в сочетании с use-gl = osmesa.osmesa по-прежнему работает не так хорошо, как FireFox в другой системе.

Редактирование продолжение: Благодаря случайности в обработке событий я каким-то образом попал в режим, в котором я мог прокручиватькарта, не удерживая кнопку мыши.К моему удивлению и изумлению, прокрутка шла очень плавно!С помощью нескольких дополнительных правок (а именно, удаления кода, который обрабатывает событие mouseup), я переключил код, чтобы мне больше не нужно было удерживать кнопку для прокрутки.И вот, я могу последовательно прокручивать очень плавно, пока я не удерживаю кнопку мыши.Поэтому я профилировал / проследил поведение, используя chrome: // трассировку с нажатой кнопкой мыши и без нее.Мои результаты приведены ниже.

Это плавная прокрутка без удержания кнопки мыши:

Selection summary:
 RenderWidget::OnHandleInputEvent                       :   1340.968ms     212 occurrences
 RenderWidget::InvalidationCallback                     :      7.867ms      27 occurrences
 RenderWidget::OnUpdateRectAck                          :      1.319ms     173 occurrences
 RenderWidget::OnSwapBuffersComplete                    :    129.018ms     173 occurrences
 V8EventListener::callListenerFunction                  :   1306.923ms     173 occurrences
 RenderWidget::DoDeferredUpdate                         :    120.033ms     204 occurrences
 EarlyOut_UpdateReplyPending                            :      0.004ms       4 occurrences
 EarlyOut_SwapStillPending                              :      0.181ms     165 occurrences
 CommandBufferHelper::WaitForToken                      :      8.358ms       3 occurrences
 WebViewImpl::layout                                    :       1.24ms     190 occurrences
 CCLayerTreeHost::updateLayers                          :     34.726ms     173 occurrences
 CCLayerTreeHost::commitTo                              :     24.426ms     173 occurrences
 CCLayerTreeHostImpl::drawLayers                        :     24.483ms     173 occurrences
 LayerRendererChromium::present                         :      8.434ms     173 occurrences
 EarlyOut_NoPendingUpdate                               :      0.018ms      17 occurrences
 CommandBufferProxy::FlushSync                          :      8.307ms       3 occurrences
 CCLayerTreeHost::updateLayers::calcDrawEtc             :     15.871ms     173 occurrences
 LayerRendererChromium::drawLayers                      :     23.441ms     173 occurrences
 RenderWidget::OnSwapBuffersPosted                      :      0.185ms     173 occurrences
 RendererGLContext::SwapBuffers                         :      4.431ms     173 occurrences
 LayerRendererChromium::drawLayersInternal::calcDrawEtc :     10.783ms     173 occurrences
 GpuCommandBufferStub::OnFlush                          :      7.581ms       3 occurrences
 GpuCommandBufferStub::OnAsyncFlush                     :   2825.339ms     352 occurrences
 GpuCommandBufferStub::OnEcho                           :       0.83ms     173 occurrences
 GpuScheduler:PutChanged                                :   2823.239ms     355 occurrences
 GLES2DecoderImpl::HandleTexImage2D                     :      5.779ms       6 occurrences
 GLES2DecoderImpl::HandleTexSubImage2D                  :      1.784ms       3 occurrences
 GLES2DecoderImpl::HandleSwapBuffers                    :   2387.561ms     173 occurrences
 GLContext::SwapBuffers                                 :   2384.623ms     173 occurrences
 ScheduledAction::execute                               :      2.453ms      16 occurrences
 v8.compile                                             :      1.037ms      14 occurrences
 v8.run                                                 :      3.142ms      14 occurrences
 EarlyOut_NotVisible                                    :      0.021ms      14 occurrences
 RenderWidgetHost::ForwardMouseEvent                    :      7.465ms     538 occurrences
 RenderWidgetHost::OnMsgInputEventAck                   :      5.218ms     212 occurrences
 RenderWidgetHost::OnMsgUpdateRect                      :      4.172ms     173 occurrences
 RenderWidgetHost::ForwardInputEvent                    :      4.551ms     212 occurrences
*Totals                                                 :  13535.811ms    5332 occurrences

Selection start                                         :    986.276ms
Selection extent                                        :   3320.488ms

А это прерывистая / медленная прокрутка при удерживании кнопки мыши:

Selection summary:
 RenderWidget::OnHandleInputEvent                       :   3852.921ms      61 occurrences
 RenderWidget::InvalidationCallback                     :      4.549ms      61 occurrences
 RenderWidget::OnUpdateRectAck                          :      1.235ms      40 occurrences
 RenderWidget::OnSwapBuffersComplete                    :     20.684ms      40 occurrences
 V8EventListener::callListenerFunction                  :    357.075ms      39 occurrences
 RenderWidget::DoDeferredUpdate                         :     25.208ms     132 occurrences
 EarlyOut_SwapStillPending                              :      0.004ms       6 occurrences
 EarlyOut_UpdateReplyPending                            :      0.032ms      32 occurrences
 CommandBufferHelper::WaitForToken                      :       8.09ms       3 occurrences
 WebViewImpl::layout                                    :      0.346ms      78 occurrences
 CCLayerTreeHost::updateLayers                          :      7.805ms      40 occurrences
 CCLayerTreeHost::commitTo                              :      4.727ms      40 occurrences
 CCLayerTreeHostImpl::drawLayers                        :      9.449ms      40 occurrences
 LayerRendererChromium::present                         :      1.122ms      40 occurrences
 EarlyOut_NoPendingUpdate                               :      0.038ms      38 occurrences
 CommandBufferProxy::FlushSync                          :       8.05ms       3 occurrences
 CCLayerTreeHost::updateLayers::calcDrawEtc             :      3.694ms      40 occurrences
 LayerRendererChromium::drawLayers                      :      9.177ms      40 occurrences
 RenderWidget::OnSwapBuffersPosted                      :      0.035ms      40 occurrences
 RendererGLContext::SwapBuffers                         :      0.684ms      40 occurrences
 LayerTextureUpdaterCanvas::paint                       :      0.483ms       1 occurrences
 LayerTextureSubImage::uploadWithMapTexSubImage         :       0.02ms       1 occurrences
 LayerRendererChromium::drawLayersInternal::calcDrawEtc :      2.329ms      40 occurrences
 GpuCommandBufferStub::OnFlush                          :      7.326ms       3 occurrences
 GpuCommandBufferStub::OnAsyncFlush                     :     226.88ms     121 occurrences
 GpuCommandBufferStub::OnEcho                           :      0.377ms      40 occurrences
 GpuScheduler:PutChanged                                :      230.2ms     124 occurrences
 GLES2DecoderImpl::HandleTexImage2D                     :      5.705ms       8 occurrences
 GLES2DecoderImpl::HandleTexSubImage2D                  :      2.057ms       4 occurrences
 GLES2DecoderImpl::HandleSwapBuffers                    :    113.857ms      40 occurrences
 GLContext::SwapBuffers                                 :    113.377ms      40 occurrences
 ScheduledAction::execute                               :     12.708ms      83 occurrences
 v8.compile                                             :      1.982ms      25 occurrences
 v8.run                                                 :      4.499ms      25 occurrences
 EarlyOut_NotVisible                                    :      0.022ms      25 occurrences
 RenderWidgetHost::ForwardMouseEvent                    :      4.671ms     640 occurrences
 RenderWidgetHost::OnMsgInputEventAck                   :      1.102ms      61 occurrences
 RenderWidgetHost::OnMsgUpdateRect                      :      0.894ms      40 occurrences
 RenderWidgetHost::ForwardInputEvent                    :      1.527ms      61 occurrences
*Totals                                                 :   5044.941ms    2235 occurrences

Selection start                                         :    956.043ms
Selection extent                                        :   6082.888ms

Из этого сравнения мне кажется, что реализация Chrome OnHandleInputEvent здесь постоянно сгорает.Что происходит?

Эффект виден, но не так ярко выражен даже в гораздо меньших / более простых проектах. Вот пример, который составляет всего около 700 КБ, что гораздо удобнее для тестирования, чем проект с 30+ МБ.Если щелкнуть и перетащить, вы увидите, что прокрутка слегка прерывистая, но если вы отпустите кнопку мыши, она продолжит прокрутку гораздо плавнее.

Ответы [ 2 ]

1 голос
/ 27 декабря 2011

Редактировать : Проблема не связана с вопросами, поднятыми в этом ответе. Я также отредактировал код, чтобы он стал немного более информативным.


BlueMonkMN : Из этого сравнения мне кажется, что реализация Chrome OnHandleInputEvent здесь все время сгорает. Что происходит?

Эффект виден, но не так ярко выражен даже в гораздо меньших / более простых проектах. Вот пример, который составляет всего около 700 КБ, что гораздо удобнее для тестирования, чем проект с 30+ МБ. Если щелкнуть и перетащить, вы увидите, что прокрутка слегка прерывистая, но если вы отпустите кнопку мыши, она продолжит прокрутку гораздо плавнее.

Глядя на ваш код (ниже), я вижу, что ваш код обработчика событий вызывает методы перерисовки (, поэтому большая часть времени процессора тратится на обработчики событий ). Все, что нужно сделать, это обновить состояние. Ваша перерисовка должна происходить в вашем Игровом цикле , что значительно упростит управление в целом.

Попробуйте исключить использование instanceof в MapLayer.prototype.draw и вместо этого найти другой способ получить кадры. instanceof является дорогостоящей операцией, и часто существует гораздо более элегантный подход, который не требует этого. Некоторые из этих объектов Tile / Map должны быть доступны через вызовы функций, а не индексы массивов, тогда вы можете получить больше свободы для типа возвращаемого объекта, фреймы могут быть обновлены, и весь этот метод MapLayer.prototype.draw может быть намного чище.

Кроме того, почему в цикле отображается каждый кадр, если typeof frames !== 'number'? При отладке он обычно рендерит только два кадра, но он выделяется.

Опять же, вы действительно должны выполнять рендеринг в игровом цикле, в обработчиках событий не должно быть ничего важного. А чтобы упростить задачу, попробуйте создать эталонный тест для одного кадра на jsperf.com , чтобы вы знали, сколько времени он потратил на эту функцию. И вы можете сузить узкое место, сравнив различные аспекты вашего кода.

// Section of our code
function beginDrag(e) {
   dragX = e.clientX;
   dragY = e.clientY;
   var srcEl = e.srcElement ? e.srcElement : e.target;
   srcEl.onmousemove = processDrag;
   return false;
}
// **Note** called on mouseout, not mouseup
function endDrag(e) {
   var srcEl = e.srcElement ? e.srcElement : e.target;
   srcEl.onmousemove = null;
}
function processDrag(e) {
   e = e || window.event;
   drag(e.clientX, e.clientY);
   return false;
}
function drag(newX, newY) {
   currentMap.scroll(currentMap.scrollX + newX - dragX, currentMap.scrollY + newY - dragY);
   dragX = newX;
   dragY = newY;
   // --- this should not be executed during an event handler, draw takes place in game loop.
   currentMap.draw(gameViewContext);
}
0 голосов
/ 28 марта 2012

Ошибка, о которой я сообщил (https://code.google.com/p/chromium/issues/detail?id=103148), с тех пор была помечена как «неспособная воспроизвести», если я правильно прочитал, поэтому я собираюсь предположить, что это ошибка в Chrome и былаисправлено (намеренно или нет) другими обновлениями. В любом случае, у меня больше нет проблемы с самим собой.

...