Browse Source

Merge branch 'round-14' of https://github.com/TechEmpower/FrameworkBenchmarks into round-14

Keith Newman 9 years ago
parent
commit
46b06d4d0e
100 changed files with 2679 additions and 401 deletions
  1. 16 0
      .github/PULL_REQUEST_TEMPLATE.md
  2. 3 0
      .gitignore
  3. 3 2
      .travis.yml
  4. 0 2
      config/create-postgres-database.sql
  5. 0 29
      config/create-postgres-old.sql
  6. 0 29
      config/create-postgres-upper-quote.sql
  7. 4 0
      config/create-postgres.sql
  8. 2 53
      config/create.sql
  9. 1 1
      config/travis_setup.sh
  10. 23 0
      frameworks/C++/ffead-cpp/benchmark_config.json
  11. 12 0
      frameworks/C++/ffead-cpp/setup-apache2.sh
  12. 1 1
      frameworks/C++/silicon/CMakeLists.txt
  13. 1 1
      frameworks/C++/silicon/setup_lwan_mysql.sh
  14. 1 1
      frameworks/C++/silicon/setup_mhd_epoll_mysql.sh
  15. 1 1
      frameworks/C++/silicon/setup_mhd_tpc_mysql.sh
  16. 19 0
      frameworks/CSharp/aspnetcore/Benchmarks/Benchmarks.xproj
  17. 11 0
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/AppSettings.cs
  18. 15 0
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleArgs.cs
  19. 85 0
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleHostScenariosConfiguration.cs
  20. 20 0
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/EnabledScenario.cs
  21. 10 0
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/IScenariosConfiguration.cs
  22. 149 0
      frameworks/CSharp/aspnetcore/Benchmarks/Configuration/Scenarios.cs
  23. 75 0
      frameworks/CSharp/aspnetcore/Benchmarks/Controllers/FortunesController.cs
  24. 46 0
      frameworks/CSharp/aspnetcore/Benchmarks/Controllers/HomeController.cs
  25. 28 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/ApplicationDbContext.cs
  26. 89 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/ApplicationDbSeeder.cs
  27. 79 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/DapperDb.cs
  28. 52 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/EfDb.cs
  29. 33 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/Fortune.cs
  30. 10 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/IRandom.cs
  31. 17 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/Random.cs
  32. 122 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/RawDb.cs
  33. 12 0
      frameworks/CSharp/aspnetcore/Benchmarks/Data/World.cs
  34. 90 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/DebugInfoPageMiddleware.cs
  35. 47 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/ErrorHandlerMiddleware.cs
  36. 51 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesDapperMiddleware.cs
  37. 51 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesEfMiddleware.cs
  38. 51 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesRawMiddleware.cs
  39. 57 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/JsonMiddleware.cs
  40. 47 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MiddlewareHelpers.cs
  41. 61 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesDapperMiddleware.cs
  42. 61 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesEfMiddleware.cs
  43. 61 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesRawMiddleware.cs
  44. 48 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/PlaintextMiddleware.cs
  45. 60 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryDapperMiddleware.cs
  46. 59 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryEfMiddleware.cs
  47. 60 0
      frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryRawMiddleware.cs
  48. 31 0
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.Designer.cs
  49. 32 0
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.cs
  50. 42 0
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.Designer.cs
  51. 32 0
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.cs
  52. 41 0
      frameworks/CSharp/aspnetcore/Benchmarks/Migrations/ApplicationDbContextModelSnapshot.cs
  53. 8 0
      frameworks/CSharp/aspnetcore/Benchmarks/NuGet.Config
  54. 138 0
      frameworks/CSharp/aspnetcore/Benchmarks/Program.cs
  55. 27 0
      frameworks/CSharp/aspnetcore/Benchmarks/Properties/launchSettings.json
  56. 185 0
      frameworks/CSharp/aspnetcore/Benchmarks/Startup.cs
  57. 12 0
      frameworks/CSharp/aspnetcore/Benchmarks/Views/Fortunes/Fortunes.cshtml
  58. 5 0
      frameworks/CSharp/aspnetcore/Benchmarks/Views/Home/Index.cshtml
  59. 3 0
      frameworks/CSharp/aspnetcore/Benchmarks/appsettings.json
  60. 55 0
      frameworks/CSharp/aspnetcore/Benchmarks/project.json
  61. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/128B.txt
  62. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/16KB.txt
  63. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/1KB.txt
  64. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/1MB.txt
  65. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/4KB.txt
  66. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/512B.txt
  67. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/512KB.txt
  68. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/5MB.txt
  69. BIN
      frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/favicon.ico
  70. 32 0
      frameworks/CSharp/aspnetcore/README.md
  71. 119 0
      frameworks/CSharp/aspnetcore/benchmark_config.json
  72. 8 0
      frameworks/CSharp/aspnetcore/run-linux.sh
  73. 8 0
      frameworks/CSharp/aspnetcore/run-windows.ps1
  74. 3 0
      frameworks/CSharp/aspnetcore/setup-mvc-weblistener.sh
  75. 3 0
      frameworks/CSharp/aspnetcore/setup-mvc-windows.sh
  76. 3 0
      frameworks/CSharp/aspnetcore/setup-mvc.sh
  77. 3 0
      frameworks/CSharp/aspnetcore/setup-weblistener.sh
  78. 3 0
      frameworks/CSharp/aspnetcore/setup-windows.sh
  79. 3 0
      frameworks/CSharp/aspnetcore/setup.sh
  80. 17 4
      frameworks/CSharp/revenj/Revenj.Bench/RestService.cs
  81. 3 3
      frameworks/Clojure/pedestal/project.clj
  82. 62 76
      frameworks/Clojure/pedestal/src/pedestal/service.clj
  83. 1 1
      frameworks/Elixir/phoenix/lib/hello/repo.ex
  84. 6 7
      frameworks/Elixir/phoenix/mix.exs
  85. 3 2
      frameworks/Elixir/phoenix/setup.sh
  86. 30 10
      frameworks/Elixir/phoenix/web/controllers/page_controller.ex
  87. 3 3
      frameworks/Elixir/phoenix/web/models/fortune.ex
  88. 3 3
      frameworks/Elixir/phoenix/web/models/world.ex
  89. 1 1
      frameworks/Elixir/phoenix/web/templates/layout/app.html.eex
  90. 10 6
      frameworks/Elixir/phoenix/web/web.ex
  91. 0 8
      frameworks/Erlang/misultin/.gitignore
  92. 0 13
      frameworks/Erlang/misultin/Makefile
  93. 0 23
      frameworks/Erlang/misultin/benchmark_config.json
  94. 0 9
      frameworks/Erlang/misultin/priv/app.config
  95. 0 5
      frameworks/Erlang/misultin/rebar.config
  96. 0 11
      frameworks/Erlang/misultin/setup.sh
  97. 0 9
      frameworks/Erlang/misultin/src/misultin_bench.app.src
  98. 0 16
      frameworks/Erlang/misultin/src/misultin_bench_app.erl
  99. 0 18
      frameworks/Erlang/misultin/src/misultin_bench_sup.erl
  100. 0 53
      frameworks/Erlang/misultin/src/web_handler.erl

+ 16 - 0
.github/PULL_REQUEST_TEMPLATE.md

@@ -0,0 +1,16 @@
+....................................
+
+MAKE SURE YOU ARE OPENING A PULL 
+REQUEST AGAINST THE CORRECT BRANCH
+
+....................................
+
+master = bug fixes directly 
+addressing the current preview round
+
+round-X = new features, frameworks, 
+tests, and any other larger changes 
+that you would like to see in the 
+next round
+
+....................................

+ 3 - 0
.gitignore

@@ -83,3 +83,6 @@ nimcache
 # crystal
 .crystal
 *.out
+
+#don't ignore merge request templates
+!.github/

+ 3 - 2
.travis.yml

@@ -22,6 +22,7 @@ env:
     - "TESTDIR=C/onion"
     - "TESTDIR=C/h2o"
     - "TESTDIR=CSharp/aspnet"
+    - "TESTDIR=CSharp/aspnetcore"
     ## - "TESTDIR=CSharp/aspnet-stripped"
     - "TESTDIR=CSharp/evhttp-sharp"
     ## - "TESTDIR=CSharp/HttpListener"
@@ -54,7 +55,6 @@ env:
     - "TESTDIR=Erlang/cowboy"
     - "TESTDIR=Erlang/elli"
     - "TESTDIR=Erlang/mochiweb"
-    - "TESTDIR=Erlang/misultin"
     - "TESTDIR=Go/beego"
     - "TESTDIR=Go/echo"
     - "TESTDIR=Go/falcore"
@@ -68,6 +68,7 @@ env:
     - "TESTDIR=Haskell/snap"
     - "TESTDIR=Haskell/wai"
     - "TESTDIR=Haskell/yesod"
+    - "TESTDIR=Haskell/yesod-postgres"
     - "TESTDIR=Haskell/servant"
     - "TESTDIR=Haskell/spock"
     - "TESTDIR=Java/activeweb"
@@ -139,7 +140,6 @@ env:
     - "TESTDIR=PHP/limonade"
     - "TESTDIR=PHP/lithium"
     - "TESTDIR=PHP/lumen"
-    - "TESTDIR=PHP/micromvc"
     - "TESTDIR=PHP/phalcon"
     - "TESTDIR=PHP/phalcon-micro"
     - "TESTDIR=PHP/phpixie"
@@ -211,6 +211,7 @@ before_install:
 services:
   - postgresql
   - redis-server
+  - mongodb
 
 addons:
   postgresql: "9.3"

+ 0 - 2
config/create-postgres-database.sql

@@ -2,5 +2,3 @@ CREATE USER benchmarkdbuser WITH PASSWORD 'benchmarkdbpass';
 
 DROP DATABASE IF EXISTS hello_world;
 CREATE DATABASE hello_world WITH ENCODING 'UTF8';
-
-GRANT ALL PRIVILEGES ON DATABASE hello_world to benchmarkdbuser;

+ 0 - 29
config/create-postgres-old.sql

