
# Бенчмарки

В репозитории есть инструмент для бенчмарков в `bin/` и `benchmarks/`. Он измеряет каждый режим поиска на реальных наборах данных (WordPress, Laravel) и созданных синтетических наборах, формирует структурированные отчеты и позволяет сравнивать серии отчетов.

Инструмент входит в репозиторий, а не в пакет Composer: поскольку 0.2.3, `benchmarks/` и скрипты `bin/bench*` не включены в пакет, запускайте их из клона (`git clone https://github.com/inline0/greph && cd greph && composer install`).

Опубликованные результаты в [README](https://github.com/inline0/greph#performance) получены в запусках GitHub Actions, а не на локальных машинах. Локальные запуски полезны для итераций; эталонными считаются запуски CI.

## Наборы данных

Синтетические наборы данных (`synthetic-1k`, `synthetic-10k`, `synthetic-100k-single`) создаются в `benchmarks/corpora/synthetic/` при первом запуске. Реальные наборы данных не включены: разместите копию в `benchmarks/corpora/wordpress` или `benchmarks/corpora/laravel` (рабочий процесс CI клонирует `WordPress/WordPress` с помощью `--depth=1`). Наборы данных, для которых отсутствует каталог, пропускаются.

## Запуск бенчмарков

```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` сравнивает два файла с сериями данных (результат `bench-series` или `bench-aggregate`) и выводит сводку Markdown, полезную при оптимизации часто используемого кода. `bin/bench-ci` запускает рабочий процесс Benchmark на GitHub Actions через `gh` CLI.

## Категории

README публикует результаты по восьми группам, каждая из которых измеряет определенный уровень движка. В каждую группу входит одна или несколько категорий бенчмарков, определенных в `benchmarks/suites/`.

### Режим сканирования: текст

Нативный текстовый поиск по буквальным строкам, регулярным выражениям и их комбинациям. Опубликованный базовый тест выполняется на наборе данных WordPress и включает:

- Буквальная строка `function`
- Буквальная строка без учета регистра
- Буквальная строка целиком
- Новое регулярное выражение
- Вызов массива регулярных выражений
- Регулярное выражение с буквальным префиксом
- Регулярное выражение с буквальным суффиксом
- Буквальная строка целиком в строке
- Сворачивание буквальных строк в регулярном выражении

### Режим сканирования: обход

Только обход файлов, без поиска. Измеряется стоимость самого обхода с учетом gitignore.

### Режим сканирования: параллельный текстовый поиск

Поиск по фиксированной строке `function` с `1`, `2` и `4` задачами. Для этого шаблона пул рабочих процессов запускается только при количестве файлов больше `jobs * 4_000` (см. [Параллельные рабочие процессы](https://greph.inline0.dev/ru/docs/advanced/parallel)), а в наборе данных WordPress файлов меньше. Поэтому все три опубликованные строки выполняются в одном процессе и не демонстрируют масштабирование пула ([#8](https://github.com/inline0/greph/issues/8)).

### Режим сканирования: AST

Нативный поиск по AST на типичных шаблонах:

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

### Режим индексированного текста

Поиск по прогретому текстовому индексу с теми же шаблонами, что и в режиме сканирования. Включает запросы по буквальным строкам, без учета регистра, по целым словам, коротким токенам и регулярным выражениям.

### Сводные запросы по индексу

Поиск по прогретому текстовому индексу с выводом количества результатов, файлов с совпадениями и файлов без совпадений. Эти запросы особенно выигрывают от хранилища списков вхождений, поскольку затраты на обработку каждого файла минимальны.

### Индексированный / кэшированный AST

Поиск фактов в прогретом индексе AST и поиск по кэшированному AST на тех же шаблонах, что и в режиме сканирования AST.

### Затраты на сборку

Затраты на построение с нуля триграммного индекса, индекса фактов AST и кэша AST. Полезно при выборе режима для конкретной нагрузки.

## Как читать опубликованные результаты

README публикует снимок последнего запуска CI для каждого базового теста. Данные каждого раздела получены в конкретном запуске GitHub Actions и снабжены сведениями о наборе данных, среде выполнения, версии PHP, а также количестве измерений и прогревов. Чтобы воспроизвести результат, используйте ту же конфигурацию локально.

Сравнительные столбцы (`rg`, `grep`, `sg`) формируются в рамках одной задачи на одной среде выполнения и на одном наборе данных. Они не рассчитаны на основе внешних бенчмарков.

## Как добавить бенчмарк

1. Добавьте определение бенчмарка в `benchmarks/`.
2. Добавьте соответствующий сценарий в набор регрессионных тестов, если аналогичного еще нет (чтобы также проверить измеряемое поведение).
3. Запустите `./bin/bench --category <yours>`, чтобы проверить новый бенчмарк.
4. Сравните результаты с `main` с помощью рабочего процесса Benchmark, который запускается для запросов на слияние, затрагивающих `src/`, `benchmarks/` или `bin/`, и публикует сравнение текущей версии с базовой в сводке запуска.
5. Обновите таблицу README после того, как запуск CI с новым бенчмарком появится в `main`.

## Подход к производительности

Greph не стремится превзойти ripgrep или grep при холодном сканировании. Ripgrep реализован на Rust с тщательно настроенным SIMD-поиском буквальных строк, и опубликованные результаты показывают, что при каждом холодном текстовом сканировании и `rg`, и GNU `grep` работают быстрее Greph. Цели здесь другие:

- Работать достаточно быстро, чтобы интерактивное использование и циклы агента ощущались естественно.
- Обрабатывать повторные запросы по прогретым индексам: индексированный поиск регулярных выражений, подсчет совпадений и списки файлов работают быстрее, чем сканирование того же дерева с помощью `rg` и `grep`.
- Превосходить `ast-grep` при работе с индексированным и кэшированным AST, где прогретые кэши Greph позволяют избежать повторного разбора дерева. Результаты холодного поиска по AST неоднозначны: `new $CLASS()` работает быстрее `sg`, а `array($$$ITEMS)` — медленнее.
- Делать каждое улучшение производительности измеримым и воспроизводимым.

Заявления о производительности без отчета о бенчмарке не принимаются.
