Skip to content
This repository has been archived by the owner on Jun 2, 2018. It is now read-only.

[WIP] Add Dash router to benchmarks #5

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 22 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,36 @@ An example route: `/9b37eef21e/{arg1}/{arg2}/{arg3}/{arg4}/{arg5}/{arg6}/{arg7}/
## Worst-case matching
This benchmark matches the last route and unknown route. It generates a randomly prefixed and suffixed route in an attempt to thwart any optimization. 1,000 routes each with 9 arguments.

This benchmark consists of 10 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.
This benchmark consists of 12 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.


Test Name | Results | Time | + Interval | Change
--------- | ------- | ---- | ---------- | ------
FastRoute - last route (1000 routes) | 999 | 0.0005987507 | +0.0000000000 | baseline
FastRoute - unknown route (1000 routes) | 974 | 0.0007073336 | +0.0001085829 | 18% slower
Symfony2 Dumped - unknown route (1000 routes) | 978 | 0.0010984190 | +0.0004996683 | 83% slower
Pux ext - last route (1000 routes) | 999 | 0.0011521092 | +0.0005533585 | 92% slower
Pux ext - unknown route (1000 routes) | 997 | 0.0011798443 | +0.0005810937 | 97% slower
Symfony2 Dumped - last route (1000 routes) | 977 | 0.0012447905 | +0.0006460398 | 108% slower
Symfony2 - unknown route (1000 routes) | 977 | 0.0065360450 | +0.0059372943 | 992% slower
Symfony2 - last route (1000 routes) | 999 | 0.0075226317 | +0.0069238810 | 1156% slower
Aura v2 - unknown route (1000 routes) | 966 | 0.0094022778 | +0.0088035271 | 1470% slower
Aura v2 - last route (1000 routes) | 999 | 0.0102424956 | +0.0096437449 | 1611% slower
FastRoute - unknown route (1000 routes) | 965 | 0.0003722053 | +0.0000000000 | baseline
FastRoute - last route (1000 routes) | 999 | 0.0003778025 | +0.0000055973 | 2% slower
Pux ext - unknown route (1000 routes) | 985 | 0.0012333790 | +0.0008611738 | 231% slower
Symfony2 Dumped - last route (1000 routes) | 983 | 0.0014034302 | +0.0010312250 | 277% slower
Symfony2 Dumped - unknown route (1000 routes) | 993 | 0.0016060610 | +0.0012338558 | 331% slower
Pux ext - last route (1000 routes) | 991 | 0.0019055481 | +0.0015333429 | 412% slower
Symfony2 - last route (1000 routes) | 999 | 0.0058133834 | +0.0054411781 | 1462% slower
Aura v2 - unknown route (1000 routes) | 970 | 0.0081023951 | +0.0077301899 | 2077% slower
Aura v2 - last route (1000 routes) | 998 | 0.0096134803 | +0.0092412750 | 2483% slower
Symfony2 - unknown route (1000 routes) | 994 | 0.0097540495 | +0.0093818442 | 2521% slower
Dash - unknown route (1000 routes) | 970 | 0.0510062439 | +0.0506340386 | 13604% slower
Dash - last route (1000 routes) | 999 | 0.0514250606 | +0.0510528553 | 13716% slower


## First route matching
This benchmark tests how quickly each router can match the first route. 1,000 routes each with 9 arguments.

This benchmark consists of 5 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.
This benchmark consists of 6 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.


Test Name | Results | Time | + Interval | Change
--------- | ------- | ---- | ---------- | ------
Pux ext - first route | 979 | 0.0000192035 | +0.0000000000 | baseline
FastRoute - first route | 991 | 0.0000276991 | +0.0000084956 | 44% slower
Symfony2 Dumped - first route | 974 | 0.0000543768 | +0.0000351733 | 183% slower
Aura v2 - first route | 986 | 0.0001890168 | +0.0001698133 | 884% slower
Symfony2 - first route | 999 | 0.0002314818 | +0.0002122782 | 1105% slower
Pux ext - first route | 978 | 0.0000191886 | +0.0000000000 | baseline
FastRoute - first route | 988 | 0.0000250497 | +0.0000058611 | 31% slower
Symfony2 Dumped - first route | 978 | 0.0000518656 | +0.0000326770 | 170% slower
Aura v2 - first route | 999 | 0.0001707521 | +0.0001515635 | 790% slower
Symfony2 - first route | 977 | 0.0001870927 | +0.0001679041 | 875% slower
Dash - first route | 999 | 0.0541013915 | +0.0540822029 | 281846% slower
8 changes: 7 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
"nikic/fast-route": "dev-master",
"corneltek/pux": "dev-master",
"symfony/routing": "dev-master",
"aura/router": "dev-develop-2"
"aura/router": "dev-develop-2",
"dasprid/dash": "dev-master"
},
"autoload": {
"psr-4": {
"RouterBenchmarks\\": "src/"
}
}
}
41 changes: 41 additions & 0 deletions first-route-tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@

namespace FirstRouteMatching;

use Dash\Router\Http\Parser\Segment;
use Dash\Router\Http\Route\Generic;
use Dash\Router\Http\Router;
use RouterBenchmarks\Dash\RouteCollection;
use TylerSommer\Nice\Benchmark\Benchmark;
use TylerSommer\Nice\Benchmark\ResultPrinter\MarkdownPrinter;
use Zend\Http\Request;

/**
* Sets up the First-route matching benchmark.
Expand All @@ -30,6 +35,7 @@ function setupBenchmark($numIterations, $numRoutes, $numArgs)
setupSymfony2($benchmark, $numRoutes, $numArgs);
setupSymfony2Optimized($benchmark, $numRoutes, $numArgs);
setupPux($benchmark, $numRoutes, $numArgs);
setupDash($benchmark, $numRoutes, $numArgs);

return $benchmark;
}
Expand Down Expand Up @@ -187,3 +193,38 @@ function setupAura2(Benchmark $benchmark, $routes, $args)
$route = $router->match($firstStr);
});
}

/**
* Sets up Dash tests
*
* https://github.com/DASPRiD/Dash
*/
function setupDash(Benchmark $benchmark, $routes, $args)
{
$argString = implode('/', array_map(function ($i) { return "{arg$i}"; }, range(1, $args)));
$str = $firstStr = $lastStr = '';
$routeCollection = new RouteCollection();
for ($i = 0; $i < $routes; $i++) {
list ($pre, $post) = getRandomParts();
$str = '/' . $pre . '/' . $argString . '/' . $post;

if (0 === $i) {
$firstStr = str_replace(array('{', '}'), '', $str);
}
$lastStr = str_replace(array('{', '}'), '', $str);

$route = new Generic();
$route->setMethods(array('get'));
$route->setPathParser(new Segment('/', $str, array()));

$routeCollection->insert('handler' . $i, $route);
}

$router = new Router($routeCollection);

$firstStrRequest = Request::fromString(sprintf('GET %s HTTP/1.1', $firstStr));

$benchmark->register(sprintf('Dash - first route', $routes), function () use ($router, $firstStrRequest) {
$route = $router->match($firstStrRequest);
});
}
105 changes: 105 additions & 0 deletions src/Dash/RouteCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

namespace RouterBenchmarks\Dash;

use Dash\Router\Exception\InvalidArgumentException;
use Dash\Router\Exception\OutOfBoundsException;
use Dash\Router\Http\Route\RouteInterface;
use Dash\Router\Http\RouteCollection\RouteCollectionInterface;

class RouteCollection implements RouteCollectionInterface
{

/**
* @var array
*/
protected $routes = array();

/**
* @var int
*/
protected $serial = 0;

/**
* @var bool
*/
protected $sorted = false;

/**
* @throws InvalidArgumentException
*/
public function insert($name, $route, $priority = 1)
{
if (!($route instanceof RouteInterface || is_array($route))) {
throw new InvalidArgumentException(sprintf(
'$route must either be an array or implement Dash\Router\Http\Route\RouteInterface, %s given',
is_object($route) ? get_class($route) : gettype($route)
));
}

$this->sorted = false;

$this->routes[$name] = array(
'priority' => (int) $priority,
'serial' => $this->serial++,
'route' => $route,
);
}

public function remove($name)
{
if (!isset($this->routes[$name])) {
return;
}

unset($this->routes[$name]);
}

public function clear()
{
$this->routes = array();
$this->serial = 0;
$this->sorted = true;
}

public function get($name)
{
if (!isset($this->routes[$name])) {
throw new OutOfBoundsException(sprintf('Route with name "%s" was not found', $name));
}

return $this->routes[$name]['route'];
}

public function current()
{
$node = current($this->routes);
return ($node !== false ? $this->get(key($this->routes)) : false);
}

public function key()
{
return key($this->routes);
}

public function next()
{
$node = next($this->routes);
return ($node !== false ? $this->get(key($this->routes)) : false);
}

public function rewind()
{
if (!$this->sorted) {
arsort($this->routes);
$this->sorted = true;
}

reset($this->routes);
}

public function valid()
{
return ($this->current() !== false);
}
}
46 changes: 46 additions & 0 deletions worst-case-tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@

namespace WorstCaseMatching;

use Dash\Router\Http\Parser\Segment;
use Dash\Router\Http\Route\Generic;
use Dash\Router\Http\Router;
use RouterBenchmarks\Dash\RouteCollection;
use TylerSommer\Nice\Benchmark\Benchmark;
use TylerSommer\Nice\Benchmark\ResultPrinter\MarkdownPrinter;
use Zend\Http\Request;

/**
* Sets up the Worst-case matching benchmark.
Expand Down Expand Up @@ -31,6 +36,7 @@ function setupBenchmark($numIterations, $numRoutes, $numArgs)
setupSymfony2($benchmark, $numRoutes, $numArgs);
setupSymfony2Optimized($benchmark, $numRoutes, $numArgs);
setupPux($benchmark, $numRoutes, $numArgs);
setupDash($benchmark, $numRoutes, $numArgs);

return $benchmark;
}
Expand Down Expand Up @@ -213,3 +219,43 @@ function setupAura2(Benchmark $benchmark, $routes, $args)
$route = $router->match('/not-even-real', $_SERVER);
});
}

/**
* Sets up Dash tests
*
* https://github.com/DASPRiD/Dash
*/
function setupDash(Benchmark $benchmark, $routes, $args)
{
$argString = implode('/', array_map(function ($i) { return "{arg$i}"; }, range(1, $args)));
$lastStr = '';
$routeCollection = new RouteCollection();
for ($i = 0, $str = 'a'; $i < $routes; $i++, $str++) {
list ($pre, $post) = getRandomParts();
$str = '/' . $pre . '/' . $argString . '/' . $post;

if (0 === $i) {
$firstStr = str_replace(array('{', '}'), '', $str);
}
$lastStr = str_replace(array('{', '}'), '', $str);

$route = new Generic();
$route->setMethods(array('get'));
$route->setPathParser(new Segment('/', $str, array()));

$routeCollection->insert('handler' . $i, $route);
}

$router = new Router($routeCollection);

$lastStrRequest = Request::fromString(sprintf('GET %s HTTP/1.1', $lastStr));
$unknownRequest = Request::fromString(sprintf('GET /not-even-real HTTP/1.1', $lastStr));

$benchmark->register(sprintf('Dash - last route (%s routes)', $routes), function () use ($router, $lastStrRequest) {
$route = $router->match($lastStrRequest);
});

$benchmark->register(sprintf('Dash - unknown route (%s routes)', $routes), function () use ($router, $unknownRequest) {
$route = $router->match($unknownRequest);
});
}