Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
df87781
Add dev tooling and update dependencies for PHP 8.4+
hyperized Apr 11, 2026
a819e76
Modernize core utilities and config for PHP 8.4+
hyperized Apr 11, 2026
cdc0b0f
Add Result DTOs for benchmark data
hyperized Apr 11, 2026
b7c939c
Refactor modules to return typed Result objects
hyperized Apr 11, 2026
06f0a92
Add CLI and HTML renderers
hyperized Apr 11, 2026
778eead
Add JSON report system
hyperized Apr 11, 2026
bdc362c
Rewrite orchestrator and entry point
hyperized Apr 11, 2026
ef5efdc
Update README for new architecture
hyperized Apr 11, 2026
87645b3
Fix Disk I/O card not spanning full width in HTML output
hyperized Apr 11, 2026
6a1d691
Add Memory benchmark module
hyperized Apr 11, 2026
b7e50d3
Fix memory benchmark reporting 0 bytes for most operations
hyperized Apr 11, 2026
0c280d0
Add Result DTOs for Network, JSON, Regex, and File Read modules
hyperized Apr 11, 2026
8e604c4
Add Network, JSON, Regex, and File Read benchmark modules
hyperized Apr 11, 2026
002cec4
Add rendering for new modules and switch all timings to milliseconds
hyperized Apr 11, 2026
831eb05
Wire new modules into orchestrator and config
hyperized Apr 11, 2026
b97747b
Add Result DTOs for Serialization, Hashing, Encryption, Function Over…
hyperized Apr 11, 2026
74a04e8
Add Serialization, Hashing, Encryption, Function Overhead, Type Casti…
hyperized Apr 11, 2026
93cfe7b
Add rendering for new benchmark modules in CLI and HTML
hyperized Apr 11, 2026
b0f79c3
Wire new modules into orchestrator and config
hyperized Apr 11, 2026
07990e0
Update README with full module list, example output, and config refer…
hyperized Apr 11, 2026
aa700a9
Add CLI progress indicator during benchmark execution
hyperized Apr 11, 2026
73252f7
Add color to CLI progress indicator
hyperized Apr 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
analyse:
name: Static Analysis & Code Style
runs-on: ubuntu-latest

strategy:
matrix:
php-version:
- 8.4
- 8.5

steps:
- uses: actions/checkout@v6

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: mysqli
tools: composer

- name: Install dependencies
run: composer install --no-interaction --prefer-dist

- name: PHPStan
run: composer analyse

