# poop: Linux performance benchmarking with hardware counters via perf_event_open

> poop is an MIT-licensed command-line tool written in Zig that compares multiple commands using Linux's perf_event_open interface, reporting peak memory usage alongside 5 hardware counters. It deliberately skips shell execution to eliminate spawning noise from measurements.

**andrewrk/poop** — Performance Optimizer Observation Platform

- Repository: https://github.com/andrewrk/poop
- Stars: 2,046 · Forks: 94
- Language: Zig
- License: MIT
- Published: 2026-10-09 · Updated: 2026-10-09 · Language: en
- Canonical page: https://hysenlabs.com/projects/andrewrk-poop

## perf_event_open exposes cache misses and branch behavior that wall-clock tools miss entirely

Most performance comparison tools measure time. poop measures time and reads hardware performance counters from the Linux kernel through perf_event_open, the system call that performance profilers use to query the CPU's built-in event counters.

The data poop reports includes peak memory usage and 5 hardware counters. Their exact names are not listed in the project documentation. Those data points reveal different things than elapsed time. A command that takes the same wall-clock duration on 2 runs but has different counter values is behaving differently at the CPU level, and hardware counter data points toward the cause in a way that timing alone cannot.

For someone comparing a naive implementation against an optimized one, peak memory and hardware counters turn a timing difference into a question that can be answered: is the faster version faster because it misses fewer caches, because it executes fewer instructions, or both? Wall-clock time shows the effect; hardware counters show part of the mechanism.

poop presents all of this in a colorful terminal interface. The first command is the reference, and the remaining commands show their data as deltas relative to that reference. Coloring signals whether each subsequent command improved or worsened relative to the reference, and because the first argument determines the reference, the user controls the direction of that comparison by choosing argument order.

## poop does not spawn a shell, which removes shell startup time from measurements but blocks quoted arguments

poop executes commands as processes directly rather than launching them through a shell interpreter. Shell startup time does not appear in the measurements. For programs that run in milliseconds, shell startup can be a noticeable fraction of the total, and excluding it from both samples removes a systematic offset from the comparison.

Shell features are unavailable as a consequence. Quoted strings, environment variable expansion, and shell-specific syntax cannot be used in poop arguments. A command like 'grep "search term" file.txt' has spaces inside an argument, which poop cannot handle without a shell to tokenize it. Comparisons that require shell syntax must use a different tool.

Hyperfine offers both modes: shell execution on by default, with an option to turn it off. poop has no such option; direct execution is the only mode. For commands with no shell dependencies, that makes no difference. For commands with glob patterns or pipes, poop cannot run them.

This also affects cross-tool comparisons. A poop number and a Hyperfine number for the same command differ if Hyperfine was in shell mode. Subtracting the 2 numbers without accounting for that difference produces a meaningless delta.

## Building from source requires Zig 0.15.1 and a single command

poop is written in Zig and must be built from source. Zig 0.15.1 is the tested version. After cloning the repository, the build step is:

```
zig build
```

The repository root holds build.zig and a src/ directory, which is the standard layout for a Zig project. The build.zig file configures the compilation, and zig build handles it without additional flags for a default build.

Zig 0.15.1 is a specific version requirement. Zig's language and standard library API change between releases, and a Zig build system file written for one version will not always compile correctly on another. The README states which version was used for testing rather than which versions are supported, so users on a different Zig version will need to check whether the build succeeds before relying on the binary.

The repository has no prebuilt binaries. Installation requires a working Zig toolchain.

## The --duration flag sets the sampling window; the default is 5,000 milliseconds

poop has one configurable option documented in the README: the --duration flag, which sets how long to repeatedly sample each command before reporting results. Its default value is 5,000 milliseconds, or 5 seconds per command.

The full usage:

```
poop [options] <command1> ... <commandN>
```

A shorter duration produces fewer samples and wider variance on the reported values. A longer duration narrows that variance at the cost of time spent waiting. For quick sanity checks, reducing the duration makes sense. For results you intend to act on, the 5-second default gives poop enough samples to smooth over noise.

The README documents no other options, which means there is no flag for warmup runs, no option to control the number of command iterations explicitly, and no output format selection. What poop shows is always the TUI table of deltas, and the only output control the user has is through the duration setting and the choice of which command to put first as the reference.

## The first command is always the reference; removing a command changes what the deltas mean

poop assigns a fixed role to command ordering. The first command in the invocation is always the reference baseline. Every subsequent command's values are expressed as deltas relative to that first command, and the coloring reflects whether each counter improved or worsened.

