О тестировании скорости или как не надо писать тесты


    Недавно увидел пост Тест производительности работы браузера с HTML5 Canvas. В результатах IE9 начал показывать сумашедшие циферки — 350+ fps.

    Это, конечно, хорошо, но почему-то браузеры, которые в других тестах javascript'а и canvas'a показывали не меньшую производительность, в этом тесте показывали в разы (а иногда и в десятки раз) меньший fps (при условии запуска на Windows-платформе, но об этом позже).

    Под катом покажу, почему тест показывает скорость совсем не HTML5-Canvas, а в самом конце будет скрин с 470 fps для FF4 без никакого фотошопа, для начала разберем что именно не так в этом тесте.


    Ну, для начала, давайте посмотрим что такое 200 fps. Это 200 прорисовок в секунду. Т.е. событие прорисовки должно происходить примерно каждые 5 мс. Если посмотреть в код теста, то там действительно есть строка:
    	setInterval(moveIt,1);
    

    Действительно, «moveIt» должен выполнятся каждую 1мс судя по спецификации (WhatWG, W3C). Но нет такого понятия, как минимальное время, через которое хендлер должен быть вызван.

    И тогда вступает в силу особенности реализации очереди событий в браузерах. Есть вот такой интересный тест, который должен показать минимальную точность setTimeout. У меня в Chrome было 4мс, а в FF4 четко на 10мс держалось. Возможно это из-за гранулированности работы с таймером для Windows систем (без использования high-performance counter-ов или мультимедия расширений) (в конце табличка с результатами).

    Так, как цель этого топика не обсуждение особенностей реализации setTimeout, а обсудить то, как же можно действительно измерить производительность той или иной операции. Как мы убедились, setTimeout не подходит (может быть только «пока не подходит»?) — он не дает возможность полностью загрузить браузер какой либо задачей.

    Совсем без таймаута тоже нельзя (т.е. просто в цикле проводить операцию), так как пользователь не увидит ничего — надо дать браузеру время отобразить результат операции.

    Возможное решение этой проблемы опубликовал Davin Baron: использовать window.postMessage (WhatWG, W3C, MSDN). Код, реализующий аналог setTimeout но, с минимальной (предпочтительно нулевой) задержкой (я модифицировал код Девида, добавив аналог setInterval-а (поправьте меня, если там нужен fn.apply):
    // Only add setZeroTimeout to the window object, and hide everything
        // else in a closure.
        (function() {
            var timeouts = [];
            var messageName = "zero-timeout-message";
     
            // Like setTimeout, but only takes a function argument.  There's
            // no time argument (always zero) and no arguments (you have to
            // use a closure).
            function setZeroTimeout(fn) {
                timeouts.push(fn);
                window.postMessage(messageName, "*");
            }
    	function intervalHelper(fn) {
    	    var h = function() {
    		fn();
    		setZeroTimeout(h);
    	    };
    	    return h;
    	}
    	function setZeroInterval(fn) {
    	    setZeroTimeout(intervalHelper(fn));
    	}
     
            function handleMessage(event) {
                if (event.source == window && event.data == messageName) {
                    event.stopPropagation();
                    if (timeouts.length> 0) {
                        var fn = timeouts.shift();
                        fn();
                    }
                }
            }
     
            window.addEventListener("message", handleMessage, true);
     
            // Add the one thing we want added to the window object.
            window.setZeroTimeout = setZeroTimeout;
    	window.setZeroInterval = setZeroInterval;
        })();
    

    Разница просто огромная (demo):
    100 iterations of setZeroTimeout took 19 milliseconds.
    100 iterations of setTimeout(0) took 393 milliseconds.
    


    С этим минимальным изменением имеем скриншот в шапке в случае Firefox4 и включенном Direct2D/DirectWrite (посмотреть можно в about:support)

    Вот типа «тест» HTML5-Canvas с примененным изменением.

    Пару слов о Google Chrome: под не-Windows платформами он часто показывает 200+ fps в этом тесте на даже не очень сильных машинах (при условии включения аппаратного ускорения вывода). На Windows он упирается в лимит VSync — 60 fps. Есть Issue об этом, за который можно проголосовать поставив звездочку.

    Ну и не забывайте смотреть about:flags — там есть GPU Accelerated Compositing/GPU Accelerated Canvas 2D.

    Вывод


    При написании теста/бенчмарка, если какой-то браузер показал необъяснимо большую разницу, не начинайте ошибочно думать о том, что этот браузер мега-супер оптимизирован. Вполне возможно просто тест тестирует не то, что кажется. К примеру, тест, который по идее должен показывать скорость HTML5-Canvas на самом деле показывал особенности реализации setTimeout и включении/выключении VSync.

    PPS. Чтоб показать совсем кривость этого теста, откройте на FF4 c моим патчем тест и табнитесь в другой таб (почти сразу), потом через секунд 15-20 вернитесь — у меня было около 400 fps и медленно падало вниз. Пруф

    В общем, перед тем как опубликовать тест — проверьте хорошо ли он тестирует, и тестирует ли он ваабще что-то толковое, а не просто рисует красивую картинку с циферками.
    Минимальные задержки setTimeout

    Собрав комментарии я составил такую табличу результатов теста:
    Opera 11 (Win) 2
    Chrome 10-11 (Win) 4
    Firefox (Win) 10
    Safari, OS X 10.6.6 10
    iPhone 10
    IE 8 15.6

    По мере поступления комментариев буду пополнять.

    По этому поводу стоит отметить, что по рекомендации HTML5 от WhatWG/W3C, setTimeout/setInterval должен работать так:
    The setInterval() method must run the following steps:
    5. If timeout is less than 10, then increase timeout to 10

    The setTimeout() method must run the following steps:
    5. If the currently running task is a task that was created by the setTimeout() method, and timeout is less than 4, then increase timeout to 4.

    Т.е. меньше чем 4 мс для setTimeout и 10 для setInterval не должно быть. Что показывает явную ошибку в любом броузере, где «оригинальный» тест дает больше 100 fps (так как в нем используется именно setInterval). 250 fps — максимум при использовании setTimeout.

    UPDATE:
    Сделал копию теста, в котором увеличил количество полигонов (в сфере до 72 сегментов и букв в 30 раз).
    Сейчас у меня результаты (Windows7 SP1 x64, nVidia gtx 260, Core Quad 2.4ghz):
    Chrome 12.0.703.0 canary build 33 fps
    IE 9.0.8112.16421 26 fps
    FireFox 4.0 58 fps

    Никаких «заточек» и т.д. не делал (кроме setZeroTimeout, который тоже увеличивает скорость оригинального «теста» в IE9). Той мега-огромной разницы как в оригинальном тесте я не вижу.

    В результате я скажу одно: криво написанный тест может "привратьприукрасить" результат в десятки, а то и сотни раз.
    Поделиться публикацией

    Похожие публикации

    Комментарии 67
      0
      >У меня в Chrome было 4мс, а в FF4 четко на 10мс держалось.
      Опера держит 2мс.
      >На Windows он упирается в лимит VSync — 60 fps. Есть Issue об этом, за который можно проголосовать поставив звездочку.
      Но зачем? Чтобы на изображении проступали вертикальные полосы несинхронизированной прорисовки?
        +2
        Там в иссю описано — чисто для бенчмарков добавить опцию в комманд-лайн. Типа мерятся у кого длинее fps :)
          +2
          Полосы, к стати, будут горизонтальные.
        +1
        И тогда вступает в силу особенности реализации очереди событий в броузерах. Есть вот такой интересный тест, который должен показать минимальную точность setTimeout. У меня в Chrome было 4мс, а в FF4 четко на 10мс держалось.

        opera 2мс выдаёт (точнее 2,3мс)
          0
          Safari, OS X 10.6.6: 10 мс.
          100 iterations of setZeroTimeout took 15 milliseconds.
          100 iterations of setTimeout(0) took 1087 milliseconds.
          Странные они, эти тесты.
            0
            ага, в сафари также, в Хроме на OS X держится на 5
            В сафаре на iPhone-е тоже 10мс
            +12
            Да, понятно было, что что-то нечисто, но не было времени разобрать. Чутьё подтверждалось тем, что автор того топика в MS работает :) (написано на его странице xaoccps.habrahabr.ru/ ).
            +16
            О, как всегда, MS в тестах сфейлили.
              +7
              У меня с этими изменениями в IE9 производительность поднялась со 150 до 400
                +1
                Что еще раз показывает бессмысленность этого теста.

                Тут был в комментах скриншот с 600 фпс. Мало?
                  0
                  Я еще затестил открытие контекстного меню поверх канваса. Динамика резко затормозилась, но ФПС-каунтер оказался очень инерционен. Счетчик просел всего на 20-30 ФПС, а видимое торможение намного больше.
                    0
                    Потому что каунтер считает средний ФПС за все время работы, а не за последние Н секунд. То есть 5 минут поработал — берется количество отрендеренных фреймов и делится на 300 секунд.
                      0
                      ИМХО Moving Average лучше
                –5
                Типичный пример того, как безграмотность меняет смысл текста.
                Как правильно хотел написать автор:
                «О, тестирование скорости! „
                или
                “О тестированиИ скорости ...»
                  +6
                  Типичный пример, как надо было писать в личку, потому что автор опечатку исправит, а ваш пост тут будет висеть тут ещё долго и безсмысленно.
                    +1
                    Нет уж, пусть все видят и сами учатся на чужих ошибках
                      +10
                      Чтоб ветка зря не пропадала, :) приставка без-/бес- пишется в зависимости от следующей за ней буквы: «без-» для гласных и звонких согласных, «бес-» для глухих согласных. Примеры: Безответственность, бездарность, беспечность.
                        +2
                        Ну тогда уж до кучи: «браузеры», а не «броузера».
                          0
                          Вы со своим оксфордским акцентом совсем английского не знаете. Правильно «бравзеры», мне одна бухгалтерша по секрету сказала…
                            –2
                            какие нафиг бравзеры? посмотрите хотя бы транскрипцию в словаре или послушайте в гугл транслейте, там четко «браузер»
                              0
                              Это вы мне или той бухгалтерше? ;)
                        • НЛО прилетело и опубликовало эту надпись здесь
                            –2
                          +1
                          Спасибо, поправил.

                          Действительно название я менял несколько раз не зная что выбрать, по этому в конце концов вышел средний вариант :)
                          0
                          А в 3.6 файрфоксе модифицированный тест работает с глюками, не смотря на точто оригинльный работал ок и показывал около 40 фпс)
                            +1
                            >Возможно это из-за гранулированности работы с таймером для Windows систем (без использования high-performance counter-ов или мультимедия расширений).

                            Все проще.

                            developer.mozilla.org/en/DOM/window.setInterval

                            As with setTimeout, there is a minimum delay enforced.

                            HTML 5 defines the minimum delay = 4 ms, starting with the second successive setTimeout().
                              +1
                              Я не нашел в спецификации W3C или WhatWG упоминания про 4мс (ссылки на setTimeout в посте есть), хотя в блог-постах действительно часто упоминается. Может раньше было?

                              Если найдете, скажите — я добавлю в текст.
                                +1
                                www.whatwg.org/specs/web-apps/current-work/multipage/timers.html

                                The setInterval() method must run the following steps:
                                5. If timeout is less than 10, then increase timeout to 10

                                The setTimeout() method must run the following steps:
                                5. If the currently running task is a task that was created by the setTimeout() method, and timeout is less than 4, then increase timeout to 4.
                                  +2
                                  Ха, забавно. Сейчас сделаю апдейт статьи.

                                  Выходит что те браузера, которые делают setTimeout < 2мс уже не следуют стандарту WhatWG.

                                  Но IE9 больше следует W3C-варианту HTML5, в котором вроде нет этого ограничения, что и объясняет огромные FPS на этом… гм, «тесте».
                            +1
                            У меня ваша версия показывает больший фпс (57 против 40), но при этом на вид не 57, а 20, все летит медленее и прерывистее, чем в оригинале, в котором все идет очень гладко и шустро.
                              +1
                              Именно это я и хотел написать — что этот тест на самом деле «меряет» вообще непонятно что.

                              Смысл поста — критика подобных «тестов», которые непонятно что показывает, да еще в ракурсе «IE 9: 300+ fps, все остальные — меньше 100», в то время в тесте столько проблем, что даже мой пост только чуть затронул.

                              Я уверен, что если еще глубже копнуть можно еще много найти откуда взялись эти 300+ fps.
                              +9
                              if (!IE) {
                              delay(100500);
                              }
                                0
                                с переключениями табок это вы лихо — понятно что фф перестает отрисовывать неактивную табку и фпс скачет до небес.

                                может попробовать setInterval(moveIt,10); и будет все честно?

                                  +1
                                  тогда Вы ограничите результат до 100 fps (которых в реальных проектах хватает с головой), и не дадите IE9 набрать свои сотни fps :)
                                    +1
                                    Создать сложную сцену, которую любой браузер гарантировано будет рендерить дольше 10мс?
                                      0
                                      кстати на моем макбук про хром показывает 30фпс. никак не «200+ под не-Windows платформами»
                                        0
                                        А включенны всякие там «GPU Accelerated Compositing/GPU Accelerated Canvas 2D»? У меня на Ubuntu без никаких трюков и на сравнительно среднем cpu/gpu — 250
                                          0
                                          насколько я понял в хроме 10.0.648.134 этого нет. вкладка about:labs — пустая.
                                            0
                                            В последних версиях Chrome about:labs переехало в about:flags
                                              0
                                              Спасибо за подсказку.
                                              Включил. Странно но теже 32фпс.
                                              0
                                              Буквально последний абзац перед «Вывод» — там про about:flags:)
                                      0
                                      На последней(сегодняшней) dev версии Chrome под Win7 x64, Ваш исправленный вариант в купе с описанной системой tab-анья даёт 600+ фпс. Пруф имг.
                                        0
                                        Если я не ошибаюсь, с «табанием» можно и до 1000+ довести :) но я не проверял — надо оставить на пол часика-часик покрутиться :)
                                          0
                                          Не надо. Главное — сразу при открытии вкладки переключиться в соседний таб.
                                        0
                                        У меня в FF 3.6 под windows 7 модифицированная версия работает чуть медленнее(15-20 фпс против 20-25) и визуально хуже (дерганней) чем оригинал
                                          0
                                          Ну это неудивительно. Данный фикс имеет смысл только если время выполнения меньше, чем минимальная задержка таймера.
                                          +1
                                          IE9 — показывает 3ms
                                            –2
                                              0
                                              win7, ff 3.6.x i7-950, hd4870 2gb.
                                              100 iterations of setZeroTimeout took 8 milliseconds.
                                              100 iterations of setTimeout(0) took 993 milliseconds.

                                              Оригинальный тест — 30-34 фпс.
                                              Модифицированный — 40 фпс. (табался, тоже самое)

                                              setTimeout — 9.5
                                                0
                                                лохе. 4890 2gb.
                                                0
                                                Веб-кит под Андроид (2.3.3) — 11.2
                                                  0
                                                  Веб-кит под iPhone4 — около 12.
                                                    0
                                                    оО на довольно сильном камне (phenom II x2 550) в хроме 10 под вин с включенным ускорением канваса — всего 46фпс в обычной версии и 21 в версии с увеличенным числом полигонов оО
                                                    почему так мало?
                                                      0
                                                      FF4, 180FPS, явные лаги прорисовки.
                                                      Люди — знайте — в ФФ нельзя использовать таймауты которые быстрее функции переносимой.
                                                      Получается просто — вы проапдейтили канвас, ФФ думает что можно бы и страницу обновить, а вы его опять начинайте апдейтить.
                                                      В итоге Браузер просто не обновляет картинку, генеря при этом жуткий ФПС( так как он попросту начинает пропускать фреймы)
                                                      Я всем сильно рекомендую вызывать аниматор «через-тик», тоесть гарантировать между двумя таймаутами один «пустой-таймауат-гарант» отрисовки( либо в одном таймауте поднимаете таймаут на отрисовку, либо просто только по четным фреймам работаете)
                                                      И не надо гнаться за ФПС, в реальность 25 кадра лично я не верю :)
                                                        0
                                                        >не надо гнаться за ФПС
                                                        надо, еще как.
                                                        хотя-бы довести до 60-70 + синхронизировать с перерисовкой монитора.
                                                        вы когда-нибудь пробовали играть в какую-нибудь 3д игрушку, одновременно записывая фрапсом например? он искуственно снижает FPS до 30 — ощущения не из приятных. больше частоты синхронизации — при резких (и даже не очень) движениях игрока (поворотах) в разные стороны будут ощутимо заметны вертикальные полосы, разделяющий 2 кадра. т.е. какбы старый кадр на месте, поверх начал отрисовываться новый и дошел только до трети монитора. поэтому идеал — синхронизация с частотой монитора.
                                                          0
                                                          хотя-бы довести до 60-70 + синхронизировать с перерисовкой монитора.

                                                          Может именно по этому у хромого не хотят отключать vsync при использовании gpu? :)
                                                            0
                                                            В браузерах это всё не имеет смысла, т.к. они обновляют картинку когда захотят.
                                                              0
                                                              ну, ГУГЛ, снова придумает какой-нибудь новый стандарт по этому поводу.
                                                          +2
                                                          Если бы еще лет 7 назад мне бы кто-нибудь сказал что люди будут меняться fps-ами в браузерах, я бы не поверил…
                                                            0
                                                            Этот комментарий надо было бы поставить как эпиграф к этому посту!
                                                            0
                                                            прошла тысяча лет, каждый линуксоид знает, что «glxgears — не бенчмарк», но каждый день находится как минимум один человек, создающий на форуме писькомерку показаний glxgears. Это неистребимо, желание помериться разницами простых мужицких timeout'ов гораздо сильнее, чем мудрствовать о сути графикики.

                                                            Для пользователей windows, glxgears — это такая прога, рисующая на экране цветные шестеренки, и печатающая fps'ы с которыми они рисуются на экране.
                                                            ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:Glxgears.gif
                                                              0
                                                              MacBook 5.2 2 Ггц 2Гб
                                                              MacOS 10.6.6
                                                              Первый тест: 5
                                                              Второй: 15fps
                                                                0
                                                                В первой табличке результат в попугаях?
                                                                  0
                                                                  Первая табличка — минимальная задержка, которую обеспечивает броузер при setTimeout(x,1) в мс. По стандарту должно быть 4мс (есть ссылочки на стандарт)

                                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                Самое читаемое