Benchmarks
These numbers measure progress-go alone. Advance draws to io.Discard, so no output is counted. A whole bar draws
to /dev/null, a character device that both versions treat as a terminal, so each frame costs a write system call,
as it would on a real terminal. With 16 goroutines at once, the time is wall time per call across all of them,
so it measures throughput.
v1 against the untagged version
Section titled “v1 against the untagged version”Both versions ran on the same harness, with the same scenarios. The untagged Bar isn’t safe from many goroutines,
so with 16 at once it runs behind a mutex, as its callers had to.
Show as a table
| Scenario | untagged | v1 |
|---|---|---|
| 1 goroutine | 133.0 ns1 alloc | 1.8 ns0 allocs |
| 16 goroutines at once | 313.2 ns2 allocs | 59.6 ns0 allocs |
| Verbose, 1 goroutine | 23.56 µs13 allocs | 1.8 ns0 allocs |
Apple M4 Max, Go 1.27.0, median of 5 runs.
Show as a table
| Scenario | untagged | v1 |
|---|---|---|
| 1,000 updates | 936.72 µs2781 allocs | 4.26 µs6 allocs |
| 1,000 updates, verbose | 25.02 ms10799 allocs | 4.83 µs8 allocs |
Apple M4 Max, Go 1.27.0, median of 5 runs.
The untagged version redrew the whole line on every Advance, formatting it with fmt and growing the bar by
string concatenation, and a verbose bar called runtime.ReadMemStats, which stops the world, each time.
v1’s Advance is one atomic add. On a terminal a timer redraws the bar ten times a second; a bar of 1,000 fast
updates draws two frames, at Start and at Stop, where the untagged version drew 1,002.
v1’s own suite
Section titled “v1’s own suite”| Benchmark | Time | Memory | Allocations |
|---|---|---|---|
AdvanceOne atomic add | 1.8 ns | 0 B | 0 |
AdvanceParallelOne bar, advanced from 16 goroutines at once | 60.7 ns | 0 B | 0 |
RedrawOne frame on a terminal, in one Write | 44.3 ns | 0 B | 0 |
RedrawVerboseOne verbose frame: heap size and times | 268.9 ns | 0 B | 0 |
BarNew, Start, 1,000 Advances and Stop | 2.00 µs | 848 B | 5 |
Run them yourself
Section titled “Run them yourself”From a clone of the repository:
go test -run '^$' -bench . -benchmemTo compare two versions, run each a few times and compare with benchstat:
go test -run '^$' -bench . -count 10 > new.txtbenchstat old.txt new.txtThe allocation counts are also enforced by tests: TestAllocations fails if a call allocates more than it should.