- name: PHP-CS-Fixer
run: composer cs-check
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/vendor/
/.idea/
/config/*.yml
composer.lock
composer.lock
.php-cs-fixer.cache
reports/*.json
CLAUDE.md
/.claude
13 changes: 13 additions & 0 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

return (new PhpCsFixer\Config())
->setRules([
'@PER-CS2.0' => true,
'strict_param' => true,
'declare_strict_types' => true,
])
->setFinder(
PhpCsFixer\Finder::create()->in(__DIR__ . '/src')
);
197 changes: 160 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,178 @@
# PHP benchmark
[![Build Status](https://scrutinizer-ci.com/g/hyperized/benchmark/badges/build.png?b=master)](https://scrutinizer-ci.com/g/hyperized/benchmark/build-status/master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/hyperized/benchmark/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/hyperized/benchmark/?branch=master)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fhyperized%2Fbenchmark.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fhyperized%2Fbenchmark?ref=badge_shield)

Simple PHP server benchmarking.
[![CI](https://github.com/hyperized/benchmark/actions/workflows/ci.yml/badge.svg)](https://github.com/hyperized/benchmark/actions/workflows/ci.yml)

This tool can help you determine if a hosting environment is suited for your projects in terms of:
- PHP.ini settings that affect uploads;
- CPU speed available to your PHP instance;
- Disk IOPS available to your PHP instance;
- MySQL query speed;
Comprehensive PHP server benchmarking utility. Tests your hosting environment across 15 benchmark modules and reports results in milliseconds.

## How to install:
composer create-project hyperized/benchmark:dev-master

Copy the `/config/config.yml.example` to `/config/config.yml` and adjust to your preferences.

## How to run:
Auto-detects CLI vs web and renders with the appropriate output mode:
- **CLI** — ANSI colors with Unicode box-drawing tables
- **Web** — styled HTML dashboard with responsive CSS grid layout

### Locally with CLI
php benchmark.php
Each run saves a JSON report with a timestamp to `reports/`.

### Locally with development server
## Benchmark Modules

php -S localhost:8000 benchmark.php

### Remotely
Install on the server by running composer and visiting the `/benchmark.php` page of the directory the project is installed at.
| Category | Module | What it measures |
|----------|--------|-----------------|
| **Environment** | PHP | Version, ini settings, memory limits, loaded extensions |
| **I/O** | Disk I/O | File creation across 8 block sizes (512B–64KB) |
| | File Read | Sequential reads across file sizes (1KB–4MB) |
| | Network | DNS resolution and TCP connection latency |
| **Compute** | CPU | Math functions, string operations, loops, conditionals |
| | Memory | Allocation speed and peak memory per operation |
| | Regex | `preg_match` and `preg_replace` across 10 pattern types |
| | JSON | Encode/decode with small, medium, and large payloads |
| | Serialization | `serialize` vs `json_encode` vs `var_export` (+ igbinary/msgpack if available) |
| | Hashing | md5, sha1, sha256, sha512, xxh3, crc32, hmac-sha256, bcrypt, argon2id |
| | Encryption | AES-128/256-CBC/GCM, ChaCha20-Poly1305 encrypt and decrypt |
| | Compression | gzip, zlib, deflate (+ brotli/lzf if available) with compression ratios |
| **Runtime** | Function Overhead | Named function, closure, first-class callable, static/instance method, arrow function |
| | Type Casting | int/string/float/bool conversions |
| | Object Instantiation | stdClass, DateTime, SplStack, SplPriorityQueue, ArrayObject |
| **Database** | MySQL | Query performance (requires ext-mysqli) |

All modules can be individually enabled/disabled and configured in `config/config.yml`.

## Requirements

- PHP >= 8.4
- ext-mysqli (for MySQL benchmarks, optional)

## Installation

```bash
composer create-project hyperized/benchmark:dev-master
cp config/config.yml.example config/config.yml
```

Adjust `config/config.yml` to your preferences. Set module toggles, cycle counts, MySQL credentials, and optionally override the output format.

## Usage

### CLI

```bash
php benchmark.php
```

Example output:

```
╔════════════════════════════════════════════════╗
║ PHP Benchmark Report ║
║ 2026-04-11 14:30:22 ║
╚════════════════════════════════════════════════╝

── PHP ───────────────────────────────────────────

PHP Version 8.5.4
Server CLI
Max Memory 128.00 MB
Max Upload 2.00 MB
Max Exec Time 0 seconds
Extensions 67 loaded

── Disk I/O ──────────────────────────────────────

Cycles: 100
ms (lower is better)

┌──────────┬──────────┬──────────┬──────────┐
│ 512.00 B │ 1.00 KB │ 2.00 KB │ 4.00 KB │ ...
├──────────┼──────────┼──────────┼──────────┤
│ 9.55ms │ 9.78ms │ 9.46ms │ 10.97ms │ ...
└──────────┴──────────┴──────────┴──────────┘

── Hashing ───────────────────────────────────────

Hash Functions (99999 cycles, ms, lower is better)

┌──────────┬──────────┬──────────┬──────────┬──────────┐
│ md5 │ sha1 │ sha256 │ sha512 │ xxh3 │ ...
├──────────┼──────────┼──────────┼──────────┼──────────┤
│ 143.00ms │ 155.71ms │ 387.45ms │ 288.95ms │ 16.35ms │ ...
└──────────┴──────────┴──────────┴──────────┴──────────┘

...

──────────────────────────────────────────────────
Total Duration 18.657s
Report saved reports/2026-04-11_143022.json
──────────────────────────────────────────────────
```

### Web

```bash
php -S localhost:8000 benchmark.php
```

Open `http://localhost:8000` for a styled HTML dashboard with cards for each module.

### Remote

Install on the server via Composer and visit `/benchmark.php` in the browser.

### Reports

JSON reports are saved to `reports/` with timestamped filenames (e.g. `2026-04-11_143022.json`). Disable via `benchmark.output.report: false` in config.

### Configuration

All modules support `enabled: true/false` and configurable cycle counts:

```yaml
benchmark:
output:
format: ~ # null = auto-detect, 'cli', or 'html'
report: true # save JSON report to reports/
php:
enabled: true
disk:
enabled: true
cycles: 100
memory:
enabled: true
count: 9999
network:
enabled: true
cycles: 3
hosts:
- google.com
- cloudflare.com
- github.com
hashing:
enabled: true
hashCount: 99999
passwordCount: 10
# ... see config/config.yml.example for all options
```

### Security
Note that you might want to add additional security to your server to not expose the config.yml file to your webtraffic.

For Apache with `mod_rewrite` you can use something like this in your `.htaccess` file:
If deploying to a web server, ensure `config.yml` is not publicly accessible. For Apache with `mod_rewrite`:

<Files "config.yml">
deny from all
</Files>
```apache
<Files "config.yml">
deny from all
</Files>
```

## Contribution
I'm open to improvements and new benchmarks via [pull requests](https://github.com/hyperized/benchmark/pulls)
## Development

Issues can be reported through [Issues](https://github.com/hyperized/benchmark/issues).
Please include the full output of the script and your config file without the password.
```bash
composer analyse # Run PHPStan (level 8)
composer cs-fix # Auto-fix code style (PER-CS2.0)
composer cs-check # Check code style (dry run)
```

## Credit
Credit where credit is due:
## Contribution

- https://github.com/odan/benchmark-php
- https://gist.github.com/RamadhanAmizudin/ca87f7be83c6237bb070
- https://stackoverflow.com/a/25370978/1757763
- http://php.net/manual/en/function.rmdir.php#119949
I'm open to improvements and new benchmarks via [pull requests](https://github.com/hyperized/benchmark/pulls).

Issues can be reported through [Issues](https://github.com/hyperized/benchmark/issues).
Please include the full output of the script and your config file without the password.

## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fhyperized%2Fbenchmark.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fhyperized%2Fbenchmark?ref=badge_large)

MIT
4 changes: 3 additions & 1 deletion autoload.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<?php

require 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
declare(strict_types=1);

require 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
23 changes: 14 additions & 9 deletions benchmark.php
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
<?php

declare(strict_types=1);

use DI\ContainerBuilder;
use DI\DependencyException;
use DI\NotFoundException;
use Hyperized\Benchmark\Benchmark;
use Hyperized\Benchmark\Report\ReportWriter;

require __DIR__ . DIRECTORY_SEPARATOR . 'autoload.php';

$builder = new ContainerBuilder();
$builder->addDefinitions([
ReportWriter::class => \DI\create(ReportWriter::class)
->constructor(__DIR__ . DIRECTORY_SEPARATOR . 'reports'),
]);
$container = $builder->build();

echo '<pre>';
try {
$benchmark = $container->get(Benchmark::class);
} catch (DependencyException $e) {
\print_r($e);
} catch (NotFoundException $e) {
\print_r($e);
$benchmark->execute();
} catch (\Throwable $e) {
if (\php_sapi_name() === 'cli') {
\fwrite(STDERR, $e->getMessage() . "\n");
exit(1);
}
echo '<pre>' . \htmlspecialchars($e->getMessage(), ENT_QUOTES | ENT_HTML5) . '</pre>';
}
echo '</pre>';

21 changes: 15 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,26 @@
}
],
"require": {
"php": ">=8.4",
"roave/security-advisories": "dev-master",
"php": ">=7.1",
"symfony/config": "^4.1",
"symfony/yaml": "^4.1",
"php-di/php-di": "^6.0",
"adbario/php-dot-notation": "2.2.0",
"ext-mysqli": "^7.1"
"symfony/config": "^7.0",
"symfony/yaml": "^7.0",
"php-di/php-di": "^7.0",
"adbario/php-dot-notation": "^3.0",
"ext-mysqli": "*"
},
"require-dev": {
"phpstan/phpstan": "^2.0",
"friendsofphp/php-cs-fixer": "^3.0"
},
"autoload": {
"psr-4": {
"Hyperized\\Benchmark\\": "src/"
}
},
"scripts": {
"analyse": "phpstan analyse",
"cs-fix": "php-cs-fixer fix --allow-risky=yes",
"cs-check": "php-cs-fixer fix --dry-run --diff --allow-risky=yes"
}
}
Loading