Browse Source

Merge remote-tracking branch 'techem/master'

David Moreno 12 years ago
parent
commit
35a15872ff
100 changed files with 4267 additions and 175 deletions
  1. 1 0
      .gitignore
  2. 8 0
      HttpListener/.gitignore
  3. 6 0
      HttpListener/.nuget/NuGet.Config
  4. 133 0
      HttpListener/.nuget/NuGet.targets
  5. 27 0
      HttpListener/HttpListener.sln
  6. 35 0
      HttpListener/HttpListener/App.config
  7. 11 0
      HttpListener/HttpListener/Fortunes.cshtml
  8. 106 0
      HttpListener/HttpListener/Fortunes.generated.cs
  9. 140 0
      HttpListener/HttpListener/HttpListener.csproj
  10. 15 0
      HttpListener/HttpListener/Models/Fortune.cs
  11. 53 0
      HttpListener/HttpListener/Models/MongoDB.cs
  12. 8 0
      HttpListener/HttpListener/Models/World.cs
  13. 403 0
      HttpListener/HttpListener/Program.cs
  14. 36 0
      HttpListener/HttpListener/Properties/AssemblyInfo.cs
  15. 8 0
      HttpListener/HttpListener/packages.config
  16. 5 0
      HttpListener/README.md
  17. 0 0
      HttpListener/__init__.py
  18. 108 0
      HttpListener/benchmark_config
  19. 14 0
      HttpListener/setup.ps1
  20. 22 0
      HttpListener/setup.py
  21. 24 0
      LICENSE
  22. 4 123
      README.md
  23. 6 0
      aspnet-stripped/.gitignore
  24. BIN
      aspnet-stripped/NuGet.exe
  25. 11 0
      aspnet-stripped/README.md
  26. 0 0
      aspnet-stripped/__init__.py
  27. 108 0
      aspnet-stripped/benchmark_config
  28. 22 0
      aspnet-stripped/setup_iis.ps1
  29. 22 0
      aspnet-stripped/setup_iis.py
  30. 32 0
      aspnet-stripped/src/App_Code/Common.cs
  31. 68 0
      aspnet-stripped/src/App_Code/DbHandler.cs
  32. 59 0
      aspnet-stripped/src/App_Code/FortunesPage.cs
  33. 17 0
      aspnet-stripped/src/App_Code/JsonHandler.cs
  34. 15 0
      aspnet-stripped/src/App_Code/Models/Fortune.cs
  35. 53 0
      aspnet-stripped/src/App_Code/Models/MongoDB.cs
  36. 8 0
      aspnet-stripped/src/App_Code/Models/World.cs
  37. 94 0
      aspnet-stripped/src/App_Code/MongoDBHandlers.cs
  38. 50 0
      aspnet-stripped/src/App_Code/MyModule.cs
  39. 18 0
      aspnet-stripped/src/App_Code/NoAspxHandlerFactory.cs
  40. 17 0
      aspnet-stripped/src/App_Code/PlaintextHandler.cs
  41. 88 0
      aspnet-stripped/src/App_Code/UpdatesHandler.cs
  42. 69 0
      aspnet-stripped/src/Web.config
  43. 1 0
      aspnet-stripped/src/fortunes.aspx
  44. 1 0
      aspnet-stripped/src/mongodbfortunes.aspx
  45. 6 0
      aspnet-stripped/src/packages.config
  46. 6 0
      aspnet/.gitignore
  47. 65 0
      aspnet/README.md
  48. 0 0
      aspnet/__init__.py
  49. 367 0
      aspnet/benchmark_config
  50. BIN
      aspnet/lib/.nuget/NuGet.exe
  51. 135 0
      aspnet/lib/.nuget/NuGet.targets
  52. 14 0
      aspnet/lib/packages.config
  53. 26 0
      aspnet/nginx.conf
  54. 21 0
      aspnet/setup_iis.ps1
  55. 22 0
      aspnet/setup_iis.py
  56. 48 0
      aspnet/setup_nginx.py
  57. 34 0
      aspnet/setup_xsp.py
  58. 90 0
      aspnet/src/Application.cs
  59. 164 0
      aspnet/src/Benchmarks.AspNet.csproj
  60. 26 0
      aspnet/src/Benchmarks.sln
  61. 169 0
      aspnet/src/Controllers/AdoController.cs
  62. 68 0
      aspnet/src/Controllers/EntityFrameworkController.cs
  63. 12 0
      aspnet/src/Controllers/HomeController.cs
  64. 68 0
      aspnet/src/Controllers/JsonController.cs
  65. 66 0
      aspnet/src/Controllers/MongoDBController.cs
  66. 12 0
      aspnet/src/Controllers/PlaintextController.cs
  67. 55 0
      aspnet/src/Models/EntityFramework.cs
  68. 15 0
      aspnet/src/Models/Fortune.cs
  69. 53 0
      aspnet/src/Models/MongoDB.cs
  70. 8 0
      aspnet/src/Models/World.cs
  71. 75 0
      aspnet/src/Properties/PublishProfiles/IIS.pubxml
  72. 26 0
      aspnet/src/Views/Fortunes.cshtml
  73. 64 0
      aspnet/src/Views/Index.cshtml
  74. 33 0
      aspnet/src/Views/Web.config
  75. 62 0
      aspnet/src/Web.config
  76. 0 0
      beego/.gitkeep
  77. 18 0
      beego/README.md
  78. 0 0
      beego/__init__.py
  79. 23 0
      beego/benchmark_config
  80. 0 0
      beego/bin/.gitkepp
  81. 0 0
      beego/pkg/.gitkeep
  82. 2 0
      beego/setup.bat
  83. 25 0
      beego/setup.py
  84. 28 0
      beego/src/hello/hello.go
  85. 10 1
      bottle/README.md
  86. 118 31
      bottle/app.py
  87. 77 2
      bottle/benchmark_config
  88. 25 16
      bottle/setup.py
  89. 32 0
      bottle/setup_py3.py
  90. 33 0
      bottle/setup_pypy.py
  91. 13 0
      bottle/views/fortune-obj.tpl
  92. 13 0
      bottle/views/fortune.tpl
  93. 9 0
      bottle/views/layout.tpl
  94. 2 2
      cake/app/Config/database.php
  95. 31 0
      cake/app/Controller/FortunesController.php
  96. 24 0
      cake/app/Controller/PlaintextController.php
  97. 6 0
      cake/app/Model/Fortune.php
  98. 14 0
      cake/app/View/Fortunes/index.ctp
  99. 11 0
      cake/app/View/Layouts/benchmark.ctp
  100. 17 0
      cake/app/webroot/web.config

+ 1 - 0
.gitignore

@@ -15,3 +15,4 @@ mods/
 *.iml
 .idea/
 .hsenv/
+azure.err

+ 8 - 0
HttpListener/.gitignore

@@ -0,0 +1,8 @@
+*.pyc
+*.user
+*.suo
+*/bin/
+*/obj/
+.nuget/NuGet.exe
+packages/
+!packages/repositories.config

+ 6 - 0
HttpListener/.nuget/NuGet.Config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <solution>
+    <add key="disableSourceControlIntegration" value="true" />
+  </solution>
+</configuration>

+ 133 - 0
HttpListener/.nuget/NuGet.targets

@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
+        
+        <!-- Enable the restore command to run before builds -->
+        <RestorePackages Condition="  '$(RestorePackages)' == '' ">false</RestorePackages>
+
+        <!-- Property that enables building a package from a project -->
+        <BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
+
+        <!-- Determines if package restore consent is required to restore packages -->
+        <RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
+        
+        <!-- Download NuGet.exe if it does not already exist -->
+        <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
+    </PropertyGroup>
+    
+    <ItemGroup Condition=" '$(PackageSources)' == '' ">
+        <!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
+        <!-- The official NuGet package source (https://nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
+        <!--
+            <PackageSource Include="https://nuget.org/api/v2/" />
+            <PackageSource Include="https://my-nuget-source/nuget/" />
+        -->
+    </ItemGroup>
+
+    <PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
+        <!-- Windows specific commands -->
+        <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
+        <PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
+    </PropertyGroup>
+    
+    <PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
+        <!-- We need to launch nuget.exe with the mono command if we're not on windows -->
+        <NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
+        <PackagesConfig>packages.config</PackagesConfig>
+    </PropertyGroup>
+    
+    <PropertyGroup>
+        <!-- NuGet command -->
+        <NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath>
+        <PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
+        
+        <NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
+        <NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>
+
+        <PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
+        
+        <RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
+        <NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>
+        
+        <!-- Commands -->
+        <RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)"  $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir "$(SolutionDir) " </RestoreCommand>
+        <BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties Configuration=$(Configuration) $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
+
+        <!-- We need to ensure packages are restored prior to assembly resolve -->
+        <BuildDependsOn Condition="$(RestorePackages) == 'true'">
+            RestorePackages;
+            $(BuildDependsOn);
+        </BuildDependsOn>
+
+        <!-- Make the build depend on restore packages -->
+        <BuildDependsOn Condition="$(BuildPackage) == 'true'">
+            $(BuildDependsOn);
+            BuildPackage;
+        </BuildDependsOn>
+    </PropertyGroup>
+
+    <Target Name="CheckPrerequisites">
+        <!-- Raise an error if we're unable to locate nuget.exe  -->
+        <Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
+        <!--
+        Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
+        This effectively acts as a lock that makes sure that the download operation will only happen once and all
+        parallel builds will have to wait for it to complete.
+        -->
+        <MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
+    </Target>
+
+    <Target Name="_DownloadNuGet">
+        <DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
+    </Target>
+
+    <Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
+        <Exec Command="$(RestoreCommand)"
+              Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
+              
+        <Exec Command="$(RestoreCommand)"
+              LogStandardErrorAsError="true"
+              Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
+    </Target>
+
+    <Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
+        <Exec Command="$(BuildCommand)" 
+              Condition=" '$(OS)' != 'Windows_NT' " />
+              
+        <Exec Command="$(BuildCommand)"
+              LogStandardErrorAsError="true"
+              Condition=" '$(OS)' == 'Windows_NT' " />
+    </Target>
+    
+    <UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
+        <ParameterGroup>
+            <OutputFilename ParameterType="System.String" Required="true" />
+        </ParameterGroup>
+        <Task>
+            <Reference Include="System.Core" />
+            <Using Namespace="System" />
+            <Using Namespace="System.IO" />
+            <Using Namespace="System.Net" />
+            <Using Namespace="Microsoft.Build.Framework" />
+            <Using Namespace="Microsoft.Build.Utilities" />
+            <Code Type="Fragment" Language="cs">
+                <![CDATA[
+                try {
+                    OutputFilename = Path.GetFullPath(OutputFilename);
+
+                    Log.LogMessage("Downloading latest version of NuGet.exe...");
+                    WebClient webClient = new WebClient();
+                    webClient.DownloadFile("https://nuget.org/nuget.exe", OutputFilename);
+
+                    return true;
+                }
+                catch (Exception ex) {
+                    Log.LogErrorFromException(ex);
+                    return false;
+                }
+            ]]>
+            </Code>
+        </Task>
+    </UsingTask>
+</Project>

+ 27 - 0
HttpListener/HttpListener.sln

@@ -0,0 +1,27 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpListener", "HttpListener\HttpListener.csproj", "{C788981C-7F54-4408-B477-C94E486A1AF5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{967712FE-DCC3-412D-A3E4-55F92B833B16}"
+	ProjectSection(SolutionItems) = preProject
+		.nuget\NuGet.Config = .nuget\NuGet.Config
+		.nuget\NuGet.exe = .nuget\NuGet.exe
+		.nuget\NuGet.targets = .nuget\NuGet.targets
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C788981C-7F54-4408-B477-C94E486A1AF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C788981C-7F54-4408-B477-C94E486A1AF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C788981C-7F54-4408-B477-C94E486A1AF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C788981C-7F54-4408-B477-C94E486A1AF5}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 35 - 0
HttpListener/HttpListener/App.config

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <configSections>
+    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+  </configSections>
+  
+  <connectionStrings>
+    <add name="MySQL" connectionString="server=localhost; user id=benchmarkdbuser; password=benchmarkdbpass; database=hello_world" providerName="MySql.Data.MySqlClient" />
+    <add name="PostgreSQL" connectionString="server=localhost; user id=benchmarkdbuser; password=benchmarkdbpass; database=hello_world" providerName="Npgsql" />
+    <add name="MongoDB" connectionString="mongodb://localhost" />
+    <!-- Set max pool size to SQL Server's default max_connections value. In practice, we don't seem to be getting close to the max at all. -->
+    <add name="SQLServer" connectionString="server=localhost; user id=benchmarkdbuser; password=B3nchmarkDBPass; database=hello_world; max pool size=32767" providerName="System.Data.SqlClient" />
+  </connectionStrings>
+
+  <system.data>
+    <DbProviderFactories>
+      <clear />
+      <add name="MySql.Data.MySqlClient" description="Data Provider for MySQL" invariant="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.7.2.0" />
+      <add name="Npgsql" description="Data Provider for PostgreSQL" invariant="Npgsql" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.12.0" />
+      <add name="SqlClient Data Provider" description=".Net Framework Data Provider for SqlServer" invariant="System.Data.SqlClient" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+    </DbProviderFactories>
+  </system.data>
+
+  <appSettings>
+    <!-- To fully saturate the CPUs, we need to allow the .NET thread pool to create many threads
+         when a large burst of requests come in. We do this by boosting the minWorkerThreads value
+         from the default of 1 per logical processor to 8 per logical processor. This seems to be
+         pretty conservative as http://support.microsoft.com/kb/821268 recommends 50.-->
+    <add key="minWorkerThreadsPerLogicalProcessor" value="8" />
+  </appSettings>
+  
+  <startup> 
+    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+  </startup>
+</configuration>

+ 11 - 0
HttpListener/HttpListener/Fortunes.cshtml

@@ -0,0 +1,11 @@
+@* Generator: Template *@@*
+*@@using System.Web;@*
+*@@functions {
+    public IEnumerable<Benchmarks.AspNet.Models.Fortune> Model { get; set; }
+}@*
+*@<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>@*
+*@@foreach (var fortune in Model)
+{
+<tr><td>@fortune.ID</td><td>@HttpUtility.HtmlEncode(fortune.Message)</td></tr>@*
+*@}
+</table></body></html>

+ 106 - 0
HttpListener/HttpListener/Fortunes.generated.cs

@@ -0,0 +1,106 @@
+#pragma warning disable 1591
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.18047
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace HttpListener
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Text;
+    
+    #line 2 "..\..\Fortunes.cshtml"
+    using System.Web;
+    
+    #line default
+    #line hidden
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
+    public partial class Fortunes : RazorGenerator.Templating.RazorTemplateBase
+    {
+#line hidden
+
+        #line 3 "..\..\Fortunes.cshtml"
+
+    public IEnumerable<Benchmarks.AspNet.Models.Fortune> Model { get; set; }
+
+        #line default
+        #line hidden
+
+        public override void Execute()
+        {
+
+
+
+
+
+
+
+
+
+
+WriteLiteral("<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id<" +
+"/th><th>message</th></tr>");
+
+
+
+
+            
+            #line 7 "..\..\Fortunes.cshtml"
+   foreach (var fortune in Model)
+{
+
+            
+            #line default
+            #line hidden
+WriteLiteral("<tr><td>");
+
+
+            
+            #line 9 "..\..\Fortunes.cshtml"
+   Write(fortune.ID);
+
+            
+            #line default
+            #line hidden
+WriteLiteral("</td><td>");
+
+
+            
+            #line 9 "..\..\Fortunes.cshtml"
+                       Write(HttpUtility.HtmlEncode(fortune.Message));
+
+            
+            #line default
+            #line hidden
+WriteLiteral("</td></tr>");
+
+
+            
+            #line 9 "..\..\Fortunes.cshtml"
+                                                                              
+            
+            #line default
+            #line hidden
+
+            
+            #line 10 "..\..\Fortunes.cshtml"
+  }
+
+            
+            #line default
+            #line hidden
+WriteLiteral("</table></body></html>");
+
+
+        }
+    }
+}
+#pragma warning restore 1591

+ 140 - 0
HttpListener/HttpListener/HttpListener.csproj

@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{C788981C-7F54-4408-B477-C94E486A1AF5}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HttpListener</RootNamespace>
+    <AssemblyName>HttpListener</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+    <RestorePackages>true</RestorePackages>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="EntityFramework">
+      <HintPath>..\packages\EntityFramework.6.0.0-beta1\lib\net45\EntityFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework.SqlServer">
+      <HintPath>..\packages\EntityFramework.6.0.0-beta1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+    </Reference>
+    <Reference Include="MongoDB.Bson">
+      <HintPath>..\packages\mongocsharpdriver.1.8.1\lib\net35\MongoDB.Bson.dll</HintPath>
+    </Reference>
+    <Reference Include="MongoDB.Driver">
+      <HintPath>..\packages\mongocsharpdriver.1.8.1\lib\net35\MongoDB.Driver.dll</HintPath>
+    </Reference>
+    <Reference Include="Mono.Security">
+      <HintPath>..\packages\Npgsql.EF6.2.0.12-pre4\lib\net45\Mono.Security.dll</HintPath>
+    </Reference>
+    <Reference Include="Mono.Security.Protocol.Tls">
+      <HintPath>..\packages\Npgsql.EF6.2.0.12-pre4\lib\net45\Mono.Security.Protocol.Tls.dll</HintPath>
+    </Reference>
+    <Reference Include="MySql.Data">
+      <HintPath>..\packages\MySql.Data.Entity.6.7.2-beta-ef6\lib\net45\MySql.Data.dll</HintPath>
+    </Reference>
+    <Reference Include="MySql.Data.Entity">
+      <HintPath>..\packages\MySql.Data.Entity.6.7.2-beta-ef6\lib\net45\MySql.Data.Entity.dll</HintPath>
+    </Reference>
+    <Reference Include="Npgsql">
+      <HintPath>..\packages\Npgsql.EF6.2.0.12-pre4\lib\net45\Npgsql.dll</HintPath>
+    </Reference>
+    <Reference Include="RazorGenerator.Templating">
+      <HintPath>..\packages\RazorGenerator.Templating.2.1.1\lib\net40\RazorGenerator.Templating.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Web.Extensions" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Fortunes.generated.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Fortunes.cshtml</DependentUpon>
+    </Compile>
+    <Compile Include="Models\Fortune.cs" />
+    <Compile Include="Models\MongoDB.cs" />
+    <Compile Include="Models\World.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="Fortunes.cshtml">
+      <Generator>RazorGenerator</Generator>
+      <LastGenOutput>Fortunes.generated.cs</LastGenOutput>
+    </None>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.5">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 15 - 0
HttpListener/HttpListener/Models/Fortune.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace Benchmarks.AspNet.Models
+{
+    public class Fortune : IComparable<Fortune>
+    {
+        public int ID { get; set; }
+        public string Message { get; set; }
+
+        public int CompareTo(Fortune other)
+        {
+            return Message.CompareTo(other.Message);
+        }
+    }
+}