@@ -1,29 +0,0 @@
-DROP TABLE IF EXISTS World;
-CREATE TABLE  "World" (
-  id integer NOT NULL,
-  randomNumber integer NOT NULL default 0,
-  PRIMARY KEY  (id)
-);
-
-INSERT INTO "World" (id, randomNumber)
-SELECT x.id, random() * 10000 + 1 FROM generate_series(1,10000) as x(id);
-
-DROP TABLE IF EXISTS Fortune;
-CREATE TABLE  "Fortune" (
-  id integer NOT NULL,
-  message varchar(2048) NOT NULL,
-  PRIMARY KEY  (id)
-);
-
-INSERT INTO fortune (id, message) VALUES (1, 'fortune: No such file or directory');
-INSERT INTO fortune (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.');
-INSERT INTO fortune (id, message) VALUES (3, 'After enough decimal places, nobody gives a damn.');
-INSERT INTO fortune (id, message) VALUES (4, 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
-INSERT INTO fortune (id, message) VALUES (5, 'A computer program does what you tell it to do, not what you want it to do.');
-INSERT INTO fortune (id, message) VALUES (6, 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
-INSERT INTO fortune (id, message) VALUES (7, 'Any program that runs right is obsolete.');
-INSERT INTO fortune (id, message) VALUES (8, 'A list is only as strong as its weakest link. — Donald Knuth');
-INSERT INTO fortune (id, message) VALUES (9, 'Feature: A bug with seniority.');
-INSERT INTO fortune (id, message) VALUES (10, 'Computers make very fast, very accurate mistakes.');
-INSERT INTO fortune (id, message) VALUES (11, '<script>alert("This should not be displayed in a browser alert box.");</script>');
-INSERT INTO fortune (id, message) VALUES (12, 'フレームワークのベンチマーク');

+ 0 - 29
config/create-postgres-upper-quote.sql

@@ -1,29 +0,0 @@
-DROP TABLE IF EXISTS "World";
-CREATE TABLE  "World" (
-  id integer NOT NULL,
-  randomNumber integer NOT NULL default 0,
-  PRIMARY KEY  (id)
-);
-
-INSERT INTO "World" (id, randomNumber)
-SELECT x.id, random() * 10000 + 1 FROM generate_series(1,10000) as x(id);
-
-DROP TABLE IF EXISTS "Fortune";
-CREATE TABLE "Fortune" (
-  id integer NOT NULL,
-  message varchar(2048) NOT NULL,
-  PRIMARY KEY  (id)
-);
-
-INSERT INTO "Fortune" (id, message) VALUES (1, 'fortune: No such file or directory');
-INSERT INTO "Fortune" (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.');
-INSERT INTO "Fortune" (id, message) VALUES (3, 'After enough decimal places, nobody gives a damn.');
-INSERT INTO "Fortune" (id, message) VALUES (4, 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
-INSERT INTO "Fortune" (id, message) VALUES (5, 'A computer program does what you tell it to do, not what you want it to do.');
-INSERT INTO "Fortune" (id, message) VALUES (6, 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
-INSERT INTO "Fortune" (id, message) VALUES (7, 'Any program that runs right is obsolete.');
-INSERT INTO "Fortune" (id, message) VALUES (8, 'A list is only as strong as its weakest link. — Donald Knuth');
-INSERT INTO "Fortune" (id, message) VALUES (9, 'Feature: A bug with seniority.');
-INSERT INTO "Fortune" (id, message) VALUES (10, 'Computers make very fast, very accurate mistakes.');
-INSERT INTO "Fortune" (id, message) VALUES (11, '<script>alert("This should not be displayed in a browser alert box.");</script>');
-INSERT INTO "Fortune" (id, message) VALUES (12, 'フレームワークのベンチマーク');

+ 4 - 0
config/create-postgres.sql

@@ -5,6 +5,7 @@ CREATE TABLE  World (
   randomNumber integer NOT NULL default 0,
   PRIMARY KEY  (id)
 );
+GRANT SELECT, UPDATE ON World to benchmarkdbuser;
 
 INSERT INTO World (id, randomnumber)
 SELECT x.id, random() * 10000 + 1 FROM generate_series(1,10000) as x(id);
@@ -15,6 +16,7 @@ CREATE TABLE Fortune (
   message varchar(2048) NOT NULL,
   PRIMARY KEY  (id)
 );
+GRANT SELECT ON Fortune to benchmarkdbuser;
 
 INSERT INTO Fortune (id, message) VALUES (1, 'fortune: No such file or directory');
 INSERT INTO Fortune (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.');
@@ -36,6 +38,7 @@ CREATE TABLE  "World" (
   randomNumber integer NOT NULL default 0,
   PRIMARY KEY  (id)
 );
+GRANT SELECT, UPDATE ON "World" to benchmarkdbuser;
 
 INSERT INTO "World" (id, randomnumber)
 SELECT x.id, random() * 10000 + 1 FROM generate_series(1,10000) as x(id);
@@ -46,6 +49,7 @@ CREATE TABLE "Fortune" (
   message varchar(2048) NOT NULL,
   PRIMARY KEY  (id)
 );
+GRANT SELECT ON "Fortune" to benchmarkdbuser;
 
 INSERT INTO "Fortune" (id, message) VALUES (1, 'fortune: No such file or directory');
 INSERT INTO "Fortune" (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.');

+ 2 - 53
config/create.sql

@@ -3,59 +3,6 @@ DROP DATABASE IF EXISTS hello_world;
 CREATE DATABASE hello_world;
 USE hello_world;
 
-DROP TABLE IF EXISTS World;
-CREATE TABLE  World (
-  id int(10) unsigned NOT NULL auto_increment,
-  randomNumber int NOT NULL default 0,
-  PRIMARY KEY  (id)
-)
-ENGINE=INNODB;
-GRANT ALL ON hello_world.world TO 'benchmarkdbuser'@'%' IDENTIFIED BY 'benchmarkdbpass';
-GRANT ALL ON hello_world.world TO 'benchmarkdbuser'@'localhost' IDENTIFIED BY 'benchmarkdbpass';
-
-DROP PROCEDURE IF EXISTS load_data;
-
-DELIMITER #
-CREATE PROCEDURE load_data()
-BEGIN
-
-declare v_max int unsigned default 10000;
-declare v_counter int unsigned default 0;
-
-  TRUNCATE TABLE World;
-  START TRANSACTION;
-  while v_counter < v_max do
-    INSERT INTO World (randomNumber) VALUES ( floor(0 + (rand() * 10000)) );
-    SET v_counter=v_counter+1;
-  end while;
-  commit;
-END #
-
-DELIMITER ;
-
-CALL load_data();
-
-DROP TABLE IF EXISTS Fortune;
-CREATE TABLE  Fortune (
-  id int(10) unsigned NOT NULL auto_increment,
-  message varchar(2048) CHARACTER SET 'utf8' NOT NULL,
-  PRIMARY KEY  (id)
-)
-ENGINE=INNODB;
-
-INSERT INTO Fortune (message) VALUES ('fortune: No such file or directory');
-INSERT INTO Fortune (message) VALUES ('A computer scientist is someone who fixes things that aren''t broken.');
-INSERT INTO Fortune (message) VALUES ('After enough decimal places, nobody gives a damn.');
-INSERT INTO Fortune (message) VALUES ('A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1');
-INSERT INTO Fortune (message) VALUES ('A computer program does what you tell it to do, not what you want it to do.');
-INSERT INTO Fortune (message) VALUES ('Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen');
-INSERT INTO Fortune (message) VALUES ('Any program that runs right is obsolete.');
-INSERT INTO Fortune (message) VALUES ('A list is only as strong as its weakest link. — Donald Knuth');
-INSERT INTO Fortune (message) VALUES ('Feature: A bug with seniority.');
-INSERT INTO Fortune (message) VALUES ('Computers make very fast, very accurate mistakes.');
-INSERT INTO Fortune (message) VALUES ('<script>alert("This should not be displayed in a browser alert box.");</script>');
-INSERT INTO Fortune (message) VALUES ('フレームワークのベンチマーク');
-
 DROP TABLE IF EXISTS world;
 CREATE TABLE  world (
   id int(10) unsigned NOT NULL auto_increment,
@@ -63,6 +10,8 @@ CREATE TABLE  world (
   PRIMARY KEY  (id)
 )
 ENGINE=INNODB;
+GRANT SELECT, UPDATE ON hello_world.world TO 'benchmarkdbuser'@'%' IDENTIFIED BY 'benchmarkdbpass';
+GRANT SELECT, UPDATE ON hello_world.world TO 'benchmarkdbuser'@'localhost' IDENTIFIED BY 'benchmarkdbpass';
 
 DROP PROCEDURE IF EXISTS load_data;
 

+ 1 - 1
config/travis_setup.sh

@@ -83,7 +83,7 @@ echo "Populating Postgres database"
 psql --version
 sudo useradd benchmarkdbuser -p benchmarkdbpass
 sudo -u postgres psql template1 < config/create-postgres-database.sql
-sudo -u benchmarkdbuser psql hello_world < config/create-postgres.sql
+sudo -u postgres psql hello_world < config/create-postgres.sql
 sudo sed -i "s|#listen_addresses = 'localhost'|listen_addresses = '*'|g" /etc/postgresql/9.3/main/postgresql.conf
 sudo sed -i 's|max_connections = 255|max_connections = 500|g' /etc/postgresql/9.3/main/postgresql.conf
 sudo service postgresql stop

+ 23 - 0
frameworks/C++/ffead-cpp/benchmark_config.json

@@ -23,6 +23,29 @@
       "display_name": "ffead-cpp",
       "notes": "",
       "versus": ""
+    },
+    "apache2": {
+      "setup_file": "setup-apache2",
+      "json_url": "/te-benchmark/json",
+      "plaintext_url": "/te-benchmark/plaintext",
+      "db_url": "/te-benchmark/db",
+      "query_url": "/te-benchmark/queries?queries=",
+      "fortune_url": "/te-benchmark/fortunes",
+      "update_url": "/te-benchmark/updates?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MongoDB",
+      "framework": "ffead-cpp",
+      "language": "C++",
+      "orm": "Full",
+      "platform": "ffead-cpp-apache",
+      "webserver": "apache2",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "ffead-cpp-apache",
+      "notes": "",
+      "versus": ""
     }
   }]
 }

+ 12 - 0
frameworks/C++/ffead-cpp/setup-apache2.sh

@@ -0,0 +1,12 @@
+#!/bin/bash
+
+fw_depends apache
+fw_depends ffead-cpp-apache
+
+export FFEAD_CPP_PATH=$TROOT/ffead-cpp-2.0
+export LD_LIBRARY_PATH=$IROOT:$FFEAD_CPP_PATH/lib:$LD_LIBRARY_PATH
+echo $FFEAD_CPP_PATH
+echo $LD_LIBRARY_PATH
+sudo rm -f $FFEAD_CPP_PATH/*.cntrl
+sudo rm -f $FFEAD_CPP_PATH/tmp/*.sess
+sudo /etc/init.d/apache2 restart > ffead.log 2>&1

+ 1 - 1
frameworks/C++/silicon/CMakeLists.txt

@@ -16,4 +16,4 @@ set_target_properties(silicon_epoll_mysql PROPERTIES COMPILE_FLAGS "-DTFB_USE_EP
 target_link_libraries(silicon_epoll_mysql microhttpd mysqlclient)
 
 add_executable(silicon_lwan_mysql techempower_lwan.cc)
-target_link_libraries(silicon_lwan_mysql mysqlclient lwan-common curl z pthread dl)
+target_link_libraries(silicon_lwan_mysql mysqlclient lwan curl z pthread dl luajit-5.1)

+ 1 - 1
frameworks/C++/silicon/setup_lwan_mysql.sh

@@ -5,7 +5,7 @@ fw_depends silicon lwan
 rm -rf build
 mkdir build
 cd build
-cmake .. -DCMAKE_CXX_COMPILER=clang++-3.5
+cmake .. -DCMAKE_CXX_COMPILER=clang++-3.8
 make silicon_lwan_mysql
 
 $TROOT/build/silicon_lwan_mysql ${DBHOST} 8080 &

+ 1 - 1
frameworks/C++/silicon/setup_mhd_epoll_mysql.sh

@@ -5,7 +5,7 @@ fw_depends silicon microhttpd
 rm -rf build
 mkdir build
 cd build
-cmake .. -DCMAKE_CXX_COMPILER=clang++-3.5
+cmake .. -DCMAKE_CXX_COMPILER=clang++-3.8
 make silicon_epoll_mysql
 
 $TROOT/build/silicon_epoll_mysql ${DBHOST} 8080 ${MAX_THREADS} &

+ 1 - 1
frameworks/C++/silicon/setup_mhd_tpc_mysql.sh

@@ -5,7 +5,7 @@ fw_depends silicon microhttpd
 rm -rf build
 mkdir build
 cd build
-cmake .. -DCMAKE_CXX_COMPILER=clang++-3.5
+cmake .. -DCMAKE_CXX_COMPILER=clang++-3.8
 make silicon_tpc_mysql
 
 $TROOT/build/silicon_tpc_mysql ${DBHOST} 8080 ${MAX_THREADS} &

+ 19 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Benchmarks.xproj

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>ec62acf4-8b19-41c2-b699-d75cab7763df</ProjectGuid>
+    <RootNamespace>Benchmarks</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+    <DevelopmentServerPort>13007</DevelopmentServerPort>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>

+ 11 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/AppSettings.cs

@@ -0,0 +1,11 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+
+namespace Benchmarks.Configuration
+{
+    public class AppSettings
+    {
+        public string ConnectionString { get; set; }
+    }
+}

+ 15 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleArgs.cs

@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+namespace Benchmarks.Configuration
+{
+    public class ConsoleArgs
+    {
+        public ConsoleArgs(string[] args)
+        {
+            Args = args;
+        }
+
+        public string[] Args { get; }
+    }
+}

+ 85 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/ConsoleHostScenariosConfiguration.cs

@@ -0,0 +1,85 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Configuration;
+
+namespace Benchmarks.Configuration
+{
+    public class ConsoleHostScenariosConfiguration : IScenariosConfiguration
+    {
+        private readonly string[] _args;
+
+        public ConsoleHostScenariosConfiguration(ConsoleArgs args)
+        {
+            _args = args.Args;
+        }
+
+        public void ConfigureScenarios(Scenarios scenarios)
+        {
+            var scenarioConfig = new ConfigurationBuilder()
+                .AddJsonFile("scenarios.json", optional: true)
+                .AddCommandLine(_args)
+                .Build();
+
+            var enabledCount = 0;
+            var configuredScenarios = scenarioConfig["scenarios"];
+            if (!string.IsNullOrWhiteSpace(configuredScenarios))
+            {
+                Console.WriteLine("Scenario configuration found in scenarios.json and/or command line args");
+                var choices = configuredScenarios.Split(',');
+                foreach (var choice in choices)
+                {
+                    enabledCount += scenarios.Enable(choice);
+                }
+            }
+            else
+            {
+                Console.WriteLine("Which scenarios would you like to enable?:");
+                Console.WriteLine();
+                foreach (var scenario in Scenarios.GetNames())
+                {
+                    Console.WriteLine("  " + scenario);
+                }
+                Console.WriteLine();
+                Console.WriteLine("Type full or partial scenario names separated by commas and hit [Enter]");
+                Console.Write("> ");
+
+                var choices = Console.ReadLine().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+                if (choices.Length > 0)
+                {
+                    foreach (var choice in choices)
+                    {
+                        enabledCount += scenarios.Enable(choice);
+                    }
+                }
+            }
+
+            if (enabledCount == 0)
+            {
+                Console.WriteLine();
+                Console.WriteLine("No matching scenarios found, enabling defaults");
+                scenarios.EnableDefault();
+            }
+
+            PrintEnabledScenarios(scenarios.GetEnabled());
+        }
+
+        private static void PrintEnabledScenarios(IEnumerable<EnabledScenario> scenarios)
+        {
+            Console.WriteLine();
+            Console.WriteLine("The following scenarios were enabled:");
+
+            var maxNameLength = scenarios.Max(s => s.Name.Length);
+
+            foreach (var scenario in scenarios)
+            {
+                Console.WriteLine($"  {scenario.Name.PadRight(maxNameLength)} -> {string.Join($"{Environment.NewLine}{"".PadLeft(maxNameLength + 6)}", scenario.Paths)}");
+            }
+            Console.WriteLine();
+        }
+    }
+}

+ 20 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/EnabledScenario.cs

@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Collections.Generic;
+
+namespace Benchmarks.Configuration
+{
+    public class EnabledScenario
+    {
+        public EnabledScenario(string name, IEnumerable<string> paths)
+        {
+            Name = name;
+            Paths = paths;
+        }
+
+        public string Name { get; }
+
+        public IEnumerable<string> Paths { get; }
+    }
+}

+ 10 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/IScenariosConfiguration.cs

@@ -0,0 +1,10 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Benchmarks.Configuration
+{
+    public interface IScenariosConfiguration
+    {
+        void ConfigureScenarios(Scenarios scenarios);
+    }
+}

+ 149 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Configuration/Scenarios.cs

@@ -0,0 +1,149 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Linq;
+using System.Linq.Expressions;
+using Microsoft.EntityFrameworkCore.Internal;
+
+namespace Benchmarks.Configuration
+{
+    public class Scenarios
+    {
+        public Scenarios(IScenariosConfiguration scenariosConfiguration)
+        {
+            scenariosConfiguration.ConfigureScenarios(this);
+        }
+
+        [ScenarioPath("/plaintext")]
+        public bool Plaintext { get; set; }
+
+        [ScenarioPath("/json")]
+        public bool Json { get; set; }
+
+        [ScenarioPath("/128B.txt", "/512B.txt", "/1KB.txt", "/4KB.txt", "/16KB.txt", "/512KB.txt", "/1MB.txt", "/5MB.txt")]
+        public bool StaticFiles { get; set; }
+
+        [ScenarioPath("/db/raw")]
+        public bool DbSingleQueryRaw { get; set; }
+
+        [ScenarioPath("/db/ef")]
+        public bool DbSingleQueryEf { get; set; }
+
+        [ScenarioPath("/db/dapper")]
+        public bool DbSingleQueryDapper { get; set; }
+
+        [ScenarioPath("/queries/raw")]
+        public bool DbMultiQueryRaw { get; set; }
+
+        [ScenarioPath("/queries/ef")]
+        public bool DbMultiQueryEf { get; set; }
+
+        [ScenarioPath("/queries/dapper")]
+        public bool DbMultiQueryDapper { get; set; }
+
+        [ScenarioPath("/fortunes/raw")]
+        public bool DbFortunesRaw { get; set; }
+
+        [ScenarioPath("/fortunes/ef")]
+        public bool DbFortunesEf { get; set; }
+
+        [ScenarioPath("/fortunes/dapper")]
+        public bool DbFortunesDapper { get; set; }
+
+        [ScenarioPath("/mvc/plaintext")]
+        public bool MvcPlaintext { get; set; }
+
+        [ScenarioPath("/mvc/json")]
+        public bool MvcJson { get; set; }
+
+        [ScenarioPath("/mvc/view")]
+        public bool MvcViews { get; set; }
+
+        //[ScenarioPath("/mvc/db/raw")]
+        //public bool MvcDbSingleQueryRaw { get; set; }
+
+        //[ScenarioPath("/mvc/db/dapper")]
+        //public bool MvcDbSingleQueryDapper { get; set; }
+
+        //[ScenarioPath("/mvc/db/ef")]
+        //public bool MvcDbSingleQueryEf { get; set; }
+
+        //[ScenarioPath("/mvc/queries/raw")]
+        //public bool MvcDbMultiQueryRaw { get; set; }
+
+        //[ScenarioPath("/mvc/queries/dapper")]
+        //public bool MvcDbMultiQueryDapper { get; set; }
+
+        //[ScenarioPath("/mvc/queries/ef")]
+        //public bool MvcDbMultiQueryEf { get; set; }
+
+        [ScenarioPath("/mvc/fortunes/raw")]
+        public bool MvcDbFortunesRaw { get; set; }
+
+        [ScenarioPath("/mvc/fortunes/ef")]
+        public bool MvcDbFortunesEf { get; set; }
+
+        [ScenarioPath("/mvc/fortunes/dapper")]
+        public bool MvcDbFortunesDapper { get; set; }
+
+        public bool Any(string partialName) =>
+            typeof(Scenarios).GetTypeInfo().DeclaredProperties
+                .Where(p => p.Name.IndexOf(partialName, StringComparison.Ordinal) >= 0 && (bool)p.GetValue(this))
+                .Any();
+
+        public IEnumerable<EnabledScenario> GetEnabled() =>
+            typeof(Scenarios).GetTypeInfo().DeclaredProperties
+                .Where(p => p.GetValue(this) is bool && (bool)p.GetValue(this))
+                .Select(p => new EnabledScenario(p.Name, p.GetCustomAttribute<ScenarioPathAttribute>()?.Paths));
+
+        public static IEnumerable<string> GetNames() =>
+            typeof(Scenarios).GetTypeInfo().DeclaredProperties
+                .Select(p => p.Name);
+
+        public static string[] GetPaths(Expression<Func<Scenarios, bool>> scenarioExpression) =>
+            scenarioExpression.GetPropertyAccess().GetCustomAttribute<ScenarioPathAttribute>().Paths;
+
+        public static string GetPath(Expression<Func<Scenarios, bool>> scenarioExpression) =>
+            GetPaths(scenarioExpression)[0];
+
+        public int Enable(string partialName)
+        {
+            if (string.Equals(partialName, "[default]", StringComparison.OrdinalIgnoreCase))
+            {
+                EnableDefault();
+                return 2;
+            }
+            
+            var props = typeof(Scenarios).GetTypeInfo().DeclaredProperties
+                .Where(p => string.Equals(partialName, "[all]", StringComparison.OrdinalIgnoreCase) || p.Name.IndexOf(partialName, StringComparison.OrdinalIgnoreCase) >= 0)
+                .ToList();
+
+            foreach (var p in props)
+            {
+                p.SetValue(this, true);
+            }
+            
+            return props.Count;
+        }
+        
+        public void EnableDefault()
+        {
+            Plaintext = true;
+            Json = true;
+        }
+    }
+
+    [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
+    public sealed class ScenarioPathAttribute : Attribute
+    {
+        public ScenarioPathAttribute(params string[] paths)
+        {
+            Paths = paths;
+        }
+
+        public string[] Paths { get; }
+    }
+}

+ 75 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Controllers/FortunesController.cs

@@ -0,0 +1,75 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Benchmarks.Controllers
+{
+    [Route("mvc")]
+    public class FortunesController : Controller
+    {
+        private RawDb _rawDb;
+        private DapperDb _dapperDb;
+        private EfDb _efDb;
+
+        private RawDb RawDb
+        {
+            get
+            {
+                if (_rawDb == null)
+                {
+                    _rawDb = HttpContext.RequestServices.GetRequiredService<RawDb>();
+                }
+
+                return _rawDb;
+            }
+        }
+
+        private DapperDb DapperDb
+        {
+            get
+            {
+                if (_dapperDb == null)
+                {
+                    _dapperDb = HttpContext.RequestServices.GetRequiredService<DapperDb>();
+                }
+
+                return _dapperDb;
+            }
+        }
+
+        private EfDb EfDb
+        {
+            get
+            {
+                if (_efDb == null)
+                {
+                    _efDb = HttpContext.RequestServices.GetRequiredService<EfDb>();
+                }
+
+                return _efDb;
+            }
+        }
+
+        [HttpGet("fortunes/raw")]
+        public async Task<IActionResult> Raw()
+        {
+            return View("Fortunes", await RawDb.LoadFortunesRows());
+        }
+
+        [HttpGet("fortunes/dapper")]
+        public async Task<IActionResult> Dapper()
+        {
+            return View("Fortunes", await DapperDb.LoadFortunesRows());
+        }
+
+        [HttpGet("fortunes/ef")]
+        public async Task<IActionResult> Ef()
+        {
+            return View("Fortunes", await EfDb.LoadFortunesRows());
+        }
+    }
+}

+ 46 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Controllers/HomeController.cs

@@ -0,0 +1,46 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Benchmarks.Controllers
+{
+    [Route("mvc")]
+    public class HomeController : Controller
+    {
+        [HttpGet("plaintext")]
+        public IActionResult Plaintext()
+        {
+            return new PlainTextActionResult();
+        }
+
+        [HttpGet("json")]
+        [Produces("application/json")]
+        public object Json()
+        {
+            return new { message = "Hello, World!" };
+        }
+        
+        [HttpGet("view")]
+        public ViewResult Index()
+        {
+            return View();
+        }
+
+        private class PlainTextActionResult : IActionResult
+        {
+            private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
+
+            public Task ExecuteResultAsync(ActionContext context)
+            {
+                context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
+                context.HttpContext.Response.ContentType = "text/plain";
+                context.HttpContext.Response.ContentLength = _helloWorldPayload.Length;
+                return context.HttpContext.Response.Body.WriteAsync(_helloWorldPayload, 0, _helloWorldPayload.Length);
+            }
+        }
+    }
+}

+ 28 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/ApplicationDbContext.cs

@@ -0,0 +1,28 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using Benchmarks.Configuration;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Options;
+
+namespace Benchmarks.Data
+{
+    public class ApplicationDbContext : DbContext
+    {
+        private readonly AppSettings _appSettings;
+
+        public ApplicationDbContext(IOptions<AppSettings> appSettings)
+        {
+            _appSettings = appSettings.Value;
+        }
+
+        public DbSet<World> World { get; set; }
+
+        public DbSet<Fortune> Fortune { get; set; }
+
+        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+        {
+            optionsBuilder.UseSqlServer(_appSettings.ConnectionString);
+        }
+    }
+}

+ 89 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/ApplicationDbSeeder.cs

@@ -0,0 +1,89 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Linq;
+
+namespace Benchmarks.Data
+{
+    public class ApplicationDbSeeder
+    {
+        private readonly object _locker = new object();
+        private readonly IRandom _random;
+        private readonly ApplicationDbContext _dbContext;
+        private bool _seeded = false;
+
+        public ApplicationDbSeeder(IRandom random, ApplicationDbContext dbContext)
+        {
+            _random = random;
+            _dbContext = dbContext;
+        }
+
+        public bool Seed()
+        {
+            if (!_seeded)
+            {
+                lock (_locker)
+                {
+                    if (!_seeded)
+                    {
+                        try
+                        {
+                            var world = _dbContext.World.Count();
+                            var fortune = _dbContext.Fortune.Count();
+
+                            if (world == 0 || fortune == 0)
+                            {
+                                if (world == 0)
+                                {
+                                    for (int i = 0; i < 10000; i++)
+                                    {
+                                        _dbContext.World.Add(new World { RandomNumber = _random.Next(1, 10001) });
+                                    }
+                                    _dbContext.SaveChanges();
+                                }
+
+                                if (fortune == 0)
+                                {
+                                    _dbContext.Fortune.Add(new Fortune { Message = "fortune: No such file or directory" });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "A computer scientist is someone who fixes things that aren't broken." });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "After enough decimal places, nobody gives a damn." });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1" });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "A computer program does what you tell it to do, not what you want it to do." });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen" });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "Any program that runs right is obsolete." });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "A list is only as strong as its weakest link. — Donald Knuth" });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "Feature: A bug with seniority." });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "Computers make very fast, very accurate mistakes." });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "<script>alert(\"This should not be displayed in a browser alert box.\");</script>" });
+                                    _dbContext.Fortune.Add(new Fortune { Message = "フレームワークのベンチマーク" });
+
+                                    _dbContext.SaveChanges();
+                                }
+
+                                Console.WriteLine("Database successfully seeded!");
+                            }
+                            else
+                            {
+                                Console.WriteLine("Database already seeded!");
+                            }
+
+                            _seeded = true;
+                            return true;
+                        }
+                        catch (Exception ex)
+                        {
+                            Console.Error.WriteLine("Error trying to seed the database. Have you run 'dnx ef database update'?");
+                            Console.Error.WriteLine(ex);
+
+                            return false;
+                        }
+                    }
+                }
+            }
+
+            Console.WriteLine("Database already seeded!");
+            return true;
+        }
+    }
+}

+ 79 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/DapperDb.cs

@@ -0,0 +1,79 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Dapper;
+using Microsoft.Extensions.Options;
+
+namespace Benchmarks.Data
+{
+    public class DapperDb
+    {
+        private readonly IRandom _random;
+        private readonly DbProviderFactory _dbProviderFactory;
+        private readonly string _connectionString;
+
+        public DapperDb(IRandom random, DbProviderFactory dbProviderFactory, IOptions<AppSettings> appSettings)
+        {
+            _random = random;
+            _dbProviderFactory = dbProviderFactory;
+            _connectionString = appSettings.Value.ConnectionString;
+        }
+
+        public async Task<World> LoadSingleQueryRow()
+        {
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+
+                // Note: Don't need to open connection if only doing one thing; let dapper do it
+                return await db.QueryFirstOrDefaultAsync<World>(
+                    "SELECT [Id], [RandomNumber] FROM [World] WHERE [Id] = @Id",
+                    new { Id = _random.Next(1, 10001) });
+            }
+        }
+
+        public async Task<World[]> LoadMultipleQueriesRows(int count)
+        {
+            var result = new World[count];
+
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                for (int i = 0; i < count; i++)
+                {
+                    result[i] = await db.QueryFirstOrDefaultAsync<World>(
+                        "SELECT [Id], [RandomNumber] FROM [World] WHERE [Id] = @Id",
+                        new { Id = _random.Next(1, 10001) });
+                }
+
+                db.Close();
+            }
+
+            return result;
+        }
+
+        public async Task<IEnumerable<Fortune>> LoadFortunesRows()
+        {
+            List<Fortune> result;
+
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+
+                // Note: don't need to open connection if only doing one thing; let dapper do it
+                result = (await db.QueryAsync<Fortune>("SELECT [Id], [Message] FROM [Fortune]")).AsList();
+            }
+
+            result.Add(new Fortune { Message = "Additional fortune added at request time." });
+            result.Sort();
+
+            return result;
+        }
+    }
+}

+ 52 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/EfDb.cs

@@ -0,0 +1,52 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+
+namespace Benchmarks.Data
+{
+    public class EfDb
+    {
+        private readonly IRandom _random;
+        private readonly ApplicationDbContext _dbContext;
+
+        public EfDb(IRandom random, ApplicationDbContext dbContext)
+        {
+            _random = random;
+            _dbContext = dbContext;
+            _dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
+        }
+
+        public Task<World> LoadSingleQueryRow()
+        {
+            var id = _random.Next(1, 10001);
+            
+            return _dbContext.World.FirstAsync(w => w.Id == id);
+        }
+
+        public async Task<World[]> LoadMultipleQueriesRows(int count)
+        {
+            var result = new World[count];
+
+            for (int i = 0; i < count; i++)
+            {
+                var id = _random.Next(1, 10001);
+                result[i] = await _dbContext.World.FirstAsync(w => w.Id == id);
+            }
+
+            return result;
+        }
+
+        public async Task<IEnumerable<Fortune>> LoadFortunesRows()
+        {
+            var result = await _dbContext.Fortune.ToListAsync();
+
+            result.Add(new Fortune { Message = "Additional fortune added at request time." });
+            result.Sort();
+
+            return result;
+        }
+    }
+}

+ 33 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/Fortune.cs

@@ -0,0 +1,33 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace Benchmarks.Data
+{
+    public class Fortune : IComparable<Fortune>, IComparable
+    {
+        public int Id { get; set; }
+
+        [StringLength(2048)]
+        public string Message { get; set; }
+        
+        public int CompareTo(object obj)
+        {
+            var other = obj as Fortune;
+
+            if (other == null)
+            {
+                throw new ArgumentException($"Object to compare must be of type {nameof(Fortune)}", nameof(obj));
+            }
+
+            return CompareTo(other);
+        }
+
+        public int CompareTo(Fortune other)
+        {
+            return Message.CompareTo(other.Message);
+        }
+    }
+}

+ 10 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/IRandom.cs

@@ -0,0 +1,10 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+namespace Benchmarks.Data
+{
+    public interface IRandom
+    {
+        int Next(int minValue, int maxValue);
+    }
+}

+ 17 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/Random.cs

@@ -0,0 +1,17 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+
+namespace Benchmarks.Data
+{
+    public class DefaultRandom : IRandom
+    {
+        private readonly Random _random = new Random();
+
+        public int Next(int minValue, int maxValue)
+        {
+            return _random.Next(minValue, maxValue);
+        }
+    }
+}

+ 122 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/RawDb.cs

@@ -0,0 +1,122 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Microsoft.Extensions.Options;
+
+namespace Benchmarks.Data
+{
+    public class RawDb
+    {
+        private readonly IRandom _random;
+        private readonly DbProviderFactory _dbProviderFactory;
+        private readonly string _connectionString;
+
+        public RawDb(IRandom random, DbProviderFactory dbProviderFactory, IOptions<AppSettings> appSettings)
+        {
+            _random = random;
+            _dbProviderFactory = dbProviderFactory;
+            _connectionString = appSettings.Value.ConnectionString;
+        }
+
+        public async Task<World> LoadSingleQueryRow()
+        {
+            using (var db = _dbProviderFactory.CreateConnection())
+            using (var cmd = db.CreateCommand())
+            {
+                cmd.CommandText = "SELECT [Id], [RandomNumber] FROM [World] WHERE [Id] = @Id";
+                var id = cmd.CreateParameter();
+                id.ParameterName = "@Id";
+                id.DbType = DbType.Int32;
+                id.Value = _random.Next(1, 10001);
+                cmd.Parameters.Add(id);
+
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection))
+                {
+                    await rdr.ReadAsync();
+
+                    return new World
+                    {
+                        Id = rdr.GetInt32(0),
+                        RandomNumber = rdr.GetInt32(1)
+                    };
+                }
+            }
+        }
+
+        public async Task<World[]> LoadMultipleQueriesRows(int count)
+        {
+            var result = new World[count];
+
+            using (var db = _dbProviderFactory.CreateConnection())
+            using (var cmd = db.CreateCommand())
+            {
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                cmd.CommandText = "SELECT [Id], [RandomNumber] FROM [World] WHERE [Id] = @Id";
+                var id = cmd.CreateParameter();
+                id.ParameterName = "@Id";
+                id.DbType = DbType.Int32;
+                cmd.Parameters.Add(id);
+
+                for (int i = 0; i < count; i++)
+                {
+                    id.Value = _random.Next(1, 10001);
+                    using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow))
+                    {
+                        await rdr.ReadAsync();
+
+                        result[i] = new World
+                        {
+                            Id = rdr.GetInt32(0),
+                            RandomNumber = rdr.GetInt32(1)
+                        };
+                    }
+                }
+
+                db.Close();
+            }
+
+            return result;
+        }
+
+        public async Task<IEnumerable<Fortune>> LoadFortunesRows()
+        {
+            var result = new List<Fortune>();
+
+            using (var db = _dbProviderFactory.CreateConnection())
+            using (var cmd = db.CreateCommand())
+            {
+                cmd.CommandText = "SELECT [Id], [Message] FROM [Fortune]";
+
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection))
+                {
+                    while (await rdr.ReadAsync())
+                    {
+                        result.Add(new Fortune
+                        {
+                            Id = rdr.GetInt32(0),
+                            Message = rdr.GetString(1)
+                        });
+                    }
+                }
+            }
+
+            result.Add(new Fortune { Message = "Additional fortune added at request time." });
+            result.Sort();
+
+            return result;
+        }
+    }
+}

+ 12 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Data/World.cs

@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+namespace Benchmarks.Data
+{
+    public class World
+    {
+        public int Id { get; set; }
+
+        public int RandomNumber { get; set; }
+    }
+}

+ 90 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/DebugInfoPageMiddleware.cs

@@ -0,0 +1,90 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Linq;
+using System.Runtime;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.PlatformAbstractions;
+
+namespace Benchmarks.Middleware
+{
+    public class DebugInfoPageMiddleware
+    {
+#if DEBUG
+        private static readonly string _configurationName = "Debug";
+#elif RELEASE
+        private static readonly string _configurationName = "Release";
+#else
+        private static readonly string _configurationName = "";
+#endif
+
+        private readonly IHostingEnvironment _hostingEnv;
+        private readonly RequestDelegate _next;
+        private readonly Scenarios _scenarios;
+        private readonly IServerAddressesFeature _serverAddresses;
+
+        public DebugInfoPageMiddleware(RequestDelegate next, IServerAddressesFeature serverAddresses, IHostingEnvironment hostingEnv, Scenarios scenarios)
+        {
+            _next = next;
+            _hostingEnv = hostingEnv;
+            _scenarios = scenarios;
+            _serverAddresses = serverAddresses;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            httpContext.Response.ContentType = "text/html";
+
+            await httpContext.Response.WriteAsync("<!DOCTYPE html><html><head><style>body{font-family:\"Segoe UI\",Arial,Helvetica,Sans-serif};h1,h2,h3{font-family:\"Segoe UI Light\"}</style></head><body>");
+            await httpContext.Response.WriteAsync("<h1>ASP.NET Core Benchmarks</h1>");
+            await httpContext.Response.WriteAsync("<h2>Configuration Information</h2>");
+            await httpContext.Response.WriteAsync("<ul>");
+            await httpContext.Response.WriteAsync($"<li>Environment: {_hostingEnv.EnvironmentName}</li>");
+            await httpContext.Response.WriteAsync($"<li>Framework: {PlatformServices.Default.Application.RuntimeFramework.FullName}</li>");
+            await httpContext.Response.WriteAsync($"<li>Server GC enabled: {GCSettings.IsServerGC}</li>");
+            await httpContext.Response.WriteAsync($"<li>Configuration: {_configurationName}</li>");
+            await httpContext.Response.WriteAsync($"<li>Server: {Program.Server}</li>");
+            await httpContext.Response.WriteAsync($"<li>Server URLs: {string.Join(", ", _serverAddresses.Addresses)}</li>");
+            await httpContext.Response.WriteAsync($"<li>Supports Send File: {httpContext.Features.Get<IHttpSendFileFeature>() != null}</li>");
+
+            await httpContext.Response.WriteAsync($"<li>Server features:<ul>");
+            foreach (var feature in httpContext.Features)
+            {
+                await httpContext.Response.WriteAsync($"<li>{feature.Key.Name}</li>");
+            }
+            await httpContext.Response.WriteAsync($"</ul></li>");
+
+            await httpContext.Response.WriteAsync($"<li>Enabled scenarios:<ul>");
+            var enabledScenarios = _scenarios.GetEnabled();
+            var maxNameLength = enabledScenarios.Max(s => s.Name.Length);
+            foreach (var scenario in enabledScenarios)
+            {
+                await httpContext.Response.WriteAsync($"<li>{scenario.Name}<ul>");
+                foreach (var path in scenario.Paths)
+                {
+                    await httpContext.Response.WriteAsync($"<li><a href=\"{path}\">{path}</a></li>");
+                }
+                await httpContext.Response.WriteAsync($"</ul></li>");
+            }
+            await httpContext.Response.WriteAsync($"</ul></li>");
+
+
+            await httpContext.Response.WriteAsync("</ul>");
+            await httpContext.Response.WriteAsync("</body></html>");
+        }
+    }
+
+    public static class DebugInfoPageMiddlewareExtensions
+    {
+        public static IApplicationBuilder RunDebugInfoPage(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<DebugInfoPageMiddleware>(builder.ServerFeatures.Get<IServerAddressesFeature>());
+        }
+    }
+}

+ 47 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/ErrorHandlerMiddleware.cs

@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace Benchmarks.Middleware
+{
+    public class ErrorHandlerMiddleware
+    {
+        private readonly RequestDelegate _next;
+
+        public ErrorHandlerMiddleware(RequestDelegate next)
+        {
+            _next = next;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            try
+            {
+                await _next(httpContext);
+            }
+            catch (Exception ex)
+            {
+                if (!httpContext.Response.HasStarted)
+                {
+                    httpContext.Response.Clear();
+                    httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
+                    httpContext.Response.ContentType = "text/html";
+                }
+                
+                await httpContext.Response.WriteAsync($"<pre style='color:red'>{ex.ToString()}</pre>");
+            }
+        }
+    }
+
+    public static class ErrorHandlerMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseErrorHandler(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<ErrorHandlerMiddleware>();
+        }
+    }
+}

+ 51 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesDapperMiddleware.cs

@@ -0,0 +1,51 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace Benchmarks.Middleware
+{
+    public class FortunesDapperMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbFortunesDapper));
+
+        private readonly RequestDelegate _next;
+        private readonly DapperDb _db;
+        private readonly HtmlEncoder _htmlEncoder;
+
+        public FortunesDapperMiddleware(RequestDelegate next, DapperDb db, HtmlEncoder htmlEncoder)
+        {
+            _next = next;
+            _db = db;
+            _htmlEncoder = htmlEncoder;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var rows = await _db.LoadFortunesRows();
+
+                await MiddlewareHelpers.RenderFortunesHtml(rows, httpContext, _htmlEncoder);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+    
+    public static class FortunesDapperMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseFortunesDapper(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<FortunesDapperMiddleware>();
+        }
+    }
+}

+ 51 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesEfMiddleware.cs

@@ -0,0 +1,51 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace Benchmarks.Middleware
+{
+    public class FortunesEfMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbFortunesEf));
+
+        private readonly RequestDelegate _next;
+        private readonly EfDb _db;
+        private readonly HtmlEncoder _htmlEncoder;
+
+        public FortunesEfMiddleware(RequestDelegate next, EfDb db, HtmlEncoder htmlEncoder)
+        {
+            _next = next;
+            _db = db;
+            _htmlEncoder = htmlEncoder;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var rows = await _db.LoadFortunesRows();
+
+                await MiddlewareHelpers.RenderFortunesHtml(rows, httpContext, _htmlEncoder);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+    
+    public static class FortunesEfMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseFortunesEf(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<FortunesEfMiddleware>();
+        }
+    }
+}

+ 51 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/FortunesRawMiddleware.cs

@@ -0,0 +1,51 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace Benchmarks.Middleware
+{
+    public class FortunesRawMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbFortunesRaw));
+
+        private readonly RequestDelegate _next;
+        private readonly RawDb _db;
+        private readonly HtmlEncoder _htmlEncoder;
+
+        public FortunesRawMiddleware(RequestDelegate next, RawDb db, HtmlEncoder htmlEncoder)
+        {
+            _next = next;
+            _db = db;
+            _htmlEncoder = htmlEncoder;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var rows = await _db.LoadFortunesRows();
+
+                await MiddlewareHelpers.RenderFortunesHtml(rows, httpContext, _htmlEncoder);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+    
+    public static class FortunesRawMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseFortunesRaw(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<FortunesRawMiddleware>();
+        }
+    }
+}

+ 57 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/JsonMiddleware.cs

@@ -0,0 +1,57 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+
+namespace Benchmarks.Middleware
+{
+    public class JsonMiddleware
+    {
+        private static readonly Task _done = Task.FromResult(0);
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.Json));
+        private static readonly JsonSerializer _json = new JsonSerializer();
+        private static readonly UTF8Encoding _encoding = new UTF8Encoding(false);
+        private const int _bufferSize = 27;
+
+        private readonly RequestDelegate _next;
+        
+        public JsonMiddleware(RequestDelegate next)
+        {
+            _next = next;
+        }
+
+        public Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                httpContext.Response.StatusCode = 200;
+                httpContext.Response.ContentType = "application/json";
+                httpContext.Response.ContentLength = _bufferSize;
+
+                using (var sw = new StreamWriter(httpContext.Response.Body, _encoding, bufferSize: _bufferSize))
+                {
+                    _json.Serialize(sw, new { message = "Hello, World!" });
+                }
+
+                return _done;
+            }
+
+            return _next(httpContext);
+        }
+    }
+    
+    public static class JsonMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseJson(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<JsonMiddleware>();
+        }
+    }
+}

+ 47 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MiddlewareHelpers.cs

@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Http;
+
+namespace Benchmarks.Middleware
+{
+    public static class MiddlewareHelpers
+    {
+        public static int GetMultipleQueriesQueryCount(HttpContext httpContext)
+        {
+            var queries = 1;
+            var queriesRaw = httpContext.Request.Query["queries"];
+
+            if (queriesRaw.Count == 1)
+            {
+                int.TryParse(queriesRaw, out queries);
+            }
+
+            return queries > 500
+                ? 500
+                : queries > 0
+                    ? queries
+                    : 1;
+        }
+
+        public static async Task RenderFortunesHtml(IEnumerable<Fortune> model, HttpContext httpContext, HtmlEncoder htmlEncoder)
+        {
+            httpContext.Response.StatusCode = StatusCodes.Status200OK;
+            httpContext.Response.ContentType = "text/html; charset=UTF-8";
+
+            await httpContext.Response.WriteAsync("<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>");
+
+            foreach (var item in model)
+            {
+                await httpContext.Response.WriteAsync(
+                    $"<tr><td>{htmlEncoder.Encode(item.Id.ToString())}</td><td>{htmlEncoder.Encode(item.Message)}</td></tr>");
+            }
+
+            await httpContext.Response.WriteAsync("</table></body></html>");
+        }
+    }
+}

+ 61 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesDapperMiddleware.cs

@@ -0,0 +1,61 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Benchmarks.Middleware
+{
+    public class MultipleQueriesDapperMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbMultiQueryDapper));
+        private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
+        {
+            ContractResolver = new CamelCasePropertyNamesContractResolver()
+        };
+
+        private readonly RequestDelegate _next;
+        private readonly DapperDb _db;
+
+        public MultipleQueriesDapperMiddleware(RequestDelegate next, DapperDb db)
+        {
+            _next = next;
+            _db = db;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
+                var rows = await _db.LoadMultipleQueriesRows(count);
+
+                var result = JsonConvert.SerializeObject(rows, _jsonSettings);
+
+                httpContext.Response.StatusCode = StatusCodes.Status200OK;
+                httpContext.Response.ContentType = "application/json";
+                httpContext.Response.ContentLength = result.Length;
+
+                await httpContext.Response.WriteAsync(result);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+
+    public static class MultipleQueriesDapperMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseMultipleQueriesDapper(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<MultipleQueriesDapperMiddleware>();
+        }
+    }
+}

+ 61 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesEfMiddleware.cs

@@ -0,0 +1,61 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Benchmarks.Middleware
+{
+    public class MultipleQueriesEfMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbMultiQueryEf));
+        private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
+        {
+            ContractResolver = new CamelCasePropertyNamesContractResolver()
+        };
+
+        private readonly RequestDelegate _next;
+        private readonly EfDb _db;
+
+        public MultipleQueriesEfMiddleware(RequestDelegate next, EfDb db)
+        {
+            _next = next;
+            _db = db;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
+                var rows = await _db.LoadMultipleQueriesRows(count);
+
+                var result = JsonConvert.SerializeObject(rows, _jsonSettings);
+
+                httpContext.Response.StatusCode = StatusCodes.Status200OK;
+                httpContext.Response.ContentType = "application/json";
+                httpContext.Response.ContentLength = result.Length;
+
+                await httpContext.Response.WriteAsync(result);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+
+    public static class MultipleQueriesEfMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseMultipleQueriesEf(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<MultipleQueriesEfMiddleware>();
+        }
+    }
+}

+ 61 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/MultipleQueriesRawMiddleware.cs

@@ -0,0 +1,61 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Benchmarks.Middleware
+{
+    public class MultipleQueriesRawMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbMultiQueryRaw));
+        private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
+        {
+            ContractResolver = new CamelCasePropertyNamesContractResolver()
+        };
+
+        private readonly RequestDelegate _next;
+        private readonly RawDb _db;
+
+        public MultipleQueriesRawMiddleware(RequestDelegate next, RawDb db)
+        {
+            _next = next;
+            _db = db;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var count = MiddlewareHelpers.GetMultipleQueriesQueryCount(httpContext);
+                var rows = await _db.LoadMultipleQueriesRows(count);
+
+                var result = JsonConvert.SerializeObject(rows, _jsonSettings);
+
+                httpContext.Response.StatusCode = StatusCodes.Status200OK;
+                httpContext.Response.ContentType = "application/json";
+                httpContext.Response.ContentLength = result.Length;
+
+                await httpContext.Response.WriteAsync(result);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+
+    public static class MultipleQueriesRawMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseMultipleQueriesRaw(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<MultipleQueriesRawMiddleware>();
+        }
+    }
+}

+ 48 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/PlaintextMiddleware.cs

@@ -0,0 +1,48 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Text;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace Benchmarks.Middleware
+{
+    public class PlaintextMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.Plaintext));
+        private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
+
+        private readonly RequestDelegate _next;
+        
+        public PlaintextMiddleware(RequestDelegate next)
+        {
+            _next = next;
+        }
+
+        public Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                httpContext.Response.StatusCode = 200;
+                httpContext.Response.ContentType = "text/plain";
+                // HACK: Setting the Content-Length header manually avoids the cost of serializing the int to a string.
+                //       This is instead of: httpContext.Response.ContentLength = _helloWorldPayload.Length;
+                httpContext.Response.Headers["Content-Length"] = "13";
+                return httpContext.Response.Body.WriteAsync(_helloWorldPayload, 0, _helloWorldPayload.Length);
+            }
+
+            return _next(httpContext);
+        }
+    }
+    
+    public static class PlaintextMiddlewareExtensions
+    {
+        public static IApplicationBuilder UsePlainText(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<PlaintextMiddleware>();
+        }
+    }
+}

+ 60 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryDapperMiddleware.cs

@@ -0,0 +1,60 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Benchmarks.Middleware
+{
+    public class SingleQueryDapperMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbSingleQueryDapper));
+        private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
+        {
+            ContractResolver = new CamelCasePropertyNamesContractResolver()
+        };
+
+        private readonly RequestDelegate _next;
+        private readonly DapperDb _db;
+
+        public SingleQueryDapperMiddleware(RequestDelegate next, DapperDb db)
+        {
+            _next = next;
+            _db = db;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var row = await _db.LoadSingleQueryRow();
+
+                var result = JsonConvert.SerializeObject(row, _jsonSettings);
+
+                httpContext.Response.StatusCode = StatusCodes.Status200OK;
+                httpContext.Response.ContentType = "application/json";
+                httpContext.Response.ContentLength = result.Length;
+
+                await httpContext.Response.WriteAsync(result);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+
+    public static class SingleQueryDapperMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseSingleQueryDapper(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<SingleQueryDapperMiddleware>();
+        }
+    }
+}

+ 59 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryEfMiddleware.cs

@@ -0,0 +1,59 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Benchmarks.Middleware
+{
+    public class SingleQueryEfMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbSingleQueryEf));
+        private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
+        {
+            ContractResolver = new CamelCasePropertyNamesContractResolver()
+        };
+
+        private readonly RequestDelegate _next;
+        private readonly EfDb _db;
+
+        public SingleQueryEfMiddleware(RequestDelegate next, EfDb db)
+        {
+            _next = next;
+            _db = db;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var row = await _db.LoadSingleQueryRow();
+                var result = JsonConvert.SerializeObject(row, _jsonSettings);
+
+                httpContext.Response.StatusCode = StatusCodes.Status200OK;
+                httpContext.Response.ContentType = "application/json";
+                httpContext.Response.ContentLength = result.Length;
+
+                await httpContext.Response.WriteAsync(result);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+
+    public static class SingleQueryEfMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseSingleQueryEf(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<SingleQueryEfMiddleware>();
+        }
+    }
+}

+ 60 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Middleware/SingleQueryRawMiddleware.cs

@@ -0,0 +1,60 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading.Tasks;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Benchmarks.Middleware
+{
+    public class SingleQueryRawMiddleware
+    {
+        private static readonly PathString _path = new PathString(Scenarios.GetPath(s => s.DbSingleQueryRaw));
+        private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
+        {
+            ContractResolver = new CamelCasePropertyNamesContractResolver()
+        };
+
+        private readonly RequestDelegate _next;
+        private readonly RawDb _db;
+
+        public SingleQueryRawMiddleware(RequestDelegate next, RawDb db)
+        {
+            _next = next;
+            _db = db;
+        }
+
+        public async Task Invoke(HttpContext httpContext)
+        {
+            if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
+            {
+                var row = await _db.LoadSingleQueryRow();
+
+                var result = JsonConvert.SerializeObject(row, _jsonSettings);
+
+                httpContext.Response.StatusCode = StatusCodes.Status200OK;
+                httpContext.Response.ContentType = "application/json";
+                httpContext.Response.ContentLength = result.Length;
+
+                await httpContext.Response.WriteAsync(result);
+
+                return;
+            }
+
+            await _next(httpContext);
+        }
+    }
+
+    public static class SingleQueryRawMiddlewareExtensions
+    {
+        public static IApplicationBuilder UseSingleQueryRaw(this IApplicationBuilder builder)
+        {
+            return builder.UseMiddleware<SingleQueryRawMiddleware>();
+        }
+    }
+}

+ 31 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.Designer.cs

@@ -0,0 +1,31 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Benchmarks.Data;
+
+namespace Benchmarks.Migrations
+{
+    [DbContext(typeof(ApplicationDbContext))]
+    [Migration("20151113004227_Initial")]
+    partial class Initial
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+            modelBuilder
+                .HasAnnotation("ProductVersion", "7.0.0-rc2-16329")
+                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+            modelBuilder.Entity("AspNet5.Data.World", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("RandomNumber");
+
+                    b.HasKey("Id");
+                });
+        }
+    }
+}

+ 32 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151113004227_Initial.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Metadata;
+using System.Text;
+
+namespace Benchmarks.Migrations
+{
+    public partial class Initial : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "World",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
+                    RandomNumber = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_World", x => x.Id);
+                });
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable("World");
+        }
+    }
+}

+ 42 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.Designer.cs

@@ -0,0 +1,42 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Benchmarks.Data;
+
+namespace Benchmarks.Migrations
+{
+    [DbContext(typeof(ApplicationDbContext))]
+    [Migration("20151124205054_Fortune")]
+    partial class Fortune
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+            modelBuilder
+                .HasAnnotation("ProductVersion", "7.0.0-rc2-16413")
+                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+            modelBuilder.Entity("Benchmarks.Data.Fortune", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Message")
+                        .HasAnnotation("MaxLength", 2048);
+
+                    b.HasKey("Id");
+                });
+
+            modelBuilder.Entity("Benchmarks.Data.World", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("RandomNumber");
+
+                    b.HasKey("Id");
+                });
+        }
+    }
+}

+ 32 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/20151124205054_Fortune.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Metadata;
+
+namespace Benchmarks.Migrations
+{
+    public partial class Fortune : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "Fortune",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
+                    Message = table.Column<string>(nullable: true)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Fortune", x => x.Id);
+                });
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "Fortune");
+        }
+    }
+}

+ 41 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Migrations/ApplicationDbContextModelSnapshot.cs

@@ -0,0 +1,41 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Benchmarks.Data;
+
+namespace Benchmarks.Migrations
+{
+    [DbContext(typeof(ApplicationDbContext))]
+    partial class ApplicationDbContextModelSnapshot : ModelSnapshot
+    {
+        protected override void BuildModel(ModelBuilder modelBuilder)
+        {
+            modelBuilder
+                .HasAnnotation("ProductVersion", "7.0.0-rc2-16413")
+                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+            modelBuilder.Entity("Benchmarks.Data.Fortune", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Message")
+                        .HasAnnotation("MaxLength", 2048);
+
+                    b.HasKey("Id");
+                });
+
+            modelBuilder.Entity("Benchmarks.Data.World", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("RandomNumber");
+
+                    b.HasKey("Id");
+                });
+        }
+    }
+}

+ 8 - 0
frameworks/CSharp/aspnetcore/Benchmarks/NuGet.Config

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <clear />
+    <add key="AspNetVNext" value="https://dotnet.myget.org/F/aspnet1/api/v3/index.json" />
+    <add key="NuGet" value="https://api.nuget.org/v3/index.json" />
+  </packageSources>
+</configuration>

+ 138 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Program.cs

@@ -0,0 +1,138 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Runtime;
+using System.Threading;
+using Benchmarks.Configuration;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Benchmarks
+{
+    public class Program
+    {
+        public static string[] Args;
+        public static string Server;
+
+        public static void Main(string[] args)
+        {
+            Args = args;
+
+            Console.WriteLine();
+            Console.WriteLine("ASP.NET Core Benchmarks");
+            Console.WriteLine("-----------------------");
+
+            Console.WriteLine($"Current directory: {Directory.GetCurrentDirectory()}");
+
+            var config = new ConfigurationBuilder()
+                .AddCommandLine(args)
+                .AddEnvironmentVariables(prefix: "ASPNETCORE_")
+                .AddJsonFile("hosting.json", optional: true)
+                .Build();
+
+            Server = config["server"] ?? "Kestrel";
+
+            var webHostBuilder = new WebHostBuilder()
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseConfiguration(config)
+                .UseStartup<Startup>()
+                .ConfigureServices(services => services
+                    .AddSingleton(new ConsoleArgs(args))
+                    .AddSingleton<IScenariosConfiguration, ConsoleHostScenariosConfiguration>()
+                    .AddSingleton<Scenarios>()
+                );
+
+            if (String.Equals(Server, "Kestrel", StringComparison.OrdinalIgnoreCase))
+            {
+                var threads = GetThreadCount(config);
+                webHostBuilder = webHostBuilder.UseKestrel((options) =>
+                {
+                    if (threads > 0)
+                    {
+                        options.ThreadCount = threads;
+                    }
+                });
+            }
+            else if (String.Equals(Server, "WebListener", StringComparison.OrdinalIgnoreCase))
+            {
+                webHostBuilder = webHostBuilder.UseWebListener();
+            }
+            else
+            {
+                throw new InvalidOperationException($"Unknown server value: {Server}");
+            }
+
+            var webHost = webHostBuilder.Build();
+
+            Console.WriteLine($"Using server {Server}");
+            Console.WriteLine($"Server GC is currently {(GCSettings.IsServerGC ? "ENABLED" : "DISABLED")}");
+
+            var nonInteractiveValue = config["NonInteractive"];
+            if (nonInteractiveValue == null || !bool.Parse(nonInteractiveValue))
+            {
+                StartInteractiveConsoleThread();
+            }
+
+            webHost.Run();
+        }
+
+        private static void StartInteractiveConsoleThread()
+        {
+            // Run the interaction on a separate thread as we don't have Console.KeyAvailable on .NET Core so can't
+            // do a pre-emptive check before we call Console.ReadKey (which blocks, hard)
+
+            var started = new ManualResetEvent(false);
+
+            var interactiveThread = new Thread(() =>
+            {
+                Console.WriteLine("Press 'C' to force GC or any other key to display GC stats");
+                Console.WriteLine();
+
+                started.Set();
+
+                while (true)
+                {
+                    var key = Console.ReadKey(intercept: true);
+
+                    if (key.Key == ConsoleKey.C)
+                    {
+                        Console.WriteLine();
+                        Console.Write("Forcing GC...");
+                        GC.Collect();
+                        GC.WaitForPendingFinalizers();
+                        GC.Collect();
+                        Console.WriteLine(" done!");
+                    }
+                    else
+                    {
+                        Console.WriteLine();
+                        Console.WriteLine($"Allocated: {GetAllocatedMemory()}");
+                        Console.WriteLine($"Gen 0: {GC.CollectionCount(0)}, Gen 1: {GC.CollectionCount(1)}, Gen 2: {GC.CollectionCount(2)}");
+                    }
+                }
+            });
+
+            interactiveThread.IsBackground = true;
+            interactiveThread.Start();
+
+            started.WaitOne();
+        }
+
+        private static string GetAllocatedMemory(bool forceFullCollection = false)
+        {
+            double bytes = GC.GetTotalMemory(forceFullCollection);
+
+            return $"{((bytes / 1024d) / 1024d).ToString("N2")} MB";
+        }
+
+        private static int GetThreadCount(IConfigurationRoot config)
+        {
+            var threadCountValue = config["threadCount"];
+            return threadCountValue == null ? -1 : int.Parse(threadCountValue);
+        }
+    }
+}
+

+ 27 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:3653/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "EnableDbTests": "true",
+        "AspNet_Environment": "Development"
+      }
+    },
+    "Benchmarks": {
+      "commandName": "Benchmarks",
+      "launchUrl": "http://localhost:5000/",
+      "environmentVariables": {
+        "AspNet_Environment": "Development"
+      }
+    }
+  }
+}

+ 185 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Startup.cs

@@ -0,0 +1,185 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Data.Common;
+using System.Data.SqlClient;
+using Benchmarks.Configuration;
+using Benchmarks.Data;
+using Benchmarks.Middleware;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.PlatformAbstractions;
+
+namespace Benchmarks
+{
+    public class Startup
+    {
+        public Startup(IHostingEnvironment hostingEnv, Scenarios scenarios)
+        {
+            // Set up configuration sources.
+            var builder = new ConfigurationBuilder()
+                .SetBasePath(PlatformServices.Default.Application.ApplicationBasePath)
+                .AddCommandLine(Program.Args)
+                .AddJsonFile("appsettings.json")
+                .AddJsonFile($"appsettings.{hostingEnv.EnvironmentName}.json", optional: true)
+                .AddEnvironmentVariables();
+
+            Configuration = builder.Build();
+
+            Scenarios = scenarios;
+        }
+
+        public IConfigurationRoot Configuration { get; set; }
+
+        public Scenarios Scenarios { get; }
+
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.Configure<AppSettings>(Configuration);
+
+            // We re-register the Scenarios as an instance singleton here to avoid it being created again due to the
+            // registration done in Program.Main
+            services.AddSingleton(Scenarios);
+
+            // Common DB services
+            services.AddSingleton<IRandom, DefaultRandom>();
+            services.AddSingleton<ApplicationDbSeeder>();
+            services.AddEntityFrameworkSqlServer()
+                .AddDbContext<ApplicationDbContext>();
+
+            if (Scenarios.Any("Raw") || Scenarios.Any("Dapper"))
+            {
+                // TODO: Add support for plugging in different DbProviderFactory implementations via configuration
+                services.AddSingleton<DbProviderFactory>(SqlClientFactory.Instance);
+            }
+
+            if (Scenarios.Any("Ef"))
+            {
+                services.AddScoped<EfDb>();
+            }
+
+            if (Scenarios.Any("Raw"))
+            {
+                services.AddScoped<RawDb>();
+            }
+
+            if (Scenarios.Any("Dapper"))
+            {
+                services.AddScoped<DapperDb>();
+            }
+
+            if (Scenarios.Any("Fortunes"))
+            {
+                services.AddWebEncoders();
+            }
+
+            if (Scenarios.Any("Mvc"))
+            {
+                var mvcBuilder = services
+                    .AddMvcCore()
+                    //.AddApplicationPart(typeof(Startup).GetTypeInfo().Assembly)
+                    .AddControllersAsServices();
+
+                if (Scenarios.MvcJson)
+                {
+                    mvcBuilder.AddJsonFormatters();
+                }
+
+                if (Scenarios.MvcViews || Scenarios.Any("MvcDbFortunes"))
+                {
+                    mvcBuilder
+                        .AddViews()
+                        .AddRazorViewEngine();
+                }
+            }
+        }
+
+        public void Configure(IApplicationBuilder app, ApplicationDbSeeder dbSeeder, ApplicationDbContext dbContext)
+        {
+            app.UseErrorHandler();
+
+            if (Scenarios.Plaintext)
+            {
+                app.UsePlainText();
+            }
+
+            if (Scenarios.Json)
+            {
+                app.UseJson();
+            }
+
+            // Single query endpoints
+            if (Scenarios.DbSingleQueryRaw)
+            {
+                app.UseSingleQueryRaw();
+            }
+
+            if (Scenarios.DbSingleQueryDapper)
+            {
+                app.UseSingleQueryDapper();
+            }
+
+            if (Scenarios.DbSingleQueryEf)
+            {
+                app.UseSingleQueryEf();
+            }
+
+            // Multiple query endpoints
+            if (Scenarios.DbMultiQueryRaw)
+            {
+                app.UseMultipleQueriesRaw();
+            }
+
+            if (Scenarios.DbMultiQueryDapper)
+            {
+                app.UseMultipleQueriesDapper();
+            }
+
+            if (Scenarios.DbMultiQueryEf)
+            {
+                app.UseMultipleQueriesEf();
+            }
+
+            // Fortunes endpoints
+            if (Scenarios.DbFortunesRaw)
+            {
+                app.UseFortunesRaw();
+            }
+
+            if (Scenarios.DbFortunesDapper)
+            {
+                app.UseFortunesDapper();
+            }
+
+            if (Scenarios.DbFortunesEf)
+            {
+                app.UseFortunesEf();
+            }
+
+            if (Scenarios.Any("Db"))
+            {
+                dbContext.Database.EnsureCreated();
+
+                if (!dbSeeder.Seed())
+                {
+                    Environment.Exit(1);
+                }
+            }
+
+            if (Scenarios.Any("Mvc"))
+            {
+                app.UseMvc();
+            }
+
+            if (Scenarios.StaticFiles)
+            {
+                app.UseStaticFiles();
+            }
+
+            app.RunDebugInfoPage();
+        }
+    }
+}

+ 12 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Views/Fortunes/Fortunes.cshtml

@@ -0,0 +1,12 @@
+@using Benchmarks.Data
+@model IEnumerable<Fortune>
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body><table><tr><th>id</th><th>message</th></tr>
+    @foreach (var item in Model)
+    {
+        <tr><td>@item.Id</td><td>@item.Message</td></tr>
+    }
+</table></body>
+</html>

+ 5 - 0
frameworks/CSharp/aspnetcore/Benchmarks/Views/Home/Index.cshtml

@@ -0,0 +1,5 @@
+@{
+    var message = "Hello, World!";
+}
+
+@message

+ 3 - 0
frameworks/CSharp/aspnetcore/Benchmarks/appsettings.json

@@ -0,0 +1,3 @@
+{
+  "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-Benchmarks;Trusted_Connection=True;MultipleActiveResultSets=true"
+}

+ 55 - 0
frameworks/CSharp/aspnetcore/Benchmarks/project.json

@@ -0,0 +1,55 @@
+{
+  "version": "1.0.0-*",
+  "compilationOptions": {
+    "emitEntryPoint": true,
+    "preserveCompilationContext": true
+  },
+  "dependencies": {
+    "Dapper": "1.50.0-*",
+    "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0-*",
+    "Microsoft.EntityFrameworkCore.Tools": {
+      "type": "build",
+      "version": "1.0.0-*"
+    },
+    "Microsoft.AspNetCore.Mvc": "1.0.0-*",
+    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-*",
+    "Microsoft.AspNetCore.Server.WebListener": "0.1.0-*",
+    "Microsoft.AspNetCore.StaticFiles": "1.0.0-*",
+    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0-*",
+    "Microsoft.Extensions.Configuration.Json": "1.0.0-*",
+    "Microsoft.Extensions.Configuration.CommandLine": "1.0.0-*",
+    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-*"
+  },
+  "frameworks": {
+    "netcoreapp1.0": {
+      "imports": [ "portable-net451+win8", "dnxcore50" ],
+      "dependencies": {
+        "Microsoft.NETCore.App": {
+          "version": "1.0.0-*",
+          "type": "platform"
+        },
+        "System.Runtime.Serialization.Primitives": "4.1.0-*"
+      }
+    },
+    "net451": { }
+  },
+  "tools": {
+    "Microsoft.EntityFrameworkCore.Tools": {
+      "version": "1.0.0-*",
+      "imports": [
+        "dnxcore50",
+        "portable-net452+win81"
+      ]
+    }
+  },
+  "content": [
+    "appsettings.json",
+    "wwwroot",
+    "Views"
+  ],
+  "runtimeOptions": {
+    "configProperties": {
+      "System.GC.Server": true
+    }
+  }
+}

BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/128B.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/16KB.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/1KB.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/1MB.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/4KB.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/512B.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/512KB.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/5MB.txt


BIN
frameworks/CSharp/aspnetcore/Benchmarks/wwwroot/favicon.ico


+ 32 - 0
frameworks/CSharp/aspnetcore/README.md

@@ -0,0 +1,32 @@
+# ASP.NET Core Tests on Windows and Linux
+
+See [.NET Core](http://dot.net) and [ASP.NET Core](https://github.com/aspnet) for more information.
+
+This includes tests for plaintext and json serialization.
+
+## Infrastructure Software Versions
+
+**Language**
+
+* C# 6.0
+
+**Platforms**
+
+* .NET Core (Windows and Linux)
+
+**Web Servers**
+
+* [Kestrel](https://github.com/aspnet/kestrelHttpServer)
+* WebListener
+
+**Web Stack**
+
+* ASP.NET Core
+* ASP.NET Core MVC
+
+## Paths & Source for Tests
+
+* [Plaintext](Benchmarks/Middleware/PlaintextMiddleware.cs): "/plaintext"
+* [Plaintext MVC](Benchmarks/Controllers/HomeController.cs): "/mvc/plaintext"
+* [JSON Serialization](Benchmarks/Middleware/JsonMiddleware.cs): "/json"
+* [JSON Serialization MVC](Benchmarks/Controllers/HomeController.cs): "/mvc/json"

+ 119 - 0
frameworks/CSharp/aspnetcore/benchmark_config.json

@@ -0,0 +1,119 @@
+{
+  "framework": "aspnetcore",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "None",
+      "framework": "aspnetcore",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "Kestrel",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnetcore-linux",
+      "notes": "",
+      "versus": ""
+    },
+    "mvc-linux": {
+      "setup_file": "setup-mvc",
+      "json_url": "/mvc/json",
+      "plaintext_url": "/mvc/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "None",
+      "framework": "aspnetcore",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "Kestrel",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnetcore-mvc-linux",
+      "notes": "",
+      "versus": ""
+    },
+    "win": {
+      "setup_file": "setup-windows",
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "None",
+      "framework": "aspnetcore",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "Kestrel",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnetcore-win",
+      "notes": "",
+      "versus": ""
+    },
+    "mvc-win": {
+      "setup_file": "setup-mvc-windows",
+      "json_url": "/mvc/json",
+      "plaintext_url": "/mvc/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "None",
+      "framework": "aspnetcore",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "Kestrel",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnetcore-mvc-win",
+      "notes": "",
+      "versus": ""
+    },
+    "weblistener": {
+      "setup_file": "setup-weblistener",
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "None",
+      "framework": "aspnetcore",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "WebListener",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnetcore-weblistener",
+      "notes": "",
+      "versus": ""
+    },
+    "mvc-weblistener": {
+      "setup_file": "setup-mvc-weblistener",
+      "json_url": "/mvc/json",
+      "plaintext_url": "/mvc/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "None",
+      "framework": "aspnetcore",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "WebListener",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnetcore-mvc-weblistener",
+      "notes": "",
+      "versus": ""
+    }
+  }]
+}

+ 8 - 0
frameworks/CSharp/aspnetcore/run-linux.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+fw_depends mono dotnetcore
+sudo apt-get install unzip libunwind8 -y
+
+cd Benchmarks
+dotnet restore
+dotnet build -c Release -f netcoreapp1.0
+dotnet run -c Release server.urls=http://*:8080 scenarios=$1 server=kestrel threadCount=1 NonInteractive=true &

+ 8 - 0
frameworks/CSharp/aspnetcore/run-windows.ps1

@@ -0,0 +1,8 @@
+param([string]$scenarios="[default]", [string]$server="kestrel")
+
+$scenarios = (-split $scenarios) -join ","
+
+cd Benchmarks
+dotnet restore
+dotnet build -c Release -f netcoreapp1.0
+Start-Process -NoNewWindow dotnet "run -c Release server.urls=http://*:8080 server=$server threadCount=1 NonInteractive=true scenarios=$scenarios"

+ 3 - 0
frameworks/CSharp/aspnetcore/setup-mvc-weblistener.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+fw_depends dotnetcore
+powershell run-windows.ps1 -scenarios 'mvcjson,mvcplain' -server weblistener

+ 3 - 0
frameworks/CSharp/aspnetcore/setup-mvc-windows.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+fw_depends dotnetcore
+powershell run-windows.ps1 -scenarios 'mvcjson,mvcplain' -server kestrel

+ 3 - 0
frameworks/CSharp/aspnetcore/setup-mvc.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+source run-linux.sh mvcjson,mvcplain

+ 3 - 0
frameworks/CSharp/aspnetcore/setup-weblistener.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+fw_depends dotnetcore
+powershell run-windows.ps1 -scenarios [default] -server weblistener

+ 3 - 0
frameworks/CSharp/aspnetcore/setup-windows.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+fw_depends dotnetcore
+powershell run-windows.ps1 -scenarios [default] -server kestrel

+ 3 - 0
frameworks/CSharp/aspnetcore/setup.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+source run-linux.sh [default]

+ 17 - 4
frameworks/CSharp/revenj/Revenj.Bench/RestService.cs

@@ -98,7 +98,8 @@ namespace Revenj.Bench
 			return ReturnJSON(world, ctx.Stream);
 		}
 
-		private void LoadWorlds(int repeat, Context ctx)
+		/* bulk loading of worlds. use such pattern for production code */
+		private void LoadWorldsFast(int repeat, Context ctx)
 		{
 			var reader = ctx.BulkReader;
 			var lazyResult = ctx.LazyWorlds;
@@ -114,6 +115,18 @@ namespace Revenj.Bench
 				worlds[i] = lazyResult[i].Value;
 		}
 
+		/* multiple roundtrips loading of worlds. don't write such production code */
+		private void LoadWorldsSlow(int repeat, Context ctx)
+		{
+			var worlds = ctx.Worlds;
+			var repository = ctx.WorldRepository;
+			for (int i = 0; i < repeat; i++)
+			{
+				var id = Random.Next(10000) + 1;
+				worlds[i] = repository.Find(IDs[id]);
+			}
+		}
+
 		public Stream MultipleQueries(string count)
 		{
 			int repeat;
@@ -121,7 +134,7 @@ namespace Revenj.Bench
 			if (repeat < 1) repeat = 1;
 			else if (repeat > 500) repeat = 500;
 			var ctx = GetContext(Services);
-			LoadWorlds(repeat, ctx);
+			LoadWorldsSlow(repeat, ctx);
 			var cms = ctx.Stream;
 			ctx.Worlds.Serialize(cms, repeat);
 			ThreadContext.Response.ContentType = "application/json";
@@ -137,7 +150,7 @@ namespace Revenj.Bench
 			if (repeat < 1) repeat = 1;
 			else if (repeat > 500) repeat = 500;
 			var ctx = GetContext(Services);
-			LoadWorlds(repeat, ctx);
+			LoadWorldsSlow(repeat, ctx);
 			var result = new World[repeat];
 			Array.Copy(ctx.Worlds, result, repeat);
 			for (int i = 0; i < result.Length; i++)
@@ -169,6 +182,6 @@ namespace Revenj.Bench
 			cms.Position = 0;
 			ThreadContext.Response.ContentType = "text/html; charset=UTF-8";
 			return cms;
-	}
+		}
 	}
 }

+ 3 - 3
frameworks/Clojure/pedestal/project.clj

@@ -4,15 +4,15 @@
   :license {:name "Eclipse Public License"
             :url "http://www.eclipse.org/legal/epl-v10.html"}
   :dependencies [[org.clojure/clojure "1.8.0"]
-                 [io.pedestal/pedestal.service "0.4.1"]
-                 [io.pedestal/pedestal.jetty "0.4.1"]
+                 [io.pedestal/pedestal.service "0.5.0"]
+                 [io.pedestal/pedestal.jetty "0.5.0"]
                  [ch.qos.logback/logback-classic "1.1.2" :exclusions [org.slf4j/slf4j-api]]
                  [org.slf4j/jul-to-slf4j "1.7.7"]
                  [org.slf4j/jcl-over-slf4j "1.7.7"]
                  [org.slf4j/log4j-over-slf4j "1.7.7"]
                  [org.clojure/data.json "0.2.6"]
                  [org.clojure/java.jdbc "0.4.2"]
-                 [korma "0.4.0"]
+                 [korma "0.4.2"]
                  [mysql/mysql-connector-java "5.1.38"]
                  [hiccup "1.0.5"]]
   :min-lein-version "2.0.0"

+ 62 - 76
frameworks/Clojure/pedestal/src/pedestal/service.clj

@@ -13,19 +13,26 @@
             [clojure.data.json :as json]
             [clojure.java.jdbc :as jdbc]))
 
