Инструменты 1С · отчёт о замерах и приёмке · v8unpack-accel 2.0.0 · 29.09.2026
Что и как измерено при выпуске 2.0.0. Две версии сравнивались на одних и тех же файлах, на одной машине, с чередованием прогонов. Результат распаковки сверялся побайтно с 1.0.0, со штатным v8unpack и с эталонной распаковкой УТ 11.5.
| Машина | Windows 11, 4 физических / 8 логических ядер, ОЗУ 35 ГиБ; Python 3.11.8, v8unpack 1.2.13, psutil 7.0.0 |
|---|---|
| Фон | рабочая машина; чужие процессы (редактор, сборки, проверки кода) занимали 60–100% CPU всё время замеров. Поэтому время по часам (wall) недостоверно, сравнение — по CPU |
| Метрика | CPU процесса распаковки: user + kernel (psutil), по этапам — через обёртки вокруг четырёх проходов extract. Все варианты серийные, один процесс, приоритет BelowNormal |
| Порядок | парный замер с чередованием: варианты по очереди, в нечётных раундах прямой порядок, в чётных обратный; каждый прогон — отдельный процесс; медиана по раундам |
| Результат | манифест каждого прогона: sha256 всех файлов и список каталогов; tree_sha — хеш отсортированного манифеста. Одинаковый tree_sha — побайтно одинаковое дерево |
| Антивирус | проверка файлов антивирусом в реальном времени на машине замеров была выключена; контрольный замер 28.09 шёл с включённой |
| Файлы | ComplexBitrix24_RU_UNF.cfe — расширение 3 МБ → 1483 файла, 598 каталогов, 30 946 055 байт; 1Cv8-ут-11.5.27.93-.cf — УТ 11.5, 883 МБ → 68 177 файлов; decode_stage_1 двух распаковок УНФ 3.0.14 для сверки разбора |
Критерии приёмки заданы заранее, до замеров: сверка разбора на 400 файлах без расхождений, побайтно то же дерево на полной распаковке, замер парами не меньше трёх раундов.
| Проверка | Объём | Итог |
|---|---|---|
Разбор 2.0.0 против исходного JsonContainerDecoder (v8unpack_fastparse_check.py) | 400 случайных файлов decode_stage_1 УНФ | 0 расхождений 394 разобрано, 6 исключений совпали |
| То же на тяжёлых формах | 3 формы 1,5–2 МБ | совпали |
Разбор через json.loads против цепочки 1.0.0 + прототипов | 11 130 файлов двух распаковок УНФ, 440 МБ | 0 расхождений запасной путь — 193 файла (1,7%) |
Запись JSON против json.dumps | 4060 JSON-файлов УТ 11.5, 216 МБ | 0 расхождений |
Контрольный .cfe: 1.0.0, 2.0.0 и 2.0.0 без каждого ускорения (bench_pair.py) | 35 прогонов, по 1483 файла | одно дерево совпадает с эталоном 28.09 |
УТ 11.5.27.93 целиком, 2.0.0 против эталонной распаковки 1.0.0 (compare_tree.py) | 68 177 файлов, 24 075 каталогов, 3,46 ГБ | побайтно равно кроме времени в записях dummy.zip, содержимое архива то же |
Патчи 2.0.0 поверх 1.0.0 (verify_release.py --replay) | 9 патчей, 12 файлов | побайтно равно tools/ |
dummy.zip — второй контейнер .cf, который v8unpack при каждой распаковке пересобирает через shutil.make_archive. В записях архива стоит время распаковки, поэтому его хеш разный при любой версии. Сверка сравнивает имена, CRC и байты записей — они совпали.
Расширение ComplexBitrix24_RU_UNF.cfe (3 МБ → 1483 файла), 5 раундов с чередованием, CPU процесса по этапам.
| Показатель (медиана 5 раундов) | 1.0.0 | 2.0.0 | Изменение |
|---|---|---|---|
| CPU прогона целиком, с | 20,98 | 6,62 | −68% |
| — user, с | 12,25 | 2,91 | −76% |
| — kernel, с | 8,92 | 3,31 | −63% |
| Распаковка бинарника | 0,49 | 0,47 | −4% |
| Вложенные контейнеры | 1,15 | 0,89 | −23% |
| Разбор объектов | 7,92 | 3,53 | −55% |
| Организатор | 10,36 | 0,63 | −94% |
| Время по часам, с (шум фона) | 37,5 | 11,9 | −68% |
| Пик памяти, МБ | 41 | 44 | +7% |
CPU всех раундов: 1.0.0 — 25,22, 20,06, 20,70, 20,98, 21,31 с; 2.0.0 — 6,77, 6,62, 5,98, 5,48, 7,50 с.
Дерево результата во всех 35 прогонах одно и то же (1483 файла, 598 каталогов, 30 946 055 байт, tree_sha 9539208d0b4b…) — в том числе с любым выключенным ускорением. Оно же было у штатного v8unpack и у 1.0.0 в контрольном замере 28.09.
Для сравнения — контрольный замер 28.09 (машина тоже загружена, защита в реальном времени включена): штатный v8unpack -E с параллельным пулом — медиана 33,46 с CPU всего дерева процессов и 218 МБ памяти, 1.0.0 — 23,51 с и 36 МБ (CPU −30%, память −84%).
Та же серия: 2.0.0, в которой переменной V8UNPACK_DISABLE выключено ровно одно ускорение. Насколько растёт CPU без него — столько оно и даёт на этом файле. Вклады не складываются: ускорения делят одни и те же проходы.
| Вариант | CPU, с | к 2.0.0 | Бинарник | Контейнеры | Разбор | Организатор |
|---|---|---|---|---|---|---|
| 2.0.0 со всеми | 6,62 | — | 0,47 | 0,89 | 3,53 | 0,63 |
без inplace | 9,41 | +42% | 0,50 | 0,93 | 3,50 | 3,28 |
без fastbrace | 8,70 | +31% | 0,53 | 1,09 | 5,67 | 0,69 |
без jsonwrite | 7,56 | +14% | 0,45 | 0,92 | 4,76 | 0,75 |
без io | 6,97 | +5% | 0,56 | 1,30 | 4,05 | 0,70 |
без accum | 6,64 | +0% | 0,39 | 0,86 | 3,56 | 0,70 |
| 1.0.0 | 20,98 | +217% | 0,49 | 1,15 | 7,92 | 10,36 |
На расширении 3 МБ мало длинных модулей, поэтому accum здесь почти не виден. Его эффект — на крупных конфигурациях: модуль 3,2 МБ раскладывался 30 с, теперь 0,08 с.
Полная распаковка 1Cv8-ут-11.5.27.93-.cf (883 МБ). 1.0.0 — прогон 28.09 по журналу ut_err.log. Парный повтор 1.0.0 не делался: версия копирует результат, и в пике на D: не хватило бы места рядом с тремя временными каталогами. Условия прогонов разные, поэтому это ориентир, а не контрольный опыт.
| Этап (по часам) | 1.0.0, 28.09 | 2.0.0, 29.09 | 2.0.0, CPU |
|---|---|---|---|
| Распаковка бинарника | 0:35 | 1:49 | 46 с |
| Распаковка вложенных контейнеров | 6:23 | 1:35 | 70 с |
| Разбор вложенных объектов | 10:27 | 4:31 | 205 с |
| Организатор («Организуем код») | 29:01 | 0:31 | 28 с |
| Всего | 46:30 | 8:25 | 365 с |
2.0.0: user 171 с, kernel 194 с; пик памяти 947 МБ. Код первого этапа в 2.0.0 не менялся. Он медленнее, вероятно, из-за фона: параллельно шла сверка тяжёлых форм исходным разборщиком (537 с CPU) и чужие процессы.
Главный выигрыш — организатор. В 1.0.0 он обходил 68 тыс. файлов decode_stage_3, копировал каждый и заново писал модули и формы. В 2.0.0 каталог переносится одним переименованием, модули и формы без областей include не перезаписываются.
CPU разбора одного файла (brace_file_read), лучший из трёх прогонов. Исходный разборщик — один прогон, v8unpack_fastparse_check.py.
| Форма УНФ | Размер | исходный v8unpack | 1.0.0 | 2.0.0 |
|---|---|---|---|---|
be7b6111 | 2018 КБ | 537,1 с | 0,531 с | 0,062 с |
c7d3fbee | 1954 КБ | 12,2 с | 0,656 с | 0,141 с |
303f4ede | 1495 КБ | 10,2 с | 0,219 с | 0,078 с |
Цифра «385 с → 0,34 с» из гайда 1.2.0 была временем по часам на другой нагрузке. Перемер по CPU: 537 с → 0,53 с (1.0.0) → 0,06 с (2.0.0), результат во всех трёх случаях тот же.
Разбор через json.loads на выборках decode_stage_1 (эталон — цепочка 1.0.0 с прототипами 2 и 3):
| Выборка | Файлов | CPU эталон | CPU 2.0.0 | Ускорение |
|---|---|---|---|---|
| УНФ, распаковка 1: 30 крупнейших + 3000 случайных | 2955, 79 МБ | 11,06 с | 3,91 с | 2,8× |
| УНФ, распаковка 2: 100 крупнейших + 8000 случайных | 7924, 361 МБ | 135,9 с | 24,6 с | 5,5× |
| — из выборки 1: формы с base64 | 450 | 6,00 с | 2,34 с | 2,6× |
| — из выборки 1: обычные скобочные файлы | 1757 | 1,62 с | 1,16 с | 1,4× |
| — из выборки 1: текстовые файлы | 628 | 2,45 с | 0,27 с | 9,2× |
Разбивка по видам снята до того, как экранирование стало условным. После этого весь разбор выборки 1 ускорился с 1,6× до 2,8×.
4060 JSON-файлов выгрузки УТ 11.5 (60 крупнейших + 4000 случайных, 216 МБ), лучший из трёх прогонов.
| Способ | Только строка | Строка + запись в файл |
|---|---|---|
json.dumps / json.dump(indent=2, ensure_ascii=False) — штатно | 11,36 с | 19,89 с |
свой сериализатор (v8unpack_jsonwrite.dumps) + одна запись | 4,22 с | 7,62 с |
Строки совпали со штатными во всех 4060 случаях. Прототип 28.09 (json.dumps одной записью) давал только −13%: основное время уходило не на запись, а на кодирование на Python.
Около половины CPU распаковки — время ядра Windows. В отчёте 28.09 его приписывали проверке антивирусом. Проверка 29.09 это не подтвердила:
Проверку файлов антивирус делает в своём процессе, а распаковка её только ждёт. Это видно по времени по часам и CPU антивируса, а не по CPU распаковки. Время ядра — сами открытия, записи и закрытия файлов, и 2.0.0 снижает его только тем, что делает этих операций меньше. Исключения антивируса для temp и результата полезны, когда защита в реальном времени включена: они снимают ожидание проверки файлов.
Сборка .cfe из распакованного дерева (v8unpack.build), 3 раунда: CPU 12,16 → 10,84 с (−11%) только от записи JSON и кэша каталогов; этап «Собираем код» −27%. Побайтно сверить собранный файл нельзя: v8unpack пишет в файл versions новые uuid4() при каждой сборке, размер .cfe от прогона к прогону плавает на десятки байт. Размер куска zlib (512 Б против 1 МБ) не меняет ни байты, ни CPU заметно.
Под профилировщиком cProfile сборка показывала 24% собственного времени в OrganizerCode.pack_file. Это артефакт: в Python 3.11 под профилировщиком строка не расширяется на месте, и склейка s += ... становится квадратичной. 80 тыс. склеек — 1,4 с без профилировщика и 80 с под ним. Без профилировщика тот же цикл на всех 287 модулях идёт 0,28 с.
rem сверка разбора с исходным v8unpack
python tools\v8unpack_fastparse_check.py "<TEMP>\tmpXXXX\decode_stage_1" 400
rem парный замер с чередованием: 1.0.0, 2.0.0 и 2.0.0 без каждого ускорения
python bench\scripts\bench_pair.py <файл.cfe> <рабочий_каталог> 5 summary.json ^
v1.0.0=releases\v8unpack-accel\v1.0.0\tools v2.0.0=tools ^
без_fastbrace=tools:fastbrace без_inplace=tools:inplace без_jsonwrite=tools:jsonwrite ^
без_io=tools:io без_accum=tools:accum
rem полная распаковка и сверка с эталонным деревом
python bench\scripts\run_variant.py tools <файл.cf> <out> <temp> result.json
python bench\scripts\compare_tree.py result.json <эталонный_каталог> compare.json
rem поставки: хеши, патчи поверх 1.0.0, рабочая копия
python releases\v8unpack-accel\verify_release.py --replay --working