Browse Source

Merge branch 'master' into ninja

Kpacha 11 years ago
parent
commit
0a73f27a65
100 changed files with 1709 additions and 286 deletions
  1. 2 0
      .gitignore
  2. 53 0
      HttpListener/HttpListener/Program.cs
  3. 5 5
      HttpListener/benchmark_config
  4. 20 2
      HttpListener/setup.ps1
  5. 2 2
      HttpListener/setup.py
  6. 88 30
      README.md
  7. 19 1
      aspnet-stripped/setup_iis.ps1
  8. 2 2
      aspnet-stripped/setup_iis.py
  9. 3 3
      aspnet/benchmark_config
  10. 21 3
      aspnet/setup_iis.ps1
  11. 2 2
      aspnet/setup_iis.py
  12. 1 1
      bottle/app.py
  13. 1 1
      bottle/benchmark_config
  14. 2 2
      config/benchmark_profile
  15. 29 0
      config/create-postgres-old.sql
  16. 29 0
      config/create-postgres-upper-quote.sql
  17. 15 15
      config/create-postgres.sql
  18. 6 3
      config/nginx_uwsgi.conf
  19. 3 2
      config/uwsgi.ini
  20. 5 0
      cowboy/.gitignore
  21. 4 0
      cowboy/Makefile
  22. 34 0
      cowboy/README.md
  23. 25 0
      cowboy/benchmark_config
  24. BIN
      cowboy/rebar
  25. 7 0
      cowboy/rebar.config
  26. 20 0
      cowboy/setup_erlang.py
  27. 7 0
      cowboy/source_code
  28. 29 0
      cowboy/src/db_handler.erl
  29. 15 0
      cowboy/src/hello_world.app.src
  30. 14 0
      cowboy/src/hello_world.erl
  31. 32 0
      cowboy/src/hello_world_app.erl
  32. 23 0
      cowboy/src/hello_world_sup.erl
  33. 18 0
      cowboy/src/json_handler.erl
  34. 4 3
      dancer/nginx.conf
  35. 7 6
      dart-start/README.md
  36. 6 5
      dart-start/pubspec.yaml
  37. 0 7
      django-stripped/source_code
  38. 5 0
      elli/.gitignore
  39. 33 0
      elli/README.md
  40. 25 0
      elli/benchmark_config
  41. BIN
      elli/rebar
  42. 6 0
      elli/rebar.config
  43. 21 0
      elli/setup_erlang.py
  44. 6 0
      elli/source_code
  45. 12 0
      elli/src/elli_bench.app.src
  46. 5 0
      elli/src/elli_bench.erl
  47. 16 0
      elli/src/elli_bench_app.erl
  48. 36 0
      elli/src/elli_bench_cb.erl
  49. 42 0
      elli/src/elli_bench_sup.erl
  50. 1 1
      falcon/benchmark_config
  51. 1 1
      flask/app.py
  52. 7 7
      flask/benchmark_config
  53. 1 1
      go/README.md
  54. 2 11
      grails/README.md
  55. 3 2
      grails/benchmark_config
  56. 2 2
      grails/hello/application.properties
  57. 2 3
      grails/hello/grails-app/conf/BuildConfig.groovy
  58. 24 0
      grails/hello/grails-app/conf/Config.groovy
  59. 4 3
      grails/hello/web-app/WEB-INF/applicationContext.xml
  60. 244 98
      grails/hello/web-app/WEB-INF/tld/spring.tld
  61. 3 3
      grizzly-bm/pom.xml
  62. 5 3
      grizzly-bm/src/main/java/org/glassfish/grizzly/bm/Server.java
  63. 11 4
      grizzly-jersey/src/main/java/hello/JerseyWebServer.java
  64. 4 3
      kelp/nginx.conf
  65. 4 3
      mojolicious/nginx.conf
  66. 21 2
      nancy/setup_iis.ps1
  67. 2 2
      nancy/setup_iis.py
  68. 1 1
      php-kohana/benchmark_config
  69. 1 1
      php-phalcon-micro/benchmark_config
  70. 1 1
      php-phalcon/benchmark_config
  71. 1 1
      php-phpixie/assets/config/db.php
  72. 1 1
      php-phpixie/benchmark_config
  73. 1 1
      plain/benchmark_config
  74. 9 9
      plain/build.sbt
  75. BIN
      plain/lib/plain-library_2.10-1.0.1-SNAPSHOT.jar
  76. 1 1
      plain/sbt
  77. 55 0
      plain/sbt.bat
  78. 13 5
      plain/setup.py
  79. 3 3
      plain/src/main/resources/application.conf
  80. 18 12
      plain/src/main/scala/com/ibm/techempower/Db.scala
  81. 33 0
      play-activate-mysql/.gitignore
  82. 27 0
      play-activate-mysql/README.md
  83. 7 0
      play-activate-mysql/app/Global.scala
  84. 62 0
      play-activate-mysql/app/controllers/Application.scala
  85. 66 0
      play-activate-mysql/app/models/Migrations.scala
  86. 35 0
      play-activate-mysql/app/models/Models.scala
  87. 28 0
      play-activate-mysql/app/models/PersistenceContext.scala
  88. 18 0
      play-activate-mysql/app/views/fortune.scala.html
  89. 13 0
      play-activate-mysql/app/views/main.scala.html
  90. 26 0
      play-activate-mysql/benchmark_config
  91. 88 0
      play-activate-mysql/conf/application.conf
  92. 1 0
      play-activate-mysql/conf/play.plugins
  93. 11 0
      play-activate-mysql/conf/routes
  94. 28 0
      play-activate-mysql/project/Build.scala
  95. 1 0
      play-activate-mysql/project/build.properties
  96. 8 0
      play-activate-mysql/project/plugins.sbt
  97. 45 0
      play-activate-mysql/setup.py
  98. 1 1
      play-java-jpa/benchmark_config
  99. 1 1
      play-java-jpa/project/plugins.sbt
  100. 4 4
      play-java/benchmark_config

+ 2 - 0
.gitignore

@@ -16,3 +16,5 @@ mods/
 .idea/
 .hsenv/
 azure.err
+php-kohana/application/logs/
+php-fuel/fuel/app/logs/

+ 53 - 0
HttpListener/HttpListener/Program.cs

@@ -12,6 +12,8 @@ using System.Web.Script.Serialization;
 using MongoDB.Driver.Builders;
 
 using Benchmarks.AspNet.Models;
+using System.Reflection;
+using System.Runtime.InteropServices;
 
 namespace HttpListener
 {
@@ -111,6 +113,10 @@ namespace HttpListener
             {
                 listener.Start();
 
+                // Increase the HTTP.SYS backlog queue from the default of 1000 to 65535.
+                // To verify that this works, run `netsh http show servicestate`.
+                Network.Utils.HttpApi.SetRequestQueueLength(listener, 65535);
+
                 for (;;)
                 {
                     HttpListenerContext context = null;
@@ -401,3 +407,50 @@ namespace HttpListener
         }
     }
 }
+
+// Adapted from:
+// http://stackoverflow.com/questions/15417062/changing-http-sys-kernel-queue-limit-when-using-net-httplistener
+namespace Network.Utils
+{
+    public static class HttpApi
+    {
+        public static void SetRequestQueueLength(System.Net.HttpListener listener, uint len)
+        {
+            var listenerType = typeof(System.Net.HttpListener);
+            var requestQueueHandleProperty = listenerType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).First(p => p.Name == "RequestQueueHandle");
+
+            var requestQueueHandle = (CriticalHandle)requestQueueHandleProperty.GetValue(listener);
+            var result = HttpSetRequestQueueProperty(requestQueueHandle, HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty, ref len, (uint)Marshal.SizeOf(len), 0, IntPtr.Zero);
+
+            if (result != 0)
+            {
+                throw new HttpListenerException((int)result);
+            }
+        }
+
+        internal enum HTTP_SERVER_PROPERTY
+        {
+            HttpServerAuthenticationProperty,
+            HttpServerLoggingProperty,
+            HttpServerQosProperty,
+            HttpServerTimeoutsProperty,
+            HttpServerQueueLengthProperty,
+            HttpServerStateProperty,
+            HttpServer503VerbosityProperty,
+            HttpServerBindingProperty,
+            HttpServerExtendedAuthenticationProperty,
+            HttpServerListenEndpointProperty,
+            HttpServerChannelBindProperty,
+            HttpServerProtectionLevelProperty,
+        }
+
+        [DllImport("httpapi.dll", CallingConvention = CallingConvention.StdCall)]
+        internal static extern uint HttpSetRequestQueueProperty(
+            CriticalHandle requestQueueHandle,
+            HTTP_SERVER_PROPERTY serverProperty,
+            ref uint pPropertyInfo,
+            uint propertyInfoLength,
+            uint reserved,
+            IntPtr pReserved);
+    }
+}

+ 5 - 5
HttpListener/benchmark_config

@@ -13,7 +13,7 @@
       "language": "C#",
       "orm": "Raw",
       "platform": "NET",
-      "webserver": "IIS",
+      "webserver": "HTTP.sys",
       "os": "Windows",
       "database_os": "Linux",
       "display_name": "http-listener",
@@ -34,7 +34,7 @@
       "language": "C#",
       "orm": "Raw",
       "platform": "NET",
-      "webserver": "IIS",
+      "webserver": "HTTP.sys",
       "os": "Windows",
       "database_os": "Linux",
       "display_name": "http-listener",
@@ -55,7 +55,7 @@
       "language": "C#",
       "orm": "Raw",
       "platform": "NET",
-      "webserver": "IIS",
+      "webserver": "HTTP.sys",
       "os": "Windows",
       "database_os": "Linux",
       "display_name": "http-listener",
@@ -76,7 +76,7 @@
       "language": "C#",
       "orm": "Raw",
       "platform": "NET",
-      "webserver": "IIS",
+      "webserver": "HTTP.sys",
       "os": "Windows",
       "database_os": "Linux",
       "display_name": "http-listener",
@@ -97,7 +97,7 @@
       "language": "C#",
       "orm": "Raw",
       "platform": "NET",
-      "webserver": "IIS",
+      "webserver": "HTTP.sys",
       "os": "Windows",
       "database_os": "Windows",
       "display_name": "http-listener",

+ 20 - 2
HttpListener/setup.ps1

@@ -1,14 +1,32 @@
 param($action)
 
+$ErrorActionPreference = 'Stop'
+
+# From http://zduck.com/2012/powershell-batch-files-exit-codes/
+function Exec
+{
+    [CmdletBinding()]
+    param (
+        [Parameter(Position=0, Mandatory=1)]
+        [scriptblock]$Command,
+        [Parameter(Position=1, Mandatory=0)]
+        [string]$ErrorMessage = "Execution of command failed.`n$Command"
+    )
+    & $Command
+    if ($LastExitCode -ne 0) {
+        throw "Exec: $ErrorMessage"
+    }
+}
+
 $root = "C:\FrameworkBenchmarks\HttpListener"
 $msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
 
 # Stop
-Stop-Process -Name HttpListener -ErrorAction SilentlyContinue
+Get-Process | Where-Object { $_.Name -ieq "HttpListener" } | Stop-Process
 
 if ($action -eq 'start') {
     # Build the project
-    &$msbuild "$root\HttpListener.sln" /p:DownloadNuGetExe=true /p:RequireRestoreConsent=false /p:Configuration=Release /t:Rebuild
+    Exec { & $msbuild "$root\HttpListener.sln" /p:DownloadNuGetExe=true /p:RequireRestoreConsent=false /p:Configuration=Release /t:Rebuild }
     
     Start-Process "$root\HttpListener\bin\Release\HttpListener.exe"
 }

+ 2 - 2
HttpListener/setup.py

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

+ 88 - 30
README.md