-
-(defn json-serialization
-  "Test 1: JSON serialization"
+(defn sanitize-queries-param
+  "Sanitizes the `queries` parameter. Clamps the value between 1 and 500.
+  Invalid (string) values become 1."
   [request]
-  (bootstrap/json-response {:message "Hello, World!"}))
-
-
-;; MySQL connection
-(defdb mysql-db
+  (let [queries (-> request
+                    :params
+                    :queries)
+        n (try (Integer/parseInt queries)
+               (catch Exception e 1))] ; default to 1 on parse failure
+    (cond
+      (< n 1) 1
+      (> n 500) 500
+      :else n)))
+
+;; MySQL database connection
+(defdb db-mysql
   (mysql {
     :classname "com.mysql.jdbc.Driver"
     :subprotocol "mysql"
-    :subname "//127.0.0.1:3306/hello_world"
+    :subname "//127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
     :user "benchmarkdbuser"
     :password "benchmarkdbpass"
     ;;OPTIONAL KEYS
@@ -37,65 +44,32 @@
 (defentity world
   (pk :id)
   (table :world)
-  (entity-fields :id :randomNumber) ;; Default fields for select
-  (database mysql-db))
+  (entity-fields :id :randomNumber) ; Default fields for select
+  (database db-mysql))
 
-
-(defn random-world
+(defn get-random-world-korma
   "Query a random World record from the database"
   []
   (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
     (select world
             (where {:id id }))))
 
-
 (defn run-queries
-  "Run query repeatedly -- Always returns an array"
+  "Run query repeatedly, return an array"
   [queries]
-  (flatten (take queries (repeatedly random-world))))
-
-
-(defn single-query-test
-  "Test 2: Single database query"
-  [request]
-  (bootstrap/json-response (first (run-queries 1))))
-
-
-(defn sanitizeQueriesParam
-  "Sanitizes the `queries` parameter. Caps the value between 1 and 500.
-  Invalid (stringy) values become 1"
-  [request]
-  (let [queries (-> request
-                    :params
-                    :queries)]
-    (if-let [n (if (= (re-find #"\A-?\d+" queries) nil)
-                   1
-                   (Integer/parseInt queries))]
-      (cond
-        (< n 1) 1
-        (> n 500) 500
-        :else n))))
+  (flatten ; Make it a list of maps
+    (take queries ; Number of queries to run
+          (repeatedly get-random-world-korma))))
 
-
-(defn multiple-query-test
-  "Test 3: Multiple database queries"
-  [request]
-  (-> request
-      (sanitizeQueriesParam)
-      (run-queries)
-      (bootstrap/json-response)))
-
-
-; Set up entity Fortune and the database representation
+;; Set up entity Fortune and the database representation
 (defentity fortune
   (pk :id)
   (table :fortune)
   (entity-fields :id :message)
-  (database mysql-db))
-
+  (database db-mysql))
 
-(defn get-all-fortunes
-  "Query all Fortune records from the database."
+(defn get-all-fortunes-korma
+  "Query all Fortune records from the database using Korma."
   []
   (select fortune
           (fields :id :message)))
@@ -107,10 +81,9 @@
   []
   (sort-by #(:message %)
     (conj
-      (get-all-fortunes)
+      (get-all-fortunes-korma)
       { :id 0 :message "Additional fortune added at request time." })))
 
-
 (defn fortunes-hiccup
   "Render the given fortunes to simple HTML using Hiccup."
   [fortunes]
@@ -128,6 +101,34 @@
         [:td (escape-html (:message x))]])
      ]]))
 
