Chris Collins

Tools · dev

Big-O explorer and benchmark

Compare growth curves, see how big an input fits a time budget, benchmark your own JavaScript to find its complexity class, look things up in a colour-coded Big-O cheat sheet, watch sorting algorithms run, and see where the costs come from: Fibonacci call trees, recursion trees, binary-search halving, and amortised appends — and why attention is O(N²) in context length, what an SSM's O(N) buys, and what a KV cache saves. Then revise for interviews: name the complexity of code snippets, drill data-structure operation costs, and solve recurrences with the master theorem.

Added · updated 29 October 2026

Works with

How to use it

⛶ Full screen (or F) gives the open tab’s picture the whole screen — the growth curves, the benchmark fit, the sorting bars, the Fibonacci call tree or the attention chart — using the browser’s full screen where it is allowed, otherwise a full-window layer (iPhone). The picture is redrawn as tall as the screen allows, with its controls above it; Escape leaves.

Growth curves plots O(1), O(log n), O(√n), O(n), O(n log n), O(n²), O(n³), O(2ⁿ), and O(n!) together, plus two adjustable curves for a growth race: nᵏ (slide k from 1 to 10) and bⁿ (type b, from 1.001 to 3). Tick the classes to compare and pick how far n goes. Switch between linear, log-y (an exponential becomes a straight line) and log-log axes (every power nᵏ becomes a straight line of slope k). With both race curves shown, the tool says where bⁿ overtakes nᵏ for good — for 1.01ⁿ against n³ that is n = 2,339 — comparing n ln b with k ln n so nothing overflows.

Time & budget turns the classes into wall-clock time. Set a speed in simple operations per second (about 10^8 for a JavaScript or C loop, 10^6 for interpreted Python) and a budget; the table gives the largest n each class can handle, and how long each takes at the sizes you list. At 10^9 operations per second, one second is enough for n = 10^9 linear steps, n ≈ 31,600 for quadratic, n = 29 for 2ⁿ, and n = 12 for n!. Factorials and powers are computed with logarithms, so even 1000! has a time (in multiples of the age of the universe). The budget buttons run from 1 ms to 1 year.

Benchmark & fit times real code. Write setup(n) to build the input — it is not timed — and run(input, n), which is. The tool runs in a background worker, for each size repeating run until a batch takes at least 20 ms, and keeps the median of five batches. It then fits time ≈ a + c·g(n) for every class, weighting each point by its relative error, and reports:

  • the best class, with its RMS error — when two classes fit within about 10%, the slower-growing one wins, because an extra log factor can always soak up a little timing noise;

  • the empirical exponent — the slope of log time against log n over the larger sizes, so n^1.02 is linear and n^1.98 quadratic;

  • the fitted model for each class, the raw timings, and a CSV to copy.

Examples cover summing an array, the built-in sort, all-pairs loops, binary search, Map lookups, naive Fibonacci, bubble sort, and matrix multiplication. To get clean results, use a range of n that spans at least two orders of magnitude, and make the work grow with n: a benchmark whose run takes a few nanoseconds is dominated by loop overhead and the JIT. If run changes its input (sorting in place, say), copy it first — every repetition reuses the same input. Stop ends a run early; any size that takes over 20 s stops the run automatically.

Cheat sheet is a colour-coded reference in the style of the well-known Big-O cheat sheet: the complexity chart (operations against elements, from excellent to horrible), then average and worst-case costs of operations on arrays, stacks, queues, linked lists, skip lists, hash tables, BSTs, Cartesian trees, B-trees, red-black, splay, and AVL trees, k-d trees, and tries; heap operations (binary, binomial, Fibonacci, pairing, Brodal); array sorting algorithms (best, average, worst, space, stability); graph algorithms; and other common algorithms. Θ marks the typical bound, O the worst case, Ω the best case. Values follow CLRS and Sedgewick & Wayne. Colours are relative to the problem: O(n log n) is fair for a sort but bad for a single lookup. Type in the search box to filter every table at once.

