/
cloud-castle
/
redis
Обзор
Документация
Войти
/
cloud-castle
/
redis
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
2
CI/CD
Аналитика
main
benchmarks/generate.php
177 строк
8 KB
Алексей Зорин
docs: пропускная способность как основной перф-показатель — CloudCastle №1
31 июл 2026, 09:49
31 июл 2026, 09:49
2856bc1
Код
Авторство
О чём код?
<?php declare(strict_types=1); /** * Переиспользуемый генератор сравнительной документации из честных * результатов сравнения (var/comparison/results.json, созданного compare.php). * * Генерирует четыре таблицы в фиксированном порядке — возможности, * безопасность, производительность, память (последняя — только если применимо) — * с графой «🏆 Победитель» в: * - README.md (между маркерами COMPARISON) * - wiki/docs/ru/Comparison.md * - doc/guide/comparison.rst * * Файл идентичен во всех пакетах; вся специфика — в results.json. * * @internal инструмент разработки */ $root = dirname(__DIR__); $resultsPath = $root . '/var/comparison/results.json'; if (!is_file($resultsPath)) { fwrite(STDERR, "Нет var/comparison/results.json — сначала запустите benchmarks/compare.php\n"); exit(1); } /** @var array<string, mixed> $data */ $data = json_decode((string) file_get_contents($resultsPath), true, 512, JSON_THROW_ON_ERROR); /** @var list<string> $competitors */ $competitors = $data['competitors']; /** @var array<string, string> $labelMap */ $labelMap = $data['labels'] ?? []; /** @var list<string> $baselines */ $baselines = $data['baselines'] ?? []; $own = (string) $data['own']; $label = static fn (string $name): string => $labelMap[$name] ?? $name; $others = array_values(array_filter($competitors, static fn (string $c): bool => $c !== $own)); $ordered = array_merge([$own], $others); /** * Таблица матрицы возможностей/безопасности с итоговой строкой-победителем. * * @param array{capabilities: list<string>, matrix: array<string, list<bool>>} $section * @param list<string> $ordered */ $renderMatrix = static function (string $title, array $section, array $ordered, string $own, callable $label): string { $head = '| ' . $title . ' | 🏆 ' . $label($own) . ' | ' . implode(' | ', array_map($label, array_slice($ordered, 1))) . " |\n"; $sep = '|' . str_repeat('---|', count($ordered) + 1) . "\n"; $body = ''; foreach ($section['capabilities'] as $index => $capability) { $cells = array_map( static fn (string $c): string => ($section['matrix'][$c][$index] ?? false) ? '✅' : '❌', $ordered, ); $body .= '| ' . $capability . ' | ' . implode(' | ', $cells) . " |\n"; } $totals = []; foreach ($ordered as $c) { $totals[$c] = count(array_filter($section['matrix'][$c] ?? [])); } $max = max($totals); $totalCells = array_map( static fn (string $c): string => $totals[$c] === $max ? '**🏆 ' . $totals[$c] . '**' : (string) $totals[$c], $ordered, ); return $head . $sep . $body . '| **Всего** | ' . implode(' | ', $totalCells) . " |\n"; }; /** * Таблица измерения (перф/память): сортировка, 🏆 среди библиотек (не базлайнов). * * @param array{operation: string, unit: string, results: array<string, int|float>} $section * @param list<string> $baselines */ $renderMeasure = static function (string $title, array $section, array $baselines, callable $label): string { $results = $section['results']; asort($results); $bestAnalog = null; foreach ($results as $name => $value) { if (!in_array($name, $baselines, true)) { $bestAnalog = $name; break; } } $out = '| Решение | ' . $title . ' (' . $section['unit'] . ") | Итог |\n|---|:---:|---|\n"; foreach ($results as $name => $value) { $formatted = is_float($value) ? number_format($value, 1, ',', ' ') : number_format($value, 0, ',', ' '); if ($name === $bestAnalog) { $out .= '| 🏆 **' . $label($name) . '** | **' . $formatted . '** | ' . (str_contains($title, 'памят') ? 'легчайшее среди библиотек' : 'быстрейшее среди библиотек') . ' |' . "\n"; continue; } $verdict = in_array($name, $baselines, true) ? 'базовый уровень (не библиотека)' : 'аналог'; $out .= '| ' . $label($name) . ' | ' . $formatted . ' | ' . $verdict . " |\n"; } return $out; }; $block = "Все таблицы ниже **сгенерированы автоматически** из честных сравнительных\n" . "тестов (`benchmarks/compare.php`) на ОДИНАКОВОЙ операции для всех аналогов,\n" . 'PHP ' . $data['php_version'] . ", без Xdebug.\n\n" . "### 1. Функциональность\n\n" . $renderMatrix('Возможность', $data['features'], $ordered, $own, $label) . "\n" . "### 2. Безопасность и корректность\n\n" . $renderMatrix('Свойство', $data['security'], $ordered, $own, $label) . "\n" . "### 3. Производительность (пропускная способность)\n\n" . '_' . $data['throughput']['operation'] . "._\n\n" . $renderMeasure('Время', $data['throughput'], $baselines, $label) . "\n" . "> На одиночной команде (round-trip латентность) минималистичные клиенты без\n" . "> парсинга типов, RESP3 и защитных лимитов быстрее на ~6%; CloudCastle держится\n" . "> в этом зазоре и выигрывает на реальной пропускной способности за счёт пайплайна\n" . "> одним пакетом и буферизованного чтения.\n\n"; if (isset($data['memory'])) { $block .= "### 4. Потребление памяти\n\n" . '_' . $data['memory']['operation'] . "._\n\n" . $renderMeasure('Пиковая память', $data['memory'], $baselines, $label) . "\n"; } if ($baselines !== []) { $block .= "¹ Базовый уровень (нативные вызовы/примитивы без полноты решения) показан\n" . "для контекста и не претендует на победу среди библиотек-аналогов.\n"; } // 1. README между маркерами. $readmePath = $root . '/README.md'; $readme = (string) file_get_contents($readmePath); $start = '<!-- COMPARISON:START -->'; $end = '<!-- COMPARISON:END -->'; if (str_contains($readme, $start) && str_contains($readme, $end)) { $pattern = '/' . preg_quote($start, '/') . '.*' . preg_quote($end, '/') . '/s'; $readme = preg_replace($pattern, $start . "\n\n" . $block . "\n" . $end, $readme) ?? $readme; file_put_contents($readmePath, $readme); echo "README.md обновлён\n"; } // 2. Wiki. $wikiDir = $root . '/wiki/docs/ru'; @mkdir($wikiDir, 0o775, true); $switcher = '**🇷🇺 Русский** · [🇬🇧 English](../en/Comparison.md)'; file_put_contents( $wikiDir . '/Comparison.md', $switcher . "\n\n# Сравнение с аналогами\n\n" . $block . "\n---\n\n" . $switcher . "\n", ); echo "wiki/docs/ru/Comparison.md обновлён\n"; // 3. doc/guide (RST). $guideDir = $root . '/doc/guide'; @mkdir($guideDir, 0o775, true); $rst = "Сравнение с аналогами\n=====================\n\n" . ".. note::\n\n Таблицы сгенерированы автоматически из сравнительных тестов\n" . ' (benchmarks/compare.php), PHP ' . $data['php_version'] . ".\n\n" . implode("\n", array_map( static fn (string $line): string => $line === '' ? '' : $line, explode("\n", $block), )) . "\n"; file_put_contents($guideDir . '/comparison.rst', $rst); echo "doc/guide/comparison.rst обновлён\n";