+ 53 - 0
HttpListener/HttpListener/Models/MongoDB.cs

@@ -0,0 +1,53 @@
+using System.Configuration;
+using System.Web.Script.Serialization;
+
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver;
+
+namespace Benchmarks.AspNet.Models
+{
+    public class MongoDB
+    {
+        public MongoCollection<MongoWorld> Worlds { get; private set; }
+        public MongoCollection<Fortune> Fortunes { get; private set; }
+
+        static MongoDB()
+        {
+            BsonClassMap.RegisterClassMap<World>(m =>
+            {
+                m.MapProperty(w => w.id);
+                m.MapProperty(w => w.randomNumber);
+            });
+
+            BsonClassMap.RegisterClassMap<MongoWorld>(m =>
+            {
+                m.MapIdProperty(w => w._id);
+            });
+
+            BsonClassMap.RegisterClassMap<Fortune>(m =>
+            {
+                m.MapProperty(f => f.ID).SetElementName("id");
+                m.MapProperty(f => f.Message).SetElementName("message");
+            });
+        }
+
+        public MongoDB(string connectionStringName)
+        {
+            string connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
+
+            MongoClient client = new MongoClient(connectionString);
+            MongoServer server = client.GetServer();
+            MongoDatabase database = server.GetDatabase("hello_world");
+
+            Worlds = database.GetCollection<MongoWorld>("world");
+            Fortunes = database.GetCollection<Fortune>("fortune");
+        }
+    }
+
+    public class MongoWorld : World
+    {
+        [ScriptIgnore]
+        public ObjectId _id { get; set; }
+    }
+}

+ 8 - 0
HttpListener/HttpListener/Models/World.cs

@@ -0,0 +1,8 @@
+namespace Benchmarks.AspNet.Models
+{
+    public class World
+    {
+        public int id { get; set; }
+        public int randomNumber { get; set; }
+    }
+}

+ 403 - 0
HttpListener/HttpListener/Program.cs

@@ -0,0 +1,403 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Configuration;
+using System.Data;
+using System.Data.Common;
+using System.Linq;
+using System.Net;
+using System.Threading;
+using System.Web.Script.Serialization;
+
+using MongoDB.Driver.Builders;
+
+using Benchmarks.AspNet.Models;
+
+namespace HttpListener
+{
+    class Program
+    {
+        private static void RequestCallback(Object state)
+        {
+            HttpListenerContext context = (HttpListenerContext)state;
+            HttpListenerRequest request = context.Request;
+            HttpListenerResponse response = context.Response;
+
+            try
+            {
+                string responseString = null;
+                switch (request.Url.LocalPath)
+                {
+                    case "/plaintext":
+                        responseString = Plaintext(response);
+                        break;
+                    case "/json":
+                        responseString = Json(response);
+                        break;
+                    case "/db":
+                        responseString = Db(request, response);
+                        break;
+                    case "/fortunes":
+                        responseString = Fortunes(request, response);
+                        break;
+                    case "/updates":
+                        responseString = Updates(request, response);
+                        break;
+                    case "/mongodbdb":
+                        responseString = MongoDBDb(request, response);
+                        break;
+                    case "/mongodbfortunes":
+                        responseString = MongoDBFortunes(request, response);
+                        break;
+                    case "/mongodbupdates":
+                        responseString = MongoDBUpdates(request, response);
+                        break;
+                    default:
+                        responseString = NotFound(response);
+                        break;
+                }
+                WriteResponse(response, responseString);
+            }
+            finally
+            {
+                response.Close();
+            }
+        }
+
+        private static void WriteResponse(HttpListenerResponse response, String responseString)
+        {
+            response.ContentType = response.ContentType + "; charset=utf-8";
+            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
+            response.ContentLength64 = buffer.Length;
+            try
+            {
+                response.OutputStream.Write(buffer, 0, buffer.Length);
+            }
+            catch (Win32Exception)
+            {
+                // Ignore I/O errors
+            }
+        }
+
+        private static void Threads()
+        {
+            // To improve CPU utilization, increase the number of threads that the .NET thread pool expands by when
+            // a burst of requests come in. We could do this by editing machine.config/system.web/processModel/minWorkerThreads,
+            // but that seems too global a change, so we do it in code for just our AppPool. More info:
+            //
+            // http://support.microsoft.com/kb/821268
+            // http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx
+            // http://blogs.msdn.com/b/perfworld/archive/2010/01/13/how-can-i-improve-the-performance-of-asp-net-by-adjusting-the-clr-thread-throttling-properties.aspx
+
+            int newMinWorkerThreads = Convert.ToInt32(ConfigurationManager.AppSettings["minWorkerThreadsPerLogicalProcessor"]);
+            if (newMinWorkerThreads > 0)
+            {
+                int minWorkerThreads, minCompletionPortThreads;
+                ThreadPool.GetMinThreads(out minWorkerThreads, out minCompletionPortThreads);
+                ThreadPool.SetMinThreads(Environment.ProcessorCount * newMinWorkerThreads, minCompletionPortThreads);
+            }
+        }
+
+        static void Main(string[] args)
+        {
+            Threads();
+
+            System.Net.HttpListener listener = new System.Net.HttpListener();
+            // This doesn't seem to ignore all write exceptions, so in WriteResponse(), we still have a catch block.
+            listener.IgnoreWriteExceptions = true;
+            listener.Prefixes.Add("http://*:8080/");
+
+            try
+            {
+                listener.Start();
+
+                for (;;)
+                {
+                    HttpListenerContext context = null;
+                    try
+                    {
+                        context = listener.GetContext();
+
+                        ThreadPool.QueueUserWorkItem(new WaitCallback(RequestCallback), context);
+                        context = null; // ownership has been transferred to RequestCallback
+                    }
+                    catch (HttpListenerException ex)
+                    {
+                        Console.WriteLine(ex.Message);
+                    }
+                    finally
+                    {
+                        if (context != null)
+                            context.Response.Close();
+                    }
+                }
+            }
+            catch (HttpListenerException ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+            finally
+            {
+                // Stop listening for requests.
+                listener.Close();
+                Console.WriteLine("Done Listening.");
+            }
+        }
+
+        public static DbConnection CreateConnection(HttpListenerRequest request)
+        {
+            string providerName = request.QueryString["provider"];
+            if (providerName == null)
+            {
+                throw new ApplicationException("Missing provider querystring argument");
+            }
+            ConnectionStringSettings connectionSettings = ConfigurationManager.ConnectionStrings[providerName];
+            DbProviderFactory factory = DbProviderFactories.GetFactory(connectionSettings.ProviderName);
+            DbConnection connection = factory.CreateConnection();
+            connection.ConnectionString = connectionSettings.ConnectionString;
+            return connection;
+        }
+
+        public static int GetQueries(HttpListenerRequest request)
+        {
+            int queries = 1;
+            string queriesString = request.QueryString["queries"];
+            if (queriesString != null)
+            {
+                // If this fails to parse, queries will be set to zero.
+                int.TryParse(queriesString, out queries);
+                queries = Math.Max(1, Math.Min(500, queries));
+            }
+            return queries;
+        }
+
+        private static string NotFound(HttpListenerResponse response)
+        {
+            response.StatusCode = (int)HttpStatusCode.NotFound;
+            response.ContentType = "text/plain";
+            return "not found";
+        }
+
+        private static string Plaintext(HttpListenerResponse response)
+        {
+            response.ContentType = "text/plain";
+            return "Hello, World!";
+        }
+
+        private static string Json(HttpListenerResponse response)
+        {
+            response.ContentType = "application/json";
+            return new JavaScriptSerializer().Serialize(new { message = "Hello, World!" });
+        }
+
+        private static string Db(HttpListenerRequest request, HttpListenerResponse response)
+        {
+            Random random = new Random();
+
+            int queries = GetQueries(request);
+            List<World> worlds = new List<World>(queries);
+
+            using (DbConnection connection = CreateConnection(request))
+            {
+                connection.Open();
+
+                using (DbCommand command = connection.CreateCommand())
+                {
+                    command.CommandText = "SELECT * FROM World WHERE id = @ID";
+
+                    DbParameter parameter = command.CreateParameter();
+                    parameter.ParameterName = "@ID";
+
+                    command.Parameters.Add(parameter);
+
+                    for (int i = 0; i < worlds.Capacity; i++)
+                    {
+                        int randomID = random.Next(0, 10000) + 1;
+
+                        parameter.Value = randomID;
+
+                        // Don't use CommandBehavior.SingleRow because that will make the MySql provider
+                        // send two extra commands to limit the result to one row.
+                        using (DbDataReader reader = command.ExecuteReader())
+                        {
+                            if (reader.Read())
+                            {
+                                worlds.Add(new World
+                                {
+                                    id = reader.GetInt32(0),
+                                    randomNumber = reader.GetInt32(1)
+                                });
+                            }
+                        }
+                    }
+                }
+            }
+
+            response.ContentType = "application/json";
+            return new JavaScriptSerializer().Serialize(
+                worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]);
+        }
+
+        private static string Fortunes(HttpListenerRequest request, HttpListenerResponse response)
+        {
+            List<Fortune> fortunes = new List<Fortune>();
+
+            using (DbConnection connection = CreateConnection(request))
+            {
+                connection.Open();
+
+                using (DbCommand command = connection.CreateCommand())
+                {
+                    command.CommandText = "SELECT * FROM Fortune";
+
+                    using (DbDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
+                    {
+                        while (reader.Read())
+                        {
+                            fortunes.Add(new Fortune
+                            {
+                                ID = reader.GetInt32(0),
+                                Message = reader.GetString(1)
+                            });
+                        }
+                    }
+                }
+            }
+
+            fortunes.Add(new Fortune { ID = 0, Message = "Additional fortune added at request time." });
+            fortunes.Sort();
+
+            response.ContentType = "text/html";
+            var template = new Fortunes { Model = fortunes };
+            return template.TransformText();
+        }
+
+        private static string Updates(HttpListenerRequest request, HttpListenerResponse response)
+        {
+            Random random = new Random();
+            List<World> worlds = new List<World>(GetQueries(request));
+
+            using (DbConnection connection = CreateConnection(request))
+            {
+                connection.Open();
+
+                using (DbCommand selectCommand = connection.CreateCommand(),
+                                 updateCommand = connection.CreateCommand())
+                {
+                    selectCommand.CommandText = "SELECT * FROM World WHERE id = @ID";
+                    updateCommand.CommandText = "UPDATE World SET randomNumber = @Number WHERE id = @ID";
+
+                    for (int i = 0; i < worlds.Capacity; i++)
+                    {
+                        int randomID = random.Next(0, 10000) + 1;
+                        int randomNumber = random.Next(0, 10000) + 1;
+
+                        DbParameter idParameter = selectCommand.CreateParameter();
+                        idParameter.ParameterName = "@ID";
+                        idParameter.Value = randomID;
+
+                        selectCommand.Parameters.Clear();
+                        selectCommand.Parameters.Add(idParameter);
+
+                        World world = null;
+
+                        // Don't use CommandBehavior.SingleRow because that will make the MySql provider
+                        // send two extra commands to limit the result to one row.
+                        using (DbDataReader reader = selectCommand.ExecuteReader())
+                        {
+                            if (reader.Read())
+                            {
+                                world = new World
+                                {
+                                    id = reader.GetInt32(0),
+                                    randomNumber = reader.GetInt32(1)
+                                };
+                            }
+                        }
+
+                        DbParameter idUpdateParameter = updateCommand.CreateParameter();
+                        idUpdateParameter.ParameterName = "@ID";
+                        idUpdateParameter.Value = randomID;
+
+                        DbParameter numberParameter = updateCommand.CreateParameter();
+                        numberParameter.ParameterName = "@Number";
+                        numberParameter.Value = randomNumber;
+
+                        updateCommand.Parameters.Clear();
+                        updateCommand.Parameters.Add(idUpdateParameter);
+                        updateCommand.Parameters.Add(numberParameter);
+
+                        updateCommand.ExecuteNonQuery();
+
+                        world.randomNumber = randomNumber;
+                        worlds.Add(world);
+                    }
+                }
+            }
+
+            response.ContentType = "application/json";
+            return new JavaScriptSerializer().Serialize(
+                worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]);
+        }
+
+        private static string MongoDBDb(HttpListenerRequest request, HttpListenerResponse response)
+        {
+            Random random = new Random();
+
+            int queries = GetQueries(request);
+            List<World> worlds = new List<World>(queries);
+
+            Benchmarks.AspNet.Models.MongoDB db = new Benchmarks.AspNet.Models.MongoDB("MongoDB");
+
+            for (int i = 0; i < worlds.Capacity; i++)
+            {
+                int randomID = random.Next(0, 10000) + 1;
+                worlds.Add(db.Worlds.FindOne(Query<World>.EQ(w => w.id, randomID)));
+            }
+
+            response.ContentType = "application/json";
+            return new JavaScriptSerializer().Serialize(
+                worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]);
+        }
+
+        private static string MongoDBFortunes(HttpListenerRequest request, HttpListenerResponse response)
+        {
+            Benchmarks.AspNet.Models.MongoDB db = new Benchmarks.AspNet.Models.MongoDB("MongoDB");
+
+            List<Fortune> fortunes = db.Fortunes.FindAll().ToList();
+
+            fortunes.Add(new Fortune { ID = 0, Message = "Additional fortune added at request time." });
+            fortunes.Sort();
+
+            response.ContentType = "text/html";
+            var template = new Fortunes { Model = fortunes };
+            return template.TransformText();
+        }
+
+        private static string MongoDBUpdates(HttpListenerRequest request, HttpListenerResponse response)
+        {
+            Random random = new Random();
+
+            Benchmarks.AspNet.Models.MongoDB db = new Benchmarks.AspNet.Models.MongoDB("MongoDB");
+
+            int queries = GetQueries(request);
+            List<World> worlds = new List<World>(queries);
+
+            for (int i = 0; i < worlds.Capacity; i++)
+            {
+                int randomID = random.Next(0, 10000) + 1;
+                int randomNumber = random.Next(0, 10000) + 1;
+
+                World world = db.Worlds.FindOne(Query<World>.EQ(w => w.id, randomID));
+                world.randomNumber = randomNumber;
+                worlds.Add(world);
+
+                db.Worlds.Save(world);
+            }
+
+            response.ContentType = "application/json";
+            return new JavaScriptSerializer().Serialize(
+                worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]);
+        }
+    }
+}

+ 36 - 0
HttpListener/HttpListener/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HttpListener")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HttpListener")]
+[assembly: AssemblyCopyright("Copyright ©  2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ac13325e-f037-4665-89ed-2de2c30e22c7")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 8 - 0
HttpListener/HttpListener/packages.config

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="EntityFramework" version="6.0.0-beta1" targetFramework="net45" />
+  <package id="mongocsharpdriver" version="1.8.1" targetFramework="net45" />
+  <package id="MySql.Data.Entity" version="6.7.2-beta-ef6" targetFramework="net45" />
+  <package id="Npgsql.EF6" version="2.0.12-pre4" targetFramework="net45" />
+  <package id="RazorGenerator.Templating" version="2.1.1" targetFramework="net45" />
+</packages>

+ 5 - 0
HttpListener/README.md

@@ -0,0 +1,5 @@
+This uses [.NET's HttpListener class](http://msdn.microsoft.com/en-us/library/system.net.httplistener.aspx) which is somewhat similar to Go's net/http package or node.js's built-in HTTP server. HttpListener is a .NET Framework wrapper around [HTTP.SYS](http://www.iis.net/learn/get-started/introduction-to-iis/introduction-to-iis-architecture#Hypertext), the kernel-mode HTTP driver that is used by IIS.
+
+These tests are based on [aspnet](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/aspnet) by [@pdonald](https://github.com/pdonald/).
+
+By using .NET's HttpListener class, we eliminate the overhead of IIS and ASP.NET. This does not use ASP.NET WebForms (.aspx), but instead uses Razor (.cshtml), with the the template parsed at design-time into C# by RazorGenerator.

+ 0 - 0
django-stripped/__init__.py → HttpListener/__init__.py


+ 108 - 0
HttpListener/benchmark_config

@@ -0,0 +1,108 @@
+{
+  "framework": "HttpListener",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "http-listener",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "http-listener",
+      "notes": "",
+      "versus": ""
+    },
+    "mysql-raw": {
+      "setup_file": "setup",
+      "db_url": "/db?provider=mysql",
+      "query_url": "/db?provider=mysql&queries=",
+      "fortune_url": "/fortunes?provider=mysql",
+      "update_url": "/updates?provider=mysql&queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "http-listener",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "http-listener",
+      "notes": "",
+      "versus": "http-listener"
+    },
+    "postgresql-raw": {
+      "setup_file": "setup",
+      "db_url": "/db?provider=postgresql",
+      "query_url": "/db?provider=postgresql&queries=",
+      "fortune_url": "/fortunes?provider=postgresql",
+      "update_url": "/updates?provider=postgresql&queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgres",
+      "framework": "http-listener",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "http-listener",
+      "notes": "",
+      "versus": "http-listener"
+    },
+    "mongodb-raw": {
+      "setup_file": "setup",
+      "db_url": "/mongodbdb",
+      "query_url": "/mongodbdb?queries=",
+      "fortune_url": "/mongodbfortunes",
+      "update_url": "/mongodbupdates?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MongoDB",
+      "framework": "http-listener",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "http-listener",
+      "notes": "",
+      "versus": "http-listener"
+    },
+    "sqlserver-raw": {
+      "setup_file": "setup",
+      "db_url": "/db?provider=sqlserver",
+      "query_url": "/db?provider=sqlserver&queries=",
+      "fortune_url": "/fortunes?provider=sqlserver",
+      "update_url": "/updates?provider=sqlserver&queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "SQLServer",
+      "framework": "http-listener",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Windows",
+      "display_name": "http-listener",
+      "notes": "",
+      "versus": "http-listener"
+    }
+  }]
+}