Sort visualiser animates eleven sorts — bubble, insertion, selection, Shell, quicksort with a naive or median-of-three pivot, mergesort, heapsort, a simplified Timsort, counting, and LSD radix — on random, nearly sorted, reversed, or few-unique data, with play, pause, single-step, speed, and size controls. Comparisons flash yellow, swaps red, and writes orange; the counters show how the totals compare with n log₂ n and n². Try quicksort with the naive pivot on reversed data to see its O(n²) worst case, then switch to median-of-three. ▶ Visualise in the cheat sheet jumps straight to an algorithm.

Fibonacci calls draws the call tree of the naive recursive fib(n) for n from 0 to 12, one node per call, coloured by its argument, so repeated colours are repeated work (fib(5) computes fib(2) three times and fib(3) twice). Tick Memoise and the tree collapses into a single path with short side-branches: a call whose answer is already cached is a small grey leaf that does no work. Animate calls and Step show the calls in the order they happen (depth first). The readout puts the call count beside 2F(n+1) − 1 (naive) and n + 1 (distinct values), and a table carries the race on to n = 40: 242,785 naive calls for n = 25 against 26 computations.

Recursion trees unrolls a divide-and-conquer recurrence level by level, with T(1) = 0: merge sort T(n) = 2T(n/2) + n, binary search T(n) = T(n/2) + 1, and visiting every node of a balanced tree T(n) = 2T(n/2) + 1. Each row is one level, its sub-problems drawn with width proportional to size, and the work done on that level at the right. Merge sort does n work on each of log₂ n levels, so T(n) = n log₂ n exactly when n is a power of 2 (T(16) = 64, T(1024) = 10,240). Other n split into ⌈n/2⌉ and ⌊n/2⌋; very large n (up to 10⁹) are drawn as "pieces × size" per level.

Halving is binary search on a sorted array of n items, n from 1 to 10¹² (type it, 1e9 works, or use the slider). The top strip is the whole array with the target in red; each row below is the range before one comparison, split at its middle, with the kept half coloured. Search animates it; Step goes one comparison at a time. Beside it are the comparisons used, log₂ n, ⌈log₂ n⌉, the bits needed for n (⌊log₂ n⌋ + 1, computed exactly, not with floating-point logs), and the height ⌊log₂ n⌋ of a balanced tree holding n keys: all "how many times can you halve n?", give or take one. Below: the in-your-head estimate (write n ≈ m × 1000ʲ, then log₂ n ≈ 10j + log₂ m, so 64 million ≈ 26) and the height log_B n of a B-tree with branching factor B.

Amortised append appends n items to a dynamic array that starts with a given capacity and, when full, either grows by a factor g (×2 like Java’s ArrayList, ×1.5 like many C++ libraries, ×1.125 like CPython; the new capacity is ⌈g × capacity⌉, at least one more) or by a constant number of slots. Every element written counts, copies included. The bars are the cost of each append, with the spikes at resizes and the running average; the accounting view charges each append a fixed number of tokens (3 for doubling, 1 + g/(g − 1) in general, 3 for a constant increment) and plots what is left in the bank. With geometric growth it never goes negative; with a constant increment it soon does, because the copying is quadratic. The table repeats the book’s run for n = 10, 1,000 and 1,000,000 under the current rule (25, 2,023 and 2,048,575 writes with doubling). Up to 10⁷ appends are counted; the charts show the first 2,000.

Attention & KV cache is the same arithmetic applied to language models. Attention vs SSM plots the work per layer over a context of N tokens: self-attention scores every pair of tokens (N²), a state-space model such as Mamba updates a fixed-size state once per token (N); the table shows what doubling the context does (×4 against ×2). KV cache: cumulative work counts the work of generating N tokens one at a time, where step i sees i tokens. Without a cache every step recomputes the keys and values of all earlier tokens: 1 + 2 + … + N = N(N+1)/2 projections, O(N²), and recomputing the whole causal attention each step adds up to N(N+1)(N+2)/6, O(N³). With a cache each step projects one new token, N in all, O(N), but still scores its query against every cached key, so attention stays Σ i = O(N²) — the cache removes the recomputation, not attention’s quadratic cost. Both charts are log-log.

