
# Benchmarks

Das Repository enthält einen Benchmark-Harness unter `bin/` und `benchmarks/`. Er misst jeden Suchmodus anhand realer Korpora (WordPress, Laravel) und generierter synthetischer Datensätze, erfasst strukturierte Berichte und ermöglicht den Vergleich zweier Berichtsreihen.

Der Harness ist Teil des Repositorys, nicht des Composer-Pakets: Seit 0.2.3 sind `benchmarks/` und die `bin/bench*`-Skripte nicht mehr im Paket enthalten. Führe sie daher in einem geklonten Repository aus (`git clone https://github.com/inline0/greph && cd greph && composer install`).

Die veröffentlichten Zahlen in der [README](https://github.com/inline0/greph#performance) stammen aus GitHub Actions-Läufen, niemals von lokalen Rechnern. Lokale Läufe eignen sich zum Ausprobieren; maßgeblich sind die CI-Läufe.

## Korpora

Die synthetischen Korpora (`synthetic-1k`, `synthetic-10k`, `synthetic-100k-single`) werden beim ersten Lauf unter `benchmarks/corpora/synthetic/` generiert. Die realen Korpora sind nicht enthalten: Lege einen Checkout unter `benchmarks/corpora/wordpress` oder `benchmarks/corpora/laravel` ab (der CI-Workflow klont `WordPress/WordPress` mit `--depth=1`). Korpora mit fehlendem Verzeichnis werden übersprungen.

## Benchmarks ausführen

```bash
# Full benchmark suite, every corpus that is present
./bin/bench

# Specific category (the category names used in benchmarks/suites/)
./bin/bench --category text
./bin/bench --category ast

# Compare against external tools when available
./bin/bench --compare rg,grep
./bin/bench --compare sg

# Choose a corpus
./bin/bench --corpus wordpress
./bin/bench --corpus laravel
./bin/bench --corpus synthetic-1k

# Write the run as JSON
./bin/bench --corpus wordpress --output build/run-1.json

# Measured series: 5 runs after 1 warmup run
./bin/bench-series --repeat 5 --warmup 1 --corpus wordpress --output build/head-series.json

# Aggregate separate runs into one series
./bin/bench-aggregate --output build/head-series.json build/run-*.json
```

`bin/bench-compare base-series.json head-series.json` vergleicht zwei Reihen von Dateien (die Ausgabe von `bench-series` oder `bench-aggregate`) und gibt eine Markdown-Zusammenfassung aus, die bei der Optimierung eines Hot Paths hilfreich ist. `bin/bench-ci` löst den Benchmark-Workflow in GitHub Actions über den `gh`-CLI aus.

## Kategorien

Die README veröffentlicht Ergebnisse aus acht Gruppen, die jeweils eine bestimmte Ebene der Engine messen. Jede Gruppe umfasst eine oder mehrere Harness-Kategorien, die in `benchmarks/suites/` definiert sind.

### Scan-Modus: Text

Native Textsuche mit literalen, Regex- und kombinierten Mustern. Die veröffentlichte Baseline läuft auf dem WordPress-Korpus und umfasst:

- Literales `function`
- Literales, ohne Beachtung der Groß- und Kleinschreibung
- Literales ganzes Wort
- Neue Regex-Instanz
- Regex-Array-Aufruf
- Literales Regex-Präfix
- Literales Regex-Suffix
- Literale Regex-exakte Zeile
- Zusammengefasstes Regex-Literal

### Scan-Modus: Traversierung

Nur Dateiverzeichnisdurchlauf, keine Suche. Misst die Kosten des gitignore-bewussten Verzeichnisdurchlaufs für sich allein.

### Scan-Modus: Paralleler Text

Eine Feststringsuche nach `function` mit `1`, `2` und `4` Jobs. Bei diesem Muster startet der Worker-Pool erst ab `jobs * 4_000` Dateien (siehe [Parallele Worker](https://greph.inline0.dev/de/docs/advanced/parallel)). Das sind mehr Dateien, als das WordPress-Korpus enthält. Daher laufen alle drei veröffentlichten Zeilen in einem einzelnen Prozess und zeigen keine Skalierung des Pools ([#8](https://github.com/inline0/greph/issues/8)).

### Scan-Modus: AST

Native AST-Suche mit repräsentativen Mustern:

- `new $CLASS()`
- `array($$$ITEMS)`

### Indexierter Textmodus

Aufgewärmte indexierte Textsuche mit denselben Mustern wie im Scan-Modus. Umfasst Abfragen nach Literalen, ohne Beachtung der Groß- und Kleinschreibung, nach ganzen Wörtern, kurzen Tokens und Regex.

### Indexierte Zusammenfassungsabfragen

Aufgewärmte indexierte Textsuche mit Ausgaben für Trefferanzahl, Dateien mit Treffern und Dateien ohne Treffer. Diese Abfragen profitieren am meisten vom Postingspeicher, da die Arbeit pro Datei am geringsten ist.

### Indexiertes / zwischengespeichertes AST

Aufgewärmte Suche nach AST-Fakten und zwischengespeicherte AST-Suche mit denselben Mustern wie im AST-Scan-Modus.

### Build-Kosten

Kosten für den Kaltstart beim Erstellen des Trigrammindex, des AST-Faktenindex und des AST-Caches. Hilfreich bei der Entscheidung, welcher Modus für eine bestimmte Arbeitslast gepflegt werden soll.

## Veröffentlichte Zahlen lesen

README veröffentlicht für jede Baseline eine Momentaufnahme des letzten CI-Laufs. Jeder Abschnitt stammt aus einem bestimmten GitHub Actions-Lauf und ist mit dem Korpus, dem Runner, der PHP-Version sowie der Anzahl der Messungen und Aufwärmläufe gekennzeichnet. Wenn du einen Wert reproduzieren möchtest, verwende lokal dieselbe Kombination.

Die Vergleichsspalten (`rg`, `grep`, `sg`) werden im selben Job, auf demselben Runner und mit demselben Korpus erfasst. Sie werden nicht aus externen Benchmarks hochgerechnet.

## Benchmark hinzufügen

1. Füge unter `benchmarks/` eine Benchmark-Definition hinzu.
2. Füge der Regressionstest-Suite ein entsprechendes Szenario hinzu, sofern es noch kein gleichwertiges gibt (damit auch das gemessene Verhalten überprüft wird).
3. Führe `./bin/bench --category <yours>` aus, um den neuen Benchmark zu validieren.
4. Vergleiche ihn mit `main` mithilfe des Benchmark-Workflows. Dieser läuft bei Pull Requests, die `src/`, `benchmarks/` oder `bin/` betreffen, und veröffentlicht in der Laufzusammenfassung einen Vergleich zwischen aktuellem Stand und Basis.
5. Aktualisiere die README-Tabelle, sobald der CI-Lauf mit dem neuen Benchmark auf `main` abgeschlossen ist.

## Grundsätze zur Performance

Greph will ripgrep oder grep bei kalten Scans nicht übertreffen. Ripgrep ist in Rust mit handoptimiertem SIMD-Literal-Scanning implementiert. Den veröffentlichten Zahlen zufolge sind sowohl `rg` als auch GNU `grep` bei jedem kalten Textscan schneller als Greph. Die Ziele sind andere:

- Schnell genug sein, damit sich die interaktive Nutzung und Agentenschleifen natürlich anfühlen.
- Wiederholte Abfragen aus aufgewärmten Indizes beantworten: Indexierte Regex-, Trefferanzahl- und Dateilistenabfragen sind schneller als Scans von `rg` und `grep` desselben Verzeichnisbaums.
- `ast-grep` bei indexierten und zwischengespeicherten AST-Arbeitslasten übertreffen, bei denen die warmen Caches von Greph das erneute Parsen des Verzeichnisbaums vermeiden. Die kalte AST-Suche liefert gemischte Ergebnisse: `new $CLASS()` ist schneller als `sg`, `array($$$ITEMS)` ist langsamer.
- Jede Performanceverbesserung messbar und reproduzierbar machen.

Performancebehauptungen ohne zugrunde liegenden Benchmark-Bericht werden nicht übernommen.
