Методика измерений: версия для чтения. Оригинал на английском: benchmarks/toolkit/README.md, ревизия репозитория 61e75e9aa9a8719dfb480bf1f5226553b3a21d70 (2026-10-04). Перевод сохраняет методику, даты, измерения и статус, зафиксированные в этой ревизии. Приведённые прошлые результаты относятся к описанным запускам и не гарантируют производительность текущего продукта или качество ответов модели.
Зафиксированная базовая версия — ed7ddc28cd127682023bd150ee377906b817e099, исправленная реализация — 0f15ab4091203f11caa7fb0b9e02da47d719a051. Обе измерялись на чистых снимках из архивов в /private/tmp, с одинаковыми исходниками измерений и байтами документов. Итоговая парная серия была запущена после остановки параллельного полного набора тестов. Более ранняя парная попытка при этой нагрузке была отброшена и не входит в опубликованное сравнение.
Базовый архив изначально не содержал нового инструмента измерений: в него скопировали точное дерево benchmarks/toolkit исправленного коммита 0f15ab4. Сравнение двух деревьев командой diff -rq не обнаружило различий. SHA-256 исходников: corpus.go — 91535e840efb20952b22e01fd512515f7c0a9b314f3e2a5c9bd3c78a114598f7, toolkit_test.go — 550eb581810580eb9ee26df4e74cffd8da70723c506b72dbd0d86fc9a202b4f9. Контрольные суммы входных данных в таблице ниже совпадают для обоих снимков.
Пять повторений для каждого коммита чередовались в порядке AB BA AB BA AB с -benchtime=100ms; использовались заранее собранные исполняемые файлы тестов Go и CLI. Базовая и исправленная версии прошли необходимые проверки до измерений. Проверка исправленной версии включает переносы строк в журнале, сноску внутри кода, старый формат даты и даты-времена с разными смещениями, обозначающие один момент. Оба зафиксированных исполняемых файла также прошли проверку strict+links+orphans вручную запускаемого набора из 10,000 заметок без диагностик.
Принятые исходные файлы: базовая версия — оригинал, SHA-256 cc278b342a0efa3f008e4631aa5ca622a5e6f873b20603a6d3962533ed862a79, и исправленная версия — оригинал, SHA-256 3b9fa38bf6bcf052e52800496ec112969391c3315c830424103c43aa0849377a. Они содержат соответственно 28 × 5 и 34 × 5 измерений операций. Полное сравнение показывает медиану ± MAD для ns/op, B/op и allocs/op; операции, существующие только в исправленной версии, помечены N/A в базовой. Исходник анализатора зафиксирован SHA-256 ae78d8e8156eae85e9c27122609b46b515fa3262f614cf3b53ab8af7f5c5718d.
Примеры медиан из чистой парной серии:
| Операция | Базовая ns/op | Исправленная ns/op | Изменение времени | Базовая → исправленная B/op | Базовая → исправленная allocs/op |
|---|---|---|---|---|---|
| Обычный типизированный журнал | 222 | 155 | −30.0% | 208 → 80 | 4 → 2 |
| 100 заметок, все проверки | 10,920,854 | 11,328,883 | +3.7% | 10,936,046 → 10,939,834 | 108,394 → 108,496 |
| 1,000 заметок, все проверки | 122,561,459 | 118,398,375 | −3.4% | 107,666,016 → 107,812,384 | 1,078,763 → 1,079,797 |
| 1,000 заметок, граф JSON-LD | 160,772,166 | 150,407,708 | −6.4% | 116,700,032 → 117,430,704 | 1,384,703 → 1,384,695 |
Исправленный парсер журнала с переносами строк, не имеющий корректного аналога в базовой версии, показал 5,030 ns/op, 5,944 B/op и 66 allocs/op. Базовая версия отвергала этот допустимый ввод, поэтому отношение скоростей не приводится. Построение графа для 10 заметок стало медленнее на 6.3%, а для 1,000 заметок — быстрее на 6.4%; изменения времени проверки также были разнонаправленными. Серия из пяти пар не доказывает общего ухудшения масштабирования. Ниже сохранены профили CPU и памяти устаревшей реализации ParseLog до добавления быстрого пути: это исторические свидетельства, а не профили зафиксированного исправленного коммита.
Машина: Apple M1 Max, macOS 27.0 / Darwin 27.0.0, go1.26.5 darwin/arm64, CGO_ENABLED=1, пустой GOFLAGS. Все запуски использовали одну машину, кеш Go, флаги, манифесты документов и исходники измерений. SHA-256 заранее собранных исполняемых файлов: базовые тесты — 6aec602c02acb507a538ba185c9a7550fc0b126005604881feffc4a31e2b7b12; базовый CLI — 313ea5a941a037a3b29bec46ee1b60809e24f1d0e1eb31eec086bb8555f40def; исправленные тесты — 9b13f43b270d87e67b7cd368f5bad7ab638f1d39a5016a9b22b6d7a1d2a9f2f1; исправленный CLI — c655b4c0b192d0525b287688063441d27632c3b5bc80c8fa1d701ce84d358fe8.
Генератор на Go создаёт снимки, которые не изменяются во время использования, с последовательными числовыми идентификаторами. Каждая заметка имеет один источник и одну Markdown-связь. Группа каталогов содержит не более 100 заметок. В наборе есть корневой индекс, индекс каждой группы и журнал. Все байты искусственные и локальные; чужой код и текст тестовых данных не копируются. Манифесты в results/ содержат контрольные суммы отдельных файлов, общую контрольную сумму отсортированных путей и содержимого с префиксами длины, а также размеры набора.
| Набор | Заметки | Файлы | Байты | Индексы | Связи | Источники | Строки с переносом | SHA-256 |
|---|---|---|---|---|---|---|---|---|
n10 |
10 | 13 | 2,033 | 2 | 10 | 10 | 0 | 2ca555604144236f282613c7ec28596c0f2fe847bda62418e0bcf89f6ffeb9c0 |
n100 |
100 | 103 | 19,313 | 2 | 100 | 100 | 0 | 4269ee5f46bc067a8ec25f4abc895337a55ca8b1a7480b496b0371ebace662d3 |
n1000 |
1,000 | 1,012 | 196,091 | 11 | 1,000 | 1,000 | 0 | ef62d3064ce91ad1ce720d29144377c16a50ffe776b661292f25eb52522bdba2 |
n10000 (вручную) |
10,000 | 10,102 | 1,999,871 | 101 | 10,000 | 10,000 | 0 | 0070d845c6eaf710629ce872c3880294fb5fc26a9a52fcda69448087d34cd2b5 |
interop |
10 | 13 | 2,040 | 2 | 10 | 10 | 1 | b61ac1a0d7d5227be226a3cdfd8b1e993fb89215b51bd46a9f8d5fc57e81e083 |
temporal-date |
10 | 13 | 2,159 | 2 | 10 | 10 | 0 | 4206ecf77a84d498acca8500c5fe95bdde83257b3391922a5c7fb192222f77a5 |
temporal-instant |
10 | 13 | 2,214 | 2 | 10 | 10 | 0 | e0623170ab61a25ef67810ab1b9e6a7090bd4d91dc6b57053724f6f1afcbe15d |
В наборе interop есть одна запись log.md с переносами строк и буквальное [^fake] внутри встроенного кода. Набор с датой-временем содержит временные метки со смещением и usage_window, границы которого используют разные смещения для одного момента. Строгая проверка тех же байтов базовой версией возвращает для interop одну ошибку журнала и два ложных предупреждения о сносках; ввод даты-времени даёт пять строгих предупреждений при её профиле даты. Поэтому у старой реализации нет корректного эквивалента для этих операций. Измерения, доступные только в исправленной версии, проверяют допустимый результат до запуска таймера и обозначаются отдельно. Ввод с датой проходит строгую проверку базовой версии без диагностик. JSON базовых проверок сохранён в results/.
Основные измерения охватывают разбор документов, загрузку снимка каталога OKF, базовую и строгую проверки, ссылки, несвязанные заметки, все проверки вместе, чтение типизированного журнала, принадлежность сносок источникам, проекцию JSON-LD библиотеками и отдельную операцию с процессом CLI. Входные данные и исполняемый файл CLI готовятся до включения таймеров. Измеряемый load вызывает bundle.Load напрямую, без тестовых утверждений внутри часто исполняемого участка; каждая операция предварительно проверяется. Предварительная проверка CLI декодирует JSON и требует правильного результата strict/links/orphans, 13/103 просмотренных файлов соответственно и отсутствия ошибок, предупреждений, нарушений политик и диагностик. B/op и allocs/op для CLI относятся к родительскому процессу тестов Go и не включают память дочернего процесса.
Базовый запуск состоялся 2026-09-26 UTC: Apple M1 Max, macOS 27.0 / Darwin 27.0.0, go1.26.5 darwin/arm64, CGO_ENABLED=1, пустой GOFLAGS. Использовались -benchtime=100ms -count=5. Исходные записи находятся в results/baseline-ed7ddc28-v3.raw.txt, SHA-256 31413f125813f0707dba65bec18e13a37d0f49b6e8efd3658fc90153bfcfddcd. Старый запуск с -benchtime=3x сохранён только как предварительное исследование. Даже запуск на 100ms содержит шум: указано медианное абсолютное отклонение (MAD); ограничение по времени и порог производительности не задаются. Итоговый парный запуск выше заменяет отдельное базовое измерение как основание для сравнения. Если в последующих запусках появится существенная разница, повторите оба коммита на одной машине в чередующемся порядке; если разница сохраняется, сохраните профили CPU и памяти. Локальный анализатор на Go выдаёт медиану ± MAD для ns/op, B/op и allocs/op, а изменения — только для эквивалентных операций обеих версий. Его исходник зафиксирован SHA-256 ae78d8e8156eae85e9c27122609b46b515fa3262f614cf3b53ab8af7f5c5718d. Контрольные суммы генератора и исходника измерений для запуска v3 — 91535e840efb20952b22e01fd512515f7c0a9b314f3e2a5c9bd3c78a114598f7 и 550eb581810580eb9ee26df4e74cffd8da70723c506b72dbd0d86fc9a202b4f9.
Чтобы воспроизвести базовое измерение, выполните из корня репозитория в новом каталоге:
snapshot=$(mktemp -d /tmp/okf-toolkit-baseline.XXXXXX)
git archive ed7ddc28cd127682023bd150ee377906b817e099 | tar -x -C "$snapshot"
mkdir -p "$snapshot/benchmarks"
cp -R benchmarks/toolkit "$snapshot/benchmarks/"
cd "$snapshot"
GOCACHE=/tmp/okf-bench-gocache go test ./benchmarks/toolkit/... -run 'TestCorpus|TestSpecial|TestAnalyzer' -count=1
GOCACHE=/tmp/okf-bench-gocache go build -o "$snapshot/okf-bench-cli" ./cmd/okf
GOCACHE=/tmp/okf-bench-gocache OKF_BENCH_CLI="$snapshot/okf-bench-cli" go test ./benchmarks/toolkit -run '^$' -bench '^BenchmarkToolkit$' -benchtime=100ms -count=5 -timeout=30m > baseline.raw.txt
GOCACHE=/tmp/okf-bench-gocache go run ./benchmarks/toolkit/cmd/analyze -baseline baseline.raw.txt
go run ./benchmarks/toolkit/cmd/corpusgen -out /tmp/okf-toolkit-bench-corpus создаёт точные входные файлы и манифесты вне измеряемых участков. Для ручных запусков с 10,000 заметок добавьте -large и задайте OKF_BENCH_LARGE=1. В обычном PR можно запускать тесты корректности без порога времени. Для исправленной версии до измерений соберите CLI этого коммита и задайте OKF_BENCH_EXPECT_CORRECTED=1; сначала запустите TestCorrectedInteropContract. Набор из 10,000 заметок прошёл OKF_BENCH_LARGE=1 go test ./benchmarks/toolkit -run '^TestCorpusContracts$' с включёнными strict, links и orphans без диагностик на предварительном рабочем дереве исправленной версии.
Для повторения итогового сравнения один раз соберите ./benchmarks/toolkit командой go test -c, а ./cmd/okf — командой go build в каждой зафиксированной копии репозитория. Обе копии должны содержать одинаковые байты исходников измерений и манифестов документов. Затем запустите программу чередования на Go:
go run ./benchmarks/toolkit/cmd/paired \
-baseline-test /path/to/baseline/toolkit.test \
-baseline-cli /path/to/baseline/okf \
-corrected-test /path/to/corrected/toolkit.test \
-corrected-cli /path/to/corrected/okf \
-out /tmp/okf-toolkit-paired
go run ./benchmarks/toolkit/cmd/analyze \
-baseline /tmp/okf-toolkit-paired/baseline.raw.txt \
-corrected /tmp/okf-toolkit-paired/corrected.raw.txt
Программа выполняет AB BA AB BA AB: по пять измерений на вариант с одинаковой целевой длительностью 100ms; каждый исходный результат записывается после успешного завершения дочернего процесса. На время запуска остановите другие измерения производительности на машине. Отношение парных медиан остаётся описательным свидетельством и не является точной оценкой на основании всего пяти выборок. Программа прошла проверочный запуск с одним исполняемым файлом для обоих вариантов при -benchtime=1x: десять дочерних процессов завершились, анализатор обнаружил пять выборок для каждой общей строки и строки только исправленной версии с N/A у базовой. Этот проверочный вывод не входит в сравнение производительности.
Отдельный запуск results/baseline-ed7ddc28-v3.raw.txt предшествовал парному сравнению. Он сохранён для отслеживания происхождения результатов, но для выводов «до/после» его заменяют зафиксированные исходные парные файлы и полная таблица выше.
Незакоммиченное дерево после основных правок 004/005 прошло TestCorrectedInteropContract и два запуска по пять повторений с -benchtime=100ms. Предварительный результат после добавления быстрого пути ParseLog находится в results/corrected-exploratory-v2.raw.txt, SHA-256 57240b9418a8f204fb95e617e935c539c4c882103efe1490d812f6bd1b076aaa3. Использовались те же контрольные суммы документов, что выше. Операции совместимости и времени, доступные только в исправленной версии, прошли предварительные проверки. Это по-прежнему незакоммиченный исследовательский запуск, а не результат зафиксированной исправленной версии.
Чтение обычного типизированного журнала показало 235 ns/op, 208 B/op и 4 allocs/op в базовой версии; после быстрого пути — 180 ns/op, 80 B/op и 2 allocs/op. Записи с переносами строк по-прежнему используют Markdown-парсер; их типизированное чтение, доступное только исправленной версии, показало 5,290 ns/op, 5,944 B/op и 66 allocs/op. Итоговая парная серия выше заменяет эти предварительные измерения времени.
До добавления быстрого пути первый предварительный запуск показал для обычного типизированного чтения 4,547 ns/op, 4,504 B/op и 54 allocs/op. Его исходный файл сохранён: results/corrected-exploratory.raw.txt, SHA-256 44c29914c82851204e47539420909a083cd065df88af9033a733b09e32ea6636. Профили CPU и памяти этой заменённой реализации сохранены в results/corrected-exploratory-log.cpu.pprof и results/corrected-exploratory-log.heap.pprof. С github.com/google/pprof@v0.0.0-20250317173921-a4b03ec1a45e профиль памяти относит около 96.6% объёма выделений к markdownowner.TopLevelStructureContext и его вызовам Goldmark. Профиль собирался с инструментированием, поэтому его ns/op не использовались в сравнении. Быстрый путь сохраняет парсер для записей с переносами строк. Другие предварительные изменения зависели от нагрузки машины; принятое сравнение — чистый зафиксированный парный запуск выше.