Revision is for interview preparation, in five parts (pick one at the top):

  • Complexity quiz (quiz) shows one of 58 short pieces of JavaScript, Python, Java or pseudo-code and asks for its time and its extra space, each from four choices — the wrong options include the usual mistake for that snippet. Space means memory beyond the input; the call stack counts, the output only when the snippet builds it. After both answers comes the explanation. The snippets cover plain and nested loops, doubling and halving loops, loops that look quadratic but are not (a geometric inner loop, the harmonic series, a pointer that never resets), recursion (Fibonacci with and without memoisation, merge sort, binary search, halving recursions, permutations and subsets), amortised costs (dynamic-array appends, a queue from two stacks, a monotonic stack, union-find) and traps such as string concatenation in a loop, in on a list, slicing inside recursion and shift() in a loop. Pick a topic to practise just one kind.

  • Operation costs (drill) asks the average or worst-case cost of one operation at a time on a dynamic array, singly and doubly linked lists, a hash map, a binary heap, an unbalanced and a balanced binary search tree, a trie, union-find with path compression and union by rank, and a graph stored as adjacency lists or as a matrix. The answers agree with the cheat sheet; the whole table is underneath.

  • Master theorem (master) solves T(n) = a·T(n/b) + f(n) for f(n) = Θ(nᵏ logᵖ n): it compares f(n) with n^(log_b a), names the case (with the extended second case for log factors, and the regularity condition in case 3) and gives the result. A recursion tree shows six levels — the number of sub-problems on each and the level’s total work relative to the root — so you can see the work grow towards the leaves (case 1), stay level (case 2) or shrink below the root (case 3). It says when the theorem does not apply (a < 1, b ≤ 1).

  • Recurrences (recs) lists sixteen that come up again and again — binary search, merge sort, Karatsuba, Strassen, Towers of Hanoi, naive Fibonacci, quicksort’s worst and average case, T(n) = T(√n) + 1 and others — with the solution and the method; Solve ▸ opens those of the master-theorem form in the solver.

  • Score (score) counts right answers in the quiz and the drill, your current and best streak, and accuracy by topic with the weakest first. It is kept in this browser; Reset score clears it.

Limits

  • The call tree is drawn up to n = 12 (465 calls); the counts table goes further with formulas.

  • The recursion tree draws individual sub-problems when a level has at most 64 of them.

  • Halving takes n up to 10¹² (JavaScript numbers are exact integers there).

  • Amortised append counts up to 10⁷ appends, growth factors from 1.01 to 4.

  • Attention & KV cache counts operations up to a constant factor (head dimension, heads, layers) for N up to 10⁷ tokens; it is the shape of the growth, not a timing.

  • The master-theorem solver takes polynomial-times-log driving functions only, f(n) = nᵏ logᵖ n; the recursion-tree picture shows the first six levels.

Related: graphing (plot your own growth functions), floating point, boolean logic, AI hardware calculator (the KV cache in bytes), softmax and attention.

The Attention & KV cache tab is a companion to AI Acceleration: From Transistors to Trillion-Parameter Models: why the KV cache’s savings compound (Part III) and beyond the transformer: state-space models (Part XVIII).

Sharing

Share link copies a URL that opens this tool exactly as you have it. Hand-written links work too: Each tab shares its own settings: Growth curves ?classes=n,nlogn,n2&n=1000&log=1, Time & budget ?ops=&budget=&sizes=, Cheat sheet ?q=heap, Sort visualiser ?algo=merge&data=reversed&size=80. A shared benchmark fills in the code but only runs when you press Run benchmark. For example ?algo=heap&data=nearly&size=100#vis.

Linking to an example

Every tab can be opened from a link written by hand. Put the tab after : growth, time, bench, ref, vis, fib, tree, halve, amort, seq or rev. Without a , the tab that owns the parameters opens. Numbers may be written 1e9, 64e6 or 1_000_000.

Parameter Meaning Example

example

one of the book’s examples, below; parameters written beside it override it

example=ch14-fib-memo

classes

growth curves shown: 1, logn, sqrtn, n, nlogn, n2, n3, 2n, nfact, nk, bn

classes=n,nlogn,nk,bn

n

growth: largest n; fib: the call fib(n), 0–12; tree: problem size; halve: array size, 1–10¹²; amort: number of appends; seq: tokens N, 2–10⁷

n=4000

log, axes

growth axes: log=1 is log y; axes=lin, semi or loglog

axes=loglog

k, b

