Benchmark

September 20, 2026 · View on GitHub

How Zircolite compares with Hayabusa and Chainsaw, two Rust tools that also run Sigma rules over Windows event logs, on the same logs and the same machine. Each tool runs at its own defaults with its own rules: this is what a user gets out of the box, not a rule-for-rule comparison of the engines.

Results

Test corpus: 4 Sysmon EVTX files, 478 MB, 452,554 events. Median of three timed passes after one warm-up pass, with the range in brackets.

ToolRules loadedWall timePeak memoryDetectionsRules matched
Zircolite4,31911.6 s (11.6–14.4)1,207 MiB149,06988
Hayabusa 4.1.04,658 (2,293 after its channel filter)24.7 s (23.3–25.1)900 MiB589,409132
Chainsaw 2.16.03,524 (388 could not be loaded)113.5 s (92.8–125.5)346 MiB40,84386

Chainsaw's times varied the most between passes; an earlier series on the same machine gave it 100.0 s (97.3–102.9).

Reading the numbers

  • The rule sets differ. Each tool loads its own conversion of SigmaHQ, and Hayabusa adds 181 rules of its own. Hayabusa's own informational and "Sysmon Alert" rules (Net Conn (Sysmon Alert), DLL Loaded (Sysmon Alert), …) match most Sysmon events, and account for most of its fourfold lead in detections. Of its 589,409 hits, 46,783 are informational, 92,205 low and 439,194 medium. Chainsaw loads only the rules its mapping file can express. Detections and rules matched are shown for context. They are not a score.
  • Rules matched are counted by Sigma rule id. Zircolite's merged ruleset carries some rules once per log source, under one id.
  • Memory is the whole process tree. Zircolite picks four worker processes for four large files, and its figure is their sum. Hayabusa and Chainsaw run as one process with several threads. --no-parallel trades Zircolite's speed for a single process.
  • The test corpus holds a single channel, Sysmon. Zircolite and Hayabusa skip the rules written for channels the logs do not contain, about half of each ruleset. A corpus that mixes Security, System and Sysmon logs runs more of them.
  • Zircolite's time includes Python start-up and loading 7.6 MB of rule SQL. On very small inputs that fixed cost dominates; on this corpus it is about a second.

Setup

Apple M1 Max (10 cores, 64 GB), macOS, Python 3.14 and SQLite 3.53 for Zircolite, with the compiled flattening kernel. Logs and outputs on the same internal SSD. Nothing else running.

ToolRules
Zircoliterules/rules_windows_merged.json, the default ruleset, as shipped in rules/ (SigmaHQ, 2026-09-13)
Hayabusa 4.1.0The rules/ directory of its release package, hayabusa-rules fffbdd1 (2026-09-03)
Chainsaw 2.16.0SigmaHQ 2e8fd89 (2026-09-15): rules, rules-emerging-threats and rules-threat-hunting, plus Chainsaw's own rules/, through mappings/sigma-event-logs-all.yml

The commands, as tools/tool-benchmark.py runs them:

# Zircolite
python3 zircolite.py -e TEST_CORPUS/ -r rules/rules_windows_merged.json -o zircolite.json -l zircolite.log

# Hayabusa, from its own directory
./hayabusa dfir-timeline -d TEST_CORPUS/ -w -q -Q -K -C -t jsonl -o hayabusa.jsonl

# Chainsaw, from its own directory
./chainsaw --no-banner hunt TEST_CORPUS/ -s sigma/rules -s sigma/rules-emerging-threats \
    -s sigma/rules-threat-hunting -r rules/ --mapping mappings/sigma-event-logs-all.yml \
    --jsonl -o chainsaw.jsonl

-w only stops Hayabusa asking which rules to load and keeps its defaults (every level, the standard output profile). -q, -Q and -K drop the banner, the error-log files and colour.

Method

The three tools run in turn, and the order rotates on every pass so none of them always follows the same neighbour. The warm-up pass fills the page cache and is not recorded. Each run is timed from launch to exit, and the resident memory of its whole process tree is sampled every 20 ms. Detections are counted from each tool's output after it exits, outside the timed region. A tool whose count changed between passes would have stopped the benchmark; none did.

Reproducing

tools/tool-benchmark.py runs the whole comparison on any logs and writes a JSON report with every pass, each tool's version and loaded rule count, and the commit of every rule checkout:

pdm run python tools/tool-benchmark.py --events /path/to/evtx \
    --hayabusa /opt/hayabusa/hayabusa \
    --chainsaw /opt/chainsaw/chainsaw \
    --chainsaw-sigma /opt/sigma/rules \
    --chainsaw-sigma /opt/sigma/rules-emerging-threats \
    --chainsaw-sigma /opt/sigma/rules-threat-hunting \
    --chainsaw-rules /opt/chainsaw/rules \
    --chainsaw-mapping /opt/chainsaw/mappings/sigma-event-logs-all.yml

See tools/README.md for every option. Zircolite's own before/after measurements, and how to measure its rule phase alone, are under Internals → Measured results.