Упаковываем UserTiming. Часть 2

Первая часть статьи: ссылка

Тест кейсы

Итак, как эти техники сжатия покажут себя в реальном мире?

Я посетил сайты из списка Alexa top 50 (по трафику), чтоб посмотреть, какие из них используют UserTiming (как оказалось, немногие). Я собрал все доступные данные и создал тест кейсы. Набралось 20 реальных и придуманных примеров использования UserTiming.

Давайте сначала сравним JSON.stringify() с лучшей из трех наших техник (для этого конкретного теста будет лучшей своя техника):

+------------------------------+
¦ Test    ¦ JSON ¦ UTC ¦ UTC % ¦
+---------+------+-----+-------¦
¦ 01.json ¦ 415  ¦ 66  ¦ 16%   ¦
+---------+------+-----+-------¦
¦ 02.json ¦ 196  ¦ 11  ¦ 6%    ¦
+---------+------+-----+-------¦
¦ 03.json ¦ 521  ¦ 18  ¦ 3%    ¦
+---------+------+-----+-------¦
¦ 04.json ¦ 217  ¦ 36  ¦ 17%   ¦
+---------+------+-----+-------¦
¦ 05.json ¦ 364  ¦ 66  ¦ 18%   ¦
+---------+------+-----+-------¦
¦ 06.json ¦ 334  ¦ 43  ¦ 13%   ¦
+---------+------+-----+-------¦
¦ 07.json ¦ 460  ¦ 43  ¦ 9%    ¦
+---------+------+-----+-------¦
¦ 08.json ¦ 91   ¦ 20  ¦ 22%   ¦
+---------+------+-----+-------¦
¦ 09.json ¦ 749  ¦ 63  ¦ 8%    ¦
+---------+------+-----+-------¦
¦ 10.json ¦ 103  ¦ 32  ¦ 31%   ¦
+---------+------+-----+-------¦
¦ 11.json ¦ 231  ¦ 20  ¦ 9%    ¦
+---------+------+-----+-------¦
¦ 12.json ¦ 232  ¦ 19  ¦ 8%    ¦
+---------+------+-----+-------¦
¦ 13.json ¦ 172  ¦ 34  ¦ 20%   ¦
+---------+------+-----+-------¦
¦ 14.json ¦ 658  ¦ 145 ¦ 22%   ¦
+---------+------+-----+-------¦
¦ 15.json ¦ 89   ¦ 48  ¦ 54%   ¦
+---------+------+-----+-------¦
¦ 16.json ¦ 415  ¦ 33  ¦ 8%    ¦
+---------+------+-----+-------¦
¦ 17.json ¦ 196  ¦ 18  ¦ 9%    ¦
+---------+------+-----+-------¦
¦ 18.json ¦ 196  ¦ 8   ¦ 4%    ¦
+---------+------+-----+-------¦
¦ 19.json ¦ 228  ¦ 50  ¦ 22%   ¦
+---------+------+-----+-------¦
¦ 20.json ¦ 651  ¦ 38  ¦ 6%    ¦
+---------+------+-----+-------¦
¦ Total   ¦ 6518 ¦ 811 ¦ 12%   ¦
+------------------------------+
 
Легенда:
* JSON      = JSON.stringify(UserTiming).length (байты)
* UTC       = Applying UserTimingCompression (байты)
* UTC %     = UTC байт / JSON  байт

Неплохо, не так ли? В среднем данные сжаты до 12%. Более того, результат является URI-совместимым.

UserTiming-Compression.js

usertiming-compression.js (и его дополнение usertiming-decompression.js) оформлены в виде open-source модулей JavaScript. Их можно скачать тут: ссылка

Предполагается, что эти скрипты предоставят простой способ упаковки данных от UserTiming. Они выбирают один из трех методов — тот, который в данном случае наиболее эффективен.

Если у вас есть детальное понимание используемых в проекте меток и измерений времени, закономерностей в именах и пр, то вероятно вы сможете создать еще более эффективную структуру для передачи данных. Вы также можете изменить скрипт так, что для сжатия всегда будет использоваться один и тот же метод (самый оптимальный).

Сравнение с Gzip / Deflate