+(defn update-and-persist
+  "Using Korma: Changes the :randomNumber of a number of world entities.
+  Persists the changes to sql then returns the updated entities"
+  [queries]
+  (let [results (map #(assoc % :randomNumber (inc (rand-int 9999))) (run-queries queries))]
+    (doseq [{:keys [id randomNumber]} results]
+      (update world
+              (set-fields {:randomNumber randomNumber})
+              (where {:id id})))
+    results))
+
+(defn json-serialization
+  "Test 1: JSON serialization"
+  [request]
+  (bootstrap/json-response {:message "Hello, World!"}))
+
+(defn single-query-test
+  "Test 2: Single database query"
+  [request]
+  (bootstrap/json-response (first (run-queries 1))))
+
+(defn multiple-queries-test
+  "Test 3: Multiple database queries"
+  [request]
+  (-> request
+      (sanitize-queries-param)
+      (run-queries)
+      (bootstrap/json-response)))
 
 (defn fortune-test
   "Test 4: Fortunes"
@@ -137,28 +138,13 @@
     (fortunes-hiccup)
     (ring-resp/response)
     (ring-resp/content-type "text/html")
-    (ring-resp/charset "utf-8")))         ;; Apply charset after content type
-
-
-(defn update-and-persist
-  "Changes the :randomNumber of a number of world entities.
-  Persists the changes to sql then returns the updated entities"
-  [request]
-  (let [results (-> request
-                    (sanitizeQueriesParam)
-                    (run-queries))]
-    (for [w results]
-      (update-in w [:randomNumber (inc (rand-int 9999))]
-        (update world
-                (set-fields {:randomNumber (:randomNumber w)})
-                (where {:id [:id w]}))))
-    results))
-
+    (ring-resp/charset "utf-8")))
 
 (defn db-updates
   "Test 5: Database updates"
   [request]
   (-> request
+      (sanitize-queries-param)
       (update-and-persist)
       (bootstrap/json-response)))
 
