Инструменты 1С · отчёт о замерах и приёмке · v8unpack-accel 2.0.0 · 29.09.2026

Замеры и приёмка v8unpack-accel 2.0.0

Что и как измерено при выпуске 2.0.0. Две версии сравнивались на одних и тех же файлах, на одной машине, с чередованием прогонов. Результат распаковки сверялся побайтно с 1.0.0, со штатным v8unpack и с эталонной распаковкой УТ 11.5.

Статья о том, как устроены ускорения, — «Ускорение распаковки 1С через v8unpack». Скрипты замеров — bench/scripts/, сырые результаты — releases/v8unpack-accel/v2.0.0/evidence/.

CPU распаковки .cfe 3 МБ
−68%
2.0.0 против 1.0.0: 20,98 → 6,62 с, медиана 5 раундов
УТ 11.5, 883 МБ, целиком
8 мин 25 с
было 46,5 мин (1.0.0); 68 177 файлов побайтно те же
Тяжёлая форма 2 МБ, разбор
537 с → 0,06 с
CPU, исходный v8unpack против 2.0.0
Результат распаковки
тот же
все 35 прогонов .cfe — одно дерево

1. Методика

Машина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 для сверки разбора

2. Приёмка: результат тот же

Критерии приёмки заданы заранее, до замеров: сверка разбора на 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.dumps4060 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 и байты записей — они совпали.

3. Контрольный .cfe: 1.0.0 против 2.0.0

Расширение ComplexBitrix24_RU_UNF.cfe (3 МБ → 1483 файла), 5 раундов с чередованием, CPU процесса по этапам.

Показатель (медиана 5 раундов)1.0.02.0.0Изменение
CPU прогона целиком, с20,986,62−68%
— user, с12,252,91−76%
— kernel, с8,923,31−63%
Распаковка бинарника0,490,47−4%
Вложенные контейнеры1,150,89−23%
Разбор объектов7,923,53−55%
Организатор10,360,63−94%
Время по часам, с (шум фона)37,511,9−68%
Пик памяти, МБ4144+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%).

4. Вклад каждого ускорения

Та же серия: 2.0.0, в которой переменной V8UNPACK_DISABLE выключено ровно одно ускорение. Насколько растёт CPU без него — столько оно и даёт на этом файле. Вклады не складываются: ускорения делят одни и те же проходы.

ВариантCPU, ск 2.0.0БинарникКонтейнерыРазборОрганизатор
2.0.0 со всеми6,62—0,470,893,530,63
без inplace9,41+42%0,500,933,503,28
без fastbrace8,70+31%0,531,095,670,69
без jsonwrite7,56+14%0,450,924,760,75
без io6,97+5%0,561,304,050,70
без accum6,64+0%0,390,863,560,70
1.0.020,98+217%0,491,157,9210,36

На расширении 3 МБ мало длинных модулей, поэтому accum здесь почти не виден. Его эффект — на крупных конфигурациях: модуль 3,2 МБ раскладывался 30 с, теперь 0,08 с.

5. УТ 11.5 целиком

Полная распаковка 1Cv8-ут-11.5.27.93-.cf (883 МБ). 1.0.0 — прогон 28.09 по журналу ut_err.log. Парный повтор 1.0.0 не делался: версия копирует результат, и в пике на D: не хватило бы места рядом с тремя временными каталогами. Условия прогонов разные, поэтому это ориентир, а не контрольный опыт.

Этап (по часам)1.0.0, 28.092.0.0, 29.092.0.0, CPU
Распаковка бинарника0:351:4946 с
Распаковка вложенных контейнеров6:231:3570 с
Разбор вложенных объектов10:274:31205 с
Организатор («Организуем код»)29:010:3128 с
Всего46:308:25365 с

2.0.0: user 171 с, kernel 194 с; пик памяти 947 МБ. Код первого этапа в 2.0.0 не менялся. Он медленнее, вероятно, из-за фона: параллельно шла сверка тяжёлых форм исходным разборщиком (537 с CPU) и чужие процессы.

Главный выигрыш — организатор. В 1.0.0 он обходил 68 тыс. файлов decode_stage_3, копировал каждый и заново писал модули и формы. В 2.0.0 каталог переносится одним переименованием, модули и формы без областей include не перезаписываются.

6. Разбор: тяжёлые формы и выборки

CPU разбора одного файла (brace_file_read), лучший из трёх прогонов. Исходный разборщик — один прогон, v8unpack_fastparse_check.py.

Форма УНФРазмерисходный v8unpack1.0.02.0.0
be7b61112018 КБ537,1 с0,531 с0,062 с
c7d3fbee1954 КБ12,2 с0,656 с0,141 с
303f4ede1495 КБ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: формы с base644506,00 с2,34 с2,6×
— из выборки 1: обычные скобочные файлы17571,62 с1,16 с1,4×
— из выборки 1: текстовые файлы6282,45 с0,27 с9,2×

Разбивка по видам снята до того, как экранирование стало условным. После этого весь разбор выборки 1 ускорился с 1,6× до 2,8×.

7. Запись JSON

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.

8. Антивирус и время ядра

Около половины CPU распаковки — время ядра Windows. В отчёте 28.09 его приписывали проверке антивирусом. Проверка 29.09 это не подтвердила:

Проверку файлов антивирус делает в своём процессе, а распаковка её только ждёт. Это видно по времени по часам и CPU антивируса, а не по CPU распаковки. Время ядра — сами открытия, записи и закрытия файлов, и 2.0.0 снижает его только тем, что делает этих операций меньше. Исключения антивируса для temp и результата полезны, когда защита в реальном времени включена: они снимают ожидание проверки файлов.

9. Сборка

Сборка .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 с.

10. Что не проверено

11. Как воспроизвести

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