diff --git a/_benchmarks/README.md b/_benchmarks/README.md index b8217e4e..92ff71ff 100644 --- a/_benchmarks/README.md +++ b/_benchmarks/README.md @@ -10,7 +10,11 @@ * **.NET Core**: https://www.microsoft.com/net/core, latest version **2.0** * **Iris**: https://github.com/kataras/iris, latest version **8.3** built with [go1.8.3](https://golang.org) -## Results +# .NET Core MVC vs Iris MVC + +The first test will contain a simple application with a text response and the second will render templates + a layout. + +## Simple We will compare two identical things here, in terms of application, the expected response and the stability of their run times, so we will not try to put more things in the game like `JSON` or `XML` encoders and decoders, just a simple text message. To achieve a fair comparison we will use the MVC architecture pattern on both sides, Go and .NET Core. @@ -60,31 +64,10 @@ Statistics Avg Stdev Max Throughput: 19.65MB/s ``` -### Iris -```bash -$ cd iris -$ go run main.go -Now listening on: http://localhost:5000 -Application started. Press CTRL+C to shut down. -``` - -```bash -$ bombardier -c 125 -n 5000000 http://localhost:5000/api/values/5 -Bombarding http://localhost:5000/api/values/5 with 5000000 requests using 125 connections - 5000000 / 5000000 [======================================================================================] 100.00% 45s -Done! -Statistics Avg Stdev Max - Reqs/sec 110809.98 8209.87 128212 - Latency 1.13ms 307.86us 18.02ms - HTTP codes: - 1xx - 0, 2xx - 5000000, 3xx - 0, 4xx - 0, 5xx - 0 - others - 0 - Throughput: 20.61MB/s -``` Click [here](screens) to navigate to the screenshots. -#### Summary +### Summary * Time to complete the `5000000 requests` - smaller is better. * Reqs/sec - bigger is better. @@ -97,8 +80,6 @@ Click [here](screens) to navigate to the screenshots. Iris MVC Application, written using 27 lines of code, ran for **47 seconds** serving **105643.71** requests per second within **1.18ms** latency in average and **22.01ms** max, the memory usage of all these was ~12MB. -Iris Application, written using 22 lines of code, ran for **45 seconds** serving **110809.98** requests per second within **1.13ms** latency in average and **18.02ms** max, the memory usage of all these was ~11MB. - #### Update: 20 August 2017 As [Josh Clark](https://twitter.com/clarkis117) and [Scott Hanselman‏](https://twitter.com/shanselman)‏ pointed out [on this status](https://twitter.com/shanselman/status/899005786826788865), on .NET Core MVC `Startup.cs` file the line with `services.AddMvc();` can be replaced with `services.AddMvcCore();`. I followed their helpful instructions and re-run the benchmarks. The article now contains the latest benchmark output for the .NET Core application with the change both Josh and Scott noted. @@ -107,7 +88,7 @@ The twitter conversion: https://twitter.com/MakisMaropoulos/status/8991132158959 For those who want to compare with the standard services.AddMvc(); you can see the old output by pressing [here](screens/5m_requests_netcore-mvc.png). -## Results with Templates +## MVC + Templates Let’s run one more benchmark, spawn `1000000 requests` but this time we expect HTML generated by templates via the view engine. @@ -157,7 +138,7 @@ Statistics Avg Stdev Max Throughput: 192.51MB/s ``` -#### Summary +### Summary * Time to complete the `1000000 requests` - smaller is better. * Reqs/sec - bigger is better. @@ -169,14 +150,79 @@ Statistics Avg Stdev Max Iris MVC with Templates Application ran for **37 seconds** serving **26656.76** requests per second with **192.51MB/s** within **1.18ms** latency in average and **22.52ms** max, the memory usage of all these was ~17MB. -## Results with Sessions +# .NET Core (Kestrel) vs Iris -Here we will check the sessions performance, this time -we wanna use the .NET Core raw, **not MVC** and Iris raw, not MVC respectfully. +_Monday, 21 August 2017_ -Spawn `5000000 requests` with 125 different "threads" that sets and gets a session with name `key` and string value `"value"` to the same static request path. +This time we will compare the speed of the “low-level” .NET Core’s server implementation named Kestrel and Iris’ “low-level” handlers, we will test two simple applications, the first will be the same as our previous application but written using handlers and the second test will contain a single route which sets and gets a session value(string) based on a key(string). -### .NET Core with Sessions +## Simple + +Spawn `1000000 requests` with 125 different "threads", tagrget to a dynamic registered route path, responds with a simple "value" text. + +### .NET Core (Kestrel) + +```bash +$ cd netcore +$ dotnet run -c Release +Hosting environment: Production +Content root path: C:\mygopath\src\github.com\kataras\iris\_benchmarks\netcore +Now listening on: http://localhost:5000 +Application started. Press Ctrl+C to shut down. +``` + +```bash +Bombarding http://localhost:5000/api/values/5 with 1000000 requests using 125 connections + 1000000 / 1000000 [======================================================================================] 100.00% 10s +Done! +Statistics Avg Stdev Max + Reqs/sec 97884.57 8699.94 110509 + Latency 1.28ms 682.63us 61.04ms + HTTP codes: + 1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0 + others - 0 + Throughput: 17.73MB/s +``` + +### Iris + +```bash +$ cd iris +$ go run main.go +Now listening on: http://localhost:5000 +Application started. Press CTRL+C to shut down. +``` + +```bash +Bombarding http://localhost:5000/api/values/5 with 1000000 requests using 125 connections + 1000000 / 1000000 [=======================================================================================] 100.00% 8s +Done! +Statistics Avg Stdev Max + Reqs/sec 117917.79 4437.04 125614 + Latency 1.06ms 278.12us 19.03ms + HTTP codes: + 1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0 + others - 0 + Throughput: 21.93MB/s +``` + +### Summary + +* Time to complete the `1000000 requests` - smaller is better. +* Reqs/sec - bigger is better. +* Latency - smaller is better +* Throughput - bigger is better. +* LOC (Lines Of Code) - smaller is better. + +.NET Core (Kestrel) Application written using **63 code of lines** ran for **10 seconds** serving **97884.57** requests per second with **17.73MB/s** within **1.28ms** latency in average and **61.04ms** max. + +Iris Application written using **14 code of lines** ran for **8 seconds** serving **117917.79** requests per second with **21.93MB/s** within **1.06ms** latency in average and **19.03ms** max. + +## Sessions + +Spawn `5000000 requests` with 125 different "threads" target a static request path, sets and gets a session with name `key` and string value `"value"` and write session value that to the response stream. + +### .NET Core (Kestrel) with Sessions ```bash $ cd netcore-sessions @@ -222,7 +268,7 @@ Statistics Avg Stdev Max Throughput: 20.65MB/s ``` -#### Summary +### Summary * Time to complete the `5000000 requests` - smaller is better. * Reqs/sec - bigger is better. @@ -233,6 +279,9 @@ Statistics Avg Stdev Max Iris with Sessions Application ran for **1 minute and 15 seconds** serving **66749.70** requests per second with **20.65MB/s** within **1.88ms** latency in average and **1.94s** max. +> A new article based on the latest, Kestrel and Iris, benchmarks is coming. Stay tuned! + +> Click [here](screens) to navigate to the screenshots. **Thank you all** for the 100% green feedback, have fun! diff --git a/_benchmarks/iris/main.go b/_benchmarks/iris/main.go index e3f9847d..a8e296a9 100644 --- a/_benchmarks/iris/main.go +++ b/_benchmarks/iris/main.go @@ -7,22 +7,8 @@ import ( func main() { app := iris.New() - // These handlers are serving the same routes as - // `ValuesController`s of netcore-mvc and iris-mvc applications do. - app.Get("/api/values/{id}", getHandler) - app.Put("/api/values/{id}", putHandler) - app.Delete("/api/values/{id}", delHandler) + app.Get("/api/values/{id}", func(ctx context.Context) { + ctx.WriteString("value") + }) app.Run(iris.Addr(":5000")) } - -// getHandler handles "GET" requests to "api/values/{id}". -func getHandler(ctx context.Context) { - // id,_ := vc.Params.GetInt("id") - ctx.WriteString("value") -} - -// putHandler handles "PUT" requests to "api/values/{id}". -func putHandler(ctx context.Context) {} - -// delHandler handles "DELETE" requests to "api/values/{id}". -func delHandler(ctx context.Context) {} diff --git a/_benchmarks/netcore/Program.cs b/_benchmarks/netcore/Program.cs new file mode 100644 index 00000000..92bb511a --- /dev/null +++ b/_benchmarks/netcore/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace netcore +{ + public class Program + { + public static void Main(string[] args) + { + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup() + .Build(); + } +} diff --git a/_benchmarks/netcore/Startup.cs b/_benchmarks/netcore/Startup.cs new file mode 100644 index 00000000..f5ff0edd --- /dev/null +++ b/_benchmarks/netcore/Startup.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Http; + +namespace netcore +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.AddRouting(); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + var routeBuilder = new RouteBuilder(app); + routeBuilder.MapGet("api/values/{id}", context =>{ + return context.Response.WriteAsync("value"); + }); + var routes = routeBuilder.Build(); + app.UseRouter(routes); + } + } +} diff --git a/_benchmarks/netcore/appsettings.json b/_benchmarks/netcore/appsettings.json new file mode 100644 index 00000000..50fe9a31 --- /dev/null +++ b/_benchmarks/netcore/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Error" + } + } +} diff --git a/_benchmarks/netcore/netcore.csproj b/_benchmarks/netcore/netcore.csproj new file mode 100644 index 00000000..b36fc56a --- /dev/null +++ b/_benchmarks/netcore/netcore.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp2.0 + + + + + + + + + + + diff --git a/_benchmarks/screens/1m_requests_iris.png b/_benchmarks/screens/1m_requests_iris.png new file mode 100644 index 00000000..78617a9a Binary files /dev/null and b/_benchmarks/screens/1m_requests_iris.png differ diff --git a/_benchmarks/screens/1m_requests_netcore.png b/_benchmarks/screens/1m_requests_netcore.png new file mode 100644 index 00000000..7e36b7ef Binary files /dev/null and b/_benchmarks/screens/1m_requests_netcore.png differ