@@ -168,15 +154,15 @@
   [request]
   (ring-resp/response "Hello, World!"))
 
-
+;; Define route handlers
 (defroutes routes
   [[
+  [  "/plaintext" {:get plaintext}]
   [  "/json"      {:get json-serialization}]
   [  "/db"        {:get single-query-test}]
-  [  "/queries"   {:get multiple-query-test}]
+  [  "/queries"   {:get multiple-queries-test}]
   [  "/fortunes"  {:get fortune-test}]
-  [  "/updates"   {:get db-updates}]
-  [  "/plaintext" {:get plaintext}]]])
+  [  "/updates"   {:get db-updates}]]])
 
 
 (def service

+ 1 - 1
frameworks/Elixir/phoenix/lib/hello/repo.ex

@@ -1,3 +1,3 @@
 defmodule Hello.Repo do
-    use Ecto.Repo, otp_app: :hello
+  use Ecto.Repo, otp_app: :hello
 end

+ 6 - 7
frameworks/Elixir/phoenix/mix.exs

@@ -3,8 +3,8 @@ defmodule Hello.Mixfile do
 
   def project do
    [app: :hello,
-    version: "0.0.1",
-    elixir: "~> 1.1",
+    version: "0.1.0",
+    elixir: "~> 1.3",
     elixirc_paths: elixirc_paths(Mix.env),
     compilers: [:phoenix] ++ Mix.compilers,
     build_embedded: Mix.env == :prod,
@@ -26,12 +26,11 @@ defmodule Hello.Mixfile do
   #
   # Type `mix help deps` for examples and options
   defp deps do
-    [{:phoenix, "~> 1.0.3"},
-     {:phoenix_ecto, "~> 1.1"},
+    [{:phoenix, "~> 1.2"},
+     {:phoenix_ecto, "~> 3.0"},
      {:postgrex, ">= 0.0.0"},
      {:cowboy, "~> 1.0.0"},
-     {:phoenix_html, "~> 2.1"},
-     {:phoenix_live_reload, "~> 1.0", only: :dev},
-     {:exrm, "~> 0.19.8"}]
+     {:phoenix_html, "~> 2.6"},
+     {:phoenix_live_reload, "~> 1.0", only: :dev}]
   end
 end

+ 3 - 2
frameworks/Elixir/phoenix/setup.sh

@@ -8,7 +8,8 @@ rm -rf _build deps
 
 export MIX_ENV=prod
 mix local.hex --force
-mix deps.get --force
+mix local.rebar --force
+mix deps.get --force --only prod
 mix compile --force
 
-elixir --detached -S mix phoenix.server
+elixir --erl "+K true" --detached  -pa _build/prod/consolidated -S mix phoenix.server

+ 30 - 10
frameworks/Elixir/phoenix/web/controllers/page_controller.ex

@@ -4,16 +4,22 @@ defmodule Hello.PageController do
   alias Hello.Fortune
 
   def index(conn, _params) do
-    json conn, %{"TE Benchmarks\n" => "Started"}
+    conn
+    |> merge_resp_headers(%{"content-type" => "application/json"})
+    |> json(%{"TE Benchmarks\n" => "Started"})
   end
 
   # avoid namespace collision
   def _json(conn, _params) do
-    json conn, %{message: "Hello, world!"}
+    conn
+    |> merge_resp_headers(%{"content-type" => "application/json"})
+    |> json(%{message: "Hello, world!"})
   end
 
   def db(conn, _params) do
-    json conn, Repo.get(World, :random.uniform(10000))
+    conn
+    |> merge_resp_headers(%{"content-type" => "application/json"})
+    |> json(Repo.get(World, :rand.uniform(10000)))
   end
 
   def queries(conn, params) do
@@ -26,11 +32,20 @@ defmodule Hello.PageController do
     rescue
       ArgumentError -> 1
     end
-    json conn, Enum.map(1..q, fn _ -> Repo.get(World, :random.uniform(10000)) end)
+
+    conn
+    |> merge_resp_headers(%{"content-type" => "application/json"})
+    |> json(Enum.map(1..q, fn _ -> Repo.get(World, :rand.uniform(10000)) end))
   end
 
   def fortunes(conn, _params) do
-    fortunes = List.insert_at(Repo.all(Fortune), 0, %Fortune{:id => 0, :message  => "Additional fortune added at request time."})
+    additional_fortune = %Fortune{
+      id: 0,
+      message: "Additional fortune added at request time."
+    }
+
+    fortunes = [additional_fortune | Repo.all(Fortune)]
+
     render conn, "fortunes.html", fortunes: Enum.sort(fortunes, fn f1, f2 -> f1.message < f2.message end)
   end
 
@@ -44,14 +59,19 @@ defmodule Hello.PageController do
     rescue
       ArgumentError -> 1
     end
-    json conn, Enum.map(1..q, fn _ ->
-      w = Repo.get(World, :random.uniform(10000))
-      changeset = World.changeset(w, %{randomNumber: :random.uniform(10000)})
+
+    conn
+    |> merge_resp_headers(%{"content-type" => "application/json"})
+    |> json(Enum.map(1..q, fn _ ->
+      w = Repo.get(World, :rand.uniform(10000))
+      changeset = World.changeset(w, %{randomNumber: :rand.uniform(10000)})
       Repo.update(changeset)
-      w end)
+      w end))
   end
 
   def plaintext(conn, _params) do
-    text conn, "Hello, world!"
+    conn
+    |> merge_resp_headers(%{"content-type" => "text/plain"})
+    |> text("Hello, world!")
   end
 end

+ 3 - 3
frameworks/Elixir/phoenix/web/models/fortune.ex

@@ -6,11 +6,11 @@ defmodule Hello.Fortune do
     field :message, :string
   end
 
-  @required_fields ~w(message)
+  @required_fields ~w(message)a
   @optional_fields ~w()
 
-  def changeset(model, params \\ nil) do
+  def changeset(model, params \\ %{}) do
     model
-    |> cast(params, @required_fields, @optional_fields)
+    |> cast(params, @required_fields)
   end
 end

+ 3 - 3
frameworks/Elixir/phoenix/web/models/world.ex

@@ -6,11 +6,11 @@ defmodule Hello.World do
     field :randomnumber, :integer
   end
 
-  @required_fields ~w(randomnumber)
+  @required_fields ~w(randomnumber)a
   @optional_fields ~w()
 
-  def changeset(model, params \\ nil) do
+  def changeset(model, params \\ %{}) do
     model
-    |> cast(params, @required_fields, @optional_fields)
+    |> cast(params, @required_fields)
   end
 end

+ 1 - 1
frameworks/Elixir/phoenix/web/templates/layout/app.html.eex

@@ -1 +1 @@
-<!DOCTYPE html><html lang="en"><head><title>Fortunes</title></head><body><%= @inner %></body></html>
+<!DOCTYPE html><html lang="en"><head><title>Fortunes</title></head><body><%= render @view_module, @view_template, assigns %></body></html>

+ 10 - 6
frameworks/Elixir/phoenix/web/web.ex

@@ -14,7 +14,11 @@ defmodule Hello.Web do
 
   def model do
     quote do
-      use Ecto.Model
+      use Ecto.Schema
+
+      import Ecto
+      import Ecto.Changeset
+      import Ecto.Query
     end
   end
 
@@ -24,7 +28,7 @@ defmodule Hello.Web do
 
       # Alias the data repository and import query/model functions
       alias Hello.Repo
-      import Ecto.Model
+      import Ecto
       import Ecto.Query
 
       # Import URL helpers from the router
@@ -40,11 +44,11 @@ defmodule Hello.Web do
       import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2,
                                         action_name: 1, controller_module: 1]
 
-      # Import URL helpers from the router
-      import Hello.Router.Helpers
 
       # Import all HTML functions (forms, tags, etc)
       use Phoenix.HTML
+
+      import Hello.Router.Helpers
     end
   end
 
@@ -60,8 +64,8 @@ defmodule Hello.Web do
       use Phoenix.Channel
       # Alias the data repository and import query/model functions
       alias Hello.Repo
-      import Ecto.Model
-      import Ecto.Query, only: [from: 2]
+      import Ecto
+      import Ecto.Query
     end
   end
 

+ 0 - 8
frameworks/Erlang/misultin/.gitignore

@@ -1,8 +0,0 @@
-.eunit
-deps
-ebin
-*.o
-*.beam
-*.plt
-erl_crash.dump
-/.rebar/

+ 0 - 13
frameworks/Erlang/misultin/Makefile

@@ -1,13 +0,0 @@
-REBAR=./rebar
-
-all:
-	@$(REBAR) -r get-deps compile
-
-clean:
-	@$(REBAR) clean
-
-run:
-	@./start.sh
-
-stop:
-	@killall beam.smp

+ 0 - 23
frameworks/Erlang/misultin/benchmark_config.json

@@ -1,23 +0,0 @@
-{
-  "framework": "misultin",
-  "tests": [{
-    "default": {
-      "setup_file": "setup",
-      "json_url": "/json",
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Platform",
-      "database": "MySQL",
-      "framework": "Misultin",
-      "language": "Erlang",
-      "orm": "Raw",
-      "platform": "Erlang",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "misultin",
-      "notes": "",
-      "versus": ""
-  }}]
-}

+ 0 - 9
frameworks/Erlang/misultin/priv/app.config

@@ -1,9 +0,0 @@
-%% -*- erlang -*-
-[{misultin_bench, [{http_port, 8080}]},
-
- {erl_bench, [{db_pool, 256},
-              {db_user, "benchmarkdbuser"},
-              {db_password, "benchmarkdbpass"},
-              {db_host, "localhost"},
-              {db_port, 3306},
-              {db_name, "hello_world"}]}].

+ 0 - 5
frameworks/Erlang/misultin/rebar.config

@@ -1,5 +0,0 @@
-%% -*- erlang -*-
-{deps, [
-  {erl_bench, ".*", {git, "git://github.com/utkarshkukreti/erl_bench.git", "cb70233d7de1e800893cf1460f181a706aa08a38"}},
-  {misultin, "0.9", {git, "git://github.com/ostinelli/misultin.git", {tag, "misultin-0.9"}}}
-]}.

+ 0 - 11
frameworks/Erlang/misultin/setup.sh

@@ -1,11 +0,0 @@
-#!/bin/bash
-
-sed -i 's|"benchmarkdbpass", ".*", 3306|"benchmarkdbpass", "'"${DBHOST}"'", 3306|g' src/misultin_bench_sup.erl
-
-fw_depends erlang
-
-rm -rf deps/* ebin/*
-rebar get-deps
-rebar compile
-
-erl +K true +sbwt very_long +swt very_low -pa ebin deps/*/ebin -boot start_sasl -config priv/app.config -s misultin_bench_app -noshell -detached

+ 0 - 9
frameworks/Erlang/misultin/src/misultin_bench.app.src

@@ -1,9 +0,0 @@
-%% -*- erlang -*-
-{application, misultin_bench,
- [{description, ""},
-  {vsn, "0.1"},
-  {modules, []},
-  {registered, []},
-  {mod, {misultin_bench_app, []}},
-  {env, []},
-  {applications, [kernel, stdlib, crypto, erl_bench]}]}.

+ 0 - 16
frameworks/Erlang/misultin/src/misultin_bench_app.erl

@@ -1,16 +0,0 @@
--module(misultin_bench_app).
--behaviour(application).
--export([start/0]).
--export([start/2, stop/1]).
-
-start() ->
-    application:ensure_all_started(misultin_bench).
-
-start(_Type, _StartArgs) ->
-    {ok, Port} = application:get_env(misultin_bench, http_port),
-    Options = [{loop, fun(Req) -> web_handler:dispatch(Req) end},
-               {port, Port}],
-    misultin_bench_sup:start_link(Options).
-
-stop(_State) ->
-    ok.

+ 0 - 18
frameworks/Erlang/misultin/src/misultin_bench_sup.erl

@@ -1,18 +0,0 @@
--module(misultin_bench_sup).
--behaviour(supervisor).
--export([start_link/1]).
--export([init/1]).
-
-start_link(Options) ->
-    supervisor:start_link(?MODULE, [Options]).
-
-init([Options]) ->
-    Misultin = supervisor(misultin, Options),
-    Processes = [Misultin],
-    Strategy = {one_for_one, 5, 30},
-    {ok, {Strategy, Processes}}.
-
-supervisor(Mod, Options) ->
-    {Mod,
-     {Mod, start_link, [Options]},
-     permanent, infinity, supervisor, [Mod]}.

+ 0 - 53
frameworks/Erlang/misultin/src/web_handler.erl

@@ -1,53 +0,0 @@
--module(web_handler).
--export([dispatch/1]).
-
-dispatch(Req) ->
-    Method = Req:get(method),
-    {_UriType, Uri} = Req:get(uri),
-    Path = string:tokens(Uri, "/"),
-    handle(Method, Path, Req).
-
-%% handle
-
-handle('GET', ["json"], Req) ->
-    json(Req, erl_bench:hello_json());
-
-handle('GET', ["plaintext"], Req) ->
-    plain(Req, erl_bench:hello_plain());
-
-handle('GET', ["db"], Req) ->
-    json(Req, erl_bench:random_json());
-
-handle('GET', ["queries"], Req) ->
-    Queries = queries(Req),
-    json(Req, erl_bench:randoms_json(Queries));
-
-handle('GET', ["updates"], Req) ->
-    Queries = queries(Req),
-    json(Req, erl_bench:update_randoms_json(Queries));
-
-handle('GET', ["fortunes"], Req) ->
-    html(Req, erl_bench:fortunes_html());
-
-handle(_Method, _Path, Req) ->
-    Req:respond(404, [{"Content-Type", "text/plain"}], "Not Found").
-
-%% private
-
-json(Req, Json) ->
-    Req:ok([{"Content-Type", "application/json"}], Json).
-
-plain(Req, Text) ->
-    Req:ok([{"Content-Type", "text/plain"}], Text).
-
-html(Req, Html) ->
-    Req:ok([{"Content-Type", "text/html"}], Html).
-
-queries(Req) ->
-    Params = Req:parse_qs(),
-    Queries = (catch list_to_integer(proplists:get_value("queries", Params, "1"))),
-    case {is_number(Queries), Queries > 500} of
-        {true, true} -> 500;
-        {false, _}   -> 1;
-        _ -> Queries
-    end.

Some files were not shown because too many files changed in this diff