o
odinpkg.dev
packages / library / toc-comparison

toc-comparison

e8e7749library

Markdown TOC generator in 24 languages for performance comparison

MIT · updated 6 months ago

TOC Generator Comparison

A markdown table of contents generator implemented in 31 languages for performance comparison, with both single-threaded and multi-threaded variants.

Usage

toc [-s] <directory>
  • Recursively finds .md files
  • Outputs a markdown TOC with links
  • -s extracts first paragraph as summary

Build

mise install     # Install toolchains
mise run build   # Build compiled versions
./benchmark.sh   # Run full benchmark

Sample Docs

The sample-docs/ directory is gitignored. To populate it for benchmarking:

# Kubernetes docs (~1,500 files)
git clone --depth 1 https://github.com/kubernetes/website.git /tmp/k8s
mkdir -p sample-docs/kubernetes
mv /tmp/k8s/content/en/docs/* sample-docs/kubernetes/
rm -rf /tmp/k8s

# VS Code docs (~300 files)
git clone --depth 1 --filter=blob:none --sparse https://github.com/microsoft/vscode-docs.git /tmp/vscode
cd /tmp/vscode && git sparse-checkout set docs && cd -
mkdir -p sample-docs/vscode
mv /tmp/vscode/docs/* sample-docs/vscode/
rm -rf /tmp/vscode

# React docs (~200 files)
git clone --depth 1 https://github.com/reactjs/react.dev.git /tmp/react
mkdir -p sample-docs/react
find /tmp/react/src/content -name "*.md" -exec cp {} sample-docs/react/ \;
rm -rf /tmp/react

# Go docs (~475 files)
git clone --depth 1 https://github.com/golang/website.git /tmp/golang
mkdir -p sample-docs/golang
cp -r /tmp/golang/_content/* sample-docs/golang/
rm -rf /tmp/golang

Benchmarks

Hardware: MacBook Pro M4 Pro (24GB RAM), macOS 15.2 Tool: hyperfine with 3 warmup runs Reproduce: ./benchmark.sh

Large Dataset - Threaded (2,652 files with -s)

# Language Time Type
1 C++ (threaded) 36 ms compiled
2 Nim (threaded) 41 ms compiled
3 Go (threaded) 44 ms compiled
4 C (threaded) 46 ms compiled
5 Rust (threaded) 47 ms compiled
6 Odin (threaded) 50 ms compiled
7 OCaml (threaded) 50 ms compiled
8 Zig (threaded) 55 ms compiled
9 V (threaded) 58 ms compiled
10 D (threaded) 63 ms compiled
11 Swift (threaded) 69 ms compiled
12 Crystal (threaded) 70 ms compiled
13 Dart (threaded) 82 ms compiled
14 Bun (threaded) 91 ms jit
15 Gleam (threaded) 105 ms compiled/vm
16 Haskell (threaded) 106 ms compiled
17 Node.js (threaded) 113 ms jit
18 Kotlin (threaded) 123 ms jit
19 F# (threaded) 136 ms compiled
20 Java (threaded) 138 ms jit
21 C# (threaded) 139 ms jit
22 Deno (threaded) 177 ms jit
23 Scala (threaded) 210 ms jit
24 Elixir (threaded) 266 ms compiled/vm
25 Erlang (threaded) 533 ms compiled/vm
xychart-beta
    title "Threaded Performance (ms) - Top 15"
    x-axis ["C++", Nim, Go, C, Rust, Odin, OCaml, Zig, V, D, Swift, Crystal, Dart, Bun, Gleam]
    y-axis "Time (ms)" 0 --> 120
    bar [36, 41, 44, 46, 47, 50, 50, 55, 58, 63, 69, 70, 82, 91, 105]
Loading

Large Dataset - Single-Threaded (2,652 files with -s)

# Language Time Type
1 Rust 46 ms compiled
2 Go 50 ms compiled
3 C++ 51 ms compiled
4 Zig 53 ms compiled
5 Nim 53 ms compiled
6 C 54 ms compiled
7 OCaml 61 ms compiled
8 Odin 63 ms compiled
9 V 65 ms compiled
10 Crystal 66 ms compiled
11 D 68 ms compiled
12 Swift 74 ms compiled
13 Perl 93 ms interpreted
14 Bun 94 ms jit
15 Haskell 99 ms compiled
16 Python 105 ms interpreted
17 Ruby 108 ms interpreted
18 PHP 121 ms interpreted
19 Gleam 128 ms compiled/vm
20 Node.js 129 ms jit
21 Kotlin 133 ms jit
22 Deno 146 ms jit
23 F# 149 ms compiled
24 Dart 150 ms compiled
25 C# 154 ms jit
26 Java 155 ms jit
27 Julia 308 ms jit
28 Scala 426 ms jit
29 Elixir 439 ms compiled/vm
30 Erlang 576 ms compiled/vm
Lua 10,300 ms interpreted
xychart-beta
    title "Single-Threaded Performance (ms) - Top 15"
    x-axis [Rust, Go, "C++", Zig, Nim, C, OCaml, Odin, V, Crystal, D, Swift, Perl, Bun, Haskell]
    y-axis "Time (ms)" 0 --> 110
    bar [46, 50, 51, 53, 53, 54, 61, 63, 65, 66, 68, 74, 93, 94, 99]
Loading

Threading Speedup

Language Single Threaded Speedup
Scala 426 ms 210 ms 2.03x
Dart 150 ms 82 ms 1.83x
Elixir 439 ms 266 ms 1.65x
C++ 51 ms 36 ms 1.42x
Nim 53 ms 41 ms 1.29x
Odin 63 ms 50 ms 1.26x
OCaml 61 ms 50 ms 1.22x
Go 52 ms 44 ms 1.18x
Node.js 129 ms 113 ms 1.14x
V 65 ms 58 ms 1.12x
F# 149 ms 136 ms 1.10x
D 68 ms 63 ms 1.08x
Erlang 576 ms 533 ms 1.08x
Swift 74 ms 69 ms 1.07x
Crystal 66 ms 70 ms 0.94x
Haskell 99 ms 106 ms 0.93x
Deno 146 ms 177 ms 0.82x
Perl 93 ms 115 ms 0.81x
xychart-beta
    title "Threading Speedup (multiplier)"
    x-axis [Scala, Dart, Elixir, "C++", Nim, Odin, OCaml, Go, Node, V, "F#", D, Erlang, Swift, Crystal, Haskell, Deno, Perl]
    y-axis "Speedup" 0 --> 2.2
    bar [2.03, 1.83, 1.65, 1.42, 1.29, 1.26, 1.22, 1.18, 1.14, 1.12, 1.10, 1.08, 1.08, 1.07, 0.94, 0.93, 0.82, 0.81]
Loading

Binary Size

Language Size
C 33 KB
C++ 39 KB
Swift 77 KB
Nim 99 KB
Zig 105 KB
V 192 KB
Odin 202 KB
Rust 327 KB
Crystal 426 KB
D 1.1 MB
C# 1.2 MB
OCaml 1.3 MB
Elixir 1.3 MB
Go 1.7 MB
F# 3.2 MB
Kotlin 5.0 MB
Dart 5.2 MB
Scala 6.8 MB
Haskell 18 MB
Bun 58 MB
Gleam 58 MB
Deno 69 MB
xychart-beta
    title "Binary Size (KB) - Compiled Languages"
    x-axis [C, "C++", Swift, Nim, Zig, V, Odin, Rust, Crystal, D, "C#", OCaml, Elixir, Go, "F#"]
    y-axis "Size (KB)" 0 --> 3500
    bar [33, 39, 77, 99, 105, 192, 202, 327, 426, 1100, 1200, 1300, 1300, 1700, 3200]
Loading

Key Findings

  • C++ threaded is fastest overall — 36ms with std::thread
  • Top 6 within 55ms — Rust, Go, C++, Zig, Nim, C all sub-55ms single-threaded
  • Perl is fastest interpreted language — 93ms, faster than Bun JIT!
  • Nim validates "compiles to C" claim — 53ms single-threaded, matches C/Rust
  • Scala has best threading speedup — 2.03x (426ms → 210ms), JVM parallelism shines
  • Dart threading is excellent — 1.83x speedup (150ms → 82ms)
  • Threading helps most compiled languages — 1.1-1.4x speedup typical
  • Threading hurts some JIT/interpreted — Deno (0.82x), Perl (0.81x) slower threaded
  • Elixir benefits from BEAM concurrency — 1.65x speedup despite VM overhead
  • BEAM VM languages are slow for CLI — Erlang 576ms, Elixir 439ms (startup cost)
  • Scala JIT startup is heavy — 426ms mostly compilation overhead
  • Julia has 300ms+ startup — JIT compilation kills CLI performance
  • Binary size varies 2,000x — C (33KB) vs Deno (69MB)

Languages

Compiled JIT/VM Interpreted
C, C++ Bun Lua
Crystal C# Perl
D Deno PHP
Dart Elixir Python
F# Erlang Ruby
Go Gleam
Haskell Java
Nim Julia
OCaml Kotlin
Odin Node.js
Rust Scala
Swift
V
Zig

Most compiled languages have both single-threaded and multi-threaded implementations.

License

MIT