Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Benchmarks

Wall-clock speed of badness against comparable tools, measured with hyperfine: the formatter against tex-fmt and latexindent, and the linter against the classic TeX Live checkers lacheck and chktex.

These numbers measure speed only, never output or diagnostic equivalence, and the tools do genuinely different amounts of work:

  • latexindent is a Perl script that parses LaTeX into a tree and reflows it according a set of highly configurable rules. It is the most featureful formatter here, but also the slowest.
  • tex-fmt breaks overfull lines greedily but does not reflow: it won’t rewrap lines that already fit, so it moves far less text than badness, which reflows each paragraph to the target width.
  • Among the linters, lacheck is a small classic checker, chktex is regex-driven, and badness lint does a full CST parse plus its rule set.

The absolute milliseconds are the real latencies—what you actually wait—but they are machine- and run-dependent. And because the tools do different work, a cross-tool difference is not a claim that one tool is faster at the same job.

The figures below are regenerated manually with task bench and committed as a machine-readable artifact (benches/benchmark_results.json); they are never re-measured when this site is built or in CI.

Formatter

How the formatter is measured

Each tool is invoked exactly as a user would pipe a document through it:

ToolInvocation
badnessbadness format --no-config --stdin-filepath bench.tex
tex-fmttex-fmt --stdin
latexindentlatexindent -g /dev/null -

The corpus is real LaTeX: a committed small.tex baseline plus larger documents (cv.tex, masters_dissertation.tex, phd_dissertation.tex) fetched by benches/documents/download.sh from a pinned tex-fmt release. Documents badness cannot yet format (parser diagnostics) are skipped, as are comparison tools missing from PATH.

The whole-project benchmark below measures recursive folder formatting rather than a single file: each tool walks a real multi-file LaTeX thesis (the pinned kks32/phd-thesis-template, its .tex fragments) and formats every file in read-only --check mode—the folder analog of the stdin -> stdout runs above (full formatting work, nothing written). Only badness and tex-fmt appear there: latexindent has no recursive directory mode, so it is excluded from that comparison by design.

ToolInvocation
badnessbadness format --check <dir>
tex-fmttex-fmt --check --recursive <dir>

The folder benchmark runs against a throwaway copy of the fetched project so both tools walk an identical, un-gitignored, .tex-only tree (badness format is .tex-only, while tex-fmt would otherwise also touch .bib/.cls). Any file badness cannot format yet is dropped from both tools, keeping the comparison symmetric. This is a different mode from the single-file runs, so read its ratio on its own terms, not against them.

Setup

  • badness: 0.7.0
  • tex-fmt: 0.5.7
  • latexindent: 3.24.7
  • backend: hyperfine (min runs: 3)
  • host: linux/x86_64, Intel(R) Core(TM) Ultra 7 155U
  • generated: 2026-07-10T00:50:18Z

Single-file results

Formatting speed relative to badness. Each dot is one document formatted by one tool; the vertical position is mean wall-clock time as a ratio to badness on a log scale, so badness lies on the dashed baseline at 1, faster tools fall below it and slower tools rise above. Color distinguishes documents; hover a dot for the exact millisecond figures.
Data table

small.tex (baseline) (1233 bytes, 48 lines)

ToolMean (ms)Min (ms)Max (ms)Relative
badness2.45450.85735.6567baseline
tex-fmt2.29800.88834.90631.1× faster
latexindent84.761977.052698.643034.5× slower

cv.tex (6273 bytes, 275 lines)

ToolMean (ms)Min (ms)Max (ms)Relative
badness3.05631.45216.5785baseline
tex-fmt2.36561.01575.15151.3× faster
latexindent105.638882.3922161.251834.6× slower

masters_dissertation.tex (95383 bytes, 2458 lines)

ToolMean (ms)Min (ms)Max (ms)Relative
badness22.592419.710726.9194baseline
tex-fmt3.58181.722810.99856.3× faster
latexindent2333.93382330.00662336.7828103.3× slower

Whole-project results

Whole-project formatting speed relative to badness. Each dot is one tool running a recursive --check over a real multi-file LaTeX project; the vertical position is mean wall-clock time as a ratio to badness on a log scale, so badness lies on the dashed baseline at 1, faster tools fall below it and slower tools rise above. This is a different mode from the single-file charts—read its ratio on its own terms. Hover a dot for the exact millisecond figures.
Data table

project (12 files) (47190 bytes, 1005 lines)

ToolMean (ms)Min (ms)Max (ms)Relative
badness4.69282.78719.3865baseline
tex-fmt3.48011.91596.73611.3× faster

Linter

How the linter is measured

The linter runs over the same single-file corpus. Linters are read-only, so each tool is handed the document path directly (no stdin plumbing—lacheck only reliably reads a real file):

ToolInvocation
badnessbadness lint --no-config <file>
chktexchktex -q <file>
lachecklacheck <file>

Findings are the normal case, and the tools signal them differently: chktex exits 2, badness lint exits 1, and lacheck always exits 0. A non-zero exit here is not a run error, so hyperfine is told to ignore it (--ignore-failure); the shell-loop fallback does the same.

There is no folder analog for the linter comparison: neither lacheck nor chktex has a recursive directory mode, so—like latexindent in the formatter folder benchmark—they would have no counterpart to measure against.

Setup

  • badness: 0.7.0
  • lacheck: 1.30
  • chktex: v1.7.9
  • backend: hyperfine (min runs: 3)
  • host: linux/x86_64, Intel(R) Core(TM) Ultra 7 155U
  • generated: 2026-07-10T00:50:18Z

Results

Linting speed relative to badness. Each dot is one document checked by one tool; the vertical position is mean wall-clock time as a ratio to badness on a log scale, so badness lies on the dashed baseline at 1, faster tools fall below it and slower tools rise above. These tools report different problems, so a difference here is not a same-job speed verdict. Color distinguishes documents; hover a dot for the exact millisecond figures.
Data table

small.tex (baseline) (1233 bytes, 48 lines)

ToolMean (ms)Min (ms)Max (ms)Relative
badness2.76151.51627.6755baseline
lacheck10.57847.707114.56983.8× slower
chktex65.400755.176493.524223.7× slower

cv.tex (6273 bytes, 275 lines)

ToolMean (ms)Min (ms)Max (ms)Relative
badness3.24691.84038.2667baseline
lacheck11.65107.185125.75713.6× slower
chktex66.145654.728181.892620.4× slower

masters_dissertation.tex (95383 bytes, 2458 lines)

ToolMean (ms)Min (ms)Max (ms)Relative
badness24.125820.717228.9816baseline
lacheck13.534610.440718.27611.8× faster
chktex68.445561.333490.87542.8× slower