+ 14 - 0
HttpListener/setup.ps1

@@ -0,0 +1,14 @@
+param($action)
+
+$root = "C:\FrameworkBenchmarks\HttpListener"
+$msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
+
+# Stop
+Stop-Process -Name HttpListener -ErrorAction SilentlyContinue
+
+if ($action -eq 'start') {
+    # Build the project
+    &$msbuild "$root\HttpListener.sln" /p:DownloadNuGetExe=true /p:RequireRestoreConsent=false /p:Configuration=Release /t:Rebuild
+    
+    Start-Process "$root\HttpListener\bin\Release\HttpListener.exe"
+}

+ 22 - 0
HttpListener/setup.py

@@ -0,0 +1,22 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args):
+  if os.name != 'nt':
+    return 1
+  
+  try:
+    setup_util.replace_text("HttpListener/HttpListener/App.config", "localhost", args.database_host)
+    subprocess.check_call("powershell -File setup.ps1 start", cwd="HttpListener")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop():
+  if os.name != 'nt':
+    return 0
+  
+  subprocess.Popen("powershell -File setup.ps1 stop", cwd="HttpListener")
+  return 0

+ 24 - 0
LICENSE

@@ -0,0 +1,24 @@
+Copyright (c) 2013, TechEmpower, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the TechEmpower, Inc. nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL TECHEMPOWER, INC. BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 4 - 123
README.md

@@ -1,6 +1,6 @@
 # Web Framework Performance Comparison
 
-This project is an attempt to provide representative and objective performance measures across a wide field of web application frameworks. With much help from the community, we now have very broad coverage and are happy to broaden it further with contributions. The project presently includes frameworks on many languages including Go, Python, Java, Ruby, PHP, Clojure, Groovy, JavaScript, Erlang, Haskell, Scala, Lua, and C.  The current tests exercise the frameworks' JSON seralization and object-relational model (ORM).  Future tests will exercise server-side template libraries and other computation.
+This project provides representative performance measures across a wide field of web application frameworks. With much help from the community, coverage is quite broad and we are happy to broaden it further with contributions. The project presently includes frameworks on many languages including Go, Python, Java, Ruby, PHP, Clojure, Groovy, JavaScript, Erlang, Haskell, Scala, Lua, and C.  The current tests exercise plaintext responses, JSON seralization, database reads and writes via the object-relational mapper (ORM), collections, sorting, server-side templates, and XSS counter-measures.  Future tests will exercise other components and greater computation.
 
 Read more and see the results of our tests on Amazon EC2 and physical hardware at http://www.techempower.com/benchmarks/
 
@@ -8,128 +8,9 @@ Join in the conversation at our Google Group: https://groups.google.com/forum/?f
 
 ## Running the test suite
 
-We ran our tests using two dedicated i7 2600k machines as well as two EC2 m1.large instances. Below you will find instructions on how to replicate our tests using either EC2 or your own dedicated machines.
+We ran our tests using two dedicated i7 2600k machines as well as two EC2 m1.large instances.
 
-###EC2 Instructions
-
-#### 1. Create EC2 Instances
-
-Create two EC2 instances running Ubuntu Server 12.04.1 LTS 64-bit. We tested on m1.large instances, but feel free to experiment with different configurations. Give the instance that will act as the application server more then the default 8GB of disk capacity (we used 20GB).
-
-##### Security Group
-
-When propmted to create a security group for the instances, here are the ports that you'll need to open.
-
-* 22 (SSH)
-* 8080 (Most of the tests run on 8080)
-* 3306 (MySQL)
-* 5432 (PostgreSQL)
-* 9000 (Play Framework)
-* 27017 (MongoDB)
-* 3000 (yesod)
-* 8000 (snap)
-
-
-#### 2. Setting up the servers
-
-To coordinate the tests via scripting, the servers need to be able to work together. So once the instances are running, the first thing you'll want to do is copy your ssh key to the application server instance so that you can ssh between the two machines:
-
-	sftp -i path-to-pem-file ubuntu@server-instance-ip
-	put path-to-pem-file .ssh/
-	exit
-
-Now ssh into the server instance and clone the latest from this repository (the scripts we use to run the tests expect that you'll clone the repository into your home directory):
-
-	ssh -i path-to-pem-file ubuntu@server-instance-ip
-	yes | sudo apt-get install git-core
-	git clone https://github.com/TechEmpower/FrameworkBenchmarks.git
-	cd FrameworkBenchmarks
-
-Next, we're going to setup the servers with all the necessary software:
-
-	./run-tests.py -s server-private-ip -c client-private-ip -i path-to-pem --install-software --list-tests
-    source ~/.bash_profile
-    # For your first time through the tests, set the ulimit for open files
-    ulimit -n 8192
-    # Most software is installed autormatically by the script, but running the mongo command below from 
-    # the install script was causing some errors. For now this needs to be run manually.
-    cd installs/jruby-rack && rvm jruby-1.7.3 do jruby -S bundle exec rake clean gem SKIP_SPECS=true
-    cd target && rvm jruby-1.7.3 do gem install jruby-rack-1.2.0.SNAPSHOT.gem
-    cd ../../..
-    cd installs && curl -sS https://getcomposer.org/installer | php -- --install-dir=bin
-    cd ..
-    sudo apt-get remove --purge openjdk-6-jre openjdk-6-jre-headless
-	  mongo --host client-private-ip < config/create.js
-
-Assuming the above finished without error, we're ready to start the test suite:
-
-	nohup ./run-tests.py -s server-private-ip -c client-private-ip -i path-to-pem --max-threads number-of-cores &
-
-For the number-of-cores parameter, you will need to know your application server's core count. For example, Amazon EC2 large instances have 2 cores.
-
-This script will run the full set of tests. Results of all the tests will output to ~/FrameworkBenchmarks/results/ec2/*timestamp*. If you use a different configuration than two m1.large instances, please use the --name option to name the results appropriately.
-
-	nohup ./run-tests.py -s server-private-ip -c client-private-ip -i path-to-pem --max-threads cores --name ec2-servertype-clienttype &
-
-So if you were running an m1.large and an m1.medium, it would look like this:
-
-	nohup ./run-tests.py -s server-private-ip -c client-private-ip -i path-to-pem --max-threads cores --name ec2-m1.large-m1.medium &
-
-This will allow us to differentiate results.
-
-Be aware that on Large instances, if you include the slower frameworks (and they are included by default), the total runtime of a full suite of tests can be measured in days, not just hours. The EC2 bill isn't going to break the bank, but it's also not going to be chump change.
-
-### Dedicated Hardware Instructions
-
-If you have two servers or workstations lying around, then you can install and run the tests on physical hardware. Please be aware that these setup instructions can overwrite software and settings, It's best to follow these instructions on clean hardware. We assume that both machines are running Ubuntu Server 12.04 64-bit.
-
-#### 1. Prerequisites
-
-Before you get started, there are a couple of steps you can take to make running the tests easier on yourself. Since the tests can run for several hours, it helps to set everything up so that once the tests are running, you can leave the machines unattended and don't need to be around to enter ssh or sudo passwords.
-
-1. Setup an ssh key for the client machine
-2. Edit your sudoers file so that you do not need to enter your password for sudo access
-
-#### 2. Setting up the servers
-
-As it currently stands, the script that runs the tests makes some assumptions about where the code is placed, we assume that the FrameworkBenchmarks repository will be located in your home directory.
-
-Check out the latest from github:
-
-	cd ~
-	git clone https://github.com/TechEmpower/FrameworkBenchmarks.git
-	cd FrameworkBenchmarks
-
-Next, we're going to setup the servers with all the necessary software:
-
-	./run-tests.py -s server-ip -c client-ip -i path-to-ssh-key --install-software --list-tests
-    source ~/.bash_profile
-    # For your first time through the tests, set the ulimit for open files
-    # Most software is installed autormatically by the script, but running the mongo command below from
-    # the install script was causing some errors. For now this needs to be run manually.
-    cd installs/jruby-rack && rvm jruby-1.7.3 do jruby -S bundle exec rake clean gem SKIP_SPECS=true
-    cd target && rvm jruby-1.7.3 do gem install jruby-rack-1.2.0.SNAPSHOT.gem
-    cd ../../..
-    cd installs && curl -sS https://getcomposer.org/installer | php -- --install-dir=bin
-    cd ..
-    sudo apt-get remove --purge openjdk-6-jre openjdk-6-jre-headless
-    mongo --host client-ip < config/create.js
-
-Assuming this finished without error, we're ready to start the test suite:
-
-	nohup ./run-tests.py -s server-ip -c client-ip -i path-to-ssh-key --max-threads cores --name unique-machine-name &
-
-This will run the full set of tests. Results of all the tests will output to ~/FrameworkBenchmarks/results/unique-machine-name/*timestamp*.
-
-## Result Files
-
-After a test run, the directory ~/FrameworkBenchmarks/results/machine-name/timestamp will contains all the result files. In this folder are four files: three CSV files, one for each of the test types (json, db, query), and a single results.json file that contains all the results as well as some additional information. The results.json file is what we use to drive our blog post, and may or may not be useful to you. There are three subdirectories: one for each of the test types (json, db, query), each of these directories contain the raw weighttp results for each framework.
-
-## Benchmarking a Single Test
-
-If you are making changes to any of the tests, or you simply want to verify a single test, you can run the script with the --test flag. For example, if you only wanted to run the JRuby tests:
-
-	nohup ./run-tests.py -s server-ip -c client-ip -i path-to-ssh-key --max-threads cores --name unique-machine-name --test rack-jruby sinatra-jruby rails-jruby
+On the [Benchmark Tools README file](toolset/README.md) you will find tools and instructions to replicate our tests using EC2, Windows Azure or your own dedicated machines.
 
 ## Updating Tests
 
@@ -145,7 +26,7 @@ Also, if you do change the dependency of any test, please update the README file
 
 If you would like to update any of the software used, again, please be as specific as possible, while we still install some software via apt-get and don't specify a version, we would like to have as much control over the versions as possible.
 
-The main file that installs all the software is in installer.py. It's broken up into two sections, server software and client software.
+The main file that installs all the software is in `toolset/setup/linux/installer.py`. It's broken up into two sections, server software and client software.
 
 Additionally, it may be necessary to update the setup.py file in the framework's directory to use this new version.
 

+ 6 - 0
aspnet-stripped/.gitignore

@@ -0,0 +1,6 @@
+*.user
+*.suo
+*/bin/*
+*/obj/*
+lib/*
+!lib/.nuget

BIN
aspnet-stripped/NuGet.exe


+ 11 - 0
aspnet-stripped/README.md

@@ -0,0 +1,11 @@
+This is a heavily stripped-down version of [pdonald](https://github.com/pdonald/)'s aspnet tests.
+Right now this is designed to run on Windows.
+
+For CPU-bound tests such as db, json, fortunes, and plaintext, this is approximately twice as fast as the non-stripped aspnet tests. The performance is obtained by using ASP.NET IHttpHandlers, old-style .aspx files (when HTML is output) and removing unnecessary IIS/ASP.NET modules, especially ones related to URL routing and especially ones written in .NET.
+
+To replace ASP.NET's URL routing, we directly specify the path to IHttpHandlers in web.config. The idea is that native code in IIS probably (definitely?) does the routing for handlers specified this way, so the routing should be extremely fast, as opposed to ASP.NET's System.Web.Routing code that is extremely configurable. To route to an .aspx page, we use NoAspxHandlerFactory, a small piece of 'middleware' that can directly route from this web.config setting to a .aspx file.
+
+This is stripped down so much that I'm not sure if anyone would actually want to use these techniques in production. The point of this is the following:
+
+1. To provide a better comparison against microframeworks/microplatforms that barely do anything.
+2. To give us a sense of the upperbound of performance for more realistic tests.

+ 0 - 0
django-stripped/hello/hello/__init__.py → aspnet-stripped/__init__.py


+ 108 - 0
aspnet-stripped/benchmark_config

@@ -0,0 +1,108 @@
+{
+  "framework": "aspnet-stripped",
+  "tests": [{
+    "default": {
+      "setup_file": "setup_iis",
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Fullstack",
+      "database": "None",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-stripped",
+      "notes": "",
+      "versus": ""
+    },
+    "mysql-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/db?provider=mysql",
+      "query_url": "/db?provider=mysql&queries=",
+      "fortune_url": "/fortunes?provider=mysql",
+      "update_url": "/updates?provider=mysql&queries=",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-stripped-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "postgresql-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/db?provider=postgresql",
+      "query_url": "/db?provider=postgresql&queries=",
+      "fortune_url": "/fortunes?provider=postgresql",
+      "update_url": "/updates?provider=postgresql&queries=",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-stripped-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "mongodb-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/mongodbdb",
+      "query_url": "/mongodbdb?queries=",
+      "fortune_url": "/mongodbfortunes",
+      "update_url": "/mongodbupdates?queries=",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Fullstack",
+      "database": "MongoDB",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-stripped-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "sqlserver-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/db?provider=sqlserver",
+      "query_url": "/db?provider=sqlserver&queries=",
+      "fortune_url": "/fortunes?provider=sqlserver",
+      "update_url": "/updates?provider=sqlserver&queries=",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Fullstack",
+      "database": "SQLServer",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Windows",
+      "display_name": "aspnet-stripped-raw",
+      "notes": "",
+      "versus": ""
+    }
+  }]
+}

+ 22 - 0
aspnet-stripped/setup_iis.ps1

@@ -0,0 +1,22 @@
+param($action)
+
+$source = "C:\FrameworkBenchmarks\aspnet-stripped\src"
+
+# Stop
+if (Get-WebSite -Name Benchmarks) { Remove-WebSite -Name Benchmarks }
+
+if ($action -eq 'start') {
+    # Because we don't use msbuild to compile the code, we do this all manually.
+    
+    & .\NuGet.exe install -o src\packages src\packages.config
+
+    if (-Not (Test-Path src\bin)) { New-Item -Path src\bin -ItemType directory | Out-Null }
+
+    $dlls = Get-ChildItem -path src\packages -recurse -include *.dll
+    foreach ($dll in $dlls) {
+        Copy-Item $dll src\bin
+    }
+
+    # Create a website in IIS
+    New-WebSite -Name Benchmarks -Port 8080 -PhysicalPath $source
+}

+ 22 - 0
aspnet-stripped/setup_iis.py

@@ -0,0 +1,22 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args):
+  if os.name != 'nt':
+    return 1
+  
+  try:
+    setup_util.replace_text("aspnet-stripped/src/Web.config", "localhost", args.database_host)
+    subprocess.check_call("powershell -File setup_iis.ps1 start", cwd="aspnet-stripped")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop():
+  if os.name != 'nt':
+    return 0
+  
+  subprocess.Popen("powershell -File setup_iis.ps1 stop", cwd="aspnet-stripped")
+  return 0

+ 32 - 0
aspnet-stripped/src/App_Code/Common.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Configuration;
+using System.Data;
+using System.Data.Common;
+using System.Web;
+
+public class Common
+{
+    public static DbConnection CreateConnection(HttpRequest request)
+    {
+        string providerName = request.QueryString["provider"];
+        if (providerName == null) {
+            throw new ApplicationException("Missing provider querystring argument");
+        }
+        ConnectionStringSettings connectionSettings = ConfigurationManager.ConnectionStrings[providerName];
+        DbProviderFactory factory = DbProviderFactories.GetFactory(connectionSettings.ProviderName);
+        DbConnection connection = factory.CreateConnection();
+        connection.ConnectionString = connectionSettings.ConnectionString;
+        return connection;
+    }
+
+    public static int GetQueries(HttpRequest request) {
+        int queries = 1;
+        string queriesString = request.QueryString["queries"];
+        if (queriesString != null) {
+            // If this fails to parse, queries will be set to zero.
+            int.TryParse(queriesString, out queries);
+            queries = Math.Max(1, Math.Min(500, queries));
+        }
+        return queries;
+    }
+}

+ 68 - 0
aspnet-stripped/src/App_Code/DbHandler.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.Common;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web;
+using System.Web.Script.Serialization;
+
+using Benchmarks.AspNet.Models;
+
+public class DbHandler : IHttpHandler
+{
+    bool IHttpHandler.IsReusable
+    {
+        get { return true; }
+    }
+
+    void IHttpHandler.ProcessRequest(HttpContext context)
+    {
+        Random random = new Random();
+
+        int queries = Common.GetQueries(context.Request);
+        List<World> worlds = new List<World>(queries);
+        
+        using (DbConnection connection = Common.CreateConnection(context.Request))
+        {
+            connection.Open();
+            
+            using (DbCommand command = connection.CreateCommand())
+            {
+                command.CommandText = "SELECT * FROM World WHERE id = @ID";
+
+                DbParameter parameter = command.CreateParameter();
+                parameter.ParameterName = "@ID";
+                
+                command.Parameters.Add(parameter);
+
+                for (int i = 0; i < worlds.Capacity; i++)
+                {
+                    int randomID = random.Next(0, 10000) + 1;
+
+                    parameter.Value = randomID;
+                    
+                    // Don't use CommandBehavior.SingleRow because that will make the MySql provider
+                    // send two extra commands to limit the result to one row.
+                    using (DbDataReader reader = command.ExecuteReader())
+                    {
+                        if (reader.Read())
+                        {
+                            worlds.Add(new World
+                            {
+                                id = reader.GetInt32(0),
+                                randomNumber = reader.GetInt32(1)
+                            });
+                        }
+                    }
+                }
+            }
+        }
+        
+        HttpResponse response = context.Response;
+        response.ContentType = "application/json";
+        response.Write(new JavaScriptSerializer().Serialize(
+            worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]));
+    }
+}

+ 59 - 0
aspnet-stripped/src/App_Code/FortunesPage.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.Common;
+using System.Linq;
+using System.Web;
+using System.Web.Security;
+using System.Web.UI;
+using System.Web.UI.HtmlControls;
+using System.Web.UI.WebControls;
+using System.Web.UI.WebControls.WebParts;
+using System.Xml.Linq;
+using System.Runtime.Serialization.Json;
+using System.IO;
+using System.Text;
+
+using Benchmarks.AspNet.Models;
+
+public partial class FortunesPage : System.Web.UI.Page
+{
+    protected void Page_Load(object sender, EventArgs e)
+    {
+        List<Fortune> fortunes = new List<Fortune>();
+        
+        using (DbConnection connection = Common.CreateConnection(Request))
+        {
+            connection.Open();
+            
+            using (DbCommand command = connection.CreateCommand())
+            {
+                command.CommandText = "SELECT * FROM Fortune";
+                
+                using (DbDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
+                {
+                    while (reader.Read())
+                    {
+                        fortunes.Add(new Fortune
+                        {
+                            ID = reader.GetInt32(0),
+                            Message = reader.GetString(1)
+                        });
+                    }
+                }
+            }
+        }
+        
+        fortunes.Add(new Fortune { ID = 0, Message = "Additional fortune added at request time." });
+        fortunes.Sort();
+        
+        Fortunes = fortunes;
+    }
+
+    public List<Fortune> Fortunes
+    {
+        get; set;
+    }
+}

+ 17 - 0
aspnet-stripped/src/App_Code/JsonHandler.cs

@@ -0,0 +1,17 @@
+using System.Web;
+using System.Web.Script.Serialization;
+
+public class JsonHandler : IHttpHandler
+{
+    bool IHttpHandler.IsReusable
+    {
+        get { return true; }
+    }
+
+    void IHttpHandler.ProcessRequest(HttpContext context)
+    {
+        HttpResponse response = context.Response;
+        response.ContentType = "application/json";
+        response.Write(new JavaScriptSerializer().Serialize(new { message = "Hello, World!" }));
+    }
+}

+ 15 - 0
aspnet-stripped/src/App_Code/Models/Fortune.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace Benchmarks.AspNet.Models
+{
+    public class Fortune : IComparable<Fortune>
+    {
+        public int ID { get; set; }
+        public string Message { get; set; }
+        
+        public int CompareTo(Fortune other)
+        {
+            return Message.CompareTo(other.Message);
+        }
+    }
+}

+ 53 - 0
aspnet-stripped/src/App_Code/Models/MongoDB.cs

@@ -0,0 +1,53 @@
+using System.Configuration;
+using System.Web.Script.Serialization;
+
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver;
+
+namespace Benchmarks.AspNet.Models
+{
+    public class MongoDB
+    {
+        public MongoCollection<MongoWorld> Worlds { get; private set; }
+        public MongoCollection<Fortune> Fortunes { get; private set; }
+
+        static MongoDB()
+        {
+            BsonClassMap.RegisterClassMap<World>(m =>
+            {
+                m.MapProperty(w => w.id);
+                m.MapProperty(w => w.randomNumber);
+            });
+
+            BsonClassMap.RegisterClassMap<MongoWorld>(m =>
+            {
+                m.MapIdProperty(w => w._id);
+            });
+
+            BsonClassMap.RegisterClassMap<Fortune>(m =>
+            {
+                m.MapProperty(f => f.ID).SetElementName("id");
+                m.MapProperty(f => f.Message).SetElementName("message");
+            });
+        }
+
+        public MongoDB(string connectionStringName)
+        {
+            string connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
+
+            MongoClient client = new MongoClient(connectionString);
+            MongoServer server = client.GetServer();
+            MongoDatabase database = server.GetDatabase("hello_world");
+
+            Worlds = database.GetCollection<MongoWorld>("world");
+            Fortunes = database.GetCollection<Fortune>("fortune");
+        }
+    }
+
+    public class MongoWorld : World
+    {
+        [ScriptIgnore]
+        public ObjectId _id { get; set; }
+    }
+}

+ 8 - 0
aspnet-stripped/src/App_Code/Models/World.cs

@@ -0,0 +1,8 @@
+namespace Benchmarks.AspNet.Models
+{
+    public class World
+    {
+        public int id { get; set; }
+        public int randomNumber { get; set; }
+    }
+}

+ 94 - 0
aspnet-stripped/src/App_Code/MongoDBHandlers.cs

@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Web;
+using System.Web.Script.Serialization;
+
+using MongoDB.Driver.Builders;
+
+using Benchmarks.AspNet.Models;
+
+public class MongoDBDbHandler : IHttpHandler
+{
+    bool IHttpHandler.IsReusable
+    {
+        get { return true; }
+    }
+
+    void IHttpHandler.ProcessRequest(HttpContext context)
+    {
+        Random random = new Random();
+        
+        int queries = Common.GetQueries(context.Request);
+        List<World> worlds = new List<World>(queries);
+
+        Benchmarks.AspNet.Models.MongoDB db = new Benchmarks.AspNet.Models.MongoDB("MongoDB");
+
+        for (int i = 0; i < worlds.Capacity; i++)
+        {
+            int randomID = random.Next(0, 10000) + 1;
+            worlds.Add(db.Worlds.FindOne(Query<World>.EQ(w => w.id, randomID)));
+        }
+
+        HttpResponse response = context.Response;
+        response.ContentType = "application/json";
+        response.Write(new JavaScriptSerializer().Serialize(
+            worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]));
+    }
+}
+
+public partial class MongoDBFortunesPage : System.Web.UI.Page
+{
+    protected void Page_Load(object sender, EventArgs e)
+    {
+        Benchmarks.AspNet.Models.MongoDB db = new Benchmarks.AspNet.Models.MongoDB("MongoDB");
+
+        List<Fortune> fortunes = db.Fortunes.FindAll().ToList();
+
+        fortunes.Add(new Fortune { ID = 0, Message = "Additional fortune added at request time." });
+        fortunes.Sort();
+
+        Fortunes = fortunes;
+    }
+
+    public List<Fortune> Fortunes
+    {
+        get; set;
+    }
+}
+
+public class MongoDBUpdatesHandler : IHttpHandler
+{
+    bool IHttpHandler.IsReusable
+    {
+        get { return true; }
+    }
+
+    void IHttpHandler.ProcessRequest(HttpContext context)
+    {
+        Random random = new Random();
+        
+        Benchmarks.AspNet.Models.MongoDB db = new Benchmarks.AspNet.Models.MongoDB("MongoDB");
+
+        int queries = Common.GetQueries(context.Request);
+        List<World> worlds = new List<World>(queries);
+
+        for (int i = 0; i < worlds.Capacity; i++)
+        {
+            int randomID = random.Next(0, 10000) + 1;
+            int randomNumber = random.Next(0, 10000) + 1;
+
+            World world = db.Worlds.FindOne(Query<World>.EQ(w => w.id, randomID));
+            world.randomNumber = randomNumber;
+            worlds.Add(world);
+
+            db.Worlds.Save(world);
+        }
+
+        HttpResponse response = context.Response;
+        response.ContentType = "application/json";
+        response.Write(new JavaScriptSerializer().Serialize(
+            worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]));
+    }
+}

+ 50 - 0
aspnet-stripped/src/App_Code/MyModule.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Configuration;
+using System.Threading;
+using System.Web;
+
+public class MyModule: IHttpModule
+{
+    private static volatile bool started = false;
+    private static object locker = new object();
+
+    public void Init(HttpApplication context)
+    {
+        if (!started)
+        {
+            lock (locker)
+            {
+                Start();
+                started = true;
+            }
+        }
+    }
+
+    private void Start()
+    {
+        Threads();
+    }
+
+    private void Threads()
+    {
+        // To improve CPU utilization, increase the number of threads that the .NET thread pool expands by when
+        // a burst of requests come in. We could do this by editing machine.config/system.web/processModel/minWorkerThreads,
+        // but that seems too global a change, so we do it in code for just our AppPool. More info:
+        //
+        // http://support.microsoft.com/kb/821268
+        // http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx
+        // http://blogs.msdn.com/b/perfworld/archive/2010/01/13/how-can-i-improve-the-performance-of-asp-net-by-adjusting-the-clr-thread-throttling-properties.aspx
+
+        int newMinWorkerThreads = Convert.ToInt32(ConfigurationManager.AppSettings["minWorkerThreadsPerLogicalProcessor"]);
+        if (newMinWorkerThreads > 0)
+        {
+            int minWorkerThreads, minCompletionPortThreads;
+            ThreadPool.GetMinThreads(out minWorkerThreads, out minCompletionPortThreads);
+            ThreadPool.SetMinThreads(Environment.ProcessorCount * newMinWorkerThreads, minCompletionPortThreads);
+        }
+    }
+
+    public void Dispose()
+    {
+    }
+}

+ 18 - 0
aspnet-stripped/src/App_Code/NoAspxHandlerFactory.cs

@@ -0,0 +1,18 @@
+using System.Web;
+using System.Web.UI;
+using System.Web.Compilation;
+
+// This bit of magic lets us access /fortunes.aspx as /fortunes. This could be used for any URL specified
+// in Web.config.
+public class NoAspxHandlerFactory : IHttpHandlerFactory
+{
+    public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path)
+    {
+        // virtualPath is like "/fortunes", turn that into "/fortunes.aspx"
+        return BuildManager.CreateInstanceFromVirtualPath(virtualPath + ".aspx", typeof(Page)) as Page;
+    }
+
+    public virtual void ReleaseHandler(IHttpHandler handler)
+    {
+    }
+}

+ 17 - 0
aspnet-stripped/src/App_Code/PlaintextHandler.cs

@@ -0,0 +1,17 @@
+using System.Web;
+using System.Web.Script.Serialization;
+
+public class PlaintextHandler : IHttpHandler
+{
+    bool IHttpHandler.IsReusable
+    {
+        get { return true; }
+    }
+
+    void IHttpHandler.ProcessRequest(HttpContext context)
+    {
+        HttpResponse response = context.Response;
+        response.ContentType = "text/plain";
+        response.Write("Hello, World!");
+    }
+}

+ 88 - 0
aspnet-stripped/src/App_Code/UpdatesHandler.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.Common;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web;
+using System.Web.Script.Serialization;
+
+using Benchmarks.AspNet.Models;
+
+public class UpdatesHandler : IHttpHandler
+{
+    bool IHttpHandler.IsReusable
+    {
+        get { return true; }
+    }
+
+    void IHttpHandler.ProcessRequest(HttpContext context)
+    {
+        Random random = new Random();
+        List<World> worlds = new List<World>(Common.GetQueries(context.Request));
+
+        using (DbConnection connection = Common.CreateConnection(context.Request))
+        {
+            connection.Open();
+
+            using (DbCommand selectCommand = connection.CreateCommand(),
+                             updateCommand = connection.CreateCommand())
+            {
+                selectCommand.CommandText = "SELECT * FROM World WHERE id = @ID";
+                updateCommand.CommandText = "UPDATE World SET randomNumber = @Number WHERE id = @ID";
+
+                for (int i = 0; i < worlds.Capacity; i++)
+                {
+                    int randomID = random.Next(0, 10000) + 1;
+                    int randomNumber = random.Next(0, 10000) + 1;
+
+                    DbParameter idParameter = selectCommand.CreateParameter();
+                    idParameter.ParameterName = "@ID";
+                    idParameter.Value = randomID;
+
+                    selectCommand.Parameters.Clear();
+                    selectCommand.Parameters.Add(idParameter);
+
+                    World world = null;
+
+                    // Don't use CommandBehavior.SingleRow because that will make the MySql provider
+                    // send two extra commands to limit the result to one row.
+                    using (DbDataReader reader = selectCommand.ExecuteReader())
+                    {
+                        if (reader.Read())
+                        {
+                            world = new World
+                            {
+                                id = reader.GetInt32(0),
+                                randomNumber = reader.GetInt32(1)
+                            };
+                        }
+                    }
+
+                    DbParameter idUpdateParameter = updateCommand.CreateParameter();
+                    idUpdateParameter.ParameterName = "@ID";
+                    idUpdateParameter.Value = randomID;
+
+                    DbParameter numberParameter = updateCommand.CreateParameter();
+                    numberParameter.ParameterName = "@Number";
+                    numberParameter.Value = randomNumber;
+
+                    updateCommand.Parameters.Clear();
+                    updateCommand.Parameters.Add(idUpdateParameter);
+                    updateCommand.Parameters.Add(numberParameter);
+
+                    updateCommand.ExecuteNonQuery();
+                    
+                    world.randomNumber = randomNumber;
+                    worlds.Add(world);
+                }
+            }
+        }
+
+        HttpResponse response = context.Response;
+        response.ContentType = "application/json";
+        response.Write(new JavaScriptSerializer().Serialize(
+            worlds.Count > 1 ? (Object)worlds : (Object)worlds[0]));
+    }
+}

+ 69 - 0
aspnet-stripped/src/Web.config

@@ -0,0 +1,69 @@
+<configuration>
+  <connectionStrings>
+    <add name="MySQL" connectionString="server=localhost; user id=benchmarkdbuser; password=benchmarkdbpass; database=hello_world" providerName="MySql.Data.MySqlClient"/>
+    <add name="PostgreSQL" connectionString="server=localhost; user id=benchmarkdbuser; password=benchmarkdbpass; database=hello_world" providerName="Npgsql"/>
+    <add name="MongoDB" connectionString="mongodb://localhost"/>
+    <!-- Set max pool size to SQL Server's default max_connections value. In practice, we don't seem to be getting close to the max at all. -->
+    <add name="SQLServer" connectionString="server=localhost; user id=benchmarkdbuser; password=B3nchmarkDBPass; database=hello_world; max pool size=32767" providerName="System.Data.SqlClient"/>
+  </connectionStrings>
+  
+  <system.data>
+    <DbProviderFactories>
+      <clear/>
+      <add name="MySql.Data.MySqlClient" description="Data Provider for MySQL" invariant="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.7.2.0"/>
+      <add name="Npgsql" description="Data Provider for PostgreSQL" invariant="Npgsql" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.12.0"/>
+      <add name="SqlClient Data Provider" description=".Net Framework Data Provider for SqlServer" invariant="System.Data.SqlClient" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
+    </DbProviderFactories>
+  </system.data>
+  
+  <appSettings>
+    <!-- To fully saturate the CPUs, we need to allow the .NET thread pool to create many threads
+         when a large burst of requests come in. We do this by boosting the minWorkerThreads value
+         from the default of 1 per logical processor to 8 per logical processor. This seems to be
+         pretty conservative as http://support.microsoft.com/kb/821268 recommends 50.-->
+    <add key="minWorkerThreadsPerLogicalProcessor" value="8" />
+  </appSettings>
+
+    <system.webServer>
+        <modules>
+            <!-- Disable unnecessary modules, especially ones written in .NET. -->
+            <remove name="UrlRoutingModule-4.0" />
+            <remove name="ScriptModule-4.0" />
+            <remove name="OutputCache" />
+            <remove name="Session" />
+            <remove name="WindowsAuthentication" />
+            <remove name="FormsAuthentication" />
+            <remove name="DefaultAuthentication" />
+            <remove name="RoleManager" />
+            <remove name="UrlAuthorization" />
+            <remove name="FileAuthorization" />
+            <remove name="AnonymousIdentification" />
+            <remove name="Profile" />
+            <remove name="UrlMappingsModule" />
+            
+            <!-- We'd like to disable these modules as well, but they're marked `lockitem` in
+                 %windir%\system32\inetsrv\config\applicationHost.config. If we could disable
+                 them, we'd probably gain 2-3% in performance. -->
+            <!--
+            <remove name="RewriteModule" />
+            <remove name="CgiModule" />
+            <remove name="FastCgiModule" />
+            -->
+            
+            <!-- Add our initialization module -->
+            <add name="MyModule" type="MyModule"/>
+        </modules>
+        <handlers>
+            <!-- Since we don't use fancy ASP.NET URL routing, we directly specify all our valid URL mappings here. -->
+            <add name="JsonHandler" path="json" verb="*" type="JsonHandler" resourceType="Unspecified" preCondition="integratedMode" />
+            <add name="DbHandler" path="db" verb="*" type="DbHandler" resourceType="Unspecified" preCondition="integratedMode" />
+            <add name="Fortunes_aspx" path="fortunes" verb="*" type="NoAspxHandlerFactory" resourceType="Unspecified" preCondition="integratedMode" />
+            <add name="UpdatesHandler" path="updates" verb="*" type="UpdatesHandler" resourceType="Unspecified" preCondition="integratedMode" />
+            <add name="PlaintextHandler" path="plaintext" verb="*" type="PlaintextHandler" resourceType="Unspecified" preCondition="integratedMode" />
+
+            <add name="MongoDBDbHandler" path="mongodbdb" verb="*" type="MongoDBDbHandler" resourceType="Unspecified" preCondition="integratedMode" />
+            <add name="MongoDBFortunes_aspx" path="mongodbfortunes" verb="*" type="NoAspxHandlerFactory" resourceType="Unspecified" preCondition="integratedMode" />
+            <add name="MongoDBUpdatesHandler" path="mongodbupdates" verb="*" type="MongoDBUpdatesHandler" resourceType="Unspecified" preCondition="integratedMode" />
+        </handlers>
+    </system.webServer>
+</configuration>

+ 1 - 0
aspnet-stripped/src/fortunes.aspx

@@ -0,0 +1 @@
+<%@ Page Language="C#" AutoEventWireup="true" Inherits="FortunesPage" %><!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><% foreach (var fortune in Fortunes) { %><tr><td><% = fortune.ID %></td><td><%: fortune.Message %></td></tr><% } %></table></body></html>

+ 1 - 0
aspnet-stripped/src/mongodbfortunes.aspx

@@ -0,0 +1 @@
+<%@ Page Language="C#" AutoEventWireup="true" Inherits="MongoDBFortunesPage" %><!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><% foreach (var fortune in Fortunes) { %><tr><td><% = fortune.ID %></td><td><%: fortune.Message %></td></tr><% } %></table></body></html>

+ 6 - 0
aspnet-stripped/src/packages.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="mongocsharpdriver" version="1.8.1" targetFramework="net45" />
+  <package id="MySql.Data.Entity" version="6.7.2-beta-ef6" targetFramework="net45" />
+  <package id="Npgsql.EF6" version="2.0.12-pre4" targetFramework="net45" />
+</packages>

+ 6 - 0
aspnet/.gitignore

@@ -0,0 +1,6 @@
+*.user
+*.suo
+*/bin/*
+*/obj/*
+lib/*
+!lib/.nuget

+ 65 - 0
aspnet/README.md

@@ -0,0 +1,65 @@
+# ASP.NET MVC on Windows and Mono
+
+## Tests
+
+* JSON serialization
+* Single database query
+* Multiple database queries
+* Server-side templates and collections
+* Database updates
+* Plaintext
+
+## Versions
+
+**Language**
+
+* C# 5.0
+
+**Platforms**
+
+* .NET Framework 4.5 (Windows)
+* Mono 3.2.1 (Linux)
+
+**Web Servers**
+
+* IIS 8 (Windows)
+* XSP latest (Linux)
+* nginx 1.4.1 & XSP FastCGI (Linux)
+
+**Web Stack**
+
+* ASP.NET 4.5
+* ASP.NET MVC Framework 4
+
+**Databases**
+
+* MySQL Connector/Net 6.7.2-beta ([custom build](https://github.com/pdonald/mysql-connector-net))
+* Npgsql 2.0.13-beta1
+* Entity Framework 6.0.0-beta1
+* Mongo C# Driver 1.8.2
+
+**Developer Tools**
+
+* Visual Studio 2012
+
+## Mono Installation
+
+    sudo apt-get install git-core build-essential autoconf automake libtool zlib1g-dev pkg-config
+
+    git clone git://github.com/mono/mono
+    cd mono
+    git checkout mono-3.2.1
+    ./autogen.sh --prefix=/usr/local
+    make get-monolite-latest
+    make EXTERNAL_MCS=${PWD}/mcs/class/lib/monolite/gmcs.exe
+    sudo make install
+
+    cd ..
+
+    git clone git://github.com/mono/xsp
+    cd xsp
+    ./autogen.sh --prefix=/usr/local
+    make
+    sudo make install
+    
+    mozroots --import --sync

+ 0 - 0
django-stripped/hello/world/__init__.py → aspnet/__init__.py


+ 367 - 0
aspnet/benchmark_config

@@ -0,0 +1,367 @@
+{
+  "framework": "aspnet",
+  "tests": [{
+    "default": {
+      "setup_file": "setup_iis",
+      "json_url": "/json/default",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "None",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet",
+      "notes": "",
+      "versus": ""
+    },
+    "jsonnet": {
+      "setup_file": "setup_iis",
+      "json_url": "/json/jsonnet",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "nginx",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-jsonnet",
+      "notes": "",
+      "versus": ""
+    },
+    "servicestack": {
+      "setup_file": "setup_iis",
+      "json_url": "/json/servicestack",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "nginx",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-svcstk",
+      "notes": "",
+      "versus": ""
+    },
+    "mysql-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/ado/mysql",
+      "query_url": "/ado/mysql?queries=",
+      "fortune_url": "/ado/mysql/fortunes",
+      "update_url": "/ado/mysql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "postgresql-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/ado/postgresql",
+      "query_url": "/ado/postgresql?queries=",
+      "fortune_url": "/ado/postgresql/fortunes",
+      "update_url": "/ado/postgresql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "mongodb-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/mongodb",
+      "query_url": "/mongodb?queries=",
+      "fortune_url": "/mongodb/fortunes",
+      "update_url": "/mongodb/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MongoDB",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "sqlserver-raw": {
+      "setup_file": "setup_iis",
+      "db_url": "/ado/sqlserver",
+      "query_url": "/ado/sqlserver?queries=",
+      "fortune_url": "/ado/sqlserver/fortunes",
+      "update_url": "/ado/sqlserver/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "SQLServer",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Full",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Windows",
+      "display_name": "aspnet-mvc-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "mysql-entityframework": {
+      "setup_file": "setup_iis",
+      "db_url": "/entityframework/mysql",
+      "query_url": "/entityframework/mysql?queries=",
+      "fortune_url": "/entityframework/mysql/fortunes",
+      "update_url": "/entityframework/mysql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Full",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc",
+      "notes": "",
+      "versus": ""
+    },
+    "postgresql-entityframework": {
+      "setup_file": "setup_iis",
+      "db_url": "/entityframework/postgresql",
+      "query_url": "/entityframework/postgresql?queries=",
+      "fortune_url": "/entityframework/postgresql/fortunes",
+      "update_url": "/entityframework/postgresql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Full",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc",
+      "notes": "",
+      "versus": ""
+    },
+    "sqlserver-entityframework": {
+      "setup_file": "setup_iis",
+      "db_url": "/entityframework/sqlserver",
+      "query_url": "/entityframework/sqlserver?queries=",
+      "fortune_url": "/entityframework/sqlserver/fortunes",
+      "update_url": "/entityframework/sqlserver/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "SQLServer",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Full",
+      "platform": "NET",
+      "webserver": "IIS",
+      "os": "Windows",
+      "database_os": "Windows",
+      "display_name": "aspnet-mvc",
+      "notes": "",
+      "versus": ""
+    },
+    "mono": {
+      "setup_file": "setup_nginx",
+      "json_url": "/json/default",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "None",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-mono",
+      "notes": "",
+      "versus": ""
+    },
+    "mono-jsonnet": {
+      "setup_file": "setup_nginx",
+      "json_url": "/json/jsonnet",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-jsonnet-mono",
+      "notes": "",
+      "versus": ""
+    },
+    "mono-servicestack": {
+      "setup_file": "setup_nginx",
+      "json_url": "/json/servicestack",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "aspnet",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-svcstk-mono",
+      "notes": "",
+      "versus": ""
+    },
+    "mono-mysql-raw": {
+      "setup_file": "setup_nginx",
+      "db_url": "/ado/mysql",
+      "query_url": "/ado/mysql?queries=",
+      "fortune_url": "/ado/mysql/fortunes",
+      "update_url": "/ado/mysql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-mono-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "mono-postgresql-raw": {
+      "setup_file": "setup_nginx",
+      "db_url": "/ado/postgresql",
+      "query_url": "/ado/postgresql?queries=",
+      "fortune_url": "/ado/postgresql/fortunes",
+      "update_url": "/ado/postgresql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-mono-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "mono-mongodb-raw": {
+      "setup_file": "setup_nginx",
+      "db_url": "/mongodb",
+      "query_url": "/mongodb?queries=",
+      "fortune_url": "/mongodb/fortunes",
+      "update_url": "/mongodb/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MongoDB",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-mono-raw",
+      "notes": "",
+      "versus": ""
+    },
+    "mono-mysql-entityframework": {
+      "setup_file": "setup_nginx",
+      "db_url": "/entityframework/mysql",
+      "query_url": "/entityframework/mysql?queries=",
+      "fortune_url": "/entityframework/mysql/fortunes",
+      "update_url": "/entityframework/mysql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Full",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-mono",
+      "notes": "Entity framework",
+      "versus": ""
+    },
+    "mono-postgresql-entityframework": {
+      "setup_file": "setup_nginx",
+      "db_url": "/entityframework/postgresql",
+      "query_url": "/entityframework/postgresql?queries=",
+      "fortune_url": "/entityframework/postgresql/fortunes",
+      "update_url": "/entityframework/postgresql/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "aspnet-mvc",
+      "language": "C#",
+      "orm": "Full",
+      "platform": "Mono",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspnet-mvc-mono",
+      "notes": "Entity framework",
+      "versus": ""
+    }
+  }]
+}

BIN
aspnet/lib/.nuget/NuGet.exe


+ 135 - 0
aspnet/lib/.nuget/NuGet.targets

@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
+        
+        <!-- Enable the restore command to run before builds -->
+        <RestorePackages Condition="  '$(RestorePackages)' == '' ">false</RestorePackages>
+
+        <!-- Property that enables building a package from a project -->
+        <BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
+
+        <!-- Determines if package restore consent is required to restore packages -->
+        <RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">false</RequireRestoreConsent>
+        
+        <!-- Download NuGet.exe if it does not already exist -->
+        <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">true</DownloadNuGetExe>
+    </PropertyGroup>
+    
+    <ItemGroup Condition=" '$(PackageSources)' == '' ">
+        <!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
+        <!-- The official NuGet package source (https://nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
+        <!--
+            <PackageSource Include="https://nuget.org/api/v2/" />
+            <PackageSource Include="https://my-nuget-source/nuget/" />
+        -->
+    </ItemGroup>
+
+    <PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
+        <!-- Windows specific commands -->
+        <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), "..", "lib", ".nuget"))</NuGetToolsPath>
+        <PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "..", "lib", "packages.config"))</PackagesConfig>
+        <RepositoryPath>$([System.IO.Path]::Combine($(SolutionDir), "..", "lib"))</RepositoryPath>
+    </PropertyGroup>
+    
+    <PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
+        <!-- We need to launch nuget.exe with the mono command if we're not on windows -->
+        <NuGetToolsPath>$(SolutionDir)..\lib\.nuget</NuGetToolsPath>
+        <PackagesConfig>$(SolutionDir)..\lib\packages.config</PackagesConfig>
+        <RepositoryPath>$(SolutionDir)..\lib</RepositoryPath>
+    </PropertyGroup>
+    
+    <PropertyGroup>
+        <!-- NuGet command -->
+        <NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath>
+        <PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
+        
+        <NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
+        <NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono $(NuGetExePath)</NuGetCommand>
+
+        <PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
+        
+        <RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
+        <NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>
+        
+        <!-- Commands -->
+        <RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)"  $(NonInteractiveSwitch) $(RequireConsentSwitch) -OutputDirectory "$(RepositoryPath)"</RestoreCommand>
+        <BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties Configuration=$(Configuration) $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
+
+        <!-- We need to ensure packages are restored prior to assembly resolve -->
+        <BuildDependsOn Condition="$(RestorePackages) == 'true'">
+            RestorePackages;
+            $(BuildDependsOn);
+        </BuildDependsOn>
+
+        <!-- Make the build depend on restore packages -->
+        <BuildDependsOn Condition="$(BuildPackage) == 'true'">
+            $(BuildDependsOn);
+            BuildPackage;
+        </BuildDependsOn>
+    </PropertyGroup>
+
+    <Target Name="CheckPrerequisites">
+        <!-- Raise an error if we're unable to locate nuget.exe  -->
+        <Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
+        <!--
+        Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
+        This effectively acts as a lock that makes sure that the download operation will only happen once and all
+        parallel builds will have to wait for it to complete.
+        -->
+        <MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
+    </Target>
+
+    <Target Name="_DownloadNuGet">
+        <DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
+    </Target>
+
+    <Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
+        <Exec Command="$(RestoreCommand)"
+              Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
+              
+        <Exec Command="$(RestoreCommand)"
+              LogStandardErrorAsError="true"
+              Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
+    </Target>
+
+    <Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
+        <Exec Command="$(BuildCommand)" 
+              Condition=" '$(OS)' != 'Windows_NT' " />
+              
+        <Exec Command="$(BuildCommand)"
+              LogStandardErrorAsError="true"
+              Condition=" '$(OS)' == 'Windows_NT' " />
+    </Target>
+    
+    <UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
+        <ParameterGroup>
+            <OutputFilename ParameterType="System.String" Required="true" />
+        </ParameterGroup>
+        <Task>
+            <Reference Include="System.Core" />
+            <Using Namespace="System" />
+            <Using Namespace="System.IO" />
+            <Using Namespace="System.Net" />
+            <Using Namespace="Microsoft.Build.Framework" />
+            <Using Namespace="Microsoft.Build.Utilities" />
+            <Code Type="Fragment" Language="cs">
+                <![CDATA[
+                try {
+                    OutputFilename = Path.GetFullPath(OutputFilename);
+
+                    Log.LogMessage("Downloading latest version of NuGet.exe...");
+                    WebClient webClient = new WebClient();
+                    webClient.DownloadFile("https://nuget.org/nuget.exe", OutputFilename);
+
+                    return true;
+                }
+                catch (Exception ex) {
+                    Log.LogErrorFromException(ex);
+                    return false;
+                }
+            ]]>
+            </Code>
+        </Task>
+    </UsingTask>
+</Project>

+ 14 - 0
aspnet/lib/packages.config

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="EntityFramework" version="6.0.0-beta1" targetFramework="net45" />
+  <package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net45" />
+  <package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net45" />
+  <package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net45" />
+  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
+  <package id="MSBuild.Microsoft.VisualStudio.Web.targets" version="11.0.2.1" />
+  <package id="mongocsharpdriver" version="1.8.2" targetFramework="net45" />
+  <package id="MySql.Data.Entity" version="6.7.2-beta-ef6" targetFramework="net45" />
+  <package id="Npgsql" version="2.0.13-beta1" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="5.0.6" targetFramework="net45" />
+  <package id="ServiceStack.Text" version="3.9.56" targetFramework="net45" />
+</packages>

+ 26 - 0
aspnet/nginx.conf

@@ -0,0 +1,26 @@
+# worker_processes n;
+pid /tmp/nginx.pid;
+error_log /dev/null crit;
+
+events {
+    worker_connections 8192;
+}
+
+http {
+    access_log off;
+
+    #upstream mono {
+    #    server 127.0.0.1:9001;
+    #}
+    include nginx.upstream.conf;
+
+    server {
+        listen 8080;
+
+        location / {
+            fastcgi_pass mono;
+            include /usr/local/nginx/conf/fastcgi_params;
+            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
+        }
+    }
+}

+ 21 - 0
aspnet/setup_iis.ps1

@@ -0,0 +1,21 @@
+param($action)
+
+$wwwroot = "C:\FrameworkBenchmarks\aspnet\www"
+$source = "C:\FrameworkBenchmarks\aspnet\src"
+$msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
+
+# Stop
+if (Get-WebSite -Name Benchmarks) { Remove-WebSite -Name Benchmarks }
+Get-ChildItem -Path $wwwroot -Recurse -ErrorAction 'SilentlyContinue' | Remove-Item -Force -Recurse -ErrorAction 'SilentlyContinue' | Out-Null 
+Remove-Item -Force -Recurse $wwwroot -ErrorAction 'SilentlyContinue' | Out-Null
+
+if ($action -eq 'start') {
+    # Create a website in IIS
+    New-Item -Path $wwwroot -Type Directory -ErrorAction 'SilentlyContinue' | Out-Null
+    New-WebSite -Name Benchmarks -Port 8080 -PhysicalPath $wwwroot
+    
+    # Build the project
+    &$msbuild "$source\Benchmarks.AspNet.csproj" /t:RestorePackages
+    &$msbuild "$source\Benchmarks.AspNet.csproj" /p:Configuration=Release /p:Platform=x64 /t:Clean
+    &$msbuild "$source\Benchmarks.AspNet.csproj" /p:Configuration=Release /p:Platform=x64 /p:DeployOnBuild=true /p:PublishProfile=IIS
+}

+ 22 - 0
aspnet/setup_iis.py

@@ -0,0 +1,22 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args):
+  if os.name != 'nt':
+    return 1
+  
+  try:
+    setup_util.replace_text("aspnet/src/Web.config", "localhost", args.database_host)
+    subprocess.check_call("powershell -File setup_iis.ps1 start", cwd="aspnet")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop():
+  if os.name != 'nt':
+    return 0
+  
+  subprocess.Popen("powershell -File setup_iis.ps1 stop", cwd="aspnet")
+  return 0

+ 48 - 0
aspnet/setup_nginx.py

@@ -0,0 +1,48 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+root = os.getcwd() + "/aspnet"
+app = root + "/src"
+
+def start(args):
+  if os.name == 'nt':
+    return 1
+  
+  setup_util.replace_text(app + "/Web.config", "localhost", args.database_host)
+
+  try:
+    # build
+    subprocess.check_call("rm -rf bin obj", shell=True, cwd=app)
+    subprocess.check_call("xbuild /p:Configuration=Release", shell=True, cwd=app)
+    subprocess.check_call("sudo chown -R $USER:$USER /usr/local/etc/mono", shell=True)
+    
+    # nginx
+    workers = 'worker_processes ' + str(args.max_threads) + ';'
+    subprocess.check_call('echo "upstream mono {\n' + ';\n'.join('\tserver 127.0.0.1:' + str(port) for port in range(9001, 9001 + args.max_threads)) + ';\n}" > ' + root + '/nginx.upstream.conf', shell=True);
+    subprocess.check_call('sudo /usr/local/nginx/sbin/nginx -c ' + root + '/nginx.conf -g "' + workers + '"', shell=True)
+    
+    # fastcgi
+    for port in range(9001, 9001 + args.max_threads):
+      subprocess.Popen("MONO_OPTIONS=--gc=sgen fastcgi-mono-server4 /applications=/:. /socket=tcp:127.0.0.1:" + str(port) + " &", shell=True, cwd=app)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop():
+  if os.name == 'nt':
+    return 0
+  
+  subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c " + root + "/nginx.conf -s stop", shell=True)
+  subprocess.check_call("rm -f " + root + "/nginx.upstream.conf", shell=True)
+  #
+  # stop mono
+  #
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'mono-server' in line:
+      pid = int(line.split(None, 2)[1])
+      os.kill(pid, 9)
+  return 0

+ 34 - 0
aspnet/setup_xsp.py

@@ -0,0 +1,34 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+def start(args):
+  if os.name == 'nt':
+    return 1
+  
+  setup_util.replace_text("aspnet/src/Web.config", "localhost", args.database_host)
+
+  try:
+    subprocess.check_call("rm -rf bin obj", shell=True, cwd="aspnet/src")
+    subprocess.check_call("xbuild /p:Configuration=Release", shell=True, cwd="aspnet/src")
+    subprocess.check_call("sudo chown -R ubuntu:ubuntu /usr/local/etc/mono", shell=True)
+    subprocess.Popen("MONO_OPTIONS=--gc=sgen xsp4 --nonstop", shell=True, cwd="aspnet/src")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop():
+  if os.name == 'nt':
+    return 0
+  
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'xsp4' in line:
+      pid = int(line.split(None, 2)[1])
+      try:
+        os.kill(pid, 9)
+      except OSError:
+        pass
+  return 0

+ 90 - 0
aspnet/src/Application.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Configuration;
+using System.Threading;
+using System.Web;
+using System.Web.Mvc;
+using System.Web.Routing;
+
+namespace Benchmarks.AspNet
+{
+    public class Application : IHttpModule
+    {
+        private static volatile bool started = false;
+        private static object locker = new object();
+
+        public void Init(HttpApplication context)
+        {
+            if (!started)
+            {
+                lock (locker)
+                {
+                    if (!started)
+                    {
+                        Start();
+                        started = true;
+                    }
+                }
+            }
+        }
+
+        private void Start()
+        {
+            Routes();
+            Views();
+            Threads();
+        }
+
+        private void Routes()
+        {
+            RouteTable.Routes.Clear();
+
+            RouteTable.Routes.MapRoute(
+                name: "JSON",
+                url: "json/{action}",
+                defaults: new { controller = "Json", action = "Default" }
+            );
+
+            RouteTable.Routes.MapRoute(
+                name: "WithProviders",
+                url: "{controller}/{providerName}/{action}",
+                defaults: new { action = "Index" },
+                constraints: new { controller = "ado|entityframework", providerName = "mysql|postgresql|sqlserver" }
+            );
+
+            RouteTable.Routes.MapRoute(
+                name: "Default",
+                url: "{controller}/{action}",
+                defaults: new { controller = "Home", action = "Index" }
+            );
+        }
+
+        private void Views()
+        {
+            ViewEngines.Engines.Clear();
+            ViewEngines.Engines.Add(new RazorViewEngine { ViewLocationFormats = new[] { "~/Views/{0}.cshtml" } });
+        }
+
+        private void Threads()
+        {
+            // To improve CPU utilization, increase the number of threads that the .NET thread pool expands by when
+            // a burst of requests come in. We could do this by editing machine.config/system.web/processModel/minWorkerThreads,
+            // but that seems too global a change, so we do it in code for just our AppPool. More info:
+            //
+            // http://support.microsoft.com/kb/821268
+            // http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx
+            // http://blogs.msdn.com/b/perfworld/archive/2010/01/13/how-can-i-improve-the-performance-of-asp-net-by-adjusting-the-clr-thread-throttling-properties.aspx
+
+            int newMinWorkerThreads = Convert.ToInt32(ConfigurationManager.AppSettings["minWorkerThreadsPerLogicalProcessor"]);
+            if (newMinWorkerThreads > 0)
+            {
+                int minWorkerThreads, minCompletionPortThreads;
+                ThreadPool.GetMinThreads(out minWorkerThreads, out minCompletionPortThreads);
+                ThreadPool.SetMinThreads(Environment.ProcessorCount * newMinWorkerThreads, minCompletionPortThreads);
+            }
+        }
+
+        public void Dispose()
+        {
+        }
+    }
+}

+ 164 - 0
aspnet/src/Benchmarks.AspNet.csproj

@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion />
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{62C3DEA2-2696-4200-BD83-011679316847}</ProjectGuid>
+    <ProjectTypeGuids>{E3E379DF-F4C6-4180-9B81-6769533ABE47};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Benchmarks.AspNet</RootNamespace>
+    <AssemblyName>Benchmarks.AspNet</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <MvcBuildViews>false</MvcBuildViews>
+    <RestorePackages>true</RestorePackages>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <ErrorReport>prompt</ErrorReport>
+    <PublishDatabases>true</PublishDatabases>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)' == 'Release'">
+    <OutputPath>bin\</OutputPath>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <ErrorReport>prompt</ErrorReport>
+    <PublishDatabases>true</PublishDatabases>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Platform)' == 'x86'">
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Platform)' == 'x64'">
+    <PlatformTarget>x64</PlatformTarget>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Web.Extensions" />
+    <Reference Include="System.Web.Mvc">
+      <Private>True</Private>
+      <HintPath>..\lib\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Helpers">
+      <Private>True</Private>
+      <HintPath>..\lib\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.Razor">
+      <Private>True</Private>
+      <HintPath>..\lib\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages">
+      <Private>True</Private>
+      <HintPath>..\lib\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Deployment">
+      <Private>True</Private>
+      <HintPath>..\lib\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Web.WebPages.Razor">
+      <Private>True</Private>
+      <HintPath>..\lib\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Web.Infrastructure">
+      <Private>True</Private>
+      <HintPath>..\lib\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\lib\Newtonsoft.Json.5.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="ServiceStack.Text">
+      <HintPath>..\lib\ServiceStack.Text.3.9.56\lib\net35\ServiceStack.Text.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework">
+      <Private>True</Private>
+      <HintPath>..\lib\EntityFramework.6.0.0-beta1\lib\net45\EntityFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework">
+      <Private>True</Private>
+      <HintPath>..\lib\EntityFramework.6.0.0-beta1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+    </Reference>
+    <Reference Include="MySql">
+      <Private>True</Private>
+      <HintPath>..\lib\MySql.Data.Entity.6.7.2-beta-ef6\lib\net45\MySql.Data.dll</HintPath>
+    </Reference>
+    <Reference Include="MySql">
+      <Private>True</Private>
+      <HintPath>..\lib\MySql.Data.Entity.6.7.2-beta-ef6\lib\net45\MySql.Data.Entity.dll</HintPath>
+    </Reference>
+    <Reference Include="Npgsql">
+      <Private>True</Private>
+      <HintPath>..\lib\Npgsql.2.0.13-beta1\lib\net45\Npgsql.dll</HintPath>
+    </Reference>
+    <Reference Include="Npgsql">
+      <Private>True</Private>
+      <HintPath>..\lib\Npgsql.2.0.13-beta1\lib\net45\Mono.Security.dll</HintPath>
+    </Reference>
+    <Reference Include="MongoDB">
+      <Private>True</Private>
+      <HintPath>..\lib\mongocsharpdriver.1.8.2\lib\net35\MongoDB.Bson.dll</HintPath>
+    </Reference>
+    <Reference Include="MongoDB">
+      <Private>True</Private>
+      <HintPath>..\lib\mongocsharpdriver.1.8.2\lib\net35\MongoDB.Driver.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Application.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Controllers\HomeController.cs" />
+    <Compile Include="Controllers\JsonController.cs" />
+    <Compile Include="Controllers\PlaintextController.cs" />
+    <Compile Include="Controllers\AdoController.cs" />
+    <Compile Include="Controllers\EntityFrameworkController.cs" />
+    <Compile Include="Controllers\MongoDBController.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Models\EntityFramework.cs" />
+    <Compile Include="Models\MongoDB.cs" />
+    <Compile Include="Models\World.cs" />
+    <Compile Include="Models\Fortune.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Views\Web.config" />
+    <Content Include="Views\Index.cshtml" />
+    <Content Include="Views\Fortunes.cshtml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Web.config">
+      <SubType>Designer</SubType>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Properties\PublishProfiles\IIS.pubxml" />
+  </ItemGroup>
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">.\</SolutionDir>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != '' And Exists('$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets')" />
+  <Import Project="..\lib\MSBuild.Microsoft.VisualStudio.Web.targets.11.0.2.1\tools\VSToolsPath\WebApplications\Microsoft.WebApplication.targets" Condition="('$(VSToolsPath)' == '' Or !Exists('$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets')) And Exists('..\lib\MSBuild.Microsoft.VisualStudio.Web.targets.11.0.2.1\tools\VSToolsPath\WebApplications\Microsoft.WebApplication.targets')" />
+  <Import Project="..\lib\.nuget\NuGet.targets" Condition="Exists('..\lib\.nuget\NuGet.targets')" />
+  <Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)' == 'true'">
+    <AspNetCompiler VirtualPath="/" PhysicalPath="$(WebProjectOutputDir)" />
+  </Target>
+  <ProjectExtensions>
+    <VisualStudio>
+      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
+        <WebProjectProperties>
+          <SaveServerSettingsInUserFile>True</SaveServerSettingsInUserFile>
+        </WebProjectProperties>
+      </FlavorProperties>
+    </VisualStudio>
+  </ProjectExtensions>
+</Project>

+ 26 - 0
aspnet/src/Benchmarks.sln

@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks.AspNet", "Benchmarks.AspNet.csproj", "{62C3DEA2-2696-4200-BD83-011679316847}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{62C3DEA2-2696-4200-BD83-011679316847}.Debug|x64.ActiveCfg = Debug|x86
+		{62C3DEA2-2696-4200-BD83-011679316847}.Debug|x64.Build.0 = Debug|x86
+		{62C3DEA2-2696-4200-BD83-011679316847}.Debug|x86.ActiveCfg = Debug|x86
+		{62C3DEA2-2696-4200-BD83-011679316847}.Debug|x86.Build.0 = Debug|x86
+		{62C3DEA2-2696-4200-BD83-011679316847}.Release|x64.ActiveCfg = Release|x64
+		{62C3DEA2-2696-4200-BD83-011679316847}.Release|x64.Build.0 = Release|x64
+		{62C3DEA2-2696-4200-BD83-011679316847}.Release|x86.ActiveCfg = Release|x86
+		{62C3DEA2-2696-4200-BD83-011679316847}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 169 - 0
aspnet/src/Controllers/AdoController.cs

@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Data.Common;
+using System.Web.Mvc;
+
+using Benchmarks.AspNet.Models;
+
+namespace Benchmarks.AspNet.Controllers
+{
+    public class AdoController : Controller
+    {
+        Random random = new Random();
+
+        private DbConnection CreateConnection(string providerName)
+        {
+            ConnectionStringSettings connectionSettings = ConfigurationManager.ConnectionStrings[providerName];
+            DbProviderFactory factory = DbProviderFactories.GetFactory(connectionSettings.ProviderName);
+            DbConnection connection = factory.CreateConnection();
+            connection.ConnectionString = connectionSettings.ConnectionString;
+            return connection;
+        }
+        
+        public ActionResult Index(string providerName, int? queries)
+        {
+            List<World> worlds = new List<World>(Math.Max(1, Math.Min(500, queries ?? 1)));
+            
+            using (DbConnection connection = CreateConnection(providerName))
+            {
+                connection.Open();
+                
+                using (DbCommand command = connection.CreateCommand())
+                {
+                    command.CommandText = "SELECT * FROM World WHERE id = @ID";
+
+                    for (int i = 0; i < worlds.Capacity; i++)
+                    {
+                        int randomID = random.Next(0, 10000) + 1;
+                        
+                        DbParameter parameter = command.CreateParameter();
+                        parameter.ParameterName = "@ID";
+                        parameter.Value = randomID;
+                        
+                        command.Parameters.Clear();
+                        command.Parameters.Add(parameter);
+                        
+                        // Don't use CommandBehavior.SingleRow because that will make the MySql provider
+                        // send two extra commands to limit the result to one row.
+                        using (DbDataReader reader = command.ExecuteReader())
+                        {
+                            if (reader.Read())
+                            {
+                                worlds.Add(new World
+                                {
+                                    id = reader.GetInt32(0),
+                                    randomNumber = reader.GetInt32(1)
+                                });
+                            }
+                        }
+                    }
+                }
+            }
+            
+            return queries != null ? Json(worlds, JsonRequestBehavior.AllowGet)
+                                   : Json(worlds[0], JsonRequestBehavior.AllowGet);
+        }
+        
+        public ActionResult Fortunes(string providerName)
+        {
+            List<Fortune> fortunes = new List<Fortune>();
+            
+            using (DbConnection connection = CreateConnection(providerName))
+            {
+                connection.Open();
+                
+                using (DbCommand command = connection.CreateCommand())
+                {
+                    command.CommandText = "SELECT * FROM Fortune";
+                    
+                    using (DbDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
+                    {
+                        while (reader.Read())
+                        {
+                            fortunes.Add(new Fortune
+                            {
+                                ID = reader.GetInt32(0),
+                                Message = reader.GetString(1)
+                            });
+                        }
+                    }
+                }
+            }
+            
+            fortunes.Add(new Fortune { ID = 0, Message = "Additional fortune added at request time." });
+            fortunes.Sort();
+            
+            return View("Fortunes", fortunes);
+        }
+
+        public ActionResult Update(string providerName, int? queries)
+        {
+            List<World> worlds = new List<World>(Math.Max(1, Math.Min(500, queries ?? 1)));
+
+            using (DbConnection connection = CreateConnection(providerName))
+            {
+                connection.Open();
+
+                using (DbCommand selectCommand = connection.CreateCommand(),
+                                 updateCommand = connection.CreateCommand())
+                {
+                    selectCommand.CommandText = "SELECT * FROM World WHERE id = @ID";
+                    updateCommand.CommandText = "UPDATE World SET randomNumber = @Number WHERE id = @ID";
+
+                    for (int i = 0; i < worlds.Capacity; i++)
+                    {
+                        int randomID = random.Next(0, 10000) + 1;
+                        int randomNumber = random.Next(0, 10000) + 1;
+
+                        DbParameter idParameter = selectCommand.CreateParameter();
+                        idParameter.ParameterName = "@ID";
+                        idParameter.Value = randomID;
+
+                        selectCommand.Parameters.Clear();
+                        selectCommand.Parameters.Add(idParameter);
+
+                        World world = null;
+
+                        // Don't use CommandBehavior.SingleRow because that will make the MySql provider
+                        // send two extra commands to limit the result to one row.
+                        using (DbDataReader reader = selectCommand.ExecuteReader())
+                        {
+                            if (reader.Read())
+                            {
+                                world = new World
+                                {
+                                    id = reader.GetInt32(0),
+                                    randomNumber = reader.GetInt32(1)
+                                };
+                            }
+                        }
+
+                        if (world == null)
+                            continue;
+                        
+                        DbParameter idUpdateParameter = updateCommand.CreateParameter();
+                        idUpdateParameter.ParameterName = "@ID";
+                        idUpdateParameter.Value = randomID;
+
+                        DbParameter numberParameter = updateCommand.CreateParameter();
+                        numberParameter.ParameterName = "@Number";
+                        numberParameter.Value = randomNumber;
+
+                        updateCommand.Parameters.Clear();
+                        updateCommand.Parameters.Add(idUpdateParameter);
+                        updateCommand.Parameters.Add(numberParameter);
+
+                        updateCommand.ExecuteNonQuery();
+                        
+                        world.randomNumber = randomNumber;
+                        worlds.Add(world);
+                    }
+                }
+            }
+
+            return Json(worlds, JsonRequestBehavior.AllowGet);
+        }
+    }
+}

+ 68 - 0
aspnet/src/Controllers/EntityFrameworkController.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Web.Mvc;
+
+using Benchmarks.AspNet.Models;
+
+namespace Benchmarks.AspNet.Controllers
+{
+    public class EntityFrameworkController : Controller
+    {
+        Random random = new Random();
+
+        public ActionResult Index(string providerName, int? queries)
+        {
+            List<World> worlds = new List<World>(Math.Max(1, Math.Min(500, queries ?? 1)));
+
+            using (EntityFramework db = new EntityFramework(providerName))
+            {
+                for (int i = 0; i < worlds.Capacity; i++)
+                {
+                    int randomID = random.Next(0, 10000) + 1;
+                    worlds.Add(db.Worlds.Find(randomID));
+                }
+            }
+
+            return queries != null ? Json(worlds, JsonRequestBehavior.AllowGet)
+                                   : Json(worlds[0], JsonRequestBehavior.AllowGet);
+        }
+
+        public ActionResult Fortunes(string providerName)
+        {
+            List<Fortune> fortunes = new List<Fortune>();
+
+            using (EntityFramework db = new EntityFramework(providerName))
+            {
+                fortunes.AddRange(db.Fortunes);
+            }
+
+            fortunes.Add(new Fortune { ID = 0, Message = "Additional fortune added at request time." });
+            fortunes.Sort();
+
+            return View("Fortunes", fortunes);
+        }
+
+        public ActionResult Update(string providerName, int? queries)
+        {
+            List<World> worlds = new List<World>(Math.Max(1, Math.Min(500, queries ?? 1)));
+
+            using (EntityFramework db = new EntityFramework(providerName))
+            {
+                for (int i = 0; i < worlds.Capacity; i++)
+                {
+                    int randomID = random.Next(0, 10000) + 1;
+                    int randomNumber = random.Next(0, 10000) + 1;
+                    
+                    World world = db.Worlds.Find(randomID);
+                    world.randomNumber = randomNumber;
+                    worlds.Add(world);
+                }
+
+                // batch update
+                db.SaveChanges();
+            }
+
+            return Json(worlds, JsonRequestBehavior.AllowGet);
+        }
+    }
+}

+ 12 - 0
aspnet/src/Controllers/HomeController.cs

@@ -0,0 +1,12 @@
+using System.Web.Mvc;
+
+namespace Benchmarks.AspNet.Controllers
+{
+    public class HomeController : Controller
+    {
+        public ActionResult Index()
+        {
+            return View();
+        }
+    }
+}

+ 68 - 0
aspnet/src/Controllers/JsonController.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Web;
+using System.Web.Mvc;
+
+namespace Benchmarks.AspNet.Controllers
+{
+    public class JsonController : Controller
+    {
+        public ActionResult Default()
+        {
+            return new JsonResult { Data = new { message = "Hello World" } };
+        }
+
+        public ActionResult JsonNet()
+        {
+            return new JsonNetResult { Data = new { message = "Hello World" } };
+        }
+
+        public ActionResult ServiceStack()
+        {
+            return new ServiceStackResult { Data = new { message = "Hello World" } };
+        }
+    }
+
+    public class JsonResult : ActionResult
+    {
+        public object Data
+        {
+            get;
+            set;
+        }
+
+        public override void ExecuteResult(ControllerContext context)
+        {
+            if (context == null)
+                throw new ArgumentNullException("context");
+
+            HttpResponseBase response = context.HttpContext.Response;
+            response.ContentType = "application/json";
+
+            if (Data != null)
+            {
+                response.Write(Serialize());
+            }
+        }
+
+        protected virtual string Serialize()
+        {
+            return new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Data);
+        }
+    }
+
+    public class JsonNetResult : JsonResult
+    {
+        protected override string Serialize()
+        {
+            return Newtonsoft.Json.JsonConvert.SerializeObject(Data);
+        }
+    }
+
+    public class ServiceStackResult : JsonResult
+    {
+        protected override string Serialize()
+        {
+            return ServiceStack.Text.JsonSerializer.SerializeToString(Data);
+        }
+    }
+}

+ 66 - 0
aspnet/src/Controllers/MongoDBController.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Web.Mvc;
+
+using MongoDB.Driver.Builders;
+
+using Benchmarks.AspNet.Models;
+
+namespace Benchmarks.AspNet.Controllers
+{
+    public class MongoDBController : Controller
+    {
+        Random random = new Random();
+        
+        public ActionResult Index(int? queries)
+        {
+            List<World> worlds = new List<World>(Math.Max(1, Math.Min(500, queries ?? 1)));
+
+            Models.MongoDB db = new Models.MongoDB("MongoDB");
+
+            for (int i = 0; i < worlds.Capacity; i++)
+            {
+                int randomID = random.Next(0, 10000) + 1;
+                worlds.Add(db.Worlds.FindOne(Query<World>.EQ(w => w.id, randomID)));
+            }
+
+            return queries != null ? Json(worlds, JsonRequestBehavior.AllowGet)
+                                   : Json(worlds[0], JsonRequestBehavior.AllowGet);
+        }
+
+        public ActionResult Fortunes()
+        {
+            Models.MongoDB db = new Models.MongoDB("MongoDB");
+
+            List<Fortune> fortunes = db.Fortunes.FindAll().ToList();
+
+            fortunes.Add(new Fortune { ID = 0, Message = "Additional fortune added at request time." });
+            fortunes.Sort();
+
+            return View("Fortunes", fortunes);
+        }
+
+        public ActionResult Update(int? queries)
+        {
+            Models.MongoDB db = new Models.MongoDB("MongoDB");
+
+            List<World> worlds = new List<World>(Math.Max(1, Math.Min(500, queries ?? 1)));
+
+            for (int i = 0; i < worlds.Capacity; i++)
+            {
+                int randomID = random.Next(0, 10000) + 1;
+                int randomNumber = random.Next(0, 10000) + 1;
+
+                World world = db.Worlds.FindOne(Query<World>.EQ(w => w.id, randomID));
+                world.randomNumber = randomNumber;
+                worlds.Add(world);
+
+                db.Worlds.Save(world);
+            }
+
+            return Json(worlds, JsonRequestBehavior.AllowGet);
+        }
+    }
+}

+ 12 - 0
aspnet/src/Controllers/PlaintextController.cs

@@ -0,0 +1,12 @@
+using System.Web.Mvc;
+
+namespace Benchmarks.AspNet.Controllers
+{
+    public class PlaintextController : Controller
+    {
+        public ActionResult Index()
+        {
+            return Content("Hello, World!", "text/plain");
+        }
+    }
+}

+ 55 - 0
aspnet/src/Models/EntityFramework.cs

@@ -0,0 +1,55 @@
+using System;
+using System.Data.Entity;
+using System.Data.Entity.ModelConfiguration.Configuration;
+using System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive;
+using System.Data.Entity.ModelConfiguration.Configuration.Types;
+using System.Data.Entity.ModelConfiguration.Conventions;
+using System.Reflection;
+
+namespace Benchmarks.AspNet.Models
+{
+    public class EntityFramework : DbContext
+    {
+        public DbSet<World> Worlds { get; set; }
+        public DbSet<Fortune> Fortunes { get; set; }
+        
+        public EntityFramework(string providerName)
+            : base(providerName)
+        {
+        }
+        
+        protected override void OnModelCreating(DbModelBuilder modelBuilder)
+        {
+            // disable migrations checks
+            Database.SetInitializer<EntityFramework>(null);
+
+            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
+
+            modelBuilder.Ignore<MongoWorld>();
+            
+            if (Database.Connection is Npgsql.NpgsqlConnection)
+                modelBuilder.Conventions.Add<PostgreSqlConfigurationConvention>();
+        }
+        
+        private class PostgreSqlConfigurationConvention
+            : IConfigurationConvention<Type, EntityTypeConfiguration>, 
+              IConfigurationConvention<PropertyInfo, PrimitivePropertyConfiguration>,
+              IConfigurationConvention<Type, ModelConfiguration>
+        {
+            public void Apply(Type memberInfo, Func<EntityTypeConfiguration> configuration)
+            {
+                configuration().ToTable(memberInfo.Name.ToLowerInvariant(), null);
+            }
+            
+            public void Apply(PropertyInfo memberInfo, Func<PrimitivePropertyConfiguration> configuration)
+            {
+                configuration().ColumnName = memberInfo.Name.ToLowerInvariant();
+            }
+            
+            public void Apply(Type memberInfo, Func<ModelConfiguration> configuration)
+            {
+                configuration().DefaultSchema = "public";
+            }
+        }
+    }
+}

+ 15 - 0
aspnet/src/Models/Fortune.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace Benchmarks.AspNet.Models
+{
+    public class Fortune : IComparable<Fortune>
+    {
+        public int ID { get; set; }
+        public string Message { get; set; }
+        
+        public int CompareTo(Fortune other)
+        {
+            return Message.CompareTo(other.Message);
+        }
+    }
+}

+ 53 - 0
aspnet/src/Models/MongoDB.cs

@@ -0,0 +1,53 @@
+using System.Configuration;
+using System.Web.Script.Serialization;
+
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver;
+
+namespace Benchmarks.AspNet.Models
+{
+    public class MongoDB
+    {
+        public MongoCollection<MongoWorld> Worlds { get; private set; }
+        public MongoCollection<Fortune> Fortunes { get; private set; }
+
+        static MongoDB()
+        {
+            BsonClassMap.RegisterClassMap<World>(m =>
+            {
+                m.MapProperty(w => w.id);
+                m.MapProperty(w => w.randomNumber);
+            });
+
+            BsonClassMap.RegisterClassMap<MongoWorld>(m =>
+            {
+                m.MapIdProperty(w => w._id);
+            });
+
+            BsonClassMap.RegisterClassMap<Fortune>(m =>
+            {
+                m.MapProperty(f => f.ID).SetElementName("id");
+                m.MapProperty(f => f.Message).SetElementName("message");
+            });
+        }
+
+        public MongoDB(string connectionStringName)
+        {
+            string connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
+
+            MongoClient client = new MongoClient(connectionString);
+            MongoServer server = client.GetServer();
+            MongoDatabase database = server.GetDatabase("hello_world");
+
+            Worlds = database.GetCollection<MongoWorld>("world");
+            Fortunes = database.GetCollection<Fortune>("fortune");
+        }
+    }
+
+    public class MongoWorld : World
+    {
+        [ScriptIgnore]
+        public ObjectId _id { get; set; }
+    }
+}

+ 8 - 0
aspnet/src/Models/World.cs

@@ -0,0 +1,8 @@
+namespace Benchmarks.AspNet.Models
+{
+    public class World
+    {
+        public int id { get; set; }
+        public int randomNumber { get; set; }
+    }
+}

+ 75 - 0
aspnet/src/Properties/PublishProfiles/IIS.pubxml

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit http://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <WebPublishMethod>MSDeploy</WebPublishMethod>
+    <MSDeployServiceURL>localhost</MSDeployServiceURL>
+    <DeployIisAppPath>Benchmarks</DeployIisAppPath>
+    <RemoteSitePhysicalPath />
+    <SkipExtraFilesOnServer>False</SkipExtraFilesOnServer>
+    <MSDeployPublishMethod>InProc</MSDeployPublishMethod>
+    <UserName />
+    <_SavePWD>False</_SavePWD>
+    <PublishDatabaseSettings>
+      <Objects xmlns="">
+        <ObjectGroup Name="Benchmarks.AspNet.Models.EntityFramework" Order="1" Enabled="False">
+          <Destination Path="" />
+          <Object Type="DbCodeFirst">
+            <Source Path="DBContext" DbContext="Benchmarks.AspNet.Models.EntityFramework, Benchmarks.AspNet" />
+          </Object>
+        </ObjectGroup>
+        <ObjectGroup Name="PostgreSQL" Order="2" Enabled="False">
+          <Destination Path="" />
+          <Object Type="DbDacFx">
+            <PreSource Path="server=localhost;user id=benchmarkdbuser;password=benchmarkdbpass;database=hello_world" includeData="False" />
+            <Source Path="$(IntermediateOutputPath)AutoScripts\PostgreSQL_IncrementalSchemaOnly.dacpac" dacpacAction="Deploy" />
+          </Object>
+          <UpdateFrom Type="Web.Config">
+            <Source MatchValue="server=localhost;user id=benchmarkdbuser;password=benchmarkdbpass;database=hello_world" MatchAttributes="$(UpdateFromConnectionStringAttributes)" />
+          </UpdateFrom>
+        </ObjectGroup>
+        <ObjectGroup Name="MongoDB" Order="3" Enabled="False">
+          <Destination Path="" />
+          <Object Type="DbDacFx">
+            <PreSource Path="mongodb://localhost" includeData="False" />
+            <Source Path="$(IntermediateOutputPath)AutoScripts\MongoDB_IncrementalSchemaOnly.dacpac" dacpacAction="Deploy" />
+          </Object>
+          <UpdateFrom Type="Web.Config">
+            <Source MatchValue="mongodb://localhost" MatchAttributes="$(UpdateFromConnectionStringAttributes)" />
+          </UpdateFrom>
+        </ObjectGroup>
+        <ObjectGroup Name="MySQL" Order="4" Enabled="False">
+          <Destination Path="" />
+          <Object Type="DbDacFx">
+            <PreSource Path="server=localhost;user id=benchmarkdbuser;password=benchmarkdbpass;database=hello_world" includeData="False" />
+            <Source Path="$(IntermediateOutputPath)AutoScripts\MySQL_IncrementalSchemaOnly.dacpac" dacpacAction="Deploy" />
+          </Object>
+          <UpdateFrom Type="Web.Config">
+            <Source MatchValue="server=localhost;user id=benchmarkdbuser;password=benchmarkdbpass;database=hello_world" MatchAttributes="$(UpdateFromConnectionStringAttributes)" />
+          </UpdateFrom>
+        </ObjectGroup>
+      </Objects>
+    </PublishDatabaseSettings>
+    <LastUsedBuildConfiguration>Debug</LastUsedBuildConfiguration>
+    <LastUsedPlatform>x64</LastUsedPlatform>
+    <ExcludeApp_Data>True</ExcludeApp_Data>
+    <EnableMSDeployBackup>False</EnableMSDeployBackup>
+    <SiteUrlToLaunchAfterPublish>/</SiteUrlToLaunchAfterPublish>
+    <PrecompileBeforePublish>True</PrecompileBeforePublish>
+    <EnableUpdateable>False</EnableUpdateable>
+    <DebugSymbols>False</DebugSymbols>
+    <WDPMergeOption>DonotMerge</WDPMergeOption>
+  </PropertyGroup>
+  <ItemGroup>
+    <MSDeployParameterValue Include="$(DeployParameterPrefix)Benchmarks.AspNet.Models.EntityFramework-Web.config Connection String" />
+    <MSDeployParameterValue Include="$(DeployParameterPrefix)MongoDB-Web.config Connection String" />
+    <MSDeployParameterValue Include="$(DeployParameterPrefix)MySQL-Web.config Connection String" />
+    <MSDeployParameterValue Include="$(DeployParameterPrefix)PostgreSQL-Web.config Connection String" />
+  </ItemGroup>
+  <ItemGroup>
+    <_ConnectionStringsToInsert Include="Benchmarks.AspNet.Models.EntityFramework" />
+  </ItemGroup>
+</Project>

+ 26 - 0
aspnet/src/Views/Fortunes.cshtml

@@ -0,0 +1,26 @@
+@model IEnumerable<Benchmarks.AspNet.Models.Fortune>
+
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Fortunes</title>
+</head>
+<body>
+
+<table>
+<tr>
+    <th>id</th>
+    <th>message</th>
+</tr>
+@foreach (var fortune in Model)
+{
+<tr>
+    <td>@fortune.ID</td>
+    <td>@fortune.Message</td>
+</tr>
+}
+</table>
+
+</body>
+</html>

+ 64 - 0
aspnet/src/Views/Index.cshtml

@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf8">
+    <title>Index</title>
+</head>
+<body>
+
+    <h1>ASP.NET Benchmarks</h1>
+
+    <h2>JSON</h2>
+    <ul>
+        <li><em>Default serializer:</em> <a href="/json/default">/json/default</a></li>
+        <li><em>Json.NET</em> <a href="/json/jsonnet">/json/jsonnet</a></li>
+        <li><em>ServiceStack.Text</em> <a href="/json/servicestack">/json/servicestack</a></li>
+    </ul>
+
+    <h2>Plaintext</h2>
+    <ul>
+        <li><a href="/plaintext">/plaintext</a></li>
+    </ul>
+
+    <h2>ADO.NET (Raw)</h2>
+    <h3>MySQL</h3>
+    <ul>
+        <li><em>DB:</em> <a href="/ado/mysql">/ado/mysql</a></li>
+        <li><em>Queries:</em> <a href="/ado/mysql?queries=10">/ado/mysql?queries=10</a></li>
+        <li><em>Fortunes:</em> <a href="/ado/mysql/fortunes">/ado/mysql/fortunes</a></li>
+        <li><em>Update:</em> <a href="/ado/mysql/update?queries=10">/ado/mysql/update?queries=10</a></li>
+    </ul>
+    <h3>PostgreSQL</h3>
+    <ul>
+        <li><em>DB:</em> <a href="/ado/postgresql">/ado/postgresql</a></li>
+        <li><em>Queries:</em> <a href="/ado/postgresql?queries=10">/ado/postgresql?queries=10</a></li>
+        <li><em>Fortunes:</em> <a href="/ado/postgresql/fortunes">/ado/postgresql/fortunes</a></li>
+        <li><em>Update:</em> <a href="/ado/postgresql/update?queries=10">/ado/postgresql/update?queries=10</a></li>
+    </ul>
+
+    <h2>Entity Framework (ORM)</h2>
+    <h3>MySQL</h3>
+    <ul>
+        <li><em>DB:</em> <a href="/entityframework/mysql">/entityframework/mysql</a></li>
+        <li><em>Queries:</em> <a href="/entityframework/mysql?queries=10">/entityframework/mysql?queries=10</a></li>
+        <li><em>Fortunes:</em> <a href="/entityframework/mysql/fortunes">/entityframework/mysql/fortunes</a></li>
+        <li><em>Update:</em> <a href="/entityframework/mysql/update?queries=10">/entityframework/mysql/update?queries=10</a></li>
+    </ul>
+    <h3>PostgreSQL</h3>
+    <ul>
+        <li><em>DB:</em> <a href="/entityframework/postgresql">/entityframework/postgresql</a></li>
+        <li><em>Queries:</em> <a href="/entityframework/postgresql?queries=10">/entityframework/postgresql?queries=10</a></li>
+        <li><em>Fortunes:</em> <a href="/entityframework/postgresql/fortunes">/entityframework/postgresql/fortunes</a></li>
+        <li><em>Update:</em> <a href="/entityframework/postgresql/update?queries=10">/entityframework/postgresql/update?queries=10</a></li>
+    </ul>
+
+    <h2>MongoDB</h2>
+    <ul>
+        <li><em>DB:</em> <a href="/mongodb">/mongodb</a></li>
+        <li><em>Queries:</em> <a href="/mongodb?queries=10">/mongodb?queries=10</a></li>
+        <li><em>Fortunes:</em> <a href="/mongodb/fortunes">/mongodb/fortunes</a></li>
+        <li><em>Update:</em> <a href="/mongodb/update?queries=10">/mongodb/update?queries=10</a></li>
+    </ul>
+
+</body>
+</html>

+ 33 - 0
aspnet/src/Views/Web.config

@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<configuration>
+  <configSections>
+    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
+      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
+    </sectionGroup>
+  </configSections>
+  <system.web.webPages.razor>
+    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
+    <pages pageBaseType="System.Web.Mvc.WebViewPage">
+      <namespaces>
+        <add namespace="System.Web.Mvc" />
+        <add namespace="System.Web.Mvc.Html" />
+      </namespaces>
+    </pages>
+  </system.web.webPages.razor>
+  <appSettings>
+    <add key="webpages:Enabled" value="false" />
+  </appSettings>
+  <system.web>
+    <httpHandlers>
+      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
+    </httpHandlers>
+  </system.web>
+  <system.webServer>
+    <validation validateIntegratedModeConfiguration="false" />
+    <handlers>
+      <remove name="BlockViewHandler"/>
+      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
+    </handlers>
+  </system.webServer>
+</configuration>

+ 62 - 0
aspnet/src/Web.config

@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<configuration>
+  <configSections>
+    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
+  </configSections>
+  <!-- Connection Strings -->
+  <!-- Names are case insensitive -->
+  <connectionStrings>
+    <add name="MySQL" connectionString="server=localhost; user id=benchmarkdbuser; password=benchmarkdbpass; database=hello_world" providerName="MySql.Data.MySqlClient"/>
+    <add name="PostgreSQL" connectionString="server=localhost; user id=benchmarkdbuser; password=benchmarkdbpass; database=hello_world" providerName="Npgsql"/>
+    <add name="MongoDB" connectionString="mongodb://localhost"/>
+    <add name="SQLServer" connectionString="server=localhost; user id=benchmarkdbuser; password=B3nchmarkDBPass; database=hello_world" providerName="System.Data.SqlClient"/>
+  </connectionStrings>
+  <!-- ADO.NET -->
+  <system.data>
+    <DbProviderFactories>
+      <clear/>
+      <add name="MySql.Data.MySqlClient" description="Data Provider for MySQL" invariant="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.7.2.0"/>
+      <add name="Npgsql" description="Data Provider for PostgreSQL" invariant="Npgsql" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.13.91"/>
+      <add name="System.Data.SqlClient" description="Data Provider for Microsoft SQL Server" invariant="System.Data.SqlClient" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=4.0.0.0"/>
+    </DbProviderFactories>
+  </system.data>
+  <!-- Entity Framework -->
+  <entityFramework>
+    <providers>
+      <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity, Version=6.7.2.0"/>
+      <provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, Npgsql, Version=2.0.13.91"/>
+      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
+    </providers>
+  </entityFramework>
+  <appSettings>
+    <!-- Disable support for directly accessing *.cshtml/*.vbhtml files because that is a perf killer
+         and because we don't use such functionality. -->
+    <add key="webpages:Enabled" value="false" />
+    <!-- To fully saturate the CPUs, we need to allow the .NET thread pool to create many threads
+         when a large burst of requests come in. We do this by boosting the minWorkerThreads value
+         from the default of 1 per logical processor to 8 per logical processor. This seems to be
+         pretty conservative as http://support.microsoft.com/kb/821268 recommends 50.-->
+    <add key="minWorkerThreadsPerLogicalProcessor" value="8" />
+  </appSettings>
+  <system.web>
+    <!-- Show errors -->
+    <customErrors mode="Off"/>
+  </system.web>
+  <!-- Register the application as an HTTP module -->
+  <system.webServer>
+    <!-- Used by IIS -->
+    <modules>
+      <remove name="Framework Benchmarks"/>
+      <add name="Framework Benchmarks" type="Benchmarks.AspNet.Application"/>
+    </modules>
+    <!-- In IIS >= 7.0 it's not possible to have both <httpModules> and <modules>, this setting disables the warning -->
+    <validation validateIntegratedModeConfiguration="false"/>
+  </system.webServer>
+  <system.web>
+    <!-- Used by the XSP web server on mono -->
+    <httpModules>
+      <remove name="Framework Benchmarks"/>
+      <add name="Framework Benchmarks" type="Benchmarks.AspNet.Application"/>
+    </httpModules>
+  </system.web>
+</configuration>

+ 0 - 0
ringojs-convinient/__init__.py → beego/.gitkeep


+ 18 - 0
beego/README.md

@@ -0,0 +1,18 @@
+# Beego Benchmarking Test
+
+This is the Beego portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [Beego JSON output](https://github.com/astaxie/beego/blob/master/docs/en/Quickstart.md#output-json-and-xml)
+
+## Versions
+
+* [Go 1.1](http://golang.org/)
+* [Beego](https://github.com/astaxie/beego/)
+
+## Test URLs
+
+### JSON Encoding Test
+
+    http://localhost:8080/json

+ 0 - 0
beego/__init__.py


+ 23 - 0
beego/benchmark_config

@@ -0,0 +1,23 @@
+{
+  "framework": "beego",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "None",
+      "framework": "beego",
+      "language": "Go",
+      "orm": "Raw",
+      "platform": "Go",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "beego",
+      "notes": "",
+      "versus": "go"
+    }
+  }]
+}

+ 0 - 0
beego/bin/.gitkepp


+ 0 - 0
beego/pkg/.gitkeep


+ 2 - 0
beego/setup.bat

@@ -0,0 +1,2 @@
+set GOPATH=C:\FrameworkBenchmarks\beego
+go run src\hello\hello.go

+ 25 - 0
beego/setup.py

@@ -0,0 +1,25 @@
+
+import subprocess
+import sys
+import os
+
+def start(args):
+  if os.name == 'nt':
+    subprocess.call("set GOPATH=C:\\FrameworkBenchmarks\\beego&&go get ./...", shell=True, cwd="beego")
+    subprocess.Popen("setup.bat", shell=True, cwd="beego")
+    return 0
+  subprocess.call("go get ./...", shell=True, cwd="beego")
+  subprocess.Popen("go run src/hello/hello.go".rsplit(" "), cwd="beego")
+  return 0
+def stop():
+  if os.name == 'nt':
+    subprocess.call("taskkill /f /im go.exe > NUL", shell=True)
+    subprocess.call("taskkill /f /im hello.exe > NUL", shell=True)
+    return 0
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'hello' in line:
+      pid = int(line.split(None, 2)[1])
+      os.kill(pid, 9)
+  return 0

+ 28 - 0
beego/src/hello/hello.go

@@ -0,0 +1,28 @@
+package main
+
+import (
+	"github.com/astaxie/beego"
+	"runtime"
+)
+
+type MessageStruct struct {
+	Message string
+}
+
+type JsonController struct {
+	beego.Controller
+}
+
+func (this *JsonController) Get() {
+	m := MessageStruct{"Hello, world"}
+	this.Data["json"] = &m
+	this.ServeJson()
+}
+
+func main() {
+	//don't need this set, beego default set it
+	//runtime.GOMAXPROCS(runtime.NumCPU())
+	beego.RunMode = "prod"
+	beego.Router("/json", &JsonController{})
+	beego.Run()
+}

+ 10 - 1
bottle/README.md

@@ -22,4 +22,13 @@ With ORM:
     http://localhost:8080/db?queries=2
 
 Without ORM (raw):
-    http://localhost:8080/dbraw?queries=2
+    http://localhost:8080/dbraw?queries=2
+
+### Fortune Test
+
+With ORM:
+    http://localhost:8080/fortune
+
+Without ORM (raw):
+    http://localhost:8080/fortuneraw
+

+ 118 - 31
bottle/app.py

@@ -1,17 +1,27 @@
-from bottle import Bottle, route, request, run
+from bottle import Bottle, route, request, run, template, response
 from bottle.ext import sqlalchemy 
-from sqlalchemy import create_engine, Column, Integer
+from sqlalchemy import create_engine, Column, Integer, Unicode
 from sqlalchemy.ext.declarative import declarative_base
 from random import randint
-import ujson
+import sys
+from operator import attrgetter, itemgetter
+from functools import partial
+
+try:
+    import ujson as json
+except ImportError:
+    import json
 
 app = Bottle()
-app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world'
+app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world?charset=utf8'
 Base = declarative_base()
 db_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])
 plugin = sqlalchemy.Plugin(db_engine, keyword='db', )
 app.install(plugin)
 
+if sys.version_info[0] == 3:
+    xrange = range
+
 
 class World(Base):
   __tablename__ = "World"
@@ -27,46 +37,123 @@ class World(Base):
          'randomNumber': self.randomNumber
      }
 
+class Fortune(Base):
+  __tablename__ = "Fortune"
+  id = Column(Integer, primary_key=True)
+  message = Column(Unicode)
+
+
 @app.route("/json")
 def hello():
-  resp = {"message": "Hello, World!"}
-  return ujson.dumps(resp)
+    response.content_type = 'application/json'
+    resp = {"message": "Hello, World!"}
+    return json.dumps(resp)
 
 @app.route("/db")
 def get_random_world(db):
-  num_queries = request.query.queries or '1'
-  worlds = []
-  for i in range(int(num_queries)):
-    wid = randint(1, 10000)
-    worlds.append(db.query(World).get(wid).serialize)
-  return ujson.dumps(worlds)
+    num_queries = request.query.get('queries', 1, type=int)
+    worlds = []
+    rp = partial(randint, 1, 10000)
+    for i in xrange(num_queries):
+        worlds.append(db.query(World).get(rp()).serialize)
+    response.content_type = 'application/json'
+    return json.dumps(worlds)
 
 @app.route("/dbs")
 def get_random_world_single(db):
-  wid = randint(1, 10000)
-  worlds = [db.query(World).get(wid).serialize]
-  return ujson.dumps(worlds)
+    wid = randint(1, 10000)
+    worlds = [db.query(World).get(wid).serialize]
+    response.content_type = 'application/json'
+    return json.dumps(worlds)
   
 @app.route("/dbraw")
 def get_random_world_raw():
-  connection = db_engine.connect()
-  num_queries = request.query.queries or '1'
-  worlds = []
-  for i in range(int(num_queries)):
-    wid = randint(1, 10000)
-    result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
-    worlds.append({'id': result[0], 'randomNumber': result[1]})
-  connection.close()
-  return ujson.dumps(worlds)
+    connection = db_engine.connect()
+    num_queries = request.query.get('queries', 1, type=int)
+    worlds = []
+    rp = partial(randint, 1, 10000)
+    for i in xrange(int(num_queries)):
+        result = connection.execute("SELECT * FROM world WHERE id = " + str(rp())).fetchone()
+        worlds.append({'id': result[0], 'randomNumber': result[1]})
+    connection.close()
+    response.content_type = 'application/json'
+    return json.dumps(worlds)
 
 @app.route("/dbsraw")
 def get_random_world_single_raw():
-  connection = db_engine.connect()
-  wid = randint(1, 10000)
-  result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
-  worlds = [{'id': result[0], 'randomNumber': result[1]}]
-  connection.close()
-  return ujson.dumps(worlds)
+    connection = db_engine.connect()
+    wid = randint(1, 10000)
+    result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
+    worlds = [{'id': result[0], 'randomNumber': result[1]}]
+    connection.close()
+    response.content_type = 'application/json'
+    return json.dumps(worlds)
+
[email protected]("/fortune")
+def fortune_orm(db):
+  fortunes=db.query(Fortune).all()
+  fortunes.append(Fortune(message="Additional fortune added at request time."))
+  fortunes=sorted(fortunes, key=attrgetter('message'))
+  return template('fortune-obj', fortunes=fortunes)
+
[email protected]("/fortuneraw")
+def fortune_raw():
+    connection = db_engine.connect()
+    fortunes=[(f.id, f.message) for f in connection.execute("SELECT * FROM Fortune")]
+    fortunes.append((0, u'Additional fortune added at request time.'))
+    fortunes=sorted(fortunes, key=itemgetter(1))
+    connection.close()
+    return template('fortune', fortunes=fortunes)
+
+
[email protected]("/updates")
+def updates(db):
+    """Test 5: Database Updates"""
+    num_queries = request.query.get('queries', 1, type=int)
+    if num_queries > 500:
+        num_queries = 500
+
+    worlds = []
+    rp = partial(randint, 1, 10000)
+    ids = [rp() for _ in xrange(num_queries)]
+    ids.sort()  # To avoid deadlock
+    for id in ids:
+        world = db.query(World).get(id)
+        world.randomNumber = rp()
+        worlds.append(world.serialize)
+
+    response.content_type = 'application/json'
+    return json.dumps(worlds)
+
+
[email protected]("/raw-updates")
+def raw_updates():
+    """Test 5: Database Updates"""
+    num_queries = request.query.get('queries', 1, type=int)
+    if num_queries > 500:
+        num_queries = 500
+
+    conn = db_engine.connect()
+
+    worlds = []
+    rp = partial(randint, 1, 10000)
+    for i in xrange(num_queries):
+        world = conn.execute("SELECT * FROM World WHERE id=%s", (rp(),)).fetchone()
+        randomNumber = rp()
+        worlds.append({'id': world['id'], 'randomNumber': randomNumber})
+        conn.execute("UPDATE World SET randomNumber=%s WHERE id=%s",
+                     (randomNumber, world['id']))
+    conn.close()
+    response.content_type = 'application/json'
+    return json.dumps(worlds)
+
+
[email protected]('/plaintext')
+def plaintext():
+    """Test 6: Plaintext"""
+    response.content_type = 'text/plain'
+    return b'Hello, World!'
+
 
 if __name__ == "__main__":
-    app.run()
+    app.run(host='0.0.0.0', debug=False)

+ 77 - 2
bottle/benchmark_config

@@ -6,15 +6,90 @@
       "json_url": "/json",
       "db_url": "/dbs",
       "query_url": "/db?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/updates?queries=",
+      "plaintext_url": "/plaintext",
       "port": 8080,
-      "sort": 88
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "bottle",
+      "language": "Python",
+      "orm": "Full",
+      "platform": "wsgi",
+      "webserver": "Gunicorn",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "bottle",
+      "notes": "",
+      "versus": "wsgi"
+    },
+    "py3": {
+      "setup_file": "setup_py3",
+      "json_url": "/json",
+      "db_url": "/dbs",
+      "query_url": "/db?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/updates?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "bottle",
+      "language": "Python",
+      "orm": "Full",
+      "platform": "wsgi",
+      "webserver": "Gunicorn",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "bottle-py3",
+      "notes": "",
+      "versus": "wsgi"
+    },
+    "pypy": {
+      "setup_file": "setup_pypy",
+      "json_url": "/json",
+      "db_url": "/dbs",
+      "query_url": "/db?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/updates?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "bottle",
+      "language": "Python",
+      "orm": "Full",
+      "platform": "wsgi",
+      "webserver": "Gunicorn",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "bottle-pypy",
+      "notes": "",
+      "versus": "wsgi"
     },
     "mysql-raw": {
       "setup_file": "setup",
       "db_url": "/dbsraw",
       "query_url": "/dbraw?queries=",
+      "fortune_url": "/fortuneraw",
+      "update_url": "/raw-updates?queries=",
       "port": 8080,
-      "sort": 89
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "bottle",
+      "language": "Python",
+      "orm": "Raw",
+      "platform": "wsgi",
+      "webserver": "Gunicorn",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "bottle-raw",
+      "notes": "",
+      "versus": "wsgi"
     }
   }]
 }

+ 25 - 16
bottle/setup.py

@@ -1,23 +1,32 @@
 import subprocess
-import sys
 import setup_util
+import multiprocessing
 import os
 
+bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py2/bin')
+NCPU = multiprocessing.cpu_count()
+
+proc = None
+
+
 def start(args):
-  setup_util.replace_text("bottle/app.py", "DBHOSTNAME", args.database_host)
-  subprocess.Popen("gunicorn app:app --worker-class=\"egg:meinheld#gunicorn_worker\" -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --preload --log-level=critical", shell=True, cwd="bottle")
-  
-  return 0
+    global proc
+    setup_util.replace_text("bottle/app.py", "DBHOSTNAME", args.database_host)
+    proc = subprocess.Popen([
+        bin_dir + "/gunicorn",
+        "app:app",
+        "-k", "meinheld.gmeinheld.MeinheldWorker",
+        "-b", "0.0.0.0:8080",
+        '-w', str(NCPU*3),
+        "--log-level=critical"],
+        cwd="bottle")
+    return 0
 
 def stop():
-  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
-  out, err = p.communicate()
-  for line in out.splitlines():
-    if 'gunicorn' in line:
-      try:
-        pid = int(line.split(None, 2)[1])
-        os.kill(pid, 9)
-      except OSError:
-        pass
-  
-  return 0
+    global proc
+    if proc is None:
+        return 0
+    proc.terminate()
+    proc.wait()
+    proc = None
+    return 0

+ 32 - 0
bottle/setup_py3.py

@@ -0,0 +1,32 @@
+import subprocess
+import setup_util
+import multiprocessing
+import os
+
+bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py3/bin')
+NCPU = multiprocessing.cpu_count()
+
+proc = None
+
+
+def start(args):
+    global proc
+    setup_util.replace_text("bottle/app.py", "DBHOSTNAME", args.database_host)
+    proc = subprocess.Popen([
+        bin_dir + "/gunicorn",
+        "app:app",
+        "-k", "meinheld.gmeinheld.MeinheldWorker",
+        "-b", "0.0.0.0:8080",
+        '-w', str(NCPU*3),
+        "--log-level=critical"],
+        cwd="bottle")
+    return 0
+
+def stop():
+    global proc
+    if proc is None:
+        return 0
+    proc.terminate()
+    proc.wait()
+    proc = None
+    return 0

+ 33 - 0
bottle/setup_pypy.py

@@ -0,0 +1,33 @@
+import subprocess
+import setup_util
+import multiprocessing
+import os
+
+bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/pypy/bin')
+NCPU = multiprocessing.cpu_count()
+
+proc = None
+
+
+def start(args):
+    global proc
+    setup_util.replace_text("bottle/app.py", "DBHOSTNAME", args.database_host)
+    proc = subprocess.Popen([
+        bin_dir + "/gunicorn",
+        "app:app",
+        "-k", "tornado",
+        "-b", "0.0.0.0:8080",
+        '-w', str(NCPU*3),
+        "--log-level=critical"],
+        cwd="bottle")
+    return 0
+
+def stop():
+    global proc
+    if proc is None:
+        return 0
+    proc.terminate()
+    proc.wait()
+    proc = None
+    return 0
+

+ 13 - 0
bottle/views/fortune-obj.tpl

@@ -0,0 +1,13 @@
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+% for fortune in fortunes:
+<tr>
+<td>{{ fortune.id }}</td>
+<td>{{ fortune.message }}</td>
+</tr>
+% end
+</table>
+%rebase layout

+ 13 - 0
bottle/views/fortune.tpl

@@ -0,0 +1,13 @@
+<table>
+<tr>
+<th>id</th>
+<th>message</th>
+</tr>
+% for fortune in fortunes:
+<tr>
+<td>{{ fortune[0] }}</td>
+<td>{{ fortune[1] }}</td>
+</tr>
+% end
+</table>
+%rebase layout

+ 9 - 0
bottle/views/layout.tpl

@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+  %include
+</body>
+</html>

+ 2 - 2
cake/app/Config/database.php

@@ -67,7 +67,7 @@ class DATABASE_CONFIG {
 		'password' => 'benchmarkdbpass',
 		'database' => 'hello_world',
 		'prefix' => '',
-		//'encoding' => 'utf8',
+		'encoding' => 'utf8',
 	);
 
 	public $test = array(
@@ -78,6 +78,6 @@ class DATABASE_CONFIG {
 		'password' => 'benchmarkdbpass',
 		'database' => 'hello_world',
 		'prefix' => '',
-		//'encoding' => 'utf8',
+		'encoding' => 'utf8',
 	);
 }

+ 31 - 0
cake/app/Controller/FortunesController.php

@@ -0,0 +1,31 @@
+<?php
+
+App::uses('AppController', 'Controller');
+
+class FortunesController extends AppController {
+
+	public function index() {
+		// use full view stack as encouraged by test rules
+		$this->layout = 'benchmark';
+		$this->set('title_for_layout', 'Fortunes');
+
+		// using prepared query as encouraged by test rules
+		$db      = $this->Fortune->getDataSource();
+		$results = $db->fetchAll('SELECT * FROM Fortune');
+
+		// stuffing in the dynamic data
+		$results[]['Fortune'] = [
+			'id'      => 0,
+			'message' => 'Additional fortune added at request time.'
+		];
+
+		// because we are performance concerned we don't use Hash::sort()
+		foreach ($results as $result) {
+			$fortunes[$result['Fortune']['id']] = $result['Fortune']['message'];
+		}
+		asort($fortunes);
+
+		$this->set('fortunes', $fortunes);
+	}
+
+}

+ 24 - 0
cake/app/Controller/PlaintextController.php

@@ -0,0 +1,24 @@
+<?php
+
+App::uses('AppController', 'Controller');
+
+class PlaintextController extends AppController {
+
+	public function index() {
+		$this->autoRender = false;
+		header("Content-type: text/plain");
+		echo 'Hello, World!';
+
+		/*
+		 * Because this test is focused on routing we don't involve the view.
+		 *
+		 * Normally we would create a template file index.ctp containing "Hello, World!"
+		 * in app/View/Plaintext and:
+		 *
+
+		$this->autoLayout = false;
+		$this->response->type('text');
+
+		 */
+	}
+}

