http bench

May 30, 2022 ยท View on GitHub

Simple framework to test HTTP servers, inspired by Simple Web Benchmark but focused on dlang frameworks and libraries.

It measures achievable RPS (requests per second) in a simple plaintext response test scenario.

Tests were gathered or modified from various places (including TechEmpower).

It uses docker container to build and host services on and can run locally or use load tester from remote host.

wrk is used as a default load generator and requests statistics collector, but hey is supported too (just use --tool switch).

Tests can be run without docker too, one just needs to have installed tested language compilers and wrk/hey workload generator (but this has been tested on linux only).

Note for io_uring tests:

  • At least Linux kernel 5.7 is needed for tests to work.
  • Problems with user limits on locked memory (ulimit -l) are possible too when run with regular user.
  • There is some performance regression starting from Kernel 5.7.16. See also these: #189, #8.

Tests

Tests are divided to two types:

  • singleCore - services are started in single core mode to measure performance without multiple threads / processes (default)
  • multiCore - services are started to use all hosts CPU cores

Some of the tests are written just with a single thread usage. To be comparable with frameworks that can utilize more threads, prefork.d was added to the suite, that just forks multiple processes and pin them to separate CPUs (tests are named prefork or has (PF) in the name).

Usage

Build execution container

  • make build - build execution container
  • make shell - enter container

Note: Performance governor is set to performance with this command.

Test runner

For simplicity, one can just run one of these commands (in the container shell):

make all        # runs all tests
make single     # runs tests limited to single CPU core usage
make multi      # runs tests limited to multiple CPU cores usage

Main entry point to more advanced tests is in _suite/runner.d which is a runnable CLI script.

  • _suite/runner.d list - list available benchmarks
  • _suite/runner.d bench - runs benchmarks
  • _suite/runner.d responses - prints out sampled response from each benchmark service
  • _suite/runner.d versions - prints out used language versions in Markdown table format

Use _suite/runner.d -h to print out CLI interface help.

Sample:

_suite/runner.d bench --type singleCore dlang rust # runs all dlang and rust tests

Remote host testing