This design puts a specific responsibility on the user: choosing which command goes first determines what the comparison is actually measuring. If you put the slow implementation first and the fast one second, you see how much the fast one improves. Swap the order and the deltas invert. Neither output is wrong, but they answer different questions.

Hyperfine handles this differently. Hyperfine's default is to print the fastest command first, with an option to change which command serves as the reference. poop has no such flag. Reordering the arguments is the only mechanism for changing the baseline.

For a two-command comparison, that distinction barely matters. For a comparison across several implementations where the reference changes depending on which question is being asked, re-running with a different argument order is the only mechanism.

## Hyperfine is cross-platform and has more options; poop is Linux-only with a simpler interface

A Hyperfine comparison section appears in the project documentation. Hyperfine is the older and more mature tool, with more configuration options and more polish. poop's differentiator is the hardware counters: peak memory and 5 hardware counters that Hyperfine does not report. The documentation notes this data might inspire the Hyperfine maintainers to add those counters, but as of the writing in that section, they were absent from Hyperfine.

Cross-platform support is the clearest capability difference. Hyperfine runs on Linux, macOS and Windows. poop uses perf_event_open, which is Linux-specific, so it does not run on macOS or Windows at all.

Shell execution is another axis. Hyperfine runs commands in a shell by default and provides a flag to disable that. poop never uses a shell. That makes Hyperfine the tool when the commands contain shell syntax, and poop the tool when shell startup noise must be excluded.

For users already on Hyperfine who want hardware counter data, the practical path is to add poop alongside it rather than replace one with the other. They measure overlapping things but with different defaults and different scope.

## MIT licence, latest release 0.5.0 from September 2024, and last push on 2026-05-04

poop is distributed under the MIT licence, which allows modification and redistribution with the licence notice preserved. The LICENSE file at the repository root contains the full text.

Release 0.5.0 was published on 2024-09-06, release 0.4.0 on 2023-06-22, and 0.3.0 on 2023-06-16. Those 3 public releases mark the tagged versions in the project's history. The last push to the repository was on 2026-05-04.

Building from source means upgrade cost is a git pull followed by zig build. There is no package manager integration for poop mentioned in the README, and no binary distribution beyond what a user compiles. Anyone who pins to a release can revert to a previous tag by checking it out and rebuilding.

poop describes itself as brand new in its documentation, contrasting with Hyperfine's maturity. The single --duration option and the absence of output format selection reflect a tool at an early stage of its scope decisions. Anyone who needs poop to export its counter data to a file or another format will find no such option in the 0.5.0 release.

## Conclusion

Use poop if you are benchmarking on Linux and care about what is happening below wall-clock time: cache misses, branch mispredictions, and peak memory are the data that help you understand why one implementation is faster than another, not just that it is. The install is a single zig build, and a first run takes the form poop 'command-a' 'command-b'. Skip it if you need cross-platform support, shell-interpolated arguments, or a stable API; those three gaps exist in the 0.5.0 release. If you are already using Hyperfine and it gives you enough information, poop adds hardware-counter columns at the cost of a Linux-only tool with fewer knobs.

## FAQ

### What does poop benchmark?

poop compares multiple commands by running them repeatedly using Linux's perf_event_open interface, then reports peak memory usage and 5 hardware counters alongside timing, displayed as deltas relative to the first command.

### How do I build poop from source?

Clone the repository and run zig build. The README states the project was tested with Zig 0.15.1. There are no prebuilt binaries.

### Does poop work on macOS or Windows?

No. poop uses Linux's perf_event_open system call, which is Linux-specific. The README explicitly notes that while Hyperfine is cross-platform, poop is Linux-only.

### How is poop different from Hyperfine?

poop reports peak memory usage and 5 hardware counters from the CPU, which Hyperfine does not. Hyperfine is cross-platform, has more configuration options, and runs commands in a shell by default; poop is Linux-only, skips shell execution entirely, and has a single --duration flag.

### How long does poop sample each command?

By default, poop samples each command for 5,000 milliseconds. The --duration flag accepts a value in milliseconds to change that window.

## Sources

- [andrewrk/poop on GitHub](https://github.com/andrewrk/poop)
- [Issues](https://github.com/andrewrk/poop/issues)
- [License: MIT](https://github.com/andrewrk/poop/blob/main/LICENSE)
- [README](https://github.com/andrewrk/poop/blob/main/README.md)
- [Releases](https://github.com/andrewrk/poop/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/andrewrk-poop