+ 6 - 0
cake/app/Model/Fortune.php

@@ -0,0 +1,6 @@
+<?php
+
+class Fortune extends AppModel {
+	public $useTable = 'Fortune'; // This model uses a database table 'Fortune'
+}
+

+ 14 - 0
cake/app/View/Fortunes/index.ctp

@@ -0,0 +1,14 @@
+<table>
+	<tr>
+		<th>id</th>
+		<th>message</th>
+	</tr>
+	<?php
+	foreach ($fortunes as $key => $fortune) {
+		?>
+		<tr>
+			<td><?php echo $key; ?></td>
+			<td><?php echo h($fortune); ?></td>
+		</tr>
+	<?php } ?>
+</table>

+ 11 - 0
cake/app/View/Layouts/benchmark.ctp

@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<title>
+		<?php echo $title_for_layout; ?>
+	</title>
+</head>
+<body>
+	<?php echo $this->fetch('content'); ?>
+</body>
+</html>

+ 17 - 0
cake/app/webroot/web.config

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+ <system.webServer>
+   <rewrite>
+    <rules>
+     <rule name="Rewrite" stopProcessing="true">
+      <match url=".*" ignoreCase="false" />
+      <conditions>
+       <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
+       <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
+      </conditions>
+      <action type="Rewrite" url="index.php?" appendQueryString="true" />
+     </rule> 
+    </rules>
+   </rewrite>
+ </system.webServer> 
+</configuration>

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