Skip to content

Instantly share code, notes, and snippets.

@slavcodev
Last active November 15, 2019 10:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slavcodev/0e9a2d89d7fef6b19d8e7801bb81e684 to your computer and use it in GitHub Desktop.
Save slavcodev/0e9a2d89d7fef6b19d8e7801bb81e684 to your computer and use it in GitHub Desktop.
Routers Benchmark
<?php
declare(strict_types=1);
use FastRoute\RouteCollector;
use Symfony\Component\Routing\Matcher\CompiledUrlMatcher;
use Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use function FastRoute\simpleDispatcher;
final class RouterTest extends TestCase
{
const STEPS = 10000;
protected function setUp(): void
{
parent::setUp();
echo "\n> {$this->getName()}\n";
}
protected function tearDown(): void
{
parent::tearDown();
self::assertTrue(true);
}
private function createRoutes(): RouteCollection
{
$routes = new RouteCollection();
for ($i = 0; $i < 400; ++$i) {
$routes->add('yes-static-'.$i, new Route('/abc'.$i));
$routes->add('not-static-'.$i, new Route('/abc{foo}/'.$i));
}
return $routes;
}
/**
* @test
*/
public function symfony(): void
{
$routes = $this->createRoutes();
$matcher = new UrlMatcher($routes, new RequestContext('', 'GET'));
// Warm
$matcher->match('/abc0');
$matcher->match('/abc0/0');
$matcher->match('/abc399');
$matcher->match('/abc0/399');
$time = microtime(true);
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc0');
}
$this->report('First static', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc399');
}
$this->report('Last static', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc0/0');
}
$this->report('First dynamic', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc399/399');
}
$this->report('Last dynamic', $time, microtime(true));
}
/**
* @test
*/
public function symfonyCompiled(): void
{
$routes = $this->createRoutes();
$dumper = new CompiledUrlMatcherDumper($routes);
$compiledRoutes = $dumper->getCompiledRoutes();
$matcher = new CompiledUrlMatcher($compiledRoutes, new RequestContext('', 'GET'));
// Warm
$matcher->match('/abc0');
$matcher->match('/abc0/0');
$matcher->match('/abc399');
$matcher->match('/abc0/399');
$time = microtime(true);
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc0');
}
$this->report('First static', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc399');
}
$this->report('Last static', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc0/0');
}
$this->report('First dynamic', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->match('/abc399/399');
}
$this->report('Last dynamic', $time, microtime(true));
}
/**
* @test
*/
public function fastroute(): void
{
$matcher = simpleDispatcher(
static function (RouteCollector $routes): void {
for ($i = 0; $i < 400; ++$i) {
$routes->addRoute('GET', '/abc' . $i, 'yes-static-'.$i);
$routes->addRoute('GET', '/abc{foo}/' . $i, 'not-static-'.$i);
}
}
);
// Warm
$matcher->dispatch('GET', '/abc0');
$matcher->dispatch('GET', '/abc0/0');
$matcher->dispatch('GET', '/abc399');
$matcher->dispatch('GET', '/abc0/399');
$time = microtime(true);
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->dispatch('GET', '/abc0');
}
$this->report('First static', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->dispatch('GET', '/abc399');
}
$this->report('Last static', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->dispatch('GET', '/abc0/0');
}
$this->report('First dynamic', $time, microtime(true));
for ($i = 0; $i < self::STEPS; ++$i) {
$matcher->dispatch('GET', '/abc399/399');
}
$this->report('Last dynamic', $time, microtime(true));
}
private function report(string $label, float &$start, float $end): void
{
printf("%s: %f ms\n", $label, $end - $start);
$start = $end;
}
}
@slavcodev
Copy link
Author

Result

> symfony
First static: 0.307559 ms
Last static: 42.694799 ms
First dynamic: 0.367971 ms
Last dynamic: 42.337238 ms

> fastroute
First static: 0.009981 ms
Last static: 0.009755 ms
First dynamic: 0.032514 ms
Last dynamic: 0.360392 ms

@slavcodev
Copy link
Author

slavcodev commented Nov 15, 2019

Result with xdebug off

> symfony
First static: 0.089548 ms
Last static: 3.154077 ms
First dynamic: 0.097837 ms
Last dynamic: 3.256220 ms

> fastroute
First static: 0.001488 ms
Last static: 0.001487 ms
First dynamic: 0.005097 ms
Last dynamic: 0.121380 ms

@slavcodev
Copy link
Author

slavcodev commented Nov 15, 2019

Result with compiled routes for Symfony (xdebug off)

> symfony
First static: 0.083611 ms
Last static: 3.227731 ms
First dynamic: 0.092768 ms
Last dynamic: 3.231728 ms

> symfonyCompiled
First static: 0.005310 ms
Last static: 0.005034 ms
First dynamic: 0.011305 ms
Last dynamic: 0.012007 ms

> fastroute
First static: 0.001489 ms
Last static: 0.001482 ms
First dynamic: 0.005152 ms
Last dynamic: 0.113381 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment