Команды¶
У takt три команды: takt run, takt import и takt compare.
takt --version выводит takt <версия>.
takt run¶
takt run запускает бенчмарки и записывает результат во все выбранные БД.
Два режима¶
takt убирает свои флаги (см. «Флаги» ниже) и смотрит на первый оставшийся аргумент:
- Если он оканчивается на
.pyи не начинается с-, takt считает его путём к pyperf-скрипту (скрипту наpyperf.Runner). takt запускает его тем же Python, в котором работает сам. - Иначе takt запускает
pyperformance run.
Режим pyperformance:
takt run -b nbody,json_dumps --fast --target local
Режим pyperf-скрипта:
takt run bench_sort.py --values 5 --db sqlite:///bench.db
Флаги¶
takt разбирает только свои флаги. Все остальные флаги без изменений уходят в pyperformance или в pyperf-скрипт, разделитель -- не нужен.
| Флаг | Можно повторять | Что делает |
|---|---|---|
--db URL |
да | SQLAlchemy URL целевой БД |
--target NAME |
да | выбрать цель из takt.toml по имени |
--config PATH |
нет | путь к takt.toml вместо ./takt.toml |
--name TEMPLATE |
нет | имя прогона или шаблон имени |
Флаги takt не совпадают с флагами pyperformance и pyperf.
Сокращения флагов отключены: --ta не считается --target.
takt раскрывает ~ в каждом пути из командной строки: в --config, в файле takt import, в --markdown, в операндах takt compare и в -o/--output.
Поэтому работает и --config=~/takt.toml, хотя оболочка оставляет ~ после = как есть.
Как выбираются цели и имя, описано на странице Настройка.
takt проверяет цели и текст шаблона имени до запуска бенчмарков.
Если там ошибка, команда завершается с кодом 2, и ни один бенчмарк не запускается.
Лимит 255 символов и :, который пришёл из значения вроде {hostname}, проверяются только после бенчмарков: см. «Имя прогона» на странице Настройка.
Файл результата¶
Если флаг -o/--output не указан, результат пишется в ./takt-<YYYYmmddTHHMMSSZ>.json, время в UTC.
takt никогда не удаляет файл результата.
takt понимает -o FILE, -oFILE, --output FILE, --output=FILE, сокращённое --out FILE и -o, склеенный с другими короткими флагами, например -fo FILE.
Он раскрывает ~ и превращает относительный путь в абсолютный от текущего каталога.
Потом takt добавляет --output <абсолютный путь> после остальных флагов команды бенчмарков, перед разделителем --, если он есть.
pyperformance и pyperf берут последний --output, поэтому результат попадает ровно в тот файл, который читает takt.
Каталог файла результата должен уже существовать, и у takt должно быть право писать в него.
Без -o это текущий каталог.
takt проверяет это до запуска бенчмарков, потому что pyperformance записывает файл только после последнего бенчмарка.
Иначе команда завершается с кодом 2 и печатает error: cannot create result file <файл>: folder <каталог> does not exist; choose another file with -o или ту же ошибку с is not writable.
takt не создаёт каталог сам: иначе опечатка в пути осталась бы незамеченной.
Вывод pyperformance и pyperf идёт в терминал как есть. Когда бенчмарки закончились, takt приводит схему каждой БД к текущей версии и записывает результат.
Вывод¶
Result 3fa2b1c4d5e6 (nightly 2026-09-25) from /home/me/takt-20260925T101500Z.json
local: written
maria_ci: written
В первой строке — первые 12 символов хеша результата, имя прогона и файл результата.
Прогон без имени показывается как unnamed.
Если результат уже был во всех БД, ничего не записано, поэтому первая строка показывает имя, под которым он там сохранён, а не то, которое вы указали; если в БД сохранены разные имена, имени в строке нет.
Дальше идёт по одной строке на каждую цель:
| Текст | Что значит |
|---|---|
written |
результат записан |
already loaded as '<имя>' |
в этой БД результат уже был под этим именем |
already loaded (unnamed) |
в этой БД результат уже был без имени |
failed: <ошибка> |
запись в эту БД не удалась |
failed: compensation failed: <ошибка> |
результат был записан, но после ошибки в другой БД takt не смог его удалить |
rolled back |
результат был записан, но удалён, потому что в другой БД произошла ошибка |
not attempted |
takt остановился раньше, чем дошёл до этой БД |
После compensation failed результат остаётся в этой БД: см. «Всем или никому» ниже.
Если запись не удалась¶
Если результат записался не во все цели, takt показывает причину для каждой цели, а потом пишет в stderr:
error: result was not written to all targets
Retry without re-running benchmarks: takt import /home/me/takt-20260925T101500Z.json --target local --target maria_ci --name 'nightly 2026-09-25'
Команда завершается с кодом 1.
Файл результата остаётся на диске: почините БД и выполните напечатанную команду takt import.
Бенчмарки заново не запускаются.
Напечатанная команда передаёт имя прогона, которое эта команда дала результату, а не шаблон имени: с nightly {date} повтор на следующий день всё равно сохранит nightly 2026-09-25.
Фигурные скобки в этом имени удвоены, поэтому остаются обычным текстом.
Если у результата нет имени, в команде нет --name.
Если бенчмарки упали¶
Если pyperformance или pyperf-скрипт завершился с ошибкой, takt ничего не пишет в БД, показывает ошибку и завершается с кодом 1. Если упавший процесс всё же успел записать новый файл результата, takt пишет в stderr ещё одну строку:
error: benchmark command failed with exit code 1: /usr/bin/python3 -m pyperformance run -b nbody,json_dumps --output /home/me/takt-20260925T101500Z.json
Partial result was written to /home/me/takt-20260925T101500Z.json. Load it without re-running benchmarks: takt import /home/me/takt-20260925T101500Z.json --target local
В файле может не быть упавших бенчмарков.
Если остальных вам хватает, выполните напечатанную команду takt import.
После Ctrl+C¶
Если нажать Ctrl+C во время бенчмарков, takt ничего не пишет в БД и завершается с кодом 130.
pyperf-скрипт записывает каждый законченный бенчмарк в файл результата сразу, поэтому после Ctrl+C в файле уже могут быть готовые бенчмарки.
Если на диске есть новый файл результата, takt печатает только строку Partial result was written to …, без строки error:.
pyperformance пишет свой файл только в конце, поэтому после Ctrl+C файла обычно нет, и такой строки тоже нет.
Если нажать Ctrl+C уже после бенчмарков, пока takt записывает результат в БД, например ждёт заблокированную БД, файл результата полный. Тогда takt пишет в stderr такую строку и завершается с кодом 130:
Result was written to /home/me/takt-20260925T101500Z.json. Load it without re-running benchmarks: takt import /home/me/takt-20260925T101500Z.json --target local --name 'nightly 2026-09-25'
Как и команда повтора выше, она передаёт имя прогона, которое эта команда дала результату. Если Ctrl+C пришёлся на подтверждение записи, в части БД результат уже может быть; напечатанная команда их пропустит (см. «Всем или никому» ниже).
takt import¶
takt import записывает готовый результат pyperf или pyperformance во все выбранные БД.
takt import result.json --db sqlite:///bench.db --name patched
- Файл может быть
.jsonили сжатым gzip.json.gz. - Флаги
--db,--target,--configи--nameте же, что уtakt run. - Вывод такой же, как у
takt run. - takt отказывается принимать файл, который не является корректным результатом pyperf: например, если замер равен NaN или бесконечности или имя бенчмарка не строка. Он пишет
error: invalid pyperf result <файл>: <причина>и завершается с кодом 1. - Если файл не открывается, не распаковывается или не читается как JSON, takt пишет
error: cannot read pyperf result <файл>: <причина>и завершается с кодом 1.
Хеш результата¶
takt узнаёт результат по хешу: это SHA-256 от содержимого JSON с отсортированными ключами и без пробелов.
Имя файла и его форматирование на хеш не влияют.
У файла .json и его копии .json.gz хеш одинаковый.
Повторный импорт¶
takt проверяет каждую БД отдельно.
Если результат в БД уже есть, takt её пропускает и пишет already loaded as '<имя>'.
Сохранённое имя не меняется, даже если передать другое --name.
Если результат уже есть во всех БД, команда ничего не пишет и завершается успешно.
Всем или никому¶
takt записывает результат либо во все выбранные БД, либо ни в одну:
- takt открывает транзакцию в каждой БД и вставляет результат.
- Если вставка упала хотя бы в одной БД, takt откатывает все транзакции и завершается с ошибкой.
- Потом takt по очереди подтверждает (commit) транзакции.
- Если подтверждение упало, когда другие БД уже подтверждены, takt удаляет результат из этих БД.
В этих случаях результат всё же остаётся только в части БД:
- takt не смог удалить результат на шаге 4. У такой БД статус
failed: compensation failed: <ошибка>. - Процесс takt убили или прервали по Ctrl+C во время подтверждения. Тогда takt не печатает отчёт, а после Ctrl+C завершается с кодом 130, и
takt runещё печатает строкуResult was written to ….
После compensation failed строка Result упавшей команды показывает первые 12 символов хеша результата и имя, под которым он сохранился в этой БД.
После остановки такой строки нет.
Остановленная команда записала результат с одним и тем же временем loaded_at во все БД, до которых дошла, поэтому в этих БД этот запрос покажет его как самый новый результат:
SELECT hash, name, loaded_at FROM takt_suite ORDER BY loaded_at DESC LIMIT 1;
Чтобы результат был во всех БД, ещё раз выполните takt import для файла результата: он пропустит БД, где результат уже есть, и допишет его в остальные.
Если в шаблоне имени есть {date} или {datetime}, takt подставит в них новое время, и в остальных БД имя может получиться другим.
Чтобы в остальных БД имя было таким же, передайте сохранённое имя через --name; команда, которую печатает takt run после compensation failed или Ctrl+C, уже делает это.
Чтобы вместо этого убрать результат, выполните эти запросы в этом порядке и только в тех БД, где его оставила упавшая команда: со статусом compensation failed или, после остановки, там, где запрос выше показывает его со временем loaded_at этой команды.
Не выполняйте их в БД со статусом already loaded: там результат был ещё до этой команды.
Дочерние таблицы идут первыми: MariaDB не удаляет строку, пока на неё ссылаются другие строки.
Вместо 3fa2b1c4d5e6 подставьте первые 12 символов хеша результата.
DELETE FROM takt_measurement WHERE suite_hash LIKE '3fa2b1c4d5e6%';
DELETE FROM takt_run_metadata WHERE suite_hash LIKE '3fa2b1c4d5e6%';
DELETE FROM takt_worker_run WHERE suite_hash LIKE '3fa2b1c4d5e6%';
DELETE FROM takt_benchmark WHERE suite_hash LIKE '3fa2b1c4d5e6%';
DELETE FROM takt_suite WHERE hash LIKE '3fa2b1c4d5e6%';
DELETE FROM takt_loaded_hash WHERE hash LIKE '3fa2b1c4d5e6%';
takt compare¶
takt compare сравнивает два или больше результата.
Первый операнд — базовый, все остальные сравниваются с ним.
takt compare 3fa2b1 "default 01.01.01" "jit+pgo:1" ~/path/to/res.json --target local
Операнды¶
takt проверяет каждый операнд в таком порядке и берёт первое совпадение:
| Операнд | Что это |
|---|---|
results/a.json, ~/r.json.gz |
файл на диске, если такой файл есть |
default |
прогон с именем default; если таких прогонов несколько — ошибка со списком вариантов |
default:0, default:2 |
N-й прогон с именем default, счёт с 0, по дате результата |
default:3fa2b1 |
прогон с именем default, у которого хеш начинается с этих символов (от 6) |
3fa2b1 |
прогон, у которого хеш начинается с этих символов (от 6 строчных hex-символов) |
Если после : только цифры, это номер; всё остальное — начало хеша.
Операнд из 1–5 hex-символов или с заглавными буквами никогда не ищется как начало хеша. Если прогона с таким именем нет, а в операнде есть и цифры, и буквы от a до f, ошибка подсказывает, как найти прогон по хешу: no file or run name matches; to find a run by hash, use 6 to 64 lowercase hex characters.
Операнд, похожий на путь к файлу результата, никогда не считается прогоном: он кончается на .json или .json.gz либо начинается с /, ./, ../ или ~/.
Если такого файла нет, takt пишет error: result file not found: <операнд> и завершается с кодом 1, есть БД или нет.
В имени прогона / при этом допустим, например release/3.14.
Операнд, который не подходит ни под одну форму, — ошибка с кодом 1: например, пустой операнд, default:, :1, a:b:c или default:XYZ.
Прогоны с одинаковой датой результата упорядочены по хешу, поэтому номера одинаковые во всех БД.
Прогоны без даты результата идут последними; в списке вариантов у них написано unknown date.
Если имени соответствуют несколько прогонов, takt их перечисляет:
error: operand 'default' is ambiguous, candidates:
default:0 2026-09-20 10:00:00 3fa2b1c4d5e6
default:1 2026-09-25 10:00:00 9c01de7a8b2f
Файлы и БД¶
- В одном сравнении можно смешивать файлы и прогоны из БД.
- Прогоны читаются из первой цели в списке. Другую цель выбирает
--target. - Если прогон не найден, ошибка называет ту единственную цель, где takt его искал, например
error: operand 'o1' not found in target 'local': no file, run name or hash prefix matches. takt compareтолько читает БД и никогда не создаёт файл SQLite. Опечатка в пути SQLite даётerror: cannot connect to database <цель>: database file not found: <путь>, а БД без таблиц takt —error: no takt results in database <цель>; код выхода 1.- Если все операнды — файлы, БД не нужна, и takt не читает
--db,--target,--config,TAKT_DBиtakt.toml. - Если операнд не файл, а ни одной цели не задано, takt пишет
error: operand '<операнд>' is not a file and no database target is configuredи завершается с кодом 2. Операнд, который не подходит ни под одну форму, и тогда даёт код 1: форму всех операндов takt проверяет раньше.
Вывод¶
takt выводит таблицу в терминал.
Если вывод идёт в файл или в конвейер, как в логе CI, takt не переносит таблицу и строки под ней, поэтому каждый заголовок столбца остаётся целым.
В узком терминале длинный заголовок столбца переносится на несколько строк; takt никогда его не обрезает.
С --markdown PATH он ещё записывает таблицу в Markdown-файл и пишет Markdown table written to <PATH>.
takt compare base.json new.json --markdown compare.md
Пример Markdown-файла:
| Benchmark | base.json | new.json |
|----------------|:---------:|:---------------------:|
| nbody | 100 ms | 90.0 ms: 1.11x faster |
| Geometric mean | (ref) | 1.04x faster |
Benchmark hidden because not significant (2): a, b
Ignored benchmarks (1) of new.json: x
Как читать таблицу:
- Заголовок столбца — операнд ровно так, как вы его ввели.
- В Markdown-файле takt пишет
|в заголовке или в имени бенчмарка как\|, чтобы таблица не развалилась на лишние столбцы; программа просмотра Markdown показывает его как|. - В Markdown-файле между таблицей и строками под ней всегда есть пустая строка, чтобы программа просмотра Markdown не показала эти строки как строки таблицы.
- В базовом столбце — среднее значение.
- В остальных столбцах — среднее значение и изменение относительно базового:
1.11x faster(быстрее),1.05x slower(медленнее),no change(без изменений) илиnot significant(разница незначима). - Строка
Geometric mean(среднее геометрическое) появляется, если общих бенчмарков больше одного и хотя бы один из них есть в таблице. Benchmark hidden because not significant— бенчмарки, где ни одна разница не значима; в таблице их нет.Ignored benchmarks … of <операнд>— бенчмарки этого операнда, которые не сравнивались. Сравниваются только бенчмарки, у которых во всех операндах есть замеры: если у какого-то операнда бенчмарка нет или у него есть только значения прогрева (warmup), бенчмарк пропускается.
Если сравнивать нечего, takt таблицу не печатает: он пишет error: benchmark suites have no benchmark in common и завершается с кодом 1.
Так бывает, даже если у результатов есть бенчмарки с одинаковыми именами, но у какого-то операнда для каждого из них есть только значения прогрева.
Числа и проверка значимости такие же, как у pyperf compare_to --table.
Коды выхода¶
| Код | Когда |
|---|---|
| 0 | успех, в том числе «всё уже было загружено» |
| 1 | ошибка выполнения: БД, файл, бенчмарк, запись не во все цели, операнд compare не подходит ни под одну форму, не найден или неоднозначен, у результатов в compare нет общих бенчмарков |
| 2 | ошибка аргументов или конфигурации, найдена до запуска бенчмарков, итоговое имя прогона нарушает правила, или операнд compare не файл, а ни одной цели не задано |
| 130 | прервано по Ctrl+C |
Ошибку в самой командной строке, например пропущенный аргумент или флаг без значения, показывает argparse.
Он печатает подсказку по использованию команды (usage), а под ней строку вроде takt import: error: the following arguments are required: PATH.
При неизвестном флаге у takt import или takt compare печатается общая подсказка takt и строка takt: error: unrecognized arguments: <флаги>.
takt run неизвестные флаги не отклоняет: он передаёт их pyperformance или pyperf-скрипту.
-o/--output у takt run проверяет сам takt: если пути к файлу нет, он печатает только строку error: option -o/--output requires a file path.
Код выхода 2.
Любая другая ошибка выводится в stderr как error: <сообщение>, без трейсбека.
Обычно это одна строка; у неоднозначного операнда под ней ещё идёт список вариантов.
Если takt run не смог записать результат или бенчмарки упали, но файл результата всё же записан, takt ещё печатает команду takt import: она загружает этот файл без повторного запуска бенчмарков.
Если после бенчмарков итоговое имя прогона нарушает правила, takt печатает путь к файлу результата: загрузите его через takt import с другим --name.