As localhost only benchmarking is discouraged (see ie https://www.mnot.net/blog/2011/05/18/http_benchmark_rules), CLI supports executing of load tester from the remote host.

Steps:

  • on a host that would run servers, enter the container shell
  • from that run something like _suite/runner.d bench --type singleCore -r foo@192.168.0.3 --host 192.168.0.2 dlang

Where -r or --remote specifies username and hostname used for executing load tester through ssh. --host is not in most cases necessary as CLI determines host IP from default route, but it's added for cases when it's needed anyway.

It's easier to generate ssh key and copy it's identity to the load generator host as otherwise underlying ssh command'll ask for password twice for each test (warmup and test itself).

Load tester (hey) must be installed on the load tester host.

Host that generates load should be ideally more performant (in a way that workload generator doesn't saturate the used CPUs).

Frameworks / libraries

Some of the top of the Techempower frameworks were added as a reference point.

Many of the tests there are using various tweaks unusable in a real life scenarios.

  • no router (ie only match on path length, etc.)
  • no HTTP request parser
  • no Date header in the response
  • prebuilt static text for response
  • etc.

I've tried at least make response sizes to be of the same size for all the tests to be more fair.

C

These are added to determine the potential of the test environment configuration. They don't try to work as a generic HTTP servers, but just utilize the eventloop at the top speed.

Epoll and io_uring are added. Both named as raw.

dlang

archttp

New http server framework using async io (epoll, kqueue, ...).

arsd-official

I've wanted to add this popular library in the mix just for comparison. Currently three configurations of internal http servers are used:

  • process - forked process, each serving one request
  • threads - threadpool to handle connected clients
  • hybrid - an experimental Linux-only hybrid implementation of forked processes, worker threads, and fibers in an event loop

They are the same in both type tests as they don't use (at the moment) some eventloop so we can compare this traditional way against the others.

See Adam's description for more.

during
  • raw - test that tries to be as fast as possible to make a theoretical limit of the used system facility (so no parsers, routers, ... - just plain event loop)

Using new asynchronous I/O io_uring it's interesting to compare against mostly used epoll on Linux systems.

epoll

Not a library, but just an underlying polling mechanism used by most frameworks. Added to test theoretical limit of the system we measure on - same as during/raw

eventcore

Library that is a basis for vibe-d framework. It generalizes event loop against epoll on linux (iocp and kqueue on windows and MacOS).

It's a microbenchmark as it has no proper http parser, router or response writer and currently only shows event loop potential of the library.

  • callbacks - uses just callbacks to handle socket events
  • fibers - uses fibers to emulate sync behavior on async events
geario

Asynchronous I/O library used by archttp to show event base loop performance (micro benchmark).

hunt
  • hunt-http - idiomatic use of the framework (HTTP router, parser and all)
  • hunt-pico - highly customized and optimized test that uses picohttpparser and tweaked handlers for just the test purpose (prebuilt responses, no router, ...) - no wonder that it's relatively high in Techempower
lighttp

Found this on code.dlang.org so I've added it to the mix too.

It has parser, router, and response writer.

Note: Currently it's disabled due to the https://github.com/etcimon/libasync/issues/90

mecca

Core library from Weka.

It uses it's own low level fibers implementation.

Note: Uses some hacks to access druntime internals so it'd be able to switch fibers. But it won't compile with current release and some compilers. I've tried to patch it, but it still can have some problems.

photon

It's not on code.dlang.org but is an interesting library that rewrites glibc syscalls and emulates them via epoll eventloop and fibers underneath.

Test uses nodejs http-parser (not that fast as pico) and doesn't use router.

serverino

New simple to use HTTP server that uses managed subprocesses as a worker pool to handle individual requests. Single dependency library, using just standard phobos features.

It falls to the same category as arsd.

There are two variants of tests, one that uses same number if worker processes as is available CPUs and one that uses pool of 16 workers.

vibe-core

Higher level library that uses eventcore and adds fiber backed tasks framework to handle event callbacks.

Still a microbenchmark as it only uses TCPConnection and reads request line by line and then just writes static response text.

No router or http parser used.

vibe-d

Finally most popular dlang web framework that has it all.

dotnet

ASP.Net Core is used as a reference.

It has multiple tweaks mentioned above (simplistic router, prepared plaintext responses, ...). It does some magic when HTTP pipelining is used.

golang

fasthttp is used as a reference.

Test uses HTTP parser, but no router.

rust

Actix is used for comparison in two variants:

  • actix-web - simple generic usage of the library
  • actix-raw - more tweaked version with less generically used features and static responses

Results

Currently test runner outputs results in a Markdown formatted table.

Column description:

  • Res[B] - size of the sample response in bytes - to check responses are of the same size ideally
  • Req - total number of requests load generator generated
  • Err - number of responses with other than 200 OK results
  • RPS - requests per second
  • BPS - bytes per second
  • min - minimal request time in [ms]
  • 25% - 25% of requests has been completed within this time in [ms]
  • 50% - 50% of requests has been completed within this time in [ms] (median)
  • 75% - 75% of requests has been completed within this time in [ms]
  • 99% - 99% of requests has been completed within this time in [ms]
  • max - maximal request time in [ms]

Environment

LanguageVersion
gogo1.18.1
ldc21.29.0
rust1.61.0
dotnet6.0.300
  • Host: AMD Ryzen 7 3700X 8-Core (16 threads), kernel 5.17.9, Fedora 36
  • Workload generator: KVM VM with 14 pinned CPUs, Ubuntu 22.04 LTS, kernel 5.15.0-33
  • Service runner: KVM VM with 2 pinned CPUs, Ubuntu 22.04 LTS, kernel 5.15.0-33
  • Network: bridged network on the host
  • wrk version: 4.1.0
  • hey version: 0.1.4

Note: Only 2 cores for server and 14 for clients as otherwise wrk will saturate the CPUs, affecting the results (we need to utilize http server cores and not client workers) - should've bought a threadripper instead ;-)

Multi core results

  • Test command: for i in 8 64 128 256; do _suite/runner.d bench --type multiCore -r tomas@192.168.122.176 --host 192.168.122.175 --tool wrk -d 30 -c $i; done
2 concurrent clients
LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
dlangepollmicroraw - lvl (PF)13169454375284004460.0260.0410.0440.0480.0713.351
dlangepollmicroraw - edge (PF)12971964309682744720.0270.0420.0450.0480.0695.888
dlangmeccamicroprefork12899574285582282970.0280.0420.0450.0480.0671.875
dlangeventcoremicrocb (PF)12843164266881923140.0270.0430.0450.0480.0691.591
dlangeventcoremicrofibers (PF)12678494212180872760.0270.0430.0460.050.071.275
dlangduringmicroraw (PF)12462844140479497180.0270.0440.0470.050.0693.06
dlangadio-httpplatformepoll (PF)12378654112578960150.0290.0440.0470.0510.079.233
cepollmicroraw - edge (PF)12013273991176629490.0290.0450.0480.0520.0817.757
cepollmicroraw - lvl (PF)12005833988676582030.0290.0450.0480.0530.0744.531
dlanggeariomicrogeario (multi)11757683906274999150.0290.0460.0490.0540.0736.632
dlangvibe-coremicroprefork11661303874174384370.0270.0460.050.0540.0775.855
dlanghuntmicrohunt-pico11613313858274078250.0290.0440.0480.0540.9075.268
dotnetaspcoreplatform11554593838773703690.0310.0460.0490.0540.30810.679
cio_uringmicroraw (PF)11399723787272715820.030.0480.0510.0550.0762.174
cnginxplatform11103453688870825990.030.0480.0520.0570.0793.845
golangfasthttpplatform11083163682170696560.0290.0450.0510.0590.0925.502
dlangadio-httpplatformio_uring (PF)10910403624769594570.0320.050.0530.0580.0774.449
rustactix-rawmicro10682053548868137990.030.050.0540.0590.0848.98
dlangphotonmicro10414913460166433970.0330.0520.0560.0610.0852.802
dlangarsdplatformhybrid10184313383464963040.0360.0520.0560.0610.1248.286
rustactix-webplatform10047303337964089080.0370.0530.0570.0630.0886.853
dlangarsdplatformprocesses9303353090859343620.040.0570.0620.0680.0993.741
dlangvibe-dplatformmanual (PF)8872732947756596810.0440.0610.0650.0710.0985.109
dlangserverinoplatformserverino7906592626750434060.0510.0660.0730.0820.121.077
dlangserverinoplatformserverino (16)7785872586649664020.0510.0680.0750.0820.1221.159
dlangvibe-dplatformgc (PF)7445522473547493010.0490.0720.0780.0860.1152.028
dlangarsdplatformthreads7325252441746881600.0380.0540.0620.0841.27411.121
dlangvibe-dplatformmanual7068212356045236540.0420.0730.080.0880.8674.975
dlangvibe-dplatformgc6973352316744481160.0430.0710.0780.0871.0283.664
dlangarchttpplatformarchttp (multi)239090794315250920.0150.0988.90426.50643.52248.034
dlanghuntplatformhunt-http9705532246190880.0640.0970.15619.92543.42744.241
8 concurrent clients
LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
dlangepollmicroraw - lvl (PF)282767593942180369960.030.0720.0820.0940.1459.47
dlangeventcoremicrocb (PF)269072889392171634470.0280.0740.0850.0990.1812.171
cepollmicroraw - lvl (PF)267608788906170700560.030.0740.0860.0990.1828.085
dlangvibe-coremicroprefork265269888129169208640.030.0670.0840.1050.2268.889
dlangepollmicroraw - edge (PF)260944786692166449770.0330.0770.0890.1020.1736.064
dlangduringmicroraw (PF)260365786500166080440.0320.070.0850.1060.2052.38
cepollmicroraw - edge (PF)258411385850164833780.0310.0720.0870.1060.2088.438
rustactix-rawmicro256010385053163302250.0330.0730.0870.1070.2239.417
dlangeventcoremicrofibers (PF)251477483547160410830.0310.0750.0890.1070.2518.924
dlangmeccamicroprefork246488381889157228410.030.0690.0920.1190.228.896
dlangadio-httpplatformio_uring (PF)244595881261156021240.0330.080.0940.110.1972.121
cnginxplatform243102880765155068890.0340.0740.0910.1150.2212.427
dlangadio-httpplatformepoll (PF)240529779910153427580.0310.0720.0860.1120.5386.418
dlanghuntmicrohunt-pico236676578630150969720.0280.0670.0840.1141.2337.417
rustactix-webplatform230259776498146876610.0350.0780.0960.1210.2554.159
cio_uringmicroraw (PF)227891675711145366070.0340.0680.0830.1290.4214.659
golangfasthttpplatform224936874729143481280.030.0760.0980.1245.83515.134
dlangphotonmicro215301071528137334850.0320.0830.0990.121.13521.05
dlanggeariomicrogeario (multi)211801370365135102490.0380.1060.1140.1220.1657.373
dotnetaspcoreplatform198898266079126871940.0380.0920.110.1353.84330.757
dlangarsdplatformprocesses157522852333100479650.0430.1030.1340.1841.19911.995
dlangarsdplatformhybrid12976444324083021540.040.0720.1360.3572.3689.136
dlangvibe-dplatformmanual (PF)12473064143879562370.0460.1410.170.230.4636.198
dlangvibe-dplatformmanual12002483987576560660.0470.1560.1820.221.147.362
dlangvibe-dplatformgc (PF)11970733976976358140.0490.1620.1880.2260.4438.018
dlangserverinoplatformserverino (16)11509923823873418750.0510.1450.1920.2510.7084.853
dlangarsdplatformthreads11200413732271658730.0360.070.1070.692.97216.095
dlangvibe-dplatformgc10741083580368742910.0480.1510.1880.2621.70716.34
dlangarchttpplatformarchttp (multi)7140542372245547630.0080.1298.95826.50643.456.037
dlangserverinoplatformserverino6515512169641657600.0530.0840.12080.225833.286004.01
dlanghuntplatformhunt-http3416091134921790340.0690.1070.16420.11743.33248.096
64 concurrent clients
LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
cepollmicroraw - lvl (PF)5627346187141359311740.0340.2440.2790.3251.01812.675
dlangepollmicroraw - lvl (PF)5313638176532338943020.0360.2580.2990.3530.70212.268
cepollmicroraw - edge (PF)5210803173116332383440.0350.2630.3060.3620.79714.538
dlangeventcoremicrocb (PF)5028078167045320727890.0330.2680.3190.3820.64313.84
dlangepollmicroraw - edge (PF)5016841166672320011120.0380.2710.3210.3790.7816.443
cio_uringmicroraw (PF)4684383155627298804490.0370.2810.3420.4160.69911.766
dlangduringmicroraw (PF)4537648150752289444650.0380.2870.3530.430.94125.645
dlangmeccamicroprefork4351115144555277546200.0310.2980.3720.4521.013203.219
dlangeventcoremicrofibers (PF)4341419144233276927720.0330.3020.3760.4530.80924.307
rustactix-rawmicro4200034139536267909140.0370.310.3870.470.87927.138
dlangvibe-coremicroprefork4134974137374263759130.0340.3110.3940.4810.94620.58
dlangadio-httpplatformepoll (PF)4110871136573262221670.0320.3230.40.480.7655.571
dlangadio-httpplatformio_uring (PF)4089210135854260839970.0360.3140.3890.4860.84415.739
cnginxplatform3862444128320246375160.0420.3350.4130.5120.87811.056
dlanghuntmicrohunt-pico3722501123671237448560.0340.2740.360.531.9717.355
rustactix-webplatform296441598485189092250.0510.4170.5230.6831.31910.352
golangfasthttpplatform295846998288188712970.0290.3060.470.7867.04321.361
dlanggeariomicrogeario (multi)281932193665179837080.0430.3010.7170.8111.16310.923
dlangphotonmicro243411380867155265670.0310.1780.340.3931.6129.751
dotnetaspcoreplatform222450073903141895010.040.3910.5871.028.91431.024
dlangarsdplatformhybrid169676156370108231930.0410.1360.6312.3539.32826.921
dlangarsdplatformprocesses159259052945101654680.040.1080.1420.1860.30810.517
dlangarchttpplatformarchttp (multi)15153045037596721530.0070.3818.41226.30143.89855.388
dlangvibe-dplatformmanual (PF)14455954807492302700.0480.9191.0991.4342.48514.146
dlangvibe-dplatformgc (PF)14080104680889872970.050.871.0461.5363.00824.329
dlangvibe-dplatformmanual13027424328083098490.0450.9021.1011.6623.5330.144
dlangvibe-dplatformgc12754784243181467650.0480.8351.1121.7286.20656.107
dlangarsdplatformthreads11329733764072269370.0360.0630.0750.1072.3399.042
dlanghuntplatformhunt-http8649972873755175880.0720.2620.44519.56444.00250.542
dlangserverinoplatformserverino6680742221742657200.0530.0750.0910.10219137.724316.2
dlangserverinoplatformserverino (16)6200342061939589790.0550.5830.7570.9111074.182515.51
128 concurrent clients
LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
dlangepollmicroraw - edge (PF)7072751234975451152220.050.4660.520.5810.88517.171
dlangepollmicroraw - lvl (PF)6984380232039445515260.0490.4690.5230.5850.96228.866
cepollmicroraw - lvl (PF)6815637226433434751590.040.4780.5340.6011.01220.963
dlangduringmicroraw (PF)6679695221916426080210.040.4570.5320.631.33123.282
cepollmicroraw - edge (PF)6531244216984416610910.0460.4910.5550.6381.21221.052
dlangeventcoremicrocb (PF)6078832201954387752730.0330.510.5930.6962.46319.506
dlangmeccamicroprefork5709961189699364223420.0330.5450.6410.7521.207407.954
cio_uringmicroraw (PF)5568514185000355200890.0280.5310.6350.7674.33720.171
dlangeventcoremicrofibers (PF)5324433176891339631600.0350.570.680.8034.51916.985
rustactix-rawmicro5103294169544325525730.0480.6060.720.8432.28522.292
dlangadio-httpplatformepoll (PF)4743039157576302546000.0340.6390.7810.9253.5520.308
dlanggeariomicrogeario (multi)4701167156340300174280.0510.4360.5271.0752.11598.489
dlangadio-httpplatformio_uring (PF)4703045156247299994890.0390.6210.7690.9472.31421.8
dlanghuntmicrohunt-pico4181250138911266710960.0430.5050.7571.1313.64623.918
cnginxplatform3862522128322246380140.0410.7360.9581.1912.03129.225
rustactix-webplatform3357019111528214135430.1040.8011.0781.4122.83621.864
golangfasthttpplatform3140006104319200292740.030.6171.0631.7328.25538.465
dlangphotonmicro3026070100533193025060.0360.4430.6051.3765.0335.768
dotnetaspcoreplatform239404179536152709590.0390.9151.2932.03210.21630.163
dlangarsdplatformhybrid186293461953118950220.0420.5580.9426.16320.56376.829
dlangarsdplatformprocesses160049353190102125170.040.1080.1430.1830.3014.672
dlangvibe-dplatformmanual (PF)14685874880693708440.0491.8092.3883.3287.57844.817
dlangvibe-dplatformgc (PF)14239904734090892970.0482.1122.3543.4636.60864.523
dlangarchttpplatformarchttp (multi)14131284696390169680.0080.99711.48329.11646.46155.152
dlangvibe-dplatformgc13392974452485487040.0451.722.6123.72310.6850.342
dlangvibe-dplatformmanual13223154397484431150.0461.9992.283.8578.17677.187
dlangarsdplatformthreads11401453790372775210.0370.060.0720.1042.34310.562
dlanghuntplatformhunt-http7523252501948036710.070.4972.51323.56346.90254.783
dlangserverinoplatformserverino6769162248843178690.0550.070.0780.10218361.524081.2
dlangserverinoplatformserverino (16)6055692011838627650.0550.5710.750.93799.1122356.72
dlangvibe-coremicroprefork4996132165984318690140.0320.6040.7360.8644.64132.442
256 concurrent clients
LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
dlangepollmicroraw - lvl (PF)8320651276433530752480.060.7770.8810.9981.77717.47
dlangepollmicroraw - edge (PF)7878303261737502536270.0730.840.9361.0421.77912.73
cepollmicroraw - lvl (PF)7869349261440501965110.0490.8070.9181.054.20323.584
dlangeventcoremicrocb (PF)7817616259721498665200.0360.8320.9311.0581.77220.822
cepollmicroraw - edge (PF)7780451258486496294540.0670.8340.9461.0612.59713.222
dlangduringmicroraw (PF)7623010253256486251800.0430.8310.9441.082.46119.509
cio_uringmicroraw (PF)7429070246812473880870.0520.8480.9591.1043.35322.446
dlangeventcoremicrofibers (PF)7233458240314461403300.0330.8710.9941.1513.31218.625
dlangmeccamicroprefork6186368205527394612170.030.961.1521.3796.946839.203
dlangvibe-coremicroprefork5614008186511358102830.0331.0661.2971.536.69931.666
rustactix-rawmicro5594392185921356970170.0611.0821.3051.5295.67321.137
dlangadio-httpplatformepoll (PF)5475263182144349717390.0321.0851.3351.5975.205213.225
dlangadio-httpplatformio_uring (PF)5413654179855345322780.0471.0281.3121.6584.116208.183
dlanggeariomicrogeario (multi)5232089173939333963120.110.8431.0012.1334.309224.177
cnginxplatform4410031146610281491340.0751.1841.6762.0595.45852.411
rustactix-webplatform3830410127425244656920.071.2531.9112.55.89135.206
dlanghuntmicrohunt-pico3530619117374225358650.0691.181.9292.9048.32425.105
dlangphotonmicro3387719112548216093700.0330.7291.0251.9946.77520.236
golangfasthttpplatform3334498110780212698870.0321.3212.0663.0758.75840.004
dotnetaspcoreplatform236257078569150852490.041.7792.764.34813.52634.656
dlangarsdplatformhybrid179674859752114724180.0410.9812.4249.23422.83299.006
dlangarsdplatformprocesses158083752554100904480.040.1080.1420.1870.3239.946
dlangvibe-dplatformmanual15304835088097690400.0483.0134.6036.53313.28551.639
dlangvibe-dplatformmanual (PF)15194945051596988970.0443.3834.1946.65613.9850.202
dlangvibe-dplatformgc (PF)14918124957895190390.0453.5844.9466.37710.75936.438
dlangarchttpplatformarchttp (multi)14617284857893270770.0053.43814.78732.66551.619301.141
dlangvibe-dplatformgc13168284379284080800.0453.7595.5857.42619.90467.111
dlangarsdplatformthreads11374093780072576440.0370.0590.0710.1032.3311.058
dlangserverinoplatformserverino7031612339144912470.0530.0710.0780.116682.828452
dlanghuntplatformhunt-http7009282329444725210.0721.2937.33430.0451.48761.043
dlangserverinoplatformserverino (16)5305001763033850440.0560.5450.9461.1083.6982280.68

Pipelining

For an idea of how HTTP pipelining is handled in the frameworks, here are some results.

Command: _suite/runner.d bench --type multiCore -r tomas@192.168.122.176 --host 192.168.122.175 --tool wrk -d 30 -c 256 --pipeline 10

LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
cepollmicroraw - lvl (PF)6420083021329174095202440.0720.3990.6770.9682.6815.774
dlangepollmicroraw - lvl (PF)6246515020752543984487970.0640.4090.6950.9874.84919.534
dlangduringmicroraw (PF)6057264020123803863769720.1130.4220.7171.032.08715.62
cepollmicroraw - edge (PF)6036746020055633850681830.0720.4230.7191.0245.34521.092
dlangepollmicroraw - edge (PF)5833890019381693721285310.1080.4390.7461.0571.71822.185
cio_uringmicroraw (PF)5715197018987363645574160.1070.4470.7611.081.84817.091
dlangmeccamicroprefork5679851018869933623027880.0420.4490.7631.0895.322408.63
rustactix-rawmicro3485345011594622226168460.0920.7341.2571.9615.73623.369
dotnetaspcoreplatform242194908049011545411120.0461.0611.8452.9189.935.599
dlangadio-httpplatformio_uring (PF)187029806213611193014000.0921.3732.3683.5557.398232.723
dlangadio-httpplatformepoll (PF)185050806154001181568120.0471.4062.4964.00210.479206.82
dlanghuntmicrohunt-pico178549795931881138922240.1361.4372.4613.66836.00664.379
dlangeventcoremicrocb (PF)178300785923611137333870.0891.442.4763.68837.8666.244
dlangeventcoremicrofibers (PF)177588575899951132790870.0971.4452.4873.72537.31163.008
dlangvibe-coremicroprefork169093595619591078962080.0791.5192.6274.09542.64477.024
golangfasthttpplatform166355905526771061140620.0481.5772.8384.53310.81759.784
rustactix-webplatform159350005295771016789630.11.5772.7734.03918.82965.503
dlangphotonmicro8801333292500561600510.0752.3294.5998.44245.83883.562
cnginxplatform6023810200126384243020.1734.3097.86112.98943.237112.092
dlangarchttpplatformarchttp (multi)3225950107174205774880.0110.1220.1270.1320.1814.953
dlangvibe-dplatformmanual270693789961172725790.1389.56416.89428.604560.4331687.64
dlangvibe-dplatformgc (PF)261663487018167074730.1349.86917.33128.298358.1391884.48
dlangvibe-dplatformmanual (PF)256592285274163727820.12710.10917.50927.832140.481176.18
dlangvibe-dplatformgc203187167526129650790.23512.75222.09733.79548.0962267.84
dlanghuntplatformhunt-http13834544597788276222.07819.19731.10744.54884.404119.169

Note: arsd, geario and serverino have problems with this and doesn't finish

Special note

As arsd (excluding arsd/hybrid) and serverino doesn't use async IO, requests can be blocked for some time when keep-alive connections are used (on by default). With wrk it's not visible much, as it just bursts requests from any client that communicates and some of the clients doesn't receive any response.

To make it stand out more, here are some results with hey with number of clients equal to available CPU cores (so they should be completed without waiting in queue) and a multiple of that.

Command: for i in 2 16; do _suite/runner.d bench --type multiCore -r tomas@192.168.122.176 --host 192.168.122.175 --tool hey -b 2 -c $i arsd serverino actix-web; done

2 concurrent clients
LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
rustactix-webplatform20001943637317780.10.10.10.10.21.1
dlangarsdplatformthreads20001870935921420.10.10.10.10.31.2
dlangarsdplatformprocesses20001792134408600.10.10.10.10.21.3
dlangarsdplatformhybrid20001752833654680.10.10.10.10.21.2
dlangserverinoplatformserverino (16)20001661131893680.10.10.10.10.34.4
dlangserverinoplatformserverino20001562530000000.10.10.10.10.31.1
64 concurrent clients
LanguageFrameworkCategoryNameReqRPSBPSmin25%50%75%99%max
rustactix-webplatform160005110198115610.10.20.20.31.39.5
dlangarsdplatformhybrid160003593869002690.10.10.20.42.67.8
dlangserverinoplatformserverino (16)160001341225752360.10.40.50.61.91082.3
dlangarsdplatformthreads1600041657998330.10.10.20.22.3013538.1
dlangarsdplatformprocesses1600024504704000.10.10.20.20.86430.2
dlangserverinoplatformserverino1600018123479710.10.10.10.10.38690