Стоп. Почему мы изобретали велосипед, имея под рукой готовые алгоритмы сжатия? Почему не стали сжимать JSON с помощью gzip?

Одна из причин: в JavaScript нет нативной поддержки gzip. Но можно использовать open-source-ную библиотеку вроде pako

Сравним наши техники с результатами gzip:

+----------------------------------------------------+
¦ Test    ¦ JSON ¦ UTC ¦ UTC % ¦ JSON.gz ¦ JSON.gz % ¦
+---------+------+-----+-------+---------+-----------¦
¦ 01.json ¦ 415  ¦ 66  ¦ 16%   ¦ 114     ¦ 27%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 02.json ¦ 196  ¦ 11  ¦ 6%    ¦ 74      ¦ 38%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 03.json ¦ 521  ¦ 18  ¦ 3%    ¦ 79      ¦ 15%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 04.json ¦ 217  ¦ 36  ¦ 17%   ¦ 92      ¦ 42%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 05.json ¦ 364  ¦ 66  ¦ 18%   ¦ 102     ¦ 28%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 06.json ¦ 334  ¦ 43  ¦ 13%   ¦ 96      ¦ 29%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 07.json ¦ 460  ¦ 43  ¦ 9%    ¦ 158     ¦ 34%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 08.json ¦ 91   ¦ 20  ¦ 22%   ¦ 88      ¦ 97%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 09.json ¦ 749  ¦ 63  ¦ 8%    ¦ 195     ¦ 26%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 10.json ¦ 103  ¦ 32  ¦ 31%   ¦ 102     ¦ 99%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 11.json ¦ 231  ¦ 20  ¦ 9%    ¦ 120     ¦ 52%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 12.json ¦ 232  ¦ 19  ¦ 8%    ¦ 123     ¦ 53%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 13.json ¦ 172  ¦ 34  ¦ 20%   ¦ 112     ¦ 65%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 14.json ¦ 658  ¦ 145 ¦ 22%   ¦ 217     ¦ 33%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 15.json ¦ 89   ¦ 48  ¦ 54%   ¦ 91      ¦ 102%      ¦
+---------+------+-----+-------+---------+-----------¦
¦ 16.json ¦ 415  ¦ 33  ¦ 8%    ¦ 114     ¦ 27%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 17.json ¦ 196  ¦ 18  ¦ 9%    ¦ 81      ¦ 41%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 18.json ¦ 196  ¦ 8   ¦ 4%    ¦ 74      ¦ 38%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 19.json ¦ 228  ¦ 50  ¦ 22%   ¦ 103     ¦ 45%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ 20.json ¦ 651  ¦ 38  ¦ 6%    ¦ 115     ¦ 18%       ¦
+---------+------+-----+-------+---------+-----------¦
¦ Total   ¦ 6518 ¦ 811 ¦ 12%   ¦ 2250    ¦ 35%       ¦
+----------------------------------------------------+
 
Легенда:
* JSON      = JSON.stringify(UserTiming).length (байт)
* UTC       = Applying UserTimingCompression (байт)
* UTC %     = UTC байт / JSON  байт
* JSON.gz   = gzip(JSON.stringify(UserTiming)).length
* JSON.gz % = JSON.gz байт / JSON  байт

Как мы видим, gzip неплохо справляется с упаковкой JSON, уменьшая его размер до 35% от первоначального. Однако, наши техники еще эффективнее и дают всего 12% от первоначального размера.

Что если вместо применения gzip к JSON, мы запакуем минимизированную карту с моментами времени? Пример:

[{"duration":0,"entryType":"mark","name":"mark1","startTime":100},{"duration":0,"entryType":"mark","name":"mark1","startTime":150},{"duration":0,"entryType":"mark","name":"mark1","startTime":500}]

Что если мы сжали gzip-ом вывод с упакованными моментами времени?

{"mark1":"2s.1e.9q"}

Вот результаты:

