From 76e3f70cb42220d6968bbd1239bd51cc1284f498 Mon Sep 17 00:00:00 2001 From: Tyler Sommer Date: Wed, 26 Feb 2014 14:24:24 -0800 Subject: [PATCH 1/5] Added initial worst case test for Dash router --- composer.json | 3 ++- worst-case-tests.php | 49 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0006e20..5214e34 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,7 @@ "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" } } diff --git a/worst-case-tests.php b/worst-case-tests.php index 5fec410..0b4ffc4 100644 --- a/worst-case-tests.php +++ b/worst-case-tests.php @@ -2,8 +2,13 @@ namespace WorstCaseMatching; +use Dash\Router\Http\Parser\Segment; +use Dash\Router\Http\Route\Generic; +use Dash\Router\Http\RouteCollection\RouteCollection; +use Dash\Router\Http\Router; use TylerSommer\Nice\Benchmark\Benchmark; use TylerSommer\Nice\Benchmark\ResultPrinter\MarkdownPrinter; +use Zend\Http\Request; /** * Sets up the Worst-case matching benchmark. @@ -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; } @@ -213,3 +219,46 @@ 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 = new Request(); + $lastStrRequest->setUri($lastStr); + + $unknownRequest = new Request(); + $unknownRequest->setUri('/not-even-real'); + + $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); + }); +} From 1b0e930d65deb1152d4d64c078c9ec93e9888be2 Mon Sep 17 00:00:00 2001 From: Tyler Sommer Date: Wed, 26 Feb 2014 16:42:22 -0800 Subject: [PATCH 2/5] Added servicemanager agnostic implementation of Dash RouteCollection --- composer.json | 5 ++ src/Dash/RouteCollection.php | 105 +++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/Dash/RouteCollection.php diff --git a/composer.json b/composer.json index 5214e34..d3e6ee9 100644 --- a/composer.json +++ b/composer.json @@ -6,5 +6,10 @@ "symfony/routing": "dev-master", "aura/router": "dev-develop-2", "dasprid/dash": "dev-master" + }, + "autoload": { + "psr-4": { + "RouterBenchmarks\\": "src/" + } } } diff --git a/src/Dash/RouteCollection.php b/src/Dash/RouteCollection.php new file mode 100644 index 0000000..9a29874 --- /dev/null +++ b/src/Dash/RouteCollection.php @@ -0,0 +1,105 @@ +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); + } +} \ No newline at end of file From ebef97c6ef2e1587360940929d9cc7aec4cb3bea Mon Sep 17 00:00:00 2001 From: Tyler Sommer Date: Wed, 26 Feb 2014 16:42:52 -0800 Subject: [PATCH 3/5] Fixed issues with dash worst case test --- worst-case-tests.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/worst-case-tests.php b/worst-case-tests.php index 0b4ffc4..4abe55e 100644 --- a/worst-case-tests.php +++ b/worst-case-tests.php @@ -4,8 +4,8 @@ use Dash\Router\Http\Parser\Segment; use Dash\Router\Http\Route\Generic; -use Dash\Router\Http\RouteCollection\RouteCollection; use Dash\Router\Http\Router; +use RouterBenchmarks\Dash\RouteCollection; use TylerSommer\Nice\Benchmark\Benchmark; use TylerSommer\Nice\Benchmark\ResultPrinter\MarkdownPrinter; use Zend\Http\Request; @@ -242,17 +242,14 @@ function setupDash(Benchmark $benchmark, $routes, $args) $route = new Generic(); $route->setMethods(array('get')); $route->setPathParser(new Segment('/', $str, array())); - + $routeCollection->insert('handler' . $i, $route); } $router = new Router($routeCollection); - - $lastStrRequest = new Request(); - $lastStrRequest->setUri($lastStr); - - $unknownRequest = new Request(); - $unknownRequest->setUri('/not-even-real'); + + $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); From 7badd56b0866fb2d96970ae28446c07a970823e4 Mon Sep 17 00:00:00 2001 From: Tyler Sommer Date: Wed, 26 Feb 2014 16:43:02 -0800 Subject: [PATCH 4/5] Added first-route test for Dash --- first-route-tests.php | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/first-route-tests.php b/first-route-tests.php index 083c5d5..00b0368 100644 --- a/first-route-tests.php +++ b/first-route-tests.php @@ -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. @@ -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; } @@ -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); + }); +} \ No newline at end of file From 87d710935eb8f5aed216cd20cd3888311fadbf03 Mon Sep 17 00:00:00 2001 From: Tyler Sommer Date: Wed, 26 Feb 2014 16:43:06 -0800 Subject: [PATCH 5/5] Updated README --- README.md | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b1b8324..0037acb 100644 --- a/README.md +++ b/README.md @@ -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 \ No newline at end of file