@@ -46,50 +46,108 @@ For descriptions of the test types that we run against each framework, see the [
 
 ## The benchmark_config File
 
-The benchmark_config file is used by our run script to identify the available tests to be run. This file should exist at the root of the test directory. Here is its basic structure:
+The benchmark_config file is used by our scripts to both identify the available tests and to extract metadata describing each test.
+
+This file should exist at the root of the test directory.
+
+Here is the basic structure of benchmark_config, using the Compojure framework as an example.  Compojure has two test *permutations*, which are identified as the "tests" list in the JSON structure below.
 
 	{
-      "framework": "my-framework",
-      "tests": [{
-        "default": {
-          "setup_file": "setup.py"
-          "json_url": "/json",
-          "db_url": "/db",
-          "query_url": "/db?queries=",
-          "port": 8080,
-          "sort": 32
-      }, {
-        "alternative": {
-          "setup_file": "alternate_setup.py"
-          "json_url": "/json",
-          "db_url": "/db",
-          "query_url": "/db?queries=",
-          "port": 8080,
-          "sort": 33
-        }
-      }]
+	  "framework": "compojure",
+	  "tests": [{
+	    "default": {
+	      "setup_file": "setup",
+	      "json_url": "/compojure/json",
+	      "db_url": "/compojure/db/1",
+	      "query_url": "/compojure/db/",
+	      "fortune_url": "/compojure/fortune-hiccup",
+	      "plaintext_url": "/compojure/plaintext",
+	      "port": 8080,
+	      "approach": "Realistic",
+	      "classification": "Micro",
+	      "database": "MySQL",
+	      "framework": "compojure",
+	      "language": "Clojure",
+	      "orm": "Micro",
+	      "platform": "Servlet",
+	      "webserver": "Resin",
+	      "os": "Linux",
+	      "database_os": "Linux",
+	      "display_name": "compojure",
+	      "notes": "",
+	      "versus": "servlet"
+	    },
+	    "raw": {
+	      "setup_file": "setup",
+	      "db_url": "/compojure/dbraw/1",
+	      "query_url": "/compojure/dbraw/",
+	      "port": 8080,
+	      "approach": "Realistic",
+	      "classification": "Micro",
+	      "database": "MySQL",
+	      "framework": "compojure",
+	      "language": "Clojure",
+	      "orm": "Raw",
+	      "platform": "Servlet",
+	      "webserver": "Resin",
+	      "os": "Linux",
+	      "database_os": "Linux",
+	      "display_name": "compojure-raw",
+	      "notes": "",
+	      "versus": "servlet"
+	    }
+	  }]
 	}
 
 * framework: Specifies the framework name.
-* tests: An array of tests that can be run for this framework. In most cases, this contains a single element for the "default" test, but additional tests can be specified.
+* tests: An list of tests that can be run for this framework. In many cases, this contains a single element for the "default" test, but additional tests can be specified.  Each test name must be unique when concatenated with the framework name.
   * setup_file: The location of the [setup file](#setup-files) that can start and stop the test. By convention this is just setup.py.
-  * json_url (optional): The relative URL path to the JSON test
-  * db_url (optional): The relative URL path to the database test
-  * query_url (optional): The relative URL path to the variable query test. The URL must be set up so that an integer can be applied to the end of the url to specify the number of queries to run, i.e. /db?queries= or /db/
-  * port: The port the server is listneing on
-  * sort: The sort order. This is important for our own blog post which relies on consistent ordering of the frameworks. You can get the next available sort order by running:
-    ./run-tests.py --next-sort
+  * json_url (optional): The URI to the JSON test, typically `/json`
+  * db_url (optional): The URI to the database test, typically `/db`
+  * query_url (optional): The URI to the variable query test. The URI must be set up so that an integer can be applied to the end of the URI to specify the number of queries to run.  For example, "/query?queries=" (to yield /query?queries=20" or "/query/" to yield "/query/20".
+  * fortune_url (optional): the URI to the fortunes test, typically `/fortune`
+  * update_url (optional): the URI to the updates test, setup in a manner similar to the query_url described above.
+  * plaintext_url (optional): the URI of the plaintext test, typically `/plaintext`
+  * port: The port the server is listening on
+  * approach (metadata): `Realistic` or `Stripped` (see results web site for description of all metadata attributes)
+  * classification (metadata): `Full`, `Micro`, or `Platform`
+  * database (metadata): `MySQL`, `Postgres`, `MongoDB`, `SQLServer`, or `None`
+  * framework (metadata): name of the framework
+  * language (metadata): name of the language
+  * orm (metadata): `Full`, `Micro`, or `Raw`
+  * platform (metadata): name of the platform
+  * webserver (metadata): name of the web-server (also referred to as the "front-end server")
+  * os (metadata): The application server's operating system, `Linux` or `Windows`
+  * database_os (metadata): The database server's operating system, `Linux` or `Windows`
+  * display_name (metadata): How to render this test permutation's name in the results web site.  Some permutation names can be really long, so the display_name is provided in order to provide something more succinct.
+  * versus (optional): The name of another test (elsewhere in this project) that is a subset of this framework.  This allows for the generation of the framework efficiency chart in the results web site.  For example, Compojure is compared to "servlet" since Compojure is built on the Servlets platform.
 
 ## Setup Files
 
 The setup file is responsible for starting and stopping the test. This script is responsible for (among other things):
 
-* Setting the database host to the correct IP
-* Compiling/packaging the code
+* Modifying the framework's configuration to point to the correct database host
+* Compiling and/or packaging the code
 * Starting the server
 * Stopping the server
 
-The setup file is a python file that contains a start() and a stop() function. Here is an example of Wicket's setup file.
+The setup file is a python script that contains a start() and a stop() function.  The start function should build the source, make any necessary changes to the framework's configuration, and then start the server.  The stop function should shutdown the server, including all sub-processes as applicable.
+
+### Configuring database connectivity in start()
+
+By convention, the configuration files used by a framework should specify the database server as `localhost` so that developing tests in a single-machine environment can be done in an ad hoc fashion, without using the benchmark scripts.
+
+When running a benchmark script, the script needs to modify each framework's configuration so that the framework connects to a database host provided as a command line argument.  In order to do this, use setup_util.replace_text() to make necessary modifications prior to starting the server.
+
+For example:
+
+    setup_util.replace_text("wicket/src/main/webapp/WEB-INF/resin-web.xml", "mysql:\/\/.*:3306", "mysql://" + args.database_host + ":3306")
+
+Using `localhost` in the raw configuration file is not a requirement as long as the `replace_text` call properly injects the database host provided to the benchmarker toolset as a command line argument.
+
+### A full example
+
+Here is an example of Wicket's setup file.
 
 	import subprocess
 	import sys

+ 19 - 1
aspnet-stripped/setup_iis.ps1

@@ -1,5 +1,23 @@
 param($action)
 
+$ErrorActionPreference = 'Stop'
+
+# From http://zduck.com/2012/powershell-batch-files-exit-codes/
+function Exec
+{
+    [CmdletBinding()]
+    param (
+        [Parameter(Position=0, Mandatory=1)]
+        [scriptblock]$Command,
+        [Parameter(Position=1, Mandatory=0)]
+        [string]$ErrorMessage = "Execution of command failed.`n$Command"
+    )
+    & $Command
+    if ($LastExitCode -ne 0) {
+        throw "Exec: $ErrorMessage"
+    }
+}
+
 $source = "C:\FrameworkBenchmarks\aspnet-stripped\src"
 
 # Stop
@@ -8,7 +26,7 @@ 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
+    Exec { & .\NuGet.exe install -o src\packages src\packages.config }
 
     if (-Not (Test-Path src\bin)) { New-Item -Path src\bin -ItemType directory | Out-Null }
 

+ 2 - 2
aspnet-stripped/setup_iis.py

@@ -9,7 +9,7 @@ def start(args):
   
   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")
+    subprocess.check_call("powershell -Command .\\setup_iis.ps1 start", cwd="aspnet-stripped")
     return 0
   except subprocess.CalledProcessError:
     return 1
@@ -18,5 +18,5 @@ def stop():
   if os.name != 'nt':
     return 0
   
-  subprocess.Popen("powershell -File setup_iis.ps1 stop", cwd="aspnet-stripped")
+  subprocess.check_call("powershell -Command .\\setup_iis.ps1 stop", cwd="aspnet-stripped")
   return 0

+ 3 - 3
aspnet/benchmark_config

@@ -31,7 +31,7 @@
       "language": "C#",
       "orm": "Raw",
       "platform": "NET",
-      "webserver": "nginx",
+      "webserver": "IIS",
       "os": "Windows",
       "database_os": "Linux",
       "display_name": "aspnet-jsonnet",
@@ -49,7 +49,7 @@
       "language": "C#",
       "orm": "Raw",
       "platform": "NET",
-      "webserver": "nginx",
+      "webserver": "IIS",
       "os": "Windows",
       "database_os": "Linux",
       "display_name": "aspnet-svcstk",
@@ -131,7 +131,7 @@
       "database": "SQLServer",
       "framework": "aspnet-mvc",
       "language": "C#",
-      "orm": "Full",
+      "orm": "Raw",
       "platform": "NET",
       "webserver": "IIS",
       "os": "Windows",

+ 21 - 3
aspnet/setup_iis.ps1

@@ -1,5 +1,23 @@
 param($action)
 
+$ErrorActionPreference = 'Stop'
+
+# From http://zduck.com/2012/powershell-batch-files-exit-codes/
+function Exec
+{
+    [CmdletBinding()]
+    param (
+        [Parameter(Position=0, Mandatory=1)]
+        [scriptblock]$Command,
+        [Parameter(Position=1, Mandatory=0)]
+        [string]$ErrorMessage = "Execution of command failed.`n$Command"
+    )
+    & $Command
+    if ($LastExitCode -ne 0) {
+        throw "Exec: $ErrorMessage"
+    }
+}
+
 $wwwroot = "C:\FrameworkBenchmarks\aspnet\www"
 $source = "C:\FrameworkBenchmarks\aspnet\src"
 $msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
@@ -15,7 +33,7 @@ if ($action -eq 'start') {
     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
+    Exec { & $msbuild "$source\Benchmarks.AspNet.csproj" /t:RestorePackages }
+    Exec { & $msbuild "$source\Benchmarks.AspNet.csproj" /p:Configuration=Release /p:Platform=x64 /t:Clean }
+    Exec { & $msbuild "$source\Benchmarks.AspNet.csproj" /p:Configuration=Release /p:Platform=x64 /p:DeployOnBuild=true /p:PublishProfile=IIS }
 }

+ 2 - 2
aspnet/setup_iis.py

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

+ 1 - 1
bottle/app.py

@@ -13,7 +13,7 @@ except ImportError:
     import json
 
 app = Bottle()
-app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://benchmarkdbuser:benchmarkdbpass@localhost:3306/hello_world?charset=utf8'
+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', )

+ 1 - 1
bottle/benchmark_config

@@ -62,7 +62,7 @@
       "framework": "bottle",
       "language": "Python",
       "orm": "Full",
-      "platform": "wsgi",
+      "platform": "pypy",
       "webserver": "Gunicorn",
       "os": "Linux",
       "database_os": "Linux",

+ 2 - 2
config/benchmark_profile

@@ -1,12 +1,12 @@
 export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-amd64
 export RESIN_HOME=~/FrameworkBenchmarks/installs/resin-4.0.36
-export GRAILS_HOME=~/FrameworkBenchmarks/installs/grails-2.1.1
+export GRAILS_HOME=~/FrameworkBenchmarks/installs/grails-2.3.1
 export VERTX_HOME=~/FrameworkBenchmarks/installs/vert.x-2.0.2-final
 export GOROOT=~/FrameworkBenchmarks/installs/go
 export GOPATH=~/FrameworkBenchmarks/go:~/FrameworkBenchmarks/webgo:~/FrameworkBenchmarks/revel
 export TOMCAT_HOME=~/FrameworkBenchmarks/installs/apache-tomcat-7.0.35
 export NODE_HOME=~/FrameworkBenchmarks/installs/node-v0.10.8-linux-x64
-export PLAY_HOME=~/FrameworkBenchmarks/installs/play-2.1.2-RC1
+export PLAY_HOME=~/FrameworkBenchmarks/installs/play-2.2.0
 export PLAY1_HOME=~/FrameworkBenchmarks/installs/play-1.2.5
 export MAVEN_HOME=~/FrameworkBenchmarks/installs/apache-maven-3.0.5
 export PERL_HOME=/opt/ActivePerl-5.16

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

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

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

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

+ 15 - 15
config/create-postgres.sql

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

+ 6 - 3
config/nginx_uwsgi.conf

@@ -2,10 +2,12 @@
 
 # One worker process per core
 worker_processes auto;
+error_log /dev/null crit;
 
 events {
-    # This may need to be increased for the high-concurrency plaintext test.
-    worker_connections  1024;
+    # This needed to be increased because the nginx error log said so.
+    # http://nginx.org/en/docs/ngx_core_module.html#worker_connections
+    worker_connections  65535;
 }
 
 http {
@@ -34,7 +36,8 @@ http {
         # For information on deferred, see:
         # http://nginx.org/en/docs/http/ngx_http_core_module.html#listen
         # http://www.techrepublic.com/article/take-advantage-of-tcp-ip-options-to-optimize-data-transmission/
-        listen       8080 default_server deferred;
+        # The backlog argument to listen() is set to match net.ipv4.tcp_max_syn_backlog and net.core.somaxconn
+        listen       8080 default_server deferred backlog=65535;
         server_name  localhost;
 
         location / {

+ 3 - 2
config/uwsgi.ini

@@ -1,7 +1,8 @@
 [uwsgi]
 master
-; increase listen queue used for nginx connecting to uWSGI
-listen = 5000
+; Increase listen queue used for nginx connecting to uWSGI. This matches
+; net.ipv4.tcp_max_syn_backlog and net.core.somaxconn.
+listen = 65535
 ; for performance
 disable-logging
 ; use UNIX sockets instead of TCP loopback for performance

+ 5 - 0
cowboy/.gitignore

@@ -0,0 +1,5 @@
+erl_crash.dump
+__init__.py
+deps
+ebin
+*.deb

+ 4 - 0
cowboy/Makefile

@@ -0,0 +1,4 @@
+all:
+	./rebar get-deps
+	./rebar compile
+	erl -pa ebin deps/*/ebin -s hello_world -noshell -detached

+ 34 - 0
cowboy/README.md

@@ -0,0 +1,34 @@
+# Cowboy Benchmarking Test
+
+This is the Cowboy portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test controller](src/json_handler.erl)
+
+
+### Data-Store/Database Mapping Test
+Uses the db abstraction class from Kohana
+
+* [DB test controller](src/db_handler.erl)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Cowboy 0.8.3](https://github.com/extend/cowboy)
+* [Erlang R16B](http://www.erlang.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db
+
+### Variable Query Test
+    
+http://localhost/db?queries=2

+ 25 - 0
cowboy/benchmark_config

@@ -0,0 +1,25 @@
+{
+  "framework": "cowboy",
+  "tests": [{
+    "default": {
+      "setup_file": "setup_erlang",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/db?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "cowboy",
+      "language": "Erlang",
+      "orm": "Raw",
+      "platform": "Cowboy",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "cowboy",
+      "notes": "",
+      "versus": "",
+      "skip": "true"
+  }}]
+}

BIN
cowboy/rebar


+ 7 - 0
cowboy/rebar.config

@@ -0,0 +1,7 @@
+{deps,
+ [
+  {jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "0.8.3"}}},
+  {mimetypes, ".*", {git, "http://github.com/spawngrid/mimetypes.git", {branch, master}}},
+  {emysql, ".*", {git, "https://github.com/Eonblast/Emysql.git"}},
+  {cowboy, ".*", {git, "https://github.com/extend/cowboy.git", {tag, "0.8.3"}}}
+ ]}.

+ 20 - 0
cowboy/setup_erlang.py

@@ -0,0 +1,20 @@
+import subprocess
+import sys
+import setup_util
+
+def start(args):
+  setup_util.replace_text("cowboy/src/hello_world_app.erl", "\"benchmarkdbpass\", \".*\", 3306", "\"benchmarkdbpass\", \"" + args.database_host + "\", 3306")
+
+  try:
+    subprocess.check_call("./rebar get-deps", shell=True, cwd="cowboy")
+    subprocess.check_call("./rebar compile", shell=True, cwd="cowboy")
+    subprocess.check_call("erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -s hello_world -noshell -detached", shell=True, cwd="cowboy")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+def stop():
+  try:
+    subprocess.check_call("killall beam.smp", shell=True, cwd="/usr/bin")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 7 - 0
cowboy/source_code

@@ -0,0 +1,7 @@
+./cowboy/src/
+./cowboy/src/hello_world_app.erl
+./cowboy/src/db_handler.erl
+./cowboy/src/hello_world_sup.erl
+./cowboy/src/hello_world.app.src
+./cowboy/src/json_handler.erl
+./cowboy/src/hello_world.erl

+ 29 - 0
cowboy/src/db_handler.erl

@@ -0,0 +1,29 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+%% @doc Hello world handler.
+-module(db_handler).
+
+-export([init/3]).
+-export([handle/2]).
+-export([terminate/3]).
+
+init(_Transport, Req, []) ->
+	{ok, Req, undefined}.
+
+handle(Req, State) ->
+        random:seed(erlang:now()),
+        {JSON, Req2} = case cowboy_req:qs_val(<<"queries">>, Req) of
+		{undefined, Req1} ->
+			{result_packet, _, _, [[ID, Rand]], _} = emysql:execute(test_pool, db_stmt, [random:uniform(10000)]),
+			{[{[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]}], Req1};
+		{N, Req1} ->
+			I = list_to_integer(binary_to_list(N)),
+			Res = [ {[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]} || 
+			        {result_packet, _, _, [[ID, Rand]], _} <- [emysql:execute(test_pool, db_stmt, [random:uniform(10000)]) || _ <- lists:seq(1, I) ]],
+			{Res, Req1}
+		end,
+	{ok, Req3} = cowboy_req:reply(200, [{<<"Content-Type">>, <<"application/json">>}], jiffy:encode(JSON), Req2),
+	{ok, Req3, State}.
+
+terminate(_Reason, _Req, _State) ->
+	ok.

+ 15 - 0
cowboy/src/hello_world.app.src

@@ -0,0 +1,15 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+{application, hello_world, [
+	{description, "Cowboy Hello World example."},
+	{vsn, "1"},
+	{modules, []},
+	{registered, []},
+	{applications, [
+		kernel,
+		stdlib,
+		cowboy
+	]},
+	{mod, {hello_world_app, []}},
+	{env, []}
+]}.

+ 14 - 0
cowboy/src/hello_world.erl

@@ -0,0 +1,14 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+-module(hello_world).
+
+%% API.
+-export([start/0]).
+
+%% API.
+
+start() ->
+	ok = application:start(crypto),
+	ok = application:start(ranch),
+	ok = application:start(cowboy),
+	ok = application:start(hello_world).

+ 32 - 0
cowboy/src/hello_world_app.erl

@@ -0,0 +1,32 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+%% @private
+-module(hello_world_app).
+-behaviour(application).
+
+%% API.
+-export([start/2]).
+-export([stop/1]).
+
+%% API.
+
+start(_Type, _Args) ->
+        crypto:start(),
+        application:start(emysql),
+        emysql:add_pool(test_pool, 5000,
+          "benchmarkdbuser", "benchmarkdbpass", "localhost", 3306,
+          "hello_world", utf8),
+	emysql:prepare(db_stmt, <<"SELECT * FROM World where id = ?">>),
+	Dispatch = cowboy_router:compile([
+		{'_', [
+			{"/json", json_handler, []},
+			{"/db", db_handler, []}
+		]}
+	]),
+	{ok, _} = cowboy:start_http(http, 5000, [{port, 8080}], [
+		{env, [{dispatch, Dispatch}]}
+	]),
+	hello_world_sup:start_link().
+
+stop(_State) ->
+	ok.

+ 23 - 0
cowboy/src/hello_world_sup.erl

@@ -0,0 +1,23 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+%% @private
+-module(hello_world_sup).
+-behaviour(supervisor).
+
+%% API.
+-export([start_link/0]).
+
+%% supervisor.
+-export([init/1]).
+
+%% API.
+
+-spec start_link() -> {ok, pid()}.
+start_link() ->
+	supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%% supervisor.
+
+init([]) ->
+	Procs = [],
+	{ok, {{one_for_one, 10, 10}, Procs}}.

+ 18 - 0
cowboy/src/json_handler.erl

@@ -0,0 +1,18 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+%% @doc Hello world handler.
+-module(json_handler).
+
+-export([init/3]).
+-export([handle/2]).
+-export([terminate/3]).
+
+init(_Transport, Req, []) ->
+	{ok, Req, undefined}.
+
+handle(Req, State) ->
+	{ok, Req2} = cowboy_req:reply(200, [{<<"Content-Type">>, <<"application/json">>}], jiffy:encode({[{<<"message">>, <<"Hello, World!">>}]}), Req),
+	{ok, Req2, State}.
+
+terminate(_Reason, _Req, _State) ->
+	ok.

+ 4 - 3
dancer/nginx.conf

@@ -1,4 +1,4 @@
-user USR;
+user tfb;
 error_log /dev/null crit;
 
 worker_processes 2;
@@ -11,13 +11,15 @@ http {
   output_buffers   1 32k;
   postpone_output  1460;
 
+  access_log       off;
+
   sendfile         on;
   tcp_nopush       on;
 
   tcp_nodelay      on;
 
   upstream backendurl {
-    server unix:/home/ubuntu/FrameworkBenchmarks/dancer/frameworks-benchmark.sock;
+    server unix:/home/tfb/FrameworkBenchmarks/dancer/frameworks-benchmark.sock;
   }
 
   server {
@@ -26,7 +28,6 @@ http {
 
     location / {
       try_files $uri @proxy;
-      access_log off;
       expires max;
     }
 

+ 7 - 6
dart-start/README.md

@@ -4,14 +4,14 @@ This test adds [Start](https://github.com/lvivski/start), a Sinatra inspired web
 
 ## Versions
 
-* [Dart SDK version 0.6.21.3_r26639](https://launchpad.net/~hachre/+archive/dart)
-* [Dart args version 0.6.21.3](http://pub.dartlang.org/packages/args)
-* [Dart crypto version 0.6.21.3](http://pub.dartlang.org/packages/crypto)
+* [Dart SDK version 0.8.1.2_r28355](https://launchpad.net/~hachre/+archive/dart)
+* [Dart args version 0.8.1](http://pub.dartlang.org/packages/args)
+* [Dart crypto version 0.8.1](http://pub.dartlang.org/packages/crypto)
 * [Dart mustache version 0.1.5](http://pub.dartlang.org/packages/mustache)
-* [Dart mongo_dart version 0.1.27](http://pub.dartlang.org/packages/mongo_dart)
+* [Dart mongo_dart version 0.1.30](http://pub.dartlang.org/packages/mongo_dart)
 * [Dart postgresql version 0.2.8](http://pub.dartlang.org/packages/postgresql)
-* [Dart start version 0.0.8](http://pub.dartlang.org/packages/start)
-* [Dart yaml version 0.6.21.3](http://pub.dartlang.org/packages/yaml)
+* [Dart start version 0.0.9+1](http://pub.dartlang.org/packages/start)
+* [Dart yaml version 0.8.1](http://pub.dartlang.org/packages/yaml)
 
 ## Test URLs
 
@@ -59,3 +59,4 @@ http://localhost:8080/updates-mongo
 #### Variable Update Test
 http://localhost:8080/updates-mongo?queries=2
 
+

+ 6 - 5
dart-start/pubspec.yaml

@@ -1,10 +1,11 @@
 name: DartStartBenchmark
 description: A benchmark of Dart Start, a Sinatra inspired web framework
 dependencies:
-  start: 0.0.8
-  args: 0.6.21+3
+  args: 0.8.1
+  crypto: 0.8.1
+  mongo_dart: 0.1.30
   mustache: 0.1.5
   postgresql: 0.2.8
-  yaml: 0.6.21+3
-  mongo_dart: 0.1.27
-  crypto: 0.6.21+3
+  start: 0.0.9+1
+  yaml: 0.8.1
+

+ 0 - 7
django-stripped/source_code

@@ -1,7 +0,0 @@
-./django-stripped/hello/world/models.py
-./django-stripped/hello/world/views.py
-./django-stripped/hello/hello/settings.py
-./django-stripped/hello/hello/urls.py
-./django-stripped/hello/hello/wsgi.py
-./django-stripped/hello/templates/
-./django-stripped/hello/templates/base.html

+ 5 - 0
elli/.gitignore

@@ -0,0 +1,5 @@
+erl_crash.dump
+__init__.py
+deps
+ebin
+*.deb

+ 33 - 0
elli/README.md

@@ -0,0 +1,33 @@
+# Elli Benchmarking Test
+
+This is the Elli portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test controller](src/elli_bench_cb.erl)
+
+
+### Data-Store/Database Mapping Test
+
+* [DB test controller](src/elli_bench_cb.erl)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Elli](git://github.com/knutin/elli)
+* [Erlang R16B](http://www.erlang.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db
+
+### Variable Query Test
+    
+http://localhost/db?queries=2

+ 25 - 0
elli/benchmark_config

@@ -0,0 +1,25 @@
+{
+  "framework": "elli",
+  "tests": [{
+    "default": {
+      "setup_file": "setup_erlang",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/db?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "elli",
+      "language": "Erlang",
+      "orm": "Raw",
+      "platform": "elli",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "elli",
+      "notes": "",
+      "versus": "",
+      "skip": "true"
+  }}]
+}

BIN
elli/rebar


+ 6 - 0
elli/rebar.config

@@ -0,0 +1,6 @@
+{deps,
+ [
+  {jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "0.8.3"}}},
+  {emysql, ".*", {git, "https://github.com/Eonblast/Emysql.git"}},
+  {elli, "", {git, "git://github.com/knutin/elli.git"}}
+ ]}.

+ 21 - 0
elli/setup_erlang.py

@@ -0,0 +1,21 @@
+import subprocess
+import sys
+import setup_util
+
+def start(args):
+  setup_util.replace_text("elli/src/elli_bench_sup.erl", "\"benchmarkdbpass\", \".*\", 3306", "\"benchmarkdbpass\", \"" + args.database_host + "\", 3306")
+  
+  try:
+    subprocess.check_call("./rebar get-deps", shell=True, cwd="elli")
+    subprocess.check_call("./rebar compile", shell=True, cwd="elli")
+    # adding +K true seemed to actually slow performance
+    subprocess.check_call("erl -pa ebin deps/*/ebin +sbwt very_long +swt very_low -s elli_bench -noshell -detached", shell=True, cwd="elli")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+def stop():
+  try:
+    subprocess.check_call("killall beam.smp", shell=True, cwd="/usr/bin")
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 6 - 0
elli/source_code

@@ -0,0 +1,6 @@
+./elli/src/
+./elli/src/elli_bench.app.src
+./elli/src/elli_bench_cb.erl
+./elli/src/elli_bench_sup.erl
+./elli/src/elli_bench.erl
+./elli/src/elli_bench_app.erl

+ 12 - 0
elli/src/elli_bench.app.src

@@ -0,0 +1,12 @@
+{application, elli_bench,
+ [
+  {description, ""},
+  {vsn, "1"},
+  {registered, []},
+  {applications, [
+                  kernel,
+                  stdlib
+                 ]},
+  {mod, { elli_bench_app, []}},
+  {env, []}
+ ]}.

+ 5 - 0
elli/src/elli_bench.erl

@@ -0,0 +1,5 @@
+-module(elli_bench).
+-export([start/0]).
+
+start() ->
+	application:start(elli_bench).

+ 16 - 0
elli/src/elli_bench_app.erl

@@ -0,0 +1,16 @@
+-module(elli_bench_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%% ===================================================================
+%% Application callbacks
+%% ===================================================================
+
+start(_StartType, _StartArgs) ->
+    elli_bench_sup:start_link().
+
+stop(_State) ->
+    ok.

+ 36 - 0
elli/src/elli_bench_cb.erl

@@ -0,0 +1,36 @@
+-module(elli_bench_cb).
+-export([handle/2, handle_event/3]).
+
+-include_lib("elli/include/elli.hrl").
+-behaviour(elli_handler).
+
+handle(Req, _Args) ->
+    %% Delegate to our handler function
+    handle(Req#req.method, elli_request:path(Req), Req).
+
+handle('GET',[<<"json">>], _Req) ->
+    %% Reply with a normal response. 'ok' can be used instead of '200'
+    %% to signal success.
+    {ok, [{<<"Content-Type">>, <<"application/json">>}], jiffy:encode({[{<<"message">>, <<"Hello, World!">>}]})};
+
+handle('GET',[<<"db">>], Req) ->
+        random:seed(erlang:now()),
+        JSON = case elli_request:get_arg(<<"queries">>, Req) of
+		undefined ->
+			{result_packet, _, _, [[ID, Rand]], _} = emysql:execute(test_pool, db_stmt, [random:uniform(10000)]),
+			[{[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]}];
+		N ->
+			I = list_to_integer(binary_to_list(N)),
+			Res = [ {[{<<"id">>, ID}, {<<"randomNumber">>, Rand}]} || 
+			        {result_packet, _, _, [[ID, Rand]], _} <- [emysql:execute(test_pool, db_stmt, [random:uniform(10000)]) || _ <- lists:seq(1, I) ]],
+			Res
+		end,
+    {ok, [{<<"Content-Type">>, <<"application/json">>}], jiffy:encode(JSON)};
+
+handle(_, _, _Req) ->
+    {404, [], <<"Not Found">>}.
+
+%% @doc: Handle request events, like request completed, exception
+%% thrown, client timeout, etc. Must return 'ok'.
+handle_event(_Event, _Data, _Args) ->
+    ok.

+ 42 - 0
elli/src/elli_bench_sup.erl

@@ -0,0 +1,42 @@
+-module(elli_bench_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+%% Helper macro for declaring children of supervisor
+-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
+
+%% ===================================================================
+%% API functions
+%% ===================================================================
+
+start_link() ->
+    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%% ===================================================================
+%% Supervisor callbacks
+%% ===================================================================
+
+init([]) ->
+    crypto:start(),
+    application:start(emysql),
+    emysql:add_pool(test_pool, 5000,
+       "benchmarkdbuser", "benchmarkdbpass", "localhost", 3306,
+       "hello_world", utf8),
+    emysql:prepare(db_stmt, <<"SELECT * FROM World where id = ?">>),
+    ElliOpts = [{callback, elli_bench_cb}, {port, 8080}],
+    ElliSpec = {
+        fancy_http,
+        {elli, start_link, [ElliOpts]},
+        permanent,
+        5000,
+        worker,
+        [elli]},
+
+    {ok, { {one_for_one, 5, 10}, [ElliSpec]} }.
+

+ 1 - 1
falcon/benchmark_config

@@ -50,7 +50,7 @@
       "framework": "falcon",
       "language": "Python",
       "orm": "Raw",
-      "platform": "wsgi",
+      "platform": "pypy",
       "webserver": "Gunicorn",
       "os": "Linux",
       "database_os": "Linux",

+ 1 - 1
flask/app.py

@@ -21,7 +21,7 @@ except ImportError:
 # setup
 
 app = Flask(__name__)
-app.config['SQLALCHEMY_DATABASE_URI'] = mysql_schema + '//benchmarkdbuser:benchmarkdbpass@localhost:3306/hello_world?charset=utf8'
+app.config['SQLALCHEMY_DATABASE_URI'] = mysql_schema + '//benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world?charset=utf8'
 app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
 db = SQLAlchemy(app)
 dbraw_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])

+ 7 - 7
flask/benchmark_config

@@ -17,7 +17,7 @@
       "language": "Python",
       "orm": "Full",
       "platform": "wsgi",
-      "webserver": "Unicorn",
+      "webserver": "Meinheld",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "flask",
@@ -38,7 +38,7 @@
       "language": "Python",
       "orm": "Raw",
       "platform": "wsgi",
-      "webserver": "Unicorn",
+      "webserver": "Meinheld",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "flask",
@@ -61,7 +61,7 @@
       "language": "Python",
       "orm": "Full",
       "platform": "wsgi",
-      "webserver": "Unicorn",
+      "webserver": "Meinheld",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "flask-py3",
@@ -83,8 +83,8 @@
       "framework": "flask",
       "language": "Python",
       "orm": "Full",
-      "platform": "wsgi",
-      "webserver": "Unicorn",
+      "platform": "pypy",
+      "webserver": "Tornado",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "flask-pypy",
@@ -104,8 +104,8 @@
       "framework": "flask",
       "language": "Python",
       "orm": "Raw",
-      "platform": "wsgi",
-      "webserver": "Unicorn",
+      "platform": "pypy",
+      "webserver": "Tornado",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "flask-pypy",

+ 1 - 1
go/README.md

@@ -7,7 +7,7 @@ This is the go portion of a [benchmarking test suite](../) comparing a variety o
 
 ## Versions
 
-* [Go 1.1beta2](http://golang.org/)
+* [Go 1.2rc3](http://golang.org/)
 
 ## Test URLs
 

+ 2 - 11
grails/README.md

@@ -2,18 +2,9 @@
 
 This is the Grails portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
 
-### JSON Encoding Test
-
-* [JSON test controller/view](hello/grails-app/HelloController.groovy) TODO: this gives 404
-
-### Data-Store/Database Mapping Test
-
-* [DB test controller](hello/grails-app/HelloController.groovy) TODO: this gives 404
-* [DB test model](hello/grails-app/domain/hello/World.groovy) TODO: this gives 404
-
 ## Infrastructure Software Versions
 The tests were run with:
-* [Grails 2.1.1](http://grails.org/)
+* [Grails 2.3.1](http://grails.org/)
 * [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
 * [Resin 4.0.34](http://www.caucho.com/)
 * [MySQL 5.5.29](https://dev.mysql.com/)
@@ -26,4 +17,4 @@ http://localhost:8080/grails/hello/json
 
 ### Data-Store/Database Mapping Test
 
-http://localhost:8080/grails/hello/db?queries=5
+http://localhost:8080/grails/hello/db?queries=5

+ 3 - 2
grails/benchmark_config

@@ -19,7 +19,8 @@
       "database_os": "Linux",
       "display_name": "grails",
       "notes": "",
-      "versus": "servlet"
+      "versus": "servlet",
+      "skip": "true"
     }
   }]
-}
+}

+ 2 - 2
grails/hello/application.properties

@@ -1,6 +1,6 @@
 #Grails Metadata file
-#Thu Apr 19 15:23:51 PDT 2012
-app.grails.version=2.1.1
+#Sat Oct 26 13:32:20 PDT 2013
+app.grails.version=2.3.1
 app.name=hello
 app.servlet.version=2.5
 app.version=0.1

+ 2 - 3
grails/hello/grails-app/conf/BuildConfig.groovy

@@ -37,7 +37,7 @@ grails.project.dependency.resolution = {
     }
 
     plugins {
-        runtime ":hibernate:$grailsVersion"
+        compile ":hibernate:3.6.10.2"
         runtime ":jquery:1.7.1"
         runtime ":resources:1.1.6"
 
@@ -45,7 +45,6 @@ grails.project.dependency.resolution = {
         //runtime ":zipped-resources:1.0"
         //runtime ":cached-resources:1.0"
         //runtime ":yui-minify-resources:0.1.4"
-
-        build ":tomcat:$grailsVersion"
+        build ':tomcat:7.0.40.1'
     }
 }

+ 24 - 0
grails/hello/grails-app/conf/Config.groovy

@@ -91,3 +91,27 @@ log4j = {
            'org.hibernate',
            'net.sf.ehcache.hibernate'
 }
+
+// Uncomment and edit the following lines to start using Grails encoding & escaping improvements
+
+/* remove this line 
+// GSP settings
+grails {
+    views {
+        gsp {
+            encoding = 'UTF-8'
+            htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping
+            codecs {
+                expression = 'html' // escapes values inside null
+                scriptlet = 'none' // escapes output from scriptlets in GSPs
+                taglib = 'none' // escapes output from taglibs
+                staticparts = 'none' // escapes output from static template parts
+            }
+        }
+        // escapes all not-encoded output at final stage of outputting
+        filteringCodecForContentType {
+            //'text/html' = 'html'
+        }
+    }
+}
+remove this line */

+ 4 - 3
grails/hello/web-app/WEB-INF/applicationContext.xml

@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="
-http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 	<bean id="grailsApplication" class="org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean">
 		<description>Grails application factory bean</description>
@@ -30,4 +29,6 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schem
 			<value>utf-8</value>
 		</property>
 	</bean>
+
+	<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" />
 </beans>

+ 244 - 98
grails/hello/web-app/WEB-INF/tld/spring.tld

@@ -1,311 +1,457 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
-
-<taglib>
-
-	<tlib-version>1.1.1</tlib-version>
-
-	<jsp-version>1.2</jsp-version>
-
-	<short-name>Spring</short-name>
-
+<?xml version="1.0" encoding="UTF-8"?>
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+		version="2.0">
+
+	<description>Spring Framework JSP Tag Library</description>
+	<tlib-version>3.0</tlib-version>
+	<short-name>spring</short-name>
 	<uri>http://www.springframework.org/tags</uri>
 
-	<description>Spring Framework JSP Tag Library. Authors: Rod Johnson, Juergen Hoeller</description>
-
-
 	<tag>
-
-		<name>htmlEscape</name>
-		<tag-class>org.springframework.web.servlet.tags.HtmlEscapeTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Sets default HTML escape value for the current page.
 			Overrides a "defaultHtmlEscape" context-param in web.xml, if any.
 		</description>
-
+		<name>htmlEscape</name>
+		<tag-class>org.springframework.web.servlet.tags.HtmlEscapeTag</tag-class>
+		<body-content>JSP</body-content>
 		<attribute>
+			<description>Set the default value for HTML escaping, to be put
+				into the current PageContext.</description>
 			<name>defaultHtmlEscape</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 	</tag>
 
-
 	<tag>
-
-		<name>escapeBody</name>
-		<tag-class>org.springframework.web.servlet.tags.EscapeBodyTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Escapes its enclosed body content, applying HTML escaping and/or JavaScript escaping.
 			The HTML escaping flag participates in a page-wide or application-wide setting
 			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
 		</description>
-
+		<name>escapeBody</name>
+		<tag-class>org.springframework.web.servlet.tags.EscapeBodyTag</tag-class>
+		<body-content>JSP</body-content>
 		<attribute>
+			<description>Set HTML escaping for this tag, as boolean value. Overrides the
+			default HTML escaping setting for the current page.</description>
 			<name>htmlEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set JavaScript escaping for this tag, as boolean value.
+			Default is false.</description>
 			<name>javaScriptEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 	</tag>
 
-
 	<tag>
-
-		<name>message</name>
-		<tag-class>org.springframework.web.servlet.tags.MessageTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Retrieves the message with the given code, or text if code isn't resolvable.
 			The HTML escaping flag participates in a page-wide or application-wide setting
 			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
 		</description>
-
+		<name>message</name>
+		<tag-class>org.springframework.web.servlet.tags.MessageTag</tag-class>
+		<body-content>JSP</body-content>
 		<attribute>
+			<description>A MessageSourceResolvable argument (direct or through JSP EL).
+				Fits nicely when used in conjunction with Spring's own validation error
+				classes which all implement the MessageSourceResolvable interface. For
+				example, this allows you to iterate over all of the errors in a form,
+				passing each error (using a runtime expression) as the value of this
+				'message' attribute, thus effecting the easy display of such error
+				messages.</description>
+			<name>message</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>The code (key) to use when looking up the message.
+			If code is not provided, the text attribute will be used.</description>
 			<name>code</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set optional message arguments for this tag, as a
+			(comma-)delimited String (each String argument can contain JSP EL),
+			an Object array (used as argument array), or a single Object (used
+			as single argument).</description>
 			<name>arguments</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The separator character to be used for splitting the
+			arguments string value; defaults to a 'comma' (',').</description>
+			<name>argumentSeparator</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>Default text to output when a message for the given code
+			could not be found. If both text and code are not set, the tag will
+			output null.</description>
 			<name>text</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The string to use when binding the result to the page,
+			request, session or application scope. If not specified, the result
+			gets outputted to the writer (i.e. typically directly to the JSP).</description>
 			<name>var</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The scope to use when exporting the result to a variable.
+			This attribute is only used when var is also set. Possible values are
+			page, request, session and application.</description>
 			<name>scope</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set HTML escaping for this tag, as boolean value.
+			Overrides the default HTML escaping setting for the current page.</description>
 			<name>htmlEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set JavaScript escaping for this tag, as boolean value. Default is false.</description>
 			<name>javaScriptEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 	</tag>
 
-
 	<tag>
-
-		<name>theme</name>
-		<tag-class>org.springframework.web.servlet.tags.ThemeTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Retrieves the theme message with the given code, or text if code isn't resolvable.
 			The HTML escaping flag participates in a page-wide or application-wide setting
 			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
 		</description>
-
+		<name>theme</name>
+		<tag-class>org.springframework.web.servlet.tags.ThemeTag</tag-class>
+		<body-content>JSP</body-content>
 		<attribute>
+			<description>A MessageSourceResolvable argument (direct or through JSP EL).</description>
+			<name>message</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>The code (key) to use when looking up the message.
+			If code is not provided, the text attribute will be used.</description>
 			<name>code</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set optional message arguments for this tag, as a
+			(comma-)delimited String (each String argument can contain JSP EL),
+			an Object array (used as argument array), or a single Object (used
+			as single argument).</description>
 			<name>arguments</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The separator character to be used for splitting the
+			arguments string value; defaults to a 'comma' (',').</description>
+			<name>argumentSeparator</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>Default text to output when a message for the given code
+			could not be found. If both text and code are not set, the tag will
+			output null.</description>
 			<name>text</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The string to use when binding the result to the page,
+			request, session or application scope. If not specified, the result
+			gets outputted to the writer (i.e. typically directly to the JSP).</description>
 			<name>var</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The scope to use when exporting the result to a variable.
+			This attribute is only used when var is also set. Possible values are
+			page, request, session and application.</description>
 			<name>scope</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set HTML escaping for this tag, as boolean value.
+			Overrides the default HTML escaping setting for the current page.</description>
 			<name>htmlEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set JavaScript escaping for this tag, as boolean value. Default is false.</description>
 			<name>javaScriptEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 	</tag>
 
-
 	<tag>
-
-		<name>hasBindErrors</name>
-		<tag-class>org.springframework.web.servlet.tags.BindErrorsTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Provides Errors instance in case of bind errors.
 			The HTML escaping flag participates in a page-wide or application-wide setting
 			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
 		</description>
-
+		<name>hasBindErrors</name>
+		<tag-class>org.springframework.web.servlet.tags.BindErrorsTag</tag-class>
+		<body-content>JSP</body-content>
 		<variable>
 			<name-given>errors</name-given>
 			<variable-class>org.springframework.validation.Errors</variable-class>
 		</variable>
-
 		<attribute>
+			<description>The name of the bean in the request, that needs to be
+			inspected for errors. If errors are available for this bean, they
+			will be bound under the 'errors' key.</description>
 			<name>name</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set HTML escaping for this tag, as boolean value.
+			Overrides the default HTML escaping setting for the current page.</description>
 			<name>htmlEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 	</tag>
 
-
 	<tag>
-
-		<name>nestedPath</name>
-		<tag-class>org.springframework.web.servlet.tags.NestedPathTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Sets a nested path to be used by the bind tag's path.
 		</description>
-
+		<name>nestedPath</name>
+		<tag-class>org.springframework.web.servlet.tags.NestedPathTag</tag-class>
+		<body-content>JSP</body-content>
 		<variable>
 			<name-given>nestedPath</name-given>
 			<variable-class>java.lang.String</variable-class>
 		</variable>
-
 		<attribute>
+			<description>Set the path that this tag should apply. E.g. 'customer'
+			to allow bind paths like 'address.street' rather than
+			'customer.address.street'.</description>
 			<name>path</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 	</tag>
 
-
 	<tag>
-
-		<name>bind</name>
-		<tag-class>org.springframework.web.servlet.tags.BindTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Provides BindStatus object for the given bind path.
 			The HTML escaping flag participates in a page-wide or application-wide setting
 			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
 		</description>
-
+		<name>bind</name>
+		<tag-class>org.springframework.web.servlet.tags.BindTag</tag-class>
+		<body-content>JSP</body-content>
 		<variable>
 			<name-given>status</name-given>
 			<variable-class>org.springframework.web.servlet.support.BindStatus</variable-class>
 		</variable>
-
 		<attribute>
+			<description>The path to the bean or bean property to bind status
+			information for. For instance account.name, company.address.zipCode
+			or just employee. The status object will exported to the page scope,
+			specifically for this bean or bean property</description>
 			<name>path</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set whether to ignore a nested path, if any. Default is to not ignore.</description>
 			<name>ignoreNestedPath</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>Set HTML escaping for this tag, as boolean value. Overrides
+			the default HTML escaping setting for the current page.</description>
 			<name>htmlEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 	</tag>
 
-
 	<tag>
-
-		<name>transform</name>
-		<tag-class>org.springframework.web.servlet.tags.TransformTag</tag-class>
-		<body-content>JSP</body-content>
-
 		<description>
 			Provides transformation of variables to Strings, using an appropriate
 			custom PropertyEditor from BindTag (can only be used inside BindTag).
 			The HTML escaping flag participates in a page-wide or application-wide setting
-			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+			(i.e. by HtmlEscapeTag or a 'defaultHtmlEscape' context-param in web.xml).
 		</description>
-
+		<name>transform</name>
+		<tag-class>org.springframework.web.servlet.tags.TransformTag</tag-class>
+		<body-content>JSP</body-content>
 		<attribute>
+			<description>The value to transform. This is the actual object you want
+			to have transformed (for instance a Date). Using the PropertyEditor that
+			is currently in use by the 'spring:bind' tag.</description>
 			<name>value</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The string to use when binding the result to the page,
+			request, session or application scope. If not specified, the result gets
+			outputted to the writer (i.e. typically directly to the JSP).</description>
 			<name>var</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
-
 		<attribute>
+			<description>The scope to use when exported the result to a variable.
+			This attribute is only used when var is also set. Possible values are
+			page, request, session and application.</description>
 			<name>scope</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
+		<attribute>
+			<description>Set HTML escaping for this tag, as boolean value. Overrides
+			the default HTML escaping setting for the current page.</description>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+	</tag>
 
+	<tag>
+		<description>URL tag based on the JSTL c:url tag.  This variant is fully 
+		backwards compatible with the standard tag.  Enhancements include support 
+		for URL template parameters.</description>
+		<name>url</name>
+		<tag-class>org.springframework.web.servlet.tags.UrlTag</tag-class>
+		<body-content>JSP</body-content>
+		<attribute>
+			<description>The URL to build.  This value can include template place holders 
+			that are replaced with the URL encoded value of the named parameter.  Parameters 
+			must be defined using the param tag inside the body of this tag.</description>
+			<name>value</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>Specifies a remote application context path.  The default is the 
+			current application context path.</description>
+			<name>context</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>The name of the variable to export the URL value to.</description>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
 		<attribute>
+			<description>The scope for the var.  'application', 'session', 'request' and 
+			'page' scopes are supported.  Defaults to page scope.  This attribute has no 
+			effect unless the var attribute is also defined.</description>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>Set HTML escaping for this tag, as a boolean value. Overrides the
+			default HTML escaping setting for the current page.</description>
 			<name>htmlEscape</name>
 			<required>false</required>
 			<rtexprvalue>true</rtexprvalue>
 		</attribute>
+		<attribute>
+			<description>Set JavaScript escaping for this tag, as a boolean value.
+			Default is false.</description>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+	</tag>
+
+	<tag>
+		<description>Parameter tag based on the JSTL c:param tag.  The sole purpose is to 
+		support params inside the spring:url tag.</description>
+		<name>param</name>
+		<tag-class>org.springframework.web.servlet.tags.ParamTag</tag-class>
+		<body-content>JSP</body-content>
+		<attribute>
+			<description>The name of the parameter.</description>
+			<name>name</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>The value of the parameter.</description>
+			<name>value</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+	</tag>
 
+	<tag>
+		<description>Evaluates a Spring expression (SpEL) and either prints the result or assigns it to a variable.</description>
+		<name>eval</name>
+		<tag-class>org.springframework.web.servlet.tags.EvalTag</tag-class>
+		<body-content>JSP</body-content>
+		<attribute>
+			<description>The expression to evaluate.</description>
+			<name>expression</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>The name of the variable to export the evaluation result to.</description>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>The scope for the var.  'application', 'session', 'request' and 
+			'page' scopes are supported.  Defaults to page scope.  This attribute has no 
+			effect unless the var attribute is also defined.</description>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>Set HTML escaping for this tag, as a boolean value. Overrides the
+			default HTML escaping setting for the current page.</description>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+		<attribute>
+			<description>Set JavaScript escaping for this tag, as a boolean value.  Default is false.</description>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
 	</tag>
 
 </taglib>

+ 3 - 3
grizzly-bm/pom.xml

@@ -68,7 +68,7 @@
         <dependency>
             <groupId>org.glassfish.grizzly</groupId>
             <artifactId>grizzly-http-server</artifactId>
-            <version>2.3.7-SNAPSHOT</version>
+            <version>2.3.5</version>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
@@ -76,10 +76,10 @@
             <version>2.2.2</version>
         </dependency>
     </dependencies>
-    <repositories>
+    <!-- <repositories>
         <repository>
             <id>grizzly-snapshots</id>
             <url>https://maven.java.net/content/repositories/snapshots/</url>
         </repository>
-    </repositories>
+    </repositories> -->
 </project>

+ 5 - 3
grizzly-bm/src/main/java/org/glassfish/grizzly/bm/Server.java

@@ -12,7 +12,7 @@ import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
 public class Server {
     public static final String SERVER_VERSION = "Grizzly/" + Grizzly.getDotedVersion();
     
-    public static void main(String[] args) throws IOException {
+    public static void main(String[] args) throws Exception {
         final int port = args.length > 0
                 ? Integer.parseInt(args[0]) : 8080;
         
@@ -39,8 +39,10 @@ public class Server {
         try {
             httpServer.start();
             
-            System.err.print("Server started. Press ENTER to stop.\n");
-            System.in.read();
+            System.err.print("Server started.\n");
+            synchronized (Server.class) {
+		Server.class.wait();
+            }
         } finally {
             httpServer.stop();
         }

+ 11 - 4
grizzly-jersey/src/main/java/hello/JerseyWebServer.java

@@ -34,10 +34,17 @@ public class JerseyWebServer {
     rc.setPropertiesAndFeatures(properties());
     rc.getContainerResponseFilters().add(new ServerResponseFilter());
     HttpServer server = GrizzlyServerFactory.createHttpServer(baseUri, rc);
-    
-    System.err.print("Server started. Press ENTER to stop.");
-    System.in.read();
-    server.stop();
+
+    try {
+        server.start();
+
+        System.err.print("Server started.\n");
+        synchronized (JerseyWebServer.class) {
+            JerseyWebServer.class.wait();
+        }
+    } finally {
+        server.stop();
+    }
   }
 
   private Map<String, Object> properties() {

+ 4 - 3
kelp/nginx.conf

@@ -1,4 +1,4 @@
-user USR;
+user tfb;
 error_log /dev/null crit;
 
 worker_processes 2;
@@ -11,13 +11,15 @@ http {
   output_buffers   1 32k;
   postpone_output  1460;
 
+  access_log       off;
+
   sendfile         on;
   tcp_nopush       on;
 
   tcp_nodelay      on;
 
   upstream backendurl {
-    server unix:/home/ubuntu/FrameworkBenchmarks/kelp/frameworks-benchmark.sock;
+    server unix:/home/tfb/FrameworkBenchmarks/kelp/frameworks-benchmark.sock;
   }
 
   server {
@@ -26,7 +28,6 @@ http {
 
     location / {
       try_files $uri @proxy;
-      access_log off;
       expires max;
     }
 

+ 4 - 3
mojolicious/nginx.conf

@@ -1,4 +1,4 @@
-user USR;
+user tfb;
 error_log /dev/null crit;
 
 worker_processes 2;
@@ -11,13 +11,15 @@ http {
   output_buffers   1 32k;
   postpone_output  1460;
 
+  access_log       off;
+
   sendfile         on;
   tcp_nopush       on;
 
   tcp_nodelay      on;
 
   upstream backendurl {
-    server unix:/home/ubuntu/FrameworkBenchmarks/mojolicious/frameworks-benchmark.sock;
+    server unix:/home/tfb/FrameworkBenchmarks/mojolicious/frameworks-benchmark.sock;
   }
 
   server {
@@ -26,7 +28,6 @@ http {
 
     location / {
       try_files $uri @proxy;
-      access_log off;
       expires max;
     }
 

+ 21 - 2
nancy/setup_iis.ps1

@@ -1,7 +1,26 @@
 param($action)
 
+$ErrorActionPreference = 'Stop'
+
+# From http://zduck.com/2012/powershell-batch-files-exit-codes/
+function Exec
+{
+    [CmdletBinding()]
+    param (
+        [Parameter(Position=0, Mandatory=1)]
+        [scriptblock]$Command,
+        [Parameter(Position=1, Mandatory=0)]
+        [string]$ErrorMessage = "Execution of command failed.`n$Command"
+    )
+    & $Command
+    if ($LastExitCode -ne 0) {
+        throw "Exec: $ErrorMessage"
+    }
+}
+
 $wwwroot = "C:\FrameworkBenchmarks\nancy\www"
 $source = "C:\FrameworkBenchmarks\nancy\src"
+$msbuild = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
 
 # Stop
 if (Get-WebSite -Name Benchmarks) { Remove-WebSite -Name Benchmarks }
@@ -14,6 +33,6 @@ if ($action -eq 'start') {
     New-WebSite -Name Benchmarks -Port 8080 -PhysicalPath $wwwroot
     
     # Build the project
-    C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe "$source\NancyBenchmark.csproj" /p:Configuration=Release /p:Platform="AnyCPU" /t:Clean
-    C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe "$source\NancyBenchmark.csproj" /p:Configuration=Release /p:Platform="AnyCPU" /p:DeployOnBuild=true /p:PublishProfile=IIS
+    Exec { & $msbuild "$source\NancyBenchmark.csproj" /p:Configuration=Release /p:Platform="AnyCPU" /t:Clean }
+    Exec { & $msbuild "$source\NancyBenchmark.csproj" /p:Configuration=Release /p:Platform="AnyCPU" /p:DeployOnBuild=true /p:PublishProfile=IIS }
 }

+ 2 - 2
nancy/setup_iis.py

@@ -9,7 +9,7 @@ def start(args):
   
   try:
     setup_util.replace_text("nancy/src/Web.config", "localhost", args.database_host)
-    subprocess.check_call("powershell -File setup_iis.ps1 start", cwd="nancy")
+    subprocess.check_call("powershell -Command .\\setup_iis.ps1 start", cwd="nancy")
     return 0
   except subprocess.CalledProcessError:
     return 1
@@ -18,5 +18,5 @@ def stop():
   if os.name != 'nt':
     return 0
   
-  subprocess.Popen("powershell -File setup_iis.ps1 stop", cwd="nancy")
+  subprocess.check_call("powershell -Command .\\setup_iis.ps1 stop", cwd="nancy")
   return 0

+ 1 - 1
php-kohana/benchmark_config

@@ -1,5 +1,5 @@
 {
-  "framework": "kohana",
+  "framework": "php-kohana",
   "tests": [{
     "default": {
       "setup_file": "setup",

+ 1 - 1
php-phalcon-micro/benchmark_config

@@ -1,5 +1,5 @@
 {
-  "framework": "phalcon-micro",
+  "framework": "php-phalcon-micro",
   "tests": [{
     "default": {
       "setup_file": "setup",

+ 1 - 1
php-phalcon/benchmark_config

@@ -1,5 +1,5 @@
 {
-  "framework": "phalcon",
+  "framework": "php-phalcon",
   "tests": [{
     "default": {
       "setup_file": "setup",

+ 1 - 1
php-phpixie/assets/config/db.php

@@ -7,7 +7,7 @@ return array(
 		'driver' => 'PDO',
 		
 		//'Connection' is required if you use the PDO driver
-		'connection'=>'mysql:host=tfbdata;dbname=hello_world',
+		'connection'=>'mysql:host=localhost;dbname=hello_world',
 		
 		// 'db' and 'host' are required if you use Mysqli driver
 		'db' => 'hello_world',

+ 1 - 1
php-phpixie/benchmark_config

@@ -1,5 +1,5 @@
 {
-  "framework": "phpixie",
+  "framework": "php-phpixie",
   "tests": [{
     "default": {
       "setup_file": "setup",

+ 1 - 1
plain/benchmark_config

@@ -15,7 +15,7 @@
       "database": "MySQL",
       "framework": "plain",
       "language": "Scala",
-      "orm": "Full",
+      "orm": "Micro",
       "platform": "Plain",
       "webserver": "None",
       "os": "Linux",

+ 9 - 9
plain/build.sbt

@@ -7,7 +7,7 @@ name := "plain-benchmark"
 
 organization := "com.ibm"
 
-scalaVersion := "2.10.2"
+scalaVersion := "2.10.3"
 
 version := "1.0.1"
 
@@ -25,29 +25,29 @@ scalacOptions in Compile ++= Seq(
 )
 
 libraryDependencies ++= Seq(
-  "org.scala-lang" % "scala-reflect" % "2.10.2",
+  "org.scala-lang" % "scala-reflect" % "2.10.3",
   "org.reflections" % "reflections" % "0.9.8",
   "com.typesafe" % "config" % "1.0.2",
   "ch.qos.logback" % "logback-classic" % "1.0.13",
   "org.codehaus.janino" % "janino" % "2.6.1",
-  "com.lmax" % "disruptor" % "3.1.1",
-  "com.typesafe.akka" %% "akka-actor" % "2.2.0",
-  "com.typesafe.akka" %% "akka-slf4j" % "2.2.0",
+  "com.lmax" % "disruptor" % "3.2.0",
+  "com.typesafe.akka" %% "akka-actor" % "2.2.1",
+  "com.typesafe.akka" %% "akka-slf4j" % "2.2.1",
   "org.apache.commons" % "commons-lang3" % "3.1",
   "org.apache.commons" % "commons-compress" % "1.5",
   "commons-io" % "commons-io" % "2.4",
   "commons-net" % "commons-net" % "3.3",
   "commons-codec" % "commons-codec" % "1.8",
   "com.googlecode.concurrentlinkedhashmap" % "concurrentlinkedhashmap-lru" % "1.3.2",
-  "net.jpountz.lz4" % "lz4" % "1.1.2",
-  "com.fasterxml.jackson.core" % "jackson-databind" % "2.2.2",
+  "net.jpountz.lz4" % "lz4" % "1.2.0",
+  "com.fasterxml.jackson.core" % "jackson-databind" % "2.2.3",
   "com.sun.jersey" % "jersey-json" % "1.17.1",
   "org.jvnet.mimepull" % "mimepull" % "1.9.3",
   "org.apache.derby" % "derby" % "10.10.1.1",
   "org.apache.derby" % "derbyclient" % "10.10.1.1",
   "com.h2database" % "h2" % "1.3.172",
-  "mysql" % "mysql-connector-java" % "5.1.25",
-  "javax.servlet" % "servlet-api" % "2.5"
+  "mysql" % "mysql-connector-java" % "5.1.26",
+  "javax.servlet" % "javax.servlet-api" % "3.1.0"
 )
 
 Revolver.settings

BIN
plain/lib/plain-library_2.10-1.0.1-SNAPSHOT.jar


+ 1 - 1
plain/sbt

@@ -1 +1 @@
-java -Xmx3g -Xms2g -Xmn1g -Xss8M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=384M -Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy -jar `dirname $0`/sbt-launch.jar "$@"
+java -server -Xnoclassgc -XX:MaxPermSize=1g -XX:ReservedCodeCacheSize=384m -Xmx8g -Xss8m -Xmn4g -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=384M -Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy -jar `dirname $0`/sbt-launch.jar "$@"

+ 55 - 0
plain/sbt.bat

@@ -0,0 +1,55 @@
+@REM SBT launcher script
+@REM 
+@REM Envioronment:
+@REM JAVA_HOME - location of a JDK home dir (mandatory)
+@REM SBT_OPTS  - JVM options (optional)
+@REM Configuration:
+@REM sbtconfig.txt found in the SBT_HOME.
+
+@REM   ZOMG! We need delayed expansion to build up CFG_OPTS later 
+@setlocal enabledelayedexpansion
+
+@echo off
+set SBT_HOME=%~dp0
+set SBT_OPTS=-Xmx3g -Xms2g -Xmn1g -Xss8M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=384M
+set ERROR_CODE=0
+
+rem FIRST we load the config file of extra options.
+set FN=%SBT_HOME%\..\conf\sbtconfig.txt
+set CFG_OPTS=
+FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%FN%") DO (
+  set DO_NOT_REUSE_ME=%%i
+  rem ZOMG (Part #2) WE use !! here to delay the expansion of
+  rem CFG_OPTS, otherwise it remains "" for this loop.
+  set CFG_OPTS=!CFG_OPTS! !DO_NOT_REUSE_ME!
+)
+
+rem We use the value of the JAVACMD environment variable if defined
+set _JAVACMD=%JAVACMD%
+
+if "%_JAVACMD%"=="" (
+  if not "%JAVA_HOME%"=="" (
+    if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe"
+  )
+)
+
+if "%_JAVACMD%"=="" set _JAVACMD=java
+
+rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config.
+set _JAVA_OPTS=%JAVA_OPTS%
+if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=%CFG_OPTS%
+
+:run
+
+"%_JAVACMD%" %_JAVA_OPTS% %SBT_OPTS% -cp "%SBT_HOME%sbt-launch.jar" xsbt.boot.Boot %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+
+@endlocal
+
+exit /B %ERROR_CODE%

+ 13 - 5
plain/setup.py

@@ -1,16 +1,24 @@
-
+import setup_util
 import subprocess
 import sys
 import time
 import os
 
-def start(args=None):
+def start(args):
+  setup_util.replace_text("plain/src/main/resources/application.conf", "127.0.0.1", args.database_host)
+  if os.name == 'nt':
+    subprocess.check_call("./sbt.bat assembly", shell=True, cwd="plain")
+  else:
     subprocess.check_call("./sbt assembly", shell=True, cwd="plain")
-    subprocess.Popen("java -server -Xnoclassgc -XX:MaxPermSize=1g -XX:ReservedCodeCacheSize=384m -Xmx8g -Xss8m -Xmn4g -jar target/scala-2.10/plain-benchmark-assembly-1.0.1.jar", cwd="plain", shell=True)
-    time.sleep(10)
-    return 0
+     
+  subprocess.Popen("java -server -Xnoclassgc -XX:MaxPermSize=1g -XX:ReservedCodeCacheSize=384m -Xmx8g -Xss8m -Xmn4g -Xms6g -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar target/scala-2.10/plain-benchmark-assembly-1.0.1.jar", cwd="plain", shell=True)
+  time.sleep(10)
+  return 0
 
 def stop():
+  if os.name == 'nt':
+    subprocess.call("taskkill /f /im *plain-benchmark* > NUL", shell=True)
+    return 0
   p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
   out, err = p.communicate()
   for line in out.splitlines():

+ 3 - 3
plain/src/main/resources/application.conf

@@ -32,11 +32,11 @@ benchmark-mysql {
 	name = MysqlBenchmark
 	driver = mysql-5-6-12
 	datasource-settings {	
-		setUrl = "jdbc:mysql://127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&dontTrackOpenResources=true&enableQueryTimeouts=false&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=1024&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=true&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true&poolPreparedStatements=true&maxOpenPreparedStatements=100"
+        	setUrl = "jdbc:mysql://127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&dontTrackOpenResources=true&enableQueryTimeouts=false&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=1024&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=true&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true&poolPreparedStatements=true&maxOpenPreparedStatements=100"
 		setUser = "benchmarkdbuser"
 		setPassword = "benchmarkdbpass"
 	}	
-	min-pool-size = 16
-	max-pool-size = 128
+	min-pool-size = 0
+	max-pool-size = 64
 }
 

+ 18 - 12
plain/src/main/scala/com/ibm/techempower/Db.scala

@@ -4,6 +4,7 @@ import java.util.concurrent.ThreadLocalRandom.{ current => random }
 
 import scala.language.implicitConversions
 import scala.language.postfixOps
+import scala.collection.mutable.MutableList
 
 import com.ibm.plain.rest.{ Form, Resource }
 import com.ibm.plain.json.{ Json => J }
@@ -33,27 +34,28 @@ sealed abstract class DbResource
     extends Resource {
 
   @inline protected[this] final def get(form: Option[Form]): J = {
-    var list: List[J] = Nil
+    val output = new MutableList[J]
     val q = form match { case None => 1 case Some(f) => queries(f) }
-    withConnection(datasource) {
-      implicit connection => for (i <- 1 to q) { for (j <- selectsql << next <<! asJson) { list = j :: list } }
+    withConnection(datasource) { implicit connection =>
+      for (i <- 1 to q) { for (j <- selectsql << next <<! asJson) { output += j } }
     }
-    form match { case None => list.head case _ => J(list) }
+    form match { case None => output.head case _ => J(output.toList) }
   }
 
   @inline protected[this] final def update(form: Form): J = {
-    var list: List[J] = Nil
+    val input = new MutableList[World]
+    val output = new MutableList[J]
     val q = queries(form)
-    withConnection(datasource) {
-      implicit connection =>
-        for (i <- 1 to q) {
-          val id = next
+    withConnection(datasource) { implicit connection =>
+      for (i <- 1 to q) { for (j <- selectsql << next <<! asTuple) { input += j } }
+      input.foreach {
+        case (id, _) =>
           val randomNumber = next
           updatesql << randomNumber << id <<!!;
-          list = asJson(id, randomNumber) :: list
-        }
+          output += asJson(id, randomNumber)
+      }
     }
-    J(list)
+    J(output.toList)
   }
 
   @inline private[this] final def queries(form: Form) = try {
@@ -70,8 +72,12 @@ sealed abstract class DbResource
 
   @inline private[this] final def asJson(id: Int, randomNumber: Int) = J(Map("id" -> id, "randomNumber" -> randomNumber))
 
+  @inline private[this] final def asTuple = (r: RichResultSet) => (r.nextInt.get, r.nextInt.get)
+
   @inline private[this] final def next = random.nextInt(1, 10001)
 
+  private[this] final type World = (Int, Int)
+
   private[this] final val selectsql = "select id, randomNumber from World where id = ?"
 
   private[this] final val updatesql = "update World set randomNumber = ? where id = ?"

+ 33 - 0
play-activate-mysql/.gitignore

@@ -0,0 +1,33 @@
+logs
+project/project
+project/target
+public
+target
+test
+tmp
+.history
+dist
+conf/evolutions
+
+# Ignore all dotfiles...
+.*
+# except for .gitignore
+!.gitignore
+
+# Ignore Play! working directory #
+db
+eclipse
+lib
+log
+logs
+modules
+precompiled
+project/project
+project/target
+target
+tmp
+test-result
+server.pid
+*.iml
+*.eml
+

+ 27 - 0
play-activate-mysql/README.md

@@ -0,0 +1,27 @@
+#Play Benchmarking Test
+
+This is the Play portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test source](app/controllers/Application.scala)
+
+### Data-Store/Database Mapping Test
+
+* [Database test controller](app/controllers/Application.scala)
+* [Database test model](app/models/World.scala)
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
+* [Play 2.1.0](http://http://www.playframework.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/db?queries=5

+ 7 - 0
play-activate-mysql/app/Global.scala

@@ -0,0 +1,7 @@
+import play.api._
+import com.typesafe.config.ConfigFactory
+
+object Global extends GlobalSettings {
+	System.setProperty("activate.offlineLocking.enable", "true")
+	System.setProperty("activate.offlineLocking.validateReads", "true")
+}

+ 62 - 0
play-activate-mysql/app/controllers/Application.scala

@@ -0,0 +1,62 @@
+package controllers
+
+import play.api.Play.current
+import play.api.mvc._
+import play.api.libs.json.Json
+import java.util.concurrent._
+import scala.concurrent._
+import scala.concurrent.Future
+import play.api.libs.concurrent.Execution.Implicits._
+import play.core.NamedThreadFactory
+import models.ActivateWorld
+import models.Models._
+import models.ActivateFortune
+import models.persistenceContext._
+
+object Application extends Controller {
+
+    private val TestDatabaseRows = 10000
+
+    def db(queries: Int) =
+        Action {
+            transactional {
+                val random = ThreadLocalRandom.current()
+
+                val worlds =
+                    for (_ <- 1 to queries) yield {
+                        ActivateWorld.fingByLegacyId(random.nextInt(TestDatabaseRows) + 1)
+                    }
+
+                Ok(Json.toJson(worlds))
+            }
+        }
+
+    def fortunes() =
+        Action {
+            val transaction = new Transaction
+            try
+                transactional(transaction) {
+                    val fortunes =
+                        ActivateFortune.all ++ List(new ActivateFortune(-1, "Additional fortune added at request time."))
+                    Ok(views.html.fortune(fortunes))
+                }
+            finally
+                transaction.rollback
+        }
+
+    def update(queries: Int) =
+        Action {
+
+            val random = ThreadLocalRandom.current()
+
+            transactional {
+                val worlds =
+                    for (_ <- 1 to queries) yield {
+                        val world = ActivateWorld.fingByLegacyId(random.nextInt(TestDatabaseRows) + 1)
+                        world.randomNumber = random.nextInt(TestDatabaseRows) + 1
+                        world
+                    }
+                Ok(Json.toJson(worlds)).withHeaders("Server" -> "Netty")
+            }
+        }
+}

+ 66 - 0
play-activate-mysql/app/models/Migrations.scala

@@ -0,0 +1,66 @@
+package models
+
+import persistenceContext._
+
+class CreateSchema extends Migration {
+
+    def timestamp = System.currentTimeMillis + 100
+
+    def up = {
+        removeAllEntitiesTables.cascade.ifExists
+        createTableForAllEntities.ifNotExists
+    }
+
+}
+
+class MigrateFortunes extends Migration {
+
+    def timestamp = System.currentTimeMillis + 200
+
+    def up = {
+        customScript {
+            val con = storage.directAccess
+            try {
+                val rs = con.createStatement.executeQuery("SELECT id, message FROM Fortune")
+                while (rs.next)
+                    new ActivateFortune(rs.getLong(1), rs.getString(2))
+            } finally
+                con.close
+        }
+    }
+
+}
+
+class MigrateWorlds extends Migration {
+
+    def timestamp = System.currentTimeMillis + 300
+
+    def up = {
+        customScript {
+            val con = storage.directAccess
+            try {
+                val rs = con.createStatement.executeQuery("SELECT id, randomNumber FROM World")
+                while (rs.next)
+                    new ActivateWorld(rs.getLong(1), rs.getInt(2))
+            } finally
+                con.close
+        }
+    }
+
+}
+
+class CreateVersionIndexes extends Migration {
+    
+    def timestamp = System.currentTimeMillis + 400
+    
+    def up = {
+        customScript {
+            val con = storage.directAccess
+            try {
+                con.createStatement.executeUpdate("CREATE UNIQUE INDEX IX_WORLD_VERSION ON ActivateWorld(id, version)")
+                con.createStatement.executeUpdate("CREATE UNIQUE INDEX IX_FORTUNE_VERSION ON ActivateFortune(id, version)")
+            } finally
+                con.close
+        }
+    }
+}

+ 35 - 0
play-activate-mysql/app/models/Models.scala

@@ -0,0 +1,35 @@
+package models
+
+import persistenceContext._
+import play.api.libs.json.JsValue
+import play.api.libs.json.Json
+import play.api.libs.json.Json.toJsFieldJsValueWrapper
+import play.api.libs.json.Writes
+
+class ActivateFortune(val legacyId: Long, val message: String) extends Entity
+
+object ActivateFortune {
+    def all = indexFortuneAll.get(1)
+}
+
+class ActivateWorld(val legacyId: Long, var randomNumber: Long) extends Entity
+
+object ActivateWorld {
+    def fingByLegacyId(legacyId: Long) =
+        indexWorldByLegacyId
+            .get(legacyId)
+            .headOption
+            .getOrElse(throw new IllegalStateException("invalid id " + legacyId))
+}
+
+object Models {
+
+    implicit val worldToJson =
+        new Writes[ActivateWorld] {
+            def writes(w: ActivateWorld): JsValue =
+                Json.obj(
+                    "id" -> w.legacyId,
+                    "randomNumber" -> w.randomNumber)
+        }
+
+}

+ 28 - 0
play-activate-mysql/app/models/PersistenceContext.scala

@@ -0,0 +1,28 @@
+package models
+
+import net.fwbrasil.activate.ActivateContext
+import net.fwbrasil.activate.storage.relational.idiom.postgresqlDialect
+import net.fwbrasil.activate.storage.relational.PooledJdbcRelationalStorage
+import net.fwbrasil.activate.storage.relational.idiom.mySqlDialect
+import play.api.Play
+import net.fwbrasil.activate.OptimisticOfflineLocking
+
+object persistenceContext extends ActivateContext {
+	require(OptimisticOfflineLocking.isEnabled)
+	require(OptimisticOfflineLocking.validateReads)
+    
+    private def config = Play.current.configuration
+    
+    val storage = new PooledJdbcRelationalStorage {
+        val jdbcDriver = config.getString("db.default.driver").get
+        val user = config.getString("db.default.user").get
+        val password = config.getString("db.default.password").get
+        val url = config.getString("db.default.url").get
+        val dialect = mySqlDialect
+        override val poolSize = 400
+    }
+    
+    val indexWorldByLegacyId = memoryIndex[ActivateWorld].on(_.legacyId)
+    val indexFortuneAll = memoryIndex[ActivateFortune].on(_ => 1)
+
+}

+ 18 - 0
play-activate-mysql/app/views/fortune.scala.html

@@ -0,0 +1,18 @@
+@(fortunes: List[ActivateFortune])
+
+@main("Testcase 4 :: Fortune :: FrameworkBenchmark") {
+    <table>
+        <tr>
+            <th>id</th>
+            <th>message</th>
+        </tr>
+
+        @fortunes.sortBy(_.message).map { fortune => 
+            <tr>
+                <td>@fortune.legacyId</td>
+                <td>@fortune.message</td>
+            </tr>
+        }
+
+    </table>
+}

+ 13 - 0
play-activate-mysql/app/views/main.scala.html

@@ -0,0 +1,13 @@
+@(title: String)(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+<head>
+    <title>@title</title>
+    <meta charset=utf-8>
+</head>
+<body>
+    @content
+</body>
+</html>

+ 26 - 0
play-activate-mysql/benchmark_config

@@ -0,0 +1,26 @@
+{
+  "framework": "play-activate-mysql",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "db_url": "/db",
+      "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/update?queries=",
+      "port": 9000,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "MySQL",
+      "framework": "play2",
+      "language": "Scala",
+      "orm": "Full",
+      "platform": "Netty",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "play-scala-activate",
+      "notes": "",
+      "versus": "netty"
+    }
+  }]
+}

+ 88 - 0
play-activate-mysql/conf/application.conf

@@ -0,0 +1,88 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+# If you deploy your application to several instances be sure to use the same key!
+application.secret="RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# global=Global
+
+# Database configuration
+# ~~~~~ 
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+#db.default.driver=org.h2.Driver
+#db.default.url="jdbc:h2:mem:play"
+#db.default.user=sa
+# db.default.password=
+#
+# You can expose this datasource via JNDI if needed (Useful for JPA)
+# db.default.jndiName=DefaultDS
+db.default.driver=com.mysql.jdbc.Driver
+db.default.url="jdbc:mysql://localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+db.default.user=benchmarkdbuser
+db.default.password=benchmarkdbpass
+db.default.jndiName=DefaultDS
+
+# db.default.partitionCount=4
+
+# The number of connections to create per partition. Setting this to 
+# 5 with 3 partitions means you will have 15 unique connections to the 
+# database. Note that BoneCP will not create all these connections in 
+# one go but rather start off with minConnectionsPerPartition and 
+# gradually increase connections as required.
+# db.default.maxConnectionsPerPartition=64
+
+# The number of initial connections, per partition.
+# db.default.minConnectionsPerPartition=64
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/), by providing a logger.xml file in the conf directory .
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=ERROR
+
+# Logger provided to your application:
+logger.application=ERROR
+
+iteratee-threadpool-size=300
+
+play {
+  akka {
+    event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
+    loglevel = WARNING
+    actor {
+      default-dispatcher = {
+        fork-join-executor {
+          parallelism-factor = 4.0
+          parallelism-max = 300
+        }
+      }
+      application = {
+        fork-join-executor {
+          parallelism-max = 300
+        }
+      }
+    }
+  }
+}

+ 1 - 0
play-activate-mysql/conf/play.plugins

@@ -0,0 +1 @@
+100:net.fwbrasil.activate.play.ActivatePlayPlugin

+ 11 - 0
play-activate-mysql/conf/routes

@@ -0,0 +1,11 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET     /db                             controllers.Application.db(queries: Int ?= 1)
+GET     /fortunes                       controllers.Application.fortunes
+GET     /update                         controllers.Application.update(queries: Int ?= 1)
+
+# Map static resources from the /public folder to the /assets URL path
+GET     /assets/*file                   controllers.Assets.at(path="/public", file)

+ 28 - 0
play-activate-mysql/project/Build.scala

@@ -0,0 +1,28 @@
+import sbt._
+import Keys._
+import play.Project._
+
+object ApplicationBuild extends Build {
+
+  val appName         = "play-activate-mysql"
+  val appVersion      = "1.0-SNAPSHOT"
+
+  val activateVersion = "1.4.4"
+  val activateCore = "net.fwbrasil" %% "activate-core" % activateVersion
+  val activateJdbc = "net.fwbrasil" %% "activate-jdbc" % activateVersion
+  val activatePlay = "net.fwbrasil" %% "activate-play" % activateVersion
+
+  val mysql = "mysql" % "mysql-connector-java" % "5.1.16"
+
+  val appDependencies = Seq(
+    mysql,
+    activateCore,
+    activateJdbc,
+    activatePlay
+  )
+
+  val main = play.Project(appName, appVersion, appDependencies).settings(
+	  resolvers ++= Seq("fwbrasil.net" at "http://fwbrasil.net/maven/")
+  )
+
+}

+ 1 - 0
play-activate-mysql/project/build.properties

@@ -0,0 +1 @@
+sbt.version=0.13.0

+ 8 - 0
play-activate-mysql/project/plugins.sbt

@@ -0,0 +1,8 @@
+// Comment to get more information during initialization
+logLevel := Level.Warn
+
+// The Typesafe repository 
+resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
+
+// Use the Play sbt plugin for Play projects
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.2.0")

+ 45 - 0
play-activate-mysql/setup.py

@@ -0,0 +1,45 @@
+
+import subprocess
+import sys
+import setup_util
+import os
+from zipfile import ZipFile
+
+def start(args):
+  setup_util.replace_text("play-activate-mysql/conf/application.conf", "jdbc:mysql:\/\/.*:3306", "jdbc:mysql://" + args.database_host + ":3306")
+
+  subprocess.check_call("play clean dist", shell=True, cwd="play-activate-mysql")
+
+  if os.name == 'nt':
+    ZipFile("./play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT.zip").extractall("./play-activate-mysql/target/universal")
+    with open("./play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT/bin/play-activate-mysql.bat", "w+") as f:
+      f.write("java %1 -cp \"./lib/*;\" play.core.server.NettyServer .")
+    subprocess.Popen("play-activate-mysql.bat", shell=True, cwd="play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT/bin")
+  else:
+    subprocess.check_call("unzip play-activate-mysql-1.0-SNAPSHOT.zip", shell=True, cwd="play-activate-mysql/target/universal")
+    subprocess.check_call("chmod +x play-activate-mysql", shell=True, cwd="play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT/bin")
+    subprocess.Popen("./play-activate-mysql", shell=True, cwd="play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT/bin")
+
+  return 0
+def stop():
+  if os.name == 'nt':
+    with open("./play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT/RUNNING_PID") as f:
+      pid = int(f.read())
+      os.kill(pid, 9)
+  else:
+    kill_running_process()
+
+  try:
+    os.remove("play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT/RUNNING_PID")
+  except OSError:
+    pass
+
+  return 0
+
+def kill_running_process():
+  try:
+    with open("./play-activate-mysql/target/universal/play-activate-mysql-1.0-SNAPSHOT/RUNNING_PID") as f:
+      pid = int(f.read())
+      os.kill(pid,9)
+  except:
+    pass

+ 1 - 1
play-java-jpa/benchmark_config

@@ -9,7 +9,7 @@
       "approach": "Realistic",
       "classification": "Fullstack",
       "database": "MySQL",
-      "framework": "play-java",
+      "framework": "play2",
       "language": "Java",
       "orm": "Full",
       "platform": "Netty",

+ 1 - 1
play-java-jpa/project/plugins.sbt

@@ -5,4 +5,4 @@ logLevel := Level.Warn
 resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
 
 // Use the Play sbt plugin for Play projects
-addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.2.0-RC2")
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.2.0")

+ 4 - 4
play-java/benchmark_config

@@ -1,5 +1,5 @@
 {
-  "framework": "play",
+  "framework": "play2",
   "tests": [{
     "default": {
       "setup_file": "setup",
@@ -10,16 +10,16 @@
       "approach": "Realistic",
       "classification": "Fullstack",
       "database": "MySQL",
-      "framework": "play-java",
+      "framework": "play2",
       "language": "Java",
       "orm": "Full",
       "platform": "Netty",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "play-java",
+      "display_name": "play-java-ebean",
       "notes": "",
       "versus": "netty"
     }
   }]
-}
+}

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