Potherca
9/15/2017 - 2:20 PM

Benchmarks for the comparison of various styles of writing a `clamp` function in PHP

Benchmarks for the comparison of various styles of writing a clamp function in PHP

<?php

namespace Potherca\Example;

/**
 * Benchmark the separate `clamp` functions.
 */
class BenchmarkClamp
{
    /**
     * @ParamProviders({"provideValues"})
     */
    public function bench_7BC1F85B($value, $min, $max)
    {
        if ($value < $min) {
            $value = $min;
        }

        if ($value > $max) {
            $value = $max;
        }

        return $value;
    }

    /**
     * @ParamProviders({"provideValues"})
     */
    public function bench_83C742FF($value, $min, $max)
    {
        if ($value < $min) {
            return $min;
        }

        if ($value > $max) {
            return $max;
        }

        return $value;
    }

    /**
     * @ParamProviders({"provideValues"})
     */
    public function bench_832B9C44($value, $min, $max)
    {
        return min($max, max($min, $value));
    }

    /**
     * @ParamProviders({"provideValues"})
     */
    public function bench_8389C469($value, $min, $max)
    {
        if ($value < $min) {
            $value = $min;
        } elseif ($value > $max) {
            $value = $max;
        }

        return $value;
    }

    /**
     * @ParamProviders({"provideValues"})
     */
    public function bench_CAB599E9($value, $min, $max)
    {
        if ($value < $min) {
            return $min;
        } elseif ($value > $max) {
            return $max;
        } else {
            return $value;
        }
    }

    /**
     * @ParamProviders({"provideValues"})
     */
    public function bench_60AA891E($value, $min, $max)
    {
        return $value < $min ? $min : ( $value > $max ? $max : $value );
    }

    /**
     * @ParamProviders({"provideValues"})
     */
    public function bench_A13E087E($value, $min, $max)
    {
        if ($value < $min) return $min;
        if ($value > $max) return $max;
        return $value;
    }

    /**
     * Provides data for 3 separate scenario's
     *
     * @return array
     */
    public function provideValues()
    {
        return [
            'above range' => [30, 10, 20],
            'beneath range' => [10, 20, 30],
            'within range' => [20, 10, 30],
        ];
    }
}

/*EOF*/

📝 This text is part of the article Comparison of various styles of writing a clamp function in PHP

Summary

Benchmarks were created using PhpBench counting in units of Ξs(1).

The final result was:

meansubjectdescription
20.035 Ξs832B9C44return min max
23.376 ΞsCAB599E9if/return, elseif/return, else/return
23.538 ΞsA13E087Eif/return, if/return, return (shorthand)
23.595 Ξs8389C469if, elseif, return
23.723 Ξs60AA891Ereturn/ternary/ternary
23.985 Ξs83C742FFif/return, if/return, return
24.089 Ξs7BC1F85Bif, if, return;

Steps taken

The following steps were taken in order to benchmark the clamp variations:

  1. Create a benchmark class
  2. Run phpbench
  3. Combine the result from the 3 scenario's
  4. Sort the results

Each step is described in detail below.

1. Create a benchmark class

I create a class that held a separate method for each variation. Each variation was fed data for 3 separate scenario's:

  1. A value within the min/max range
  2. A value above the min/max range
  3. A value below the min/max range

The source code can be seen in the BenchmarkClamp.php file.

2. Run phpbench

PhpBench was run using the following command:

phpbench  run ./BenchmarkClamp.php  --iterations=15 --revs=1000 --retry-threshold=5 --report='generator: "table", cols: [ "subject", "params", "mean", "diff" ], break: ["benchmark"], sort: {subject: "asc", mean: "desc"}'

This gives the following results:

7 subjects, 315 iterations, 21,000 revs, 0 rejects
(best [mean mode] worst) = 19.098 [23.192 23.167] 20.588 (Ξs)
⅀T: 7,305.424ξs ξSD/r 0.408ξs ξRSD/r: 1.761%
benchmark: BenchmarkClamp

+----------------+------------+----------+---------+
| subject        | params     | mean     | diff    |
+----------------+------------+----------+---------+
| bench_60AA891E | [20,10,30] | 23.944Ξs | +19.98% |
| bench_60AA891E | [30,10,20] | 23.657Ξs | +18.54% |
| bench_60AA891E | [10,20,30] | 23.569Ξs | +18.10% |
| bench_7BC1F85B | [30,10,20] | 24.395Ξs | +22.24% |
| bench_7BC1F85B | [20,10,30] | 24.335Ξs | +21.94% |
| bench_7BC1F85B | [10,20,30] | 23.538Ξs | +17.95% |
| bench_832B9C44 | [30,10,20] | 20.188Ξs | +1.16%  |
| bench_832B9C44 | [10,20,30] | 19.961Ξs | +0.02%  |
| bench_832B9C44 | [20,10,30] | 19.957Ξs | 0.00%   |
| bench_8389C469 | [30,10,20] | 23.668Ξs | +18.60% |
| bench_8389C469 | [20,10,30] | 23.581Ξs | +18.16% |
| bench_8389C469 | [10,20,30] | 23.537Ξs | +17.94% |
| bench_83C742FF | [10,20,30] | 24.324Ξs | +21.89% |
| bench_83C742FF | [20,10,30] | 23.890Ξs | +19.71% |
| bench_83C742FF | [30,10,20] | 23.742Ξs | +18.97% |
| bench_A13E087E | [10,20,30] | 23.752Ξs | +19.02% |
| bench_A13E087E | [30,10,20] | 23.513Ξs | +17.82% |
| bench_A13E087E | [20,10,30] | 23.349Ξs | +17.00% |
| bench_CAB599E9 | [20,10,30] | 23.678Ξs | +18.65% |
| bench_CAB599E9 | [30,10,20] | 23.317Ξs | +16.84% |
| bench_CAB599E9 | [10,20,30] | 23.135Ξs | +15.93% |
+----------------+------------+----------+---------+

3. Combine the results

Combining the result-sets for the 3 separate scenario's, we get:

subjectmean
832B9C44(20.188 + 19.961 + 19.957)/3 =20.0353333
CAB599E9(23.678 + 23.317 + 23.135)/3 =23.3766667
A13E087E(23.752 + 23.513 + 23.349)/3 =23.5380000
8389C469(23.668 + 23.581 + 23.537)/3 =23.5953333
60AA891E(23.944 + 23.657 + 23.569)/3 =23.7233333
83C742FF(24.324 + 23.890 + 23.742)/3 =23.9853333
7BC1F85B(24.395 + 24.335 + 23.538)/3 =24.0893333

4. Sort the results

Translating this back to each variation this gives us:

meansubjectdescription
20.0353333 Ξs832B9C44return min max
23.3766667 ΞsCAB599E9if/return, elseif/return, else/return
23.5380000 ΞsA13E087Eif/return, if/return, return (shorthand)
23.5953333 Ξs8389C469if, elseif, return
23.7233333 Ξs60AA891Ereturn/ternary/ternary
23.9853333 Ξs83C742FFif/return, if/return, return
24.0893333 Ξs7BC1F85Bif, if, return;

Footnotes

  1. one millionth of a second