growth race: the power in nᵏ (1–10) and the base of bⁿ (1.001–3)

k=3&b=1.01

ops, budget, sizes

time & budget: operations per second, budget in seconds, sizes to time

ops=1e9&budget=3600

code, lo, hi, count, scale

benchmark: code, size range, number of sizes, geometric or linear

lo=1000&hi=1e6

q

cheat sheet search

q=heap

algo, data, size

sort visualiser: algorithm, random/nearly/reversed/few, element count

algo=merge&data=reversed

memo

fib: 1 to memoise

memo=1

rec

tree: merge, bsearch or visit

rec=bsearch

t

halve: target position as a fraction of n, 0–1

t=0.37

B

halve: B-tree branching factor

B=500

g

amort: growth factor

g=1.5

inc

amort: grow by this many slots instead (a constant increment)

inc=100

cap

amort: starting capacity

cap=1

view

seq: attn (attention against an SSM) or kv (cumulative work with and without a KV cache)

view=kv

rev

revision: the part to open — quiz, drill, master, recs or score

rev=drill

ma, mb, mk, mp

revision, master theorem: a, b, and f(n) = n^mk log^mp n in T(n) = a·T(n/b) + f(n)

rev=master&ma=3&mb=2&mk=1

Examples from Mathematics, Reconnected (?example=…):

Name Shows

ch03-growth-curves

n to n! on a log axis (chapter 3’s growth race)

ch03-race-second, ch03-race-hour, ch03-race-year

the largest n each class handles at 10⁹ steps per second in a second, an hour, a year

ch12-growth-race

log n, n, n log n, n³ and 1.01ⁿ to n = 4000 on a log y-axis: 1.01ⁿ overtakes n³ near 2,340

ch12-growth-loglog

the same race on log-log axes

ch12-halving

the halving explorer on a million items

ch12-billion

a billion items: 30 comparisons

ch12-log-estimate

log₂ of 64 million in your head: 26 (exact 25.93)

ch12-btree

a B-tree with B = 500 holds a billion keys in about 3.3 levels

ch12-merge-sort

merge sort on 64 items: log₂ n levels of n work

ch14-dynamic-array

1,000 appends with doubling: 2,023 writes

ch14-dynamic-array-10

10 appends: 25 writes

ch14-grow-by-100

growing by a fixed 100 slots: quadratic copying

ch14-grow-1.5

growth factor 1.5

ch14-merge-sort

T(n) = 2T(n/2) + n for n = 16: 64 = 16 log₂ 16

ch14-binary-search

T(n) = T(n/2) + 1 unrolls to log₂ n

ch14-tree-visit

T(n) = 2T(n/2) + 1 sums a geometric series to n − 1

ch14-fib-5

the call tree of naive fib(5), as in the book’s figure

ch14-fib-naive

naive fib(10): 177 calls

ch14-fib-memo

memoised fib(10): a single path with short side-branches

Examples from AI Acceleration (?example=…):

Name Shows

p18-attention-vs-ssm

attention’s N² against an SSM’s N up to 128K tokens: doubling the context is ×4 against ×2 (open)

p18-n2-vs-n

O(N²) and O(N) to a million on the growth chart, log-log (open)

p03-kv-cache-work

generating 5,000 tokens: 12,502,500 K/V projections without a cache, 5,000 with one; attention 2.1 × 10¹⁰ against 1.25 × 10⁷ (open)

p03-kv-cache-50

50 tokens: 1,275 projections against 50 (open)

Revision examples (?example=…):

Name Shows

rev-quiz

the complexity quiz on code snippets (open)

rev-drill

the drill on data-structure operation costs (open)

rev-master-merge

merge sort, T(n) = 2T(n/2) + n: case 2, Θ(n log n) (open)

rev-karatsuba

Karatsuba, T(n) = 3T(n/2) + n: case 1, Θ(n^(log₂ 3)) ≈ Θ(n^1.585) (open)

rev-strassen

Strassen, T(n) = 7T(n/2) + n²: case 1, Θ(n^(log₂ 7)) ≈ Θ(n^2.807) (open)

rev-case3

T(n) = 2T(n/2) + n²: case 3, the root dominates, Θ(n²) (open)

Runs entirely in your browser; nothing you type leaves this page.