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.
140 lines
5.1 KiB
Markdown
140 lines
5.1 KiB
Markdown
# Contributing to fastwc
|
|
|
|
We're building the word counter GNU wc is still trying to be after forty
|
|
years. If that sounds like your kind of project, keep reading.
|
|
|
|
## The rules
|
|
|
|
These aren't guidelines. They're the deal.
|
|
|
|
### 1. The benchmark is the contract
|
|
|
|
`./benchmarks/test-all.sh` must pass. Not "mostly pass." Not "pass on
|
|
your machine." Pass. Every suite — words, lines (monsters included),
|
|
and stdin — races fastwc against GNU wc.
|
|
|
|
The moment fastwc is slower than GNU wc — or disagrees with it on a
|
|
single count — your change does not ship. We did not spend this much
|
|
effort being faster than a forty-year-old dependency museum just so you
|
|
could add a `strlen()` in the hot loop.
|
|
|
|
The old standing exception — the 1M-line case, where GNU's hand-tuned
|
|
AVX-512 assembly squeaked out a one-millisecond win — is closed. We
|
|
beat them there too now (see docs/PERFORMANCE.md). There are no
|
|
exceptions left, and there is no excuse to be slower anywhere else.
|
|
|
|
### 2. C99, or don't bother
|
|
|
|
We compile with `-Wall -Wextra` and zero warnings. Zero. If the compiler
|
|
is complaining, the compiler is right and you are wrong. We target C99
|
|
with POSIX extensions, not whatever your compiler vendor's imagination
|
|
happens to ship this quarter.
|
|
|
|
### 3. No new dependencies. Ever.
|
|
|
|
The C standard library is the only thing we trust. No gettext. No gnulib.
|
|
No `libutf8pro` with its own translation team. GNU wc needs a build
|
|
system the size of a small country to count newlines. We need `cc`.
|
|
|
|
If your feature needs a library, the feature is too big. Make the
|
|
feature smaller.
|
|
|
|
### 4. The hot path is sacred
|
|
|
|
`count_stream()`, `count_newlines()`, `count_words()`, and the SIMD
|
|
kernels in `src/main.c` are the entire point of this project. You may
|
|
touch them only if `./benchmarks/test-all.sh` still passes afterward.
|
|
Rules for the counting loops:
|
|
|
|
- fixed stride, no per-token function calls
|
|
- no allocation, no locking, no syscalls — the read is the only syscall
|
|
- branchless where it costs nothing; lookup tables are the foundation,
|
|
not a hack
|
|
- if you make it "clearer" but 2x slower, it's not clearer, it's worse
|
|
|
|
### 5. Never suppress the truth
|
|
|
|
No casts to silence warnings. No `-Wno-*` flags to make the noise go
|
|
away. No `void*` where a real type exists. If the type system is
|
|
fighting you, you're fighting the design. Fix the design.
|
|
|
|
### 6. The codebase is one file. Keep it that way.
|
|
|
|
`src/main.c` is one file and it will stay one file. GNU wc needs
|
|
forty-two translation units and a build system with its own mailing
|
|
list. We have one file and we can read all of it in one sitting. If your
|
|
feature needs a new file, your feature is over-engineered.
|
|
|
|
### 7. Tests are the benchmarks
|
|
|
|
There is no separate test suite, because the benchmark *is* the test
|
|
suite — it checks correctness against GNU wc (the only oracle around,
|
|
and it's wrong often enough to keep us humble) and speed in the same
|
|
breath. Add a flag? It gets benchmarked. Change the counting? It gets
|
|
benchmarked. The fail-fast scripts in `benchmarks/` are your tests, and
|
|
all of them must pass before you open a PR.
|
|
|
|
### 8. No AI slop
|
|
|
|
If it looks like ChatGPT wrote it, it gets rejected. We can tell. Write
|
|
code like a human who's been doing this for a decade and is tired of
|
|
GNU's excuses.
|
|
|
|
## How to contribute
|
|
|
|
### Pick something
|
|
|
|
Good first issues:
|
|
|
|
- Benchmark case coverage for `-m` and multiple files
|
|
- Move the 1B-line monster behind a flag so quick CI runs stay quick
|
|
|
|
Ambitious issues:
|
|
|
|
- A word counter that doesn't just beat GNU — it embarrasses it
|
|
- Wider strides, less patience, and a 10B-line monster
|
|
|
|
### Send a PR
|
|
|
|
1. Fork the repo
|
|
2. Create a branch: `feat/my-thing` or `fix/my-bug`
|
|
3. Write code that follows the rules above
|
|
4. Run `./benchmarks/test-all.sh` — everything must pass
|
|
5. Open a PR against `main`
|
|
|
|
### PR requirements
|
|
|
|
- Build must pass with zero warnings: `make && make release`
|
|
- Benchmarks must pass: `./benchmarks/test-all.sh`
|
|
- Follow [STYLEGUIDE.md](STYLEGUIDE.md). The style is the law.
|
|
- No commented-out code. No dead code. No TODO without a date.
|
|
- Commit messages in imperative: `Count newlines in 8-byte strides` not
|
|
`Added newline counting optimization`
|
|
|
|
## What we won't merge
|
|
|
|
- **Anything slower than GNU wc.** We didn't come this far to tie.
|
|
- **Dependencies.** If it needs a library, it needs to not need a library.
|
|
- **GNU-style bloat.** Long options with help strings in fourteen
|
|
languages. Translation infrastructure. "Enterprise" anything. This is
|
|
a word counter, not a CRM.
|
|
- **Abstract nonsense.** Three layers of indirection to add a feature
|
|
means the feature is too complicated. GNU wc is what happens when you
|
|
let abstractions win.
|
|
- **AI slop.** See rule 8.
|
|
|
|
## Communication
|
|
|
|
We don't have a Discord. We don't have a forum. We don't have a mailing
|
|
list with a code of conduct and a weekly digest. Open an issue. Write a
|
|
clear title, a reproduction case, and what you expected. We'll respond
|
|
when we respond.
|
|
|
|
If you want to propose a major feature, open an issue first. Surprise
|
|
PRs that rewrite the counting loops get closed without review — the
|
|
benchmark is the referee, and it doesn't know you.
|
|
|
|
---
|
|
|
|
fastwc is 0.1.0. Everything is subject to change except the rules above.
|