Suites split into benchmarks/files/{lines,words} and
benchmarks/stdin/piping, with the monsters bolted onto the lines suite:
100M lines raced against coreutils (~2x win), 1B lines solo (~6-8s,
11 GB in one pass). Stdin redirects from regular files are now mmap'd
in count_stream, so the stdin suite wins too — up to 12.00x on words.
The ratio column now reports how many times faster fastwc is, not how
much of GNU's time it used. busybox was removed from the suite: it
stopped being a challenge and started being a participation trophy.
GNU wc's lone win — 1M lines by one millisecond on hand-tuned AVX-512
assembly — is now a historical footnote, and the README says so.
4.1 KiB
4.1 KiB
fastwc Style Guide
The style is the law. GNU wc can afford to look like a committee designed it — it was. We're one file, one purpose, one opinion.
The language
- C99 with POSIX.
_POSIX_C_SOURCE 200809L. We target the standard, not a compiler vendor's mood. - Zero warnings with
-Wall -Wextra. A warning is a bug you haven't fixed yet. Fix it. - No compiler-specific extensions unless they're guarded and the
benchmark gets faster because of it.
__builtin_popcountllis the one exception — it's the price of admission on every compiler that matters, and the benchmark proves it.
Format
- 4 spaces. Not tabs, not 8 spaces. GNU uses tabs because GNU was written in 1985 by people who had strong opinions about typewriters.
- 80 columns. If your line is longer, your idea is longer than it needs to be.
- Braces on the next line (Allman). Everywhere. Functions, blocks, switch cases. Consistency is the only religion here, and we're devout.
- Snake case for everything.
count_stream,ws_tab,nread. No CamelCase — that's for languages that need help knowing what a word is.
Structure
- One file:
src/main.c. See CONTRIBUTING.md rule 6. This is not a suggestion. - Everything is
static. The binary exports nothing. We're not a library, we're a verdict. - Types end in
_t.counts_t, and not much else. GNU has a type for everything and a committee to name it. We have counts, and we count. - No globals except what's truly process-wide.
flagsandws_tablive at file scope because they're the program's identity. Everything else gets passed around like it's hot.
The hot path
count_stream(), count_newlines(), count_words(), and the SIMD
kernels (count_lw_avx512, count_lw_avx2, count_lw_sse2) are the
product. The rest of the file is just the packaging.
- Fixed stride. No per-token function calls. No
isspace()in a loop — that's what the lookup table is for. - No allocation, no locks, no syscalls in the counting loop. The
kernels are pure; parallel slices need no locks. The
fread(or the singlemmap) is the only syscall, and it's not yours to add to. - Branchless where it costs nothing. A predictable branch is fine; a mispredicted one is a lie you told the CPU.
- Regular files are mapped, not streamed. The kernel hands us the
pages; we count them, split across cores for anything past 8 MiB.
This includes stdin redirects from regular files. Real pipes, ttys,
and the
-mpath fall back to thestatic, 128 KiB buffer that never grows.
Counts
long longfor everything that counts. Files can be bigger than your opinions. Signed, because overflow should scream, not wrap.- Lines are
'\n's. Not "lines of text," not "records." A file without a trailing newline has fewer newlines than it has lines, and that's correct. GNU agrees with us on this one, so it must be right. - Words are whitespace-delimited runs. The lookup table decides what whitespace is; the popcount decides how many words; you don't get an opinion.
Errors
fastwc: <file>: <message>on stderr, and keep going. GNU wc fails gracefully across multiple files, and we'll credit them that one thing. Then we'll be faster at it.- Exit 1 if anything failed, 0 otherwise. No drama, no
EXIT_FAILUREpoetry.
Comments
- Only when the code can't speak for itself. The SWAR newline
counter in
count_newlines()gets a comment because(x ^ nl) & clis a sentence in a language you don't speak yet.i++does not get a comment. - No commented-out code. The dead don't get to live in the file.
- No TODO without a date. A TODO without a date is a promise you plan to break.
What the style is not
- It is not GNU's style. GNU's style was written by a committee, ratified by a foundation, and translated into fourteen languages.
- It is not "whatever your editor defaults to." Your editor has opinions. So do we. Ours are right.
- It is not negotiable in review. If a PR violates the style, the PR is a rewrite request with extra steps.