+-----------------------------------+
¦ Test    ¦ UTC ¦ UTC.gz ¦ UTC.gz % ¦
+---------+-----+--------+----------¦
¦ 01.json ¦ 66  ¦ 62     ¦ 94%      ¦
+---------+-----+--------+----------¦
¦ 02.json ¦ 11  ¦ 24     ¦ 218%     ¦
+---------+-----+--------+----------¦
¦ 03.json ¦ 18  ¦ 28     ¦ 156%     ¦
+---------+-----+--------+----------¦
¦ 04.json ¦ 36  ¦ 46     ¦ 128%     ¦
+---------+-----+--------+----------¦
¦ 05.json ¦ 66  ¦ 58     ¦ 88%      ¦
+---------+-----+--------+----------¦
¦ 06.json ¦ 43  ¦ 43     ¦ 100%     ¦
+---------+-----+--------+----------¦
¦ 07.json ¦ 43  ¦ 60     ¦ 140%     ¦
+---------+-----+--------+----------¦
¦ 08.json ¦ 20  ¦ 33     ¦ 165%     ¦
+---------+-----+--------+----------¦
¦ 09.json ¦ 63  ¦ 76     ¦ 121%     ¦
+---------+-----+--------+----------¦
¦ 10.json ¦ 32  ¦ 45     ¦ 141%     ¦
+---------+-----+--------+----------¦
¦ 11.json ¦ 20  ¦ 37     ¦ 185%     ¦
+---------+-----+--------+----------¦
¦ 12.json ¦ 19  ¦ 35     ¦ 184%     ¦
+---------+-----+--------+----------¦
¦ 13.json ¦ 34  ¦ 40     ¦ 118%     ¦
+---------+-----+--------+----------¦
¦ 14.json ¦ 145 ¦ 112    ¦ 77%      ¦
+---------+-----+--------+----------¦
¦ 15.json ¦ 48  ¦ 45     ¦ 94%      ¦
+---------+-----+--------+----------¦
¦ 16.json ¦ 33  ¦ 50     ¦ 152%     ¦
+---------+-----+--------+----------¦
¦ 17.json ¦ 18  ¦ 37     ¦ 206%     ¦
+---------+-----+--------+----------¦
¦ 18.json ¦ 8   ¦ 23     ¦ 288%     ¦
+---------+-----+--------+----------¦
¦ 19.json ¦ 50  ¦ 53     ¦ 106%     ¦
+---------+-----+--------+----------¦
¦ 20.json ¦ 38  ¦ 51     ¦ 134%     ¦
+---------+-----+--------+----------¦
¦ Total   ¦ 811 ¦ 958    ¦ 118%     ¦
+-----------------------------------+
 
Легенда:
* UTC     = Applying full UserTimingCompression (байт)
* TS.gz   = gzip(UTC timestamp compression).length
* TS.gz % = TS.gz байт / UTC  байт

Даже если применить gzip к результатам timestamp сжатия и потом упаковать gzip-ом результат, наши техники оказываются более эффективными. Результат gzip в среднем на 18% больше. В некоторых тестах gzip работает эффективнее, очевидно, в них много повторяющихся строк.

Надо упомянуть, что использование gzip требует включения сторонней библиотеки вроде pako, а ее размер 26.3 Кбайт. Скрипт usertiming-compression.js намного меньше — 3.9 Кбайт.

Наконец, при использовании gzip сжатия не получится передать строку в строке запроса, т.к. алгоритм URI encode значительно увеличит ее размер из-за экранирования.

Сравнение с MessagePack

MessagePack — это еще один интересный метод упаковки. Девиз проекта: “It’s like JSON. But fast and small“. MessagePack работает с любыми JSON и является переносимым.

Какие результаты он покажет на наших тестах?

Первоначальный JSON он пережимает до 72%. Неплохо для библиотеки, которая нацелена вообще на любой JSON, но плоховато в сравнении с нашими техниками. Одна из причин в том, что MP сохраняет для каждого объекта повторяющиеся строки (startTime, duration ).

+--------------------------------------------------------+
¦         ¦ JSON ¦ UTC ¦ UTC % ¦ JSON.pack ¦ JSON.pack % ¦
+---------+------+-----+-------+-----------+-------------¦
¦ Total   ¦ 6518 ¦ 811 ¦ 12%   ¦ 4718      ¦ 72%         ¦
+--------------------------------------------------------+
 
