notrab / dumbo

A lightweight, friendly PHP framework for HTTP.
MIT License
158 stars 16 forks source link

Perf. improvement on Router.php #59

Closed yoh closed 1 month ago

yoh commented 1 month ago

Hi, nice job work in progress here ! I think there is a performance hole in Router.php rebuildDispatcher() is call every times a new route/group is added, and for all routes. I think this method must be call only 1 time, before the handle() call in the Dumbo->run() method. I think also that we can optionally use the FastRoute\cachedDispatcher to cache routes and get better perf.

Here are my benchmarks. This give you idea of improvements. I can make a PR if you want. [EDIT] : better use of cache

<?php

require __DIR__ . "/../vendor/autoload.php";

// -- just echo "ok" to bench basic performance
// echo "ok";

use Dumbo\Dumbo;

$nbIter = 1000;
$app = new Dumbo();

// -- don't use closure for cache
function static_handler($context)
{
    $i = trim($context->req->routePath(), '/dumbo/static/');
    return $context->json(["message" => "Hello, Dumbo {$i}!"]);
}

// $cacheFile = __DIR__ . "/../storage/cache/routes.php";
if (!isset($cacheFile) || !file_exists($cacheFile)) {
    foreach (range(1, $nbIter) as $i) {
        $app->get("/dumbo/static/{$i}", 'static_handler');
    }
}

$app->run($cacheFile ?? null);

Platform :

fixed dumbo

fixed dumbo + cache

Results

Nb static routes Current Dumbo Fixed Dumbo Fixed Dumbo + Cache
5 13.7k 14.2k 13.7k
20 8.6k 13.0k 13.7k
50 3.2k 11.3k 14.0k
100 950 9.9k 13.8k
1000 9 3.1k 13.3k

basic echo "ok" : 15.9k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/99 Running 5s test @ http://stack.local/dumbo/static/99 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 522.66us 393.98us 12.02ms 98.80% Req/Sec 4.01k 328.77 5.14k 89.16% 80901 requests in 5.10s, 15.97MB read Requests/sec: 15863.04 Transfer/sec: 3.13MB


current dumbo 5 static routes : 13.7k req/sec

rebuildDispatcher is call for each addRoute ➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 590.62us 182.00us 5.22ms 93.98% Req/Sec 3.43k 391.23 3.83k 93.14% 69607 requests in 5.10s, 15.07MB read Requests/sec: 13650.02 Transfer/sec: 2.95MB

current dumbo 20 static routes : 8.6k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 0.94ms 240.91us 6.95ms 88.44% Req/Sec 2.15k 187.41 2.29k 84.31% 43609 requests in 5.10s, 9.44MB read Requests/sec: 8551.44 Transfer/sec: 1.85MB

current dumbo 50 static routes : 3.2k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 2.50ms 0.93ms 21.26ms 93.70% Req/Sec 815.79 122.28 1.32k 82.67% 16409 requests in 5.10s, 3.55MB read Requests/sec: 3214.73 Transfer/sec: 712.62KB

current dumbo 100 static routes : 950 req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 8.45ms 1.82ms 40.66ms 95.54% Req/Sec 238.85 26.14 272.00 88.50% 4770 requests in 5.02s, 1.03MB read Requests/sec: 950.69 Transfer/sec: 210.75KB

current dumbo 1000 static routes : 9 req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 776.50ms 181.52ms 1.20s 75.00% Req/Sec 2.52 2.15 10.00 92.50% 48 requests in 5.05s, 10.64KB read Requests/sec: 9.50 Transfer/sec: 2.11KB


fixed dumbo 5 static routes : 14.2k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 590.23us 465.86us 12.79ms 98.59% Req/Sec 3.58k 439.73 4.03k 89.71% 72673 requests in 5.10s, 15.73MB read Requests/sec: 14249.09 Transfer/sec: 3.08MB

fixed dumbo 20 static routes : 13k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 632.72us 369.00us 12.98ms 98.36% Req/Sec 3.26k 356.40 3.74k 79.90% 66234 requests in 5.10s, 14.34MB read Requests/sec: 12985.34 Transfer/sec: 2.81MB

fixed dumbo 50 static routes : 11.3k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 721.28us 310.39us 9.78ms 98.16% Req/Sec 2.83k 219.32 3.08k 94.61% 57511 requests in 5.10s, 12.45MB read Requests/sec: 11277.24 Transfer/sec: 2.44MB

fixed dumbo 100 static routes : 9.9k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 833.16us 492.17us 13.25ms 98.05% Req/Sec 2.50k 266.87 2.70k 89.71% 50703 requests in 5.10s, 10.98MB read Requests/sec: 9940.52 Transfer/sec: 2.15MB

fixed dumbo 1000 static routes : 3.1k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 2.61ms 1.36ms 29.73ms 96.53% Req/Sec 792.43 93.19 1.05k 92.12% 16023 requests in 5.10s, 3.47MB read Requests/sec: 3139.33 Transfer/sec: 695.91KB


fixed dumbo + cache 5 static routes : 13.7k req/sec :

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 586.56us 158.95us 4.77ms 86.53% Req/Sec 3.44k 277.81 4.11k 80.39% 69793 requests in 5.10s, 15.11MB read Requests/sec: 13684.46 Transfer/sec: 2.96MB

fixed dumbo + cache 50 static routes : 13.7k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 610.24us 509.10us 17.55ms 98.91% Req/Sec 3.44k 358.20 4.12k 82.84% 69741 requests in 5.10s, 15.10MB read Requests/sec: 13675.00 Transfer/sec: 2.96MB

fixed dumbo + cache 50 static routes : 14k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 575.41us 160.67us 4.55ms 87.35% Req/Sec 3.51k 283.01 3.99k 87.75% 71185 requests in 5.10s, 15.41MB read Requests/sec: 13955.51 Transfer/sec: 3.02MB

fixed dumbo + cache 100 static routes : 13.8k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 594.58us 335.33us 9.51ms 98.53% Req/Sec 3.47k 375.13 4.14k 78.43% 70365 requests in 5.10s, 15.23MB read Requests/sec: 13798.47 Transfer/sec: 2.99MB

fixed dumbo + cache 1000 static routes : 13.3k req/sec

➜ dumbo wrk -t4 -c10 -d5s http://stack.local/dumbo/static/2 Running 5s test @ http://stack.local/dumbo/static/2 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 624.40us 477.67us 12.59ms 98.55% Req/Sec 3.37k 403.62 5.51k 84.73% 68020 requests in 5.10s, 14.72MB read Requests/sec: 13336.70 Transfer/sec: 2.89MB

notrab commented 1 month ago

This is fantastic @yoh!! Wow. If you open a PR I will merge.

it would also be really cool to add to the root README the benchmarks 😍😍

notrab commented 1 month ago

@yoh I merged this yesterday, and today added a simple benchmark in the examples folder. If you're up for it, I would love that benchmark to be improved with what you did originally, and maybe we could even add these benchmarks as part of the github workflow.

I'll close this PR now since the original work was implemented, but feel free to open as many as you like for other things 🫶