Quick Start

This tutorial will walk you through creating a typical, simple, project that uses PHPBench as a dependency. You may also install PHPBench globally, see the Installing chapter for more information.

You may skip various sections according to your needs and use this as a general reference.

Create your project

Create a directory for the tutorial:

$ mkdir phpbench-tutorial

And create the following Composer file within it:

{
    "name": "acme/phpbench-test",
    "require-dev": {
        "phpbench/phpbench": "^1.0@dev"
    },
    "autoload": {
        "psr-4": {
            "Acme\\": "lib"
        }
    }
}

Now perform a Composer install:

$ composer install

Note

You may also install PHPBench globally, see the Installing chapter for more information.

PHPBench should now be installed. Now create two directories, benchmarks and lib which we will need further on:

$ mkdir benchmarks
$ mkdir lib

PHPBench configuration

In order for PHPBench to be able to autoload files from your library, you should specify the path to your bootstrap file (i.e. vendor/autoload.php). This can be done in the PHPBench configuration.

Create the file phpbench.json in the projects root directory:

{
    "bootstrap": "vendor/autoload.php"
}

Note

PHPBench does not require a bootstrap (or a configuration file for that matter). You may omit it if you do not need autoloading, or you want to include files manually.

Warning

Some PHP extensions such as Xdebug will affect the performance of your benchmark subjects and you may want to disable them, see Disabling the PHP INI file.

Creating and running a benchmark

You will need some code to benchmark, create a simple class in lib which consumes time itself:

<?php

namespace Acme;

class TimeConsumer
{
    public function consume()
    {
        usleep(100);
    }
}

In order to benchmark your code you will need to execute that code within a method of a benchmarking class. Benchmarking classes MUST have the Bench suffix and each benchmarking method must be prefixed with bench.

Create the following class in the benchmarks directory:

<?php

use Acme\TimeConsumer;

class TimeConsumerBench
{
    public function benchConsume()
    {
       $consumer = new TimeConsumer();
       $consumer->consume();
    }
}

Now you can execute the benchmark as follows:

$ ./vendor/bin/phpbench run benchmarks/TimeConsumerBench.php --report=default

And you should see some output similar to the following:

PhpBench 0.8.0-dev. Running benchmarks.

\TimeConsumerBench

    benchConsume                  I0 P0         [μ Mo]/r: 173.00μs   [μSD μRSD]/r: 0.00μs 0.00%

1 subjects, 1 iterations, 1 revs, 0 rejects
⅀T: 173μs μSD/r 0.00μs μRSD/r: 0.00%
min [mean mode] max: 173.00 [173.00 1732.00] 173.00 (μs/r)

+-------------------+---------------+-------+--------+------+------+-----+----------+------------+---------+-------+
| benchmark         | subject       | group | params | revs | iter | rej | mem      | time       | z-score | diff  |
+-------------------+---------------+-------+--------+------+------+-----+----------+------------+---------+-------+
| TimeConsumerBench | benchConsume  |       | []     | 1    | 0    | 0   | 265,936b | 173.0000μs | 0.00σ   | 1.00x |
+-------------------+---------------+-------+--------+------+------+-----+----------+------------+---------+-------+

You may have guessed that the code was only executed once (as indicated by the revs column). To achieve a better measurement we should increase the number of times that the code is consecutively executed.

<?php

// ...

class TimeConsumerBench
{
    /**
     * @Revs(1000)
     */
    public function benchConsume()
    {
        // ...
    }
}

Run the benchmark again and you should notice that the report states that 1000 revolutions were performed. Revolutions in PHPBench represent the number of times that the code is executed consecutively within a single measurement.

Currently we only execute the benchmark subject a single time, to verify the result you should increase the number of iterations using the @Iterations annotation (either as a replacement or in addition to @Revs:

<?php

// ...

class TimeConsumerBench
{
    /**
     * @Revs(1000)
     * @Iterations(5)
     */
    public function benchConsume()
    {
        // ...
    }
}

Now when you run the report you should see that it contains 5 rows. One measurement for each iteration, and each iteration executed the code 1000 times.

Note

You can override the number of iterations and revolutions on the CLI using the --iterations and --revs options.

At this point it would be better for you to use the aggregate report rather than default:

$ php vendor/bin/phpbench run benchmarks/TimeConsumerBench.php --report=aggregate

Increase Stability

You will see the columns stdev and rstdev. stdev is the standard deviation of the set of iterations and rstdev is relative standard deviation.

Stability can be inferred from rstdev, with 0% being the best and anything about 2% should be treated as suspicious.

To increase stability you can use the --retry-threshold to automatically repeat the iterations until the diff (the percentage difference from the lowest measurement) fits within a given threshold:

$ php vendor/bin/phpbench run benchmarks/TimeConsumerBench.php --report=aggregate --retry-threshold=5

Warning

Lower values for retry-threshold, depending on the stability of your system, generally lead to increased total benchmarking time.

Customize Reports

PHPBench also allows you to customize reports on the command line, try the following:

$ ./vendor/bin/phpbench run benchmarks/TimeConsumerBench.php --report='{"extends": "aggregate", "cols": ["subject", "mode"]}'

Above we configure a new report which extends the default report that we have already used, but we use only the subject and mode columns. A full list of all the options for the default reports can be found in the Report Generators chapter.

Configuration

Now to finish off, lets add the path and new report to the configuration file:

{
    ...
    "path": "benchmarks",
    "reports": {
        "consumation_of_time": {
            "extends": "default",
            "title": "The Consumation of Time",
            "description": "Benchmark how long it takes to consume time",
            "cols": [ "subject", "mode" ]
        }
    }
}

Warning

JSON files are very strict - be sure not to have commas after the final elements in arrays or objects!

Above you tell PHPBench where the benchmarks are located and you define a new report, consumation_of_time with a title, description and sort order.

We can now run the new report:

$ php vendor/bin/phpbench run --report=consumation_of_time

Note

Note that we did not specify the path to the benchmark file, by default all benchmarks under the given or configured path will be executed.

This quick start demonstrated some of the features of PHPBench, but there is more to discover everything can be found in this manual. Happy benchmarking.