Легенда:
* UTC         = Applying UserTimingCompression (bytes)
* UTC %       = UTC bytes / JSON bytes
* JSON.pack   = MsgPack(JSON.stringify(UserTiming)).length
* JSON.pack % = TS.pack bytes / UTC bytes

А что если пропустить через MessagePack упакованные timestamp? (например, {«mark1″:»2s.1e.9q», …})

+---------------------------------------+
¦ Test    ¦ UTC ¦ TS.pack  ¦ TS.pack %  ¦
+---------+-----+----------+------------¦
¦ 01.json ¦ 66  ¦ 73       ¦ 111%       ¦
+---------+-----+----------+------------¦
¦ 02.json ¦ 11  ¦ 12       ¦ 109%       ¦
+---------+-----+----------+------------¦
¦ 03.json ¦ 18  ¦ 19       ¦ 106%       ¦
+---------+-----+----------+------------¦
¦ 04.json ¦ 36  ¦ 43       ¦ 119%       ¦
+---------+-----+----------+------------¦
¦ 05.json ¦ 66  ¦ 76       ¦ 115%       ¦
+---------+-----+----------+------------¦
¦ 06.json ¦ 43  ¦ 44       ¦ 102%       ¦
+---------+-----+----------+------------¦
¦ 07.json ¦ 43  ¦ 43       ¦ 100%       ¦
+---------+-----+----------+------------¦
¦ 08.json ¦ 20  ¦ 21       ¦ 105%       ¦
+---------+-----+----------+------------¦
¦ 09.json ¦ 63  ¦ 63       ¦ 100%       ¦
+---------+-----+----------+------------¦
¦ 10.json ¦ 32  ¦ 33       ¦ 103%       ¦
+---------+-----+----------+------------¦
¦ 11.json ¦ 20  ¦ 21       ¦ 105%       ¦
+---------+-----+----------+------------¦
¦ 12.json ¦ 19  ¦ 20       ¦ 105%       ¦
+---------+-----+----------+------------¦
¦ 13.json ¦ 34  ¦ 33       ¦ 97%        ¦
+---------+-----+----------+------------¦
¦ 14.json ¦ 145 ¦ 171      ¦ 118%       ¦
+---------+-----+----------+------------¦
¦ 15.json ¦ 48  ¦ 31       ¦ 65%        ¦
+---------+-----+----------+------------¦
¦ 16.json ¦ 33  ¦ 40       ¦ 121%       ¦
+---------+-----+----------+------------¦
¦ 17.json ¦ 18  ¦ 21       ¦ 117%       ¦
+---------+-----+----------+------------¦
¦ 18.json ¦ 8   ¦ 11       ¦ 138%       ¦
+---------+-----+----------+------------¦
¦ 19.json ¦ 50  ¦ 52       ¦ 104%       ¦
+---------+-----+----------+------------¦
¦ 20.json ¦ 38  ¦ 40       ¦ 105%       ¦
+---------+-----+----------+------------¦
¦ Total   ¦ 811 ¦ 867      ¦ 107%       ¦
+---------------------------------------+
 
Легенда:
* UTC       = Applying full UserTimingCompression (байт)
* TS.pack   = MsgPack(UTC timestamp compression).length
* TS.pack % = TS.pack байт / UTC  байт

Для 20 тестов результат MessagePack на 7% больше результатов наших методик.
Размер популярных библиотек MessagePack тоже кусается: 29.2, 36.9 и 104 Кбайт.

Если у вас есть хорошее понимание закономерностей в ваших данных, то собственный алгоритм сжатия может быть более эффективным по сравнению с общепринятыми вроде gzip или MessagePack.

Выводы

Бывает интересно изучить нужную в работе структуру данных и сжать ее насколько это возможно.

UserTiming — это могучий и недооцененный API. Если вы его уже используете, то наверно уже решили задачу упаковки данных при передаче. Если нет, данная заметка вам поможет.

Английский оригинал: оригинал статьи

Документация и полезные ссылки:

UserTiming W3C Specification
PerformanceTimeline W3C Specification
UserTiming in Practice
Steve Souders’ UserTiming and Custom Metrics
ResourceTiming in Practice
Compressing ResourceTiming

You can leave a response, or trackback from your own site.

Leave a Reply