Explorar el Código

Merge branch 'master' of https://github.com/TechEmpower/FrameworkBenchmarks into environ

Hamilton Turner hace 11 años
padre
commit
c1a7b530dc
Se han modificado 77 ficheros con 929 adiciones y 583 borrados
  1. 1 0
      README.md
  2. 1 1
      bottle/app.py
  3. 1 1
      bottle/benchmark_config
  4. 11 0
      bottle/gunicorn_conf.py
  5. 2 9
      bottle/setup.py
  6. 2 9
      bottle/setup_py3.py
  7. 2 2
      config/requirements-pypy.txt
  8. 1 0
      config/requirements.txt
  9. 9 4
      cpoll_cppsp/www/db
  10. 9 4
      cpoll_cppsp/www/db_pg_async
  11. 9 4
      cpoll_cppsp/www/db_pg_threadpool
  12. 3 0
      dropwizard/benchmark_config
  13. 10 26
      dropwizard/hello-world.yml
  14. 20 10
      dropwizard/pom.xml
  15. 14 10
      dropwizard/setup.py
  16. 15 5
      dropwizard/source_code
  17. 0 25
      dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java
  18. 34 37
      dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java
  19. 20 0
      dropwizard/src/main/java/com/example/helloworld/config/HelloWorldConfiguration.java
  20. 0 36
      dropwizard/src/main/java/com/example/helloworld/core/World.java
  21. 18 0
      dropwizard/src/main/java/com/example/helloworld/db/FortuneDAO.java
  22. 14 15
      dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java
  23. 35 0
      dropwizard/src/main/java/com/example/helloworld/db/model/Fortune.java
  24. 29 0
      dropwizard/src/main/java/com/example/helloworld/db/model/World.java
  25. 37 0
      dropwizard/src/main/java/com/example/helloworld/resources/FortuneResource.java
  26. 6 18
      dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java
  27. 16 0
      dropwizard/src/main/java/com/example/helloworld/resources/TextResource.java
  28. 47 28
      dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java
  29. 17 0
      dropwizard/src/main/java/com/example/helloworld/resources/api/HelloMessage.java
  30. 23 0
      dropwizard/src/main/java/com/example/helloworld/resources/views/FortuneView.java
  31. 14 0
      dropwizard/src/main/resources/fortunes.mustache
  32. 20 0
      falcon/gunicorn_conf.py
  33. 8 7
      falcon/setup.py
  34. 2 6
      falcon/setup_py3.py
  35. 12 10
      falcon/setup_pypy.py
  36. 28 16
      flask/app.py
  37. 7 7
      flask/benchmark_config
  38. 1 0
      flask/requirements.txt
  39. 28 14
      flask/setup.py
  40. 24 9
      flask/setup_py3.py
  41. 1 1
      flask/setup_pypy.py
  42. 2 2
      netty/README.md
  43. 5 4
      netty/pom.xml
  44. 57 66
      netty/src/main/java/hello/HelloServerHandler.java
  45. 9 7
      netty/src/main/java/hello/HelloServerInitializer.java
  46. 33 39
      netty/src/main/java/hello/HelloWebServer.java
  47. 9 9
      netty/src/main/java/hello/Message.java
  48. 3 5
      plack/README.md
  49. 24 14
      plack/app.psgi
  50. 2 2
      plack/benchmark_config
  51. 6 1
      plack/cpanfile
  52. 31 0
      plack/nginx.conf
  53. 12 4
      plack/setup.py
  54. 2 0
      plack/source_code
  55. 4 4
      spring/README.md
  56. 12 18
      spring/pom.xml
  57. 1 1
      spring/src/main/java/com/techempower/spring/web/FortuneController.java
  58. 1 1
      spring/src/main/java/com/techempower/spring/web/WorldDatabaseController.java
  59. 0 2
      spring/src/main/resources/application.yml
  60. 0 4
      spring/src/main/resources/import.sql
  61. 2 3
      toolset/setup/linux/frameworks/wt.sh
  62. 2 2
      toolset/setup/linux/languages/php.sh
  63. 5 5
      toolset/setup/linux/prerequisites.sh
  64. 11 11
      tornado/benchmark_config
  65. 50 1
      tornado/server.py
  66. 32 0
      tornado/setup_pg.py
  67. 0 30
      tornado/setup_pypy.py
  68. 2 2
      undertow-edge/pom.xml
  69. 4 2
      undertow-edge/src/main/java/hello/HelloWebServer.java
  70. 3 3
      undertow-edge/src/main/resources/hello/server.properties
  71. 12 10
      undertow/pom.xml
  72. 6 3
      undertow/src/main/java/hello/HelloWebServer.java
  73. 3 3
      undertow/src/main/resources/hello/server.properties
  74. 1 1
      wsgi/benchmark_config
  75. 10 2
      wsgi/hello.py
  76. 2 0
      wsgi/requirements.txt
  77. 20 8
      wsgi/setup.py

+ 1 - 0
README.md

@@ -25,6 +25,7 @@ $ sudo apt-get install openssh-server
 * If Ubuntu is already installed, run the following command and follow the prompts.
 ```bash
 $ sudo adduser tfb
+$ sudo usermod -a -G sudo tfb
 ```
 * Log in as `tfb`
 * Fully update **NOTE**: If you update the kernel (linux-firmware), it is generally a good idea to reboot aftewards.

+ 1 - 1
bottle/app.py

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

@@ -44,7 +44,7 @@
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "bottle-py3",
-      "notes": "CPython 3.3",
+      "notes": "CPython 3.4",
       "versus": "wsgi"
     },
     "pypy": {

+ 11 - 0
bottle/gunicorn_conf.py

@@ -0,0 +1,11 @@
+import multiprocessing
+
+workers = multiprocessing.cpu_count() * 3
+bind = "0.0.0.0:8080"
+worker_class = "meinheld.gmeinheld.MeinheldWorker"
+keepalive = 120
+
+def post_fork(server, worker):
+    # Disalbe access log
+    import meinheld.server
+    meinheld.server.set_access_logger(None)

+ 2 - 9
bottle/setup.py

@@ -1,10 +1,8 @@
 import subprocess
 import setup_util
-import multiprocessing
 import os
 
 bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py2/bin')
-NCPU = multiprocessing.cpu_count()
 
 proc = None
 
@@ -12,13 +10,8 @@ proc = None
 def start(args, logfile, errfile):
     global proc
     setup_util.replace_text("bottle/app.py", "DBHOSTNAME", args.database_host)
-    proc = subprocess.Popen([
-        bin_dir + "/gunicorn",
-        "app:app",
-        "-k", "meinheld.gmeinheld.MeinheldWorker",
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU*3),
-        "--log-level=critical"],
+    proc = subprocess.Popen(
+        [bin_dir + "/gunicorn", "-c", "gunicorn_conf.py", "app:app"],
         cwd="bottle", stderr=errfile, stdout=logfile)
     return 0
 

+ 2 - 9
bottle/setup_py3.py

@@ -1,10 +1,8 @@
 import subprocess
 import setup_util
-import multiprocessing
 import os
 
 bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py3/bin')
-NCPU = multiprocessing.cpu_count()
 
 proc = None
 
@@ -12,13 +10,8 @@ proc = None
 def start(args, logfile, errfile):
     global proc
     setup_util.replace_text("bottle/app.py", "DBHOSTNAME", args.database_host)
-    proc = subprocess.Popen([
-        bin_dir + "/gunicorn",
-        "app:app",
-        "-k", "meinheld.gmeinheld.MeinheldWorker",
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU*3),
-        "--log-level=critical"],
+    proc = subprocess.Popen(
+        [bin_dir + "/gunicorn", "-c", "gunicorn_conf.py", "app:app"],
         cwd="bottle", stderr=errfile, stdout=logfile)
     return 0
 

+ 2 - 2
config/requirements-pypy.txt

@@ -9,7 +9,7 @@ PyMySQL==0.6.2
 # uwsgi is released too often to stick on single version.
 uwsgi
 
-gunicorn==19.0
+gunicorn==18.0
 meinheld==0.5.6
 
 # Tornado
@@ -33,4 +33,4 @@ bottle-sqlalchemy==0.4.1
 
 # Falcon
 # Cython==0.20.1
-# falcon==0.1.8
+falcon==0.1.8

+ 1 - 0
config/requirements.txt

@@ -1,3 +1,4 @@
+circus
 mysqlclient==1.3.1
 PyMySQL==0.6.2
 psycopg2==2.5.3

+ 9 - 4
cpoll_cppsp/www/db

@@ -128,13 +128,18 @@ void efdCB(eventfd_t efdVal) {
 void waitCB(eventfd_t efdVal) {
 	this->doInit();
 }
-
-%>[<%
+%><%
+if (queries>1) {
+	%>[<%
+}
 for (int i=0;i<queries;i++){
 	if(i>0) output.write(',');
 	%>{"id":<%=items[i].id%>,"randomNumber":<%=items[i].rnd%>}<%
 }
-
+if (queries>1) {
+	%>]<%
+}
+%><%
 response->headers["Content-Type"]="application/json";
 response->headers["Server"]="cppsp/0.2";
-%>]
+%>

+ 9 - 4
cpoll_cppsp/www/db_pg_async

@@ -107,13 +107,18 @@ void evtIn(int) {
 	PQclear(res);
 	beginGetItems();
 }
-
-%>[<%
+%><%
+if(queries>1) {
+	%>[<%
+}
 for (int i=0;i<queries;i++){
 	if(i>0) output.write(',');
 	%>{"id":<%=items[i].id%>,"randomNumber":<%=items[i].rnd%>}<%
 }
-
+if(queries>1) {
+        %>]<%
+}
+%><%
 response->headers["Content-Type"]="application/json";
 response->headers["Server"]="cppsp/0.2";
-%>]
+%>

+ 9 - 4
cpoll_cppsp/www/db_pg_threadpool

@@ -94,13 +94,18 @@ void efdCB(eventfd_t efdVal) {
 void waitCB(eventfd_t efdVal) {
 	this->doInit();
 }
-
-%>[<%
+%><%
+if(queries>1) {
+	%>[<%
+}
 for (int i=0;i<queries;i++){
 	if(i>0) output.write(',');
 	%>{"id":<%=items[i].id%>,"randomNumber":<%=items[i].rnd%>}<%
 }
-
+if(queries>1) {
+        %>]<%
+}
+%><%
 response->headers["Content-Type"]="application/json";
 response->headers["Server"]="cppsp/0.2";
-%>]
+%>

+ 3 - 0
dropwizard/benchmark_config

@@ -6,6 +6,9 @@
       "json_url": "/json",
       "db_url": "/db",
       "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/db/update?queries=",
+      "plaintext_url": "/plaintext",
       "port": 9000,
       "approach": "Realistic",
       "classification": "Fullstack",

+ 10 - 26
dropwizard/hello-world.yml

@@ -1,12 +1,16 @@
-http:
-  port: 9000
+server:
+  type: simple
+  applicationContextPath: /
+  connector:
+    type: http
+    port: 9000
+    useServerHeader: true
 
   requestLog:
+    appenders: []
 
-    # Settings for logging to stdout.
-    console:
-      # If true, log requests to stdout.
-      enabled: false
+logging:
+  appenders: []
 
 database:
   # the name of your JDBC driver
@@ -28,9 +32,6 @@ database:
   # the maximum amount of time to wait on an empty pool before throwing an exception
   maxWaitForConnection: 1s
 
-  # the SQL query to run when validating a connection's liveness
-  validationQuery: "/* MyService Health Check */ SELECT 1"
-
   # the minimum number of connections to keep open
   minSize: 8
 
@@ -39,20 +40,3 @@ database:
 
   # whether or not idle connections should be validated
   checkConnectionWhileIdle: false
-
-  # how long a connection must be held before it can be validated
-  checkConnectionHealthWhenIdleFor: 10s
-
-  # the maximum lifetime of an idle connection
-  closeConnectionIfIdleFor: 1 minute
-
-logging:
-
-  # The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
-  level: OFF
-
-  console:
-
-    # If true, write log statements to stdout.
-    enabled: false
-

+ 20 - 10
dropwizard/pom.xml

@@ -1,28 +1,38 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>com.xekm</groupId>
     <artifactId>hello-world</artifactId>
     <version>0.0.1-SNAPSHOT</version>
 
+    <properties>
+        <jdk.version>1.7</jdk.version>
+
+        <dropwizard.version>0.7.0</dropwizard.version>
+        <mysql-connector-java.version>5.1.30</mysql-connector-java.version>
+    </properties>
+
     <dependencies>
         <dependency>
-            <groupId>com.yammer.dropwizard</groupId>
+            <groupId>io.dropwizard</groupId>
             <artifactId>dropwizard-core</artifactId>
-            <version>0.6.2</version>
+            <version>${dropwizard.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.yammer.dropwizard</groupId>
+            <groupId>io.dropwizard</groupId>
             <artifactId>dropwizard-hibernate</artifactId>
-            <version>0.6.2</version>
+            <version>${dropwizard.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-views-mustache</artifactId>
+            <version>${dropwizard.version}</version>
         </dependency>
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
-            <version>5.1.6</version>
+            <version>${mysql-connector-java.version}</version>
         </dependency>
     </dependencies>
 
@@ -33,8 +43,8 @@
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>2.3.2</version>
                 <configuration>
-                    <source>1.7</source>
-                    <target>1.7</target>
+                    <source>${jdk.version}</source>
+                    <target>${jdk.version}</target>
                 </configuration>
             </plugin>
             <plugin>

+ 14 - 10
dropwizard/setup.py

@@ -1,25 +1,29 @@
 import subprocess
-import sys
 import setup_util
 from os.path import expanduser
 import os
 
 home = expanduser("~")
 
+
 def start(args, logfile, errfile):
-    setup_util.replace_text("dropwizard/hello-world.yml", "url: jdbc:mysql://.*/hello_world", "url: jdbc:mysql://" + args.database_host + ":3306/hello_world")
+    setup_util.replace_text("dropwizard/hello-world.yml", "url: jdbc:mysql://.*/hello_world",
+                            "url: jdbc:mysql://" + args.database_host + ":3306/hello_world")
 
     try:
         subprocess.check_call("mvn clean package;", shell=True, cwd="dropwizard", stderr=errfile, stdout=logfile)
-        subprocess.Popen("java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml", shell=True, cwd="dropwizard", stderr=errfile, stdout=logfile)
+        subprocess.Popen("java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml", shell=True,
+                         cwd="dropwizard", stderr=errfile, stdout=logfile)
         return 0
     except subprocess.CalledProcessError:
         return 1
+
+
 def stop(logfile, errfile):
-  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
-  out, err = p.communicate()
-  for line in out.splitlines():
-    if 'hello-world' in line:
-      pid = int(line.split(None, 2)[1])
-      os.kill(pid, 15)
-  return 0
+    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+    out, err = p.communicate()
+    for line in out.splitlines():
+        if 'hello-world' in line:
+            pid = int(line.split(None, 2)[1])
+            os.kill(pid, 15)
+    return 0

+ 15 - 5
dropwizard/source_code

@@ -1,10 +1,20 @@
 ./dropwizard/src/main/java/com/example/helloworld/
+./dropwizard/src/main/java/com/example/helloworld/config
+./dropwizard/src/main/java/com/example/helloworld/config/HelloWorldConfiguration
 ./dropwizard/src/main/java/com/example/helloworld/db
+./dropwizard/src/main/java/com/example/helloworld/db/model
+./dropwizard/src/main/java/com/example/helloworld/db/model/Fortune
+./dropwizard/src/main/java/com/example/helloworld/db/model/World
+./dropwizard/src/main/java/com/example/helloworld/db/FortuneDAO.java
 ./dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java
-./dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java
 ./dropwizard/src/main/java/com/example/helloworld/resources
-./dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java
+./dropwizard/src/main/java/com/example/helloworld/resources/api
+./dropwizard/src/main/java/com/example/helloworld/resources/api/HelloMessage
+./dropwizard/src/main/java/com/example/helloworld/resources/views
+./dropwizard/src/main/java/com/example/helloworld/resources/views/FortuneView
+./dropwizard/src/main/java/com/example/helloworld/resources/FortuneResource.java
 ./dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java
-./dropwizard/src/main/java/com/example/helloworld/core
-./dropwizard/src/main/java/com/example/helloworld/core/World.java
-./dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java
+./dropwizard/src/main/java/com/example/helloworld/resources/TextResource.java
+./dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java
+./dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java
+./dropwizard/src/main/resources/fortunes.mustache

+ 0 - 25
dropwizard/src/main/java/com/example/helloworld/HelloWorldConfiguration.java

@@ -1,25 +0,0 @@
-
-package com.example.helloworld;
-
-import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
-
-import org.hibernate.validator.constraints.NotEmpty;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.yammer.dropwizard.config.Configuration;
-import com.yammer.dropwizard.db.DatabaseConfiguration;
-
-public class HelloWorldConfiguration
-    extends Configuration
-{
-  @Valid
-  @NotNull
-  @JsonProperty
-  private DatabaseConfiguration database    = new DatabaseConfiguration();
-
-  public DatabaseConfiguration getDatabaseConfiguration()
-  {
-    return database;
-  }
-}

+ 34 - 37
dropwizard/src/main/java/com/example/helloworld/HelloWorldService.java

@@ -1,48 +1,45 @@
-
 package com.example.helloworld;
 
-import com.example.helloworld.core.World;
+import com.example.helloworld.config.HelloWorldConfiguration;
+import com.example.helloworld.db.FortuneDAO;
+import com.example.helloworld.db.model.Fortune;
+import com.example.helloworld.db.model.World;
 import com.example.helloworld.db.WorldDAO;
+import com.example.helloworld.resources.FortuneResource;
 import com.example.helloworld.resources.JsonResource;
+import com.example.helloworld.resources.TextResource;
 import com.example.helloworld.resources.WorldResource;
-import com.yammer.dropwizard.Service;
-import com.yammer.dropwizard.config.Bootstrap;
-import com.yammer.dropwizard.config.Environment;
-import com.yammer.dropwizard.db.DatabaseConfiguration;
-import com.yammer.dropwizard.hibernate.HibernateBundle;
+import io.dropwizard.Application;
+import io.dropwizard.db.DataSourceFactory;
+import io.dropwizard.hibernate.HibernateBundle;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+import io.dropwizard.views.ViewBundle;
 
-public class HelloWorldService
-    extends Service<HelloWorldConfiguration>
-{
-  private final HibernateBundle<HelloWorldConfiguration> hibernate = new HibernateBundle<HelloWorldConfiguration>(
-                                                                       World.class)
-                                                                   {
-                                                                     @Override
-                                                                     public DatabaseConfiguration getDatabaseConfiguration(
-                                                                         HelloWorldConfiguration configuration)
-                                                                     {
-                                                                       return configuration.getDatabaseConfiguration();
-                                                                     }
-                                                                   };
+public class HelloWorldService extends Application<HelloWorldConfiguration> {
 
-  public static void main(String[] args) throws Exception
-  {
-    new HelloWorldService().run(args);
-  }
+    private final HibernateBundle<HelloWorldConfiguration> hibernate = new HibernateBundle<HelloWorldConfiguration>(World.class, Fortune.class) {
+        @Override
+        public DataSourceFactory getDataSourceFactory(HelloWorldConfiguration configuration) {
+            return configuration.getDatabaseConfiguration();
+        }
+    };
 
-  @Override
-  public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap)
-  {
-    bootstrap.setName("hello-world");
-    bootstrap.addBundle(hibernate);
-  }
+    public static void main(String[] args) throws Exception {
+        new HelloWorldService().run(args);
+    }
 
-  @Override
-  public void run(HelloWorldConfiguration config, Environment environment)
-  {
-    final WorldDAO dao = new WorldDAO(hibernate.getSessionFactory());
-    environment.addResource(new WorldResource(dao));
-    environment.addResource(new JsonResource());
-  }
+    @Override
+    public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
+        bootstrap.addBundle(hibernate);
+        bootstrap.addBundle(new ViewBundle());
+    }
 
+    @Override
+    public void run(HelloWorldConfiguration config, Environment environment) {
+        environment.jersey().register(new JsonResource()); // Test type 1: JSON serialization
+        environment.jersey().register(new WorldResource(new WorldDAO(hibernate.getSessionFactory()))); // Test types 2, 3 & 5: Single database query, Multiple database queries & Database updates
+        environment.jersey().register(new FortuneResource(new FortuneDAO(hibernate.getSessionFactory()))); // Test type 4: Fortunes
+        environment.jersey().register(new TextResource()); // Test type 6: Plaintext
+    }
 }

+ 20 - 0
dropwizard/src/main/java/com/example/helloworld/config/HelloWorldConfiguration.java

@@ -0,0 +1,20 @@
+package com.example.helloworld.config;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.dropwizard.Configuration;
+import io.dropwizard.db.DataSourceFactory;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+public class HelloWorldConfiguration extends Configuration {
+
+    @Valid
+    @NotNull
+    @JsonProperty
+    private DataSourceFactory database = new DataSourceFactory();
+
+    public DataSourceFactory getDatabaseConfiguration() {
+        return database;
+    }
+}

+ 0 - 36
dropwizard/src/main/java/com/example/helloworld/core/World.java

@@ -1,36 +0,0 @@
-
-package com.example.helloworld.core;
-
-import javax.persistence.*;
-
-@Entity
-@Table(name = "World")
-public class World
-{
-  @Id
-  @GeneratedValue(strategy = GenerationType.AUTO)
-  private long id;
-
-  @Column(name = "randomNumber", nullable = false)
-  private long randomNumber;
-
-  public long getId()
-  {
-    return id;
-  }
-
-  public void setId(long id)
-  {
-    this.id = id;
-  }
-
-  public long getRandomNumber()
-  {
-    return this.randomNumber;
-  }
-
-  public void setRandomNumber(long randomNumber)
-  {
-    this.randomNumber = randomNumber;
-  }
-}

+ 18 - 0
dropwizard/src/main/java/com/example/helloworld/db/FortuneDAO.java

@@ -0,0 +1,18 @@
+package com.example.helloworld.db;
+
+import com.example.helloworld.db.model.Fortune;
+import io.dropwizard.hibernate.AbstractDAO;
+import org.hibernate.SessionFactory;
+
+import java.util.List;
+
+public class FortuneDAO extends AbstractDAO<Fortune> {
+
+    public FortuneDAO(SessionFactory factory) {
+        super(factory);
+    }
+
+    public List<Fortune> list() {
+        return list(criteria());
+    }
+}

+ 14 - 15
dropwizard/src/main/java/com/example/helloworld/db/WorldDAO.java

@@ -1,22 +1,21 @@
-
 package com.example.helloworld.db;
 
+import com.example.helloworld.db.model.World;
+import com.google.common.base.Optional;
+import io.dropwizard.hibernate.AbstractDAO;
 import org.hibernate.SessionFactory;
 
-import com.example.helloworld.core.World;
-import com.google.common.base.Optional;
-import com.yammer.dropwizard.hibernate.AbstractDAO;
+public class WorldDAO extends AbstractDAO<World> {
+
+    public WorldDAO(SessionFactory factory) {
+        super(factory);
+    }
 
-public class WorldDAO
-    extends AbstractDAO<World>
-{
-  public WorldDAO(SessionFactory factory)
-  {
-    super(factory);
-  }
+    public Optional<World> findById(Long id) {
+        return Optional.fromNullable(get(id));
+    }
 
-  public Optional<World> findById(Long id)
-  {
-    return Optional.fromNullable(get(id));
-  }
+    public World update(World world) {
+        return persist(world);
+    }
 }

+ 35 - 0
dropwizard/src/main/java/com/example/helloworld/db/model/Fortune.java

@@ -0,0 +1,35 @@
+package com.example.helloworld.db.model;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "Fortune")
+public class Fortune implements Comparable<Fortune> {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private long id;
+
+    @Column(name = "message", nullable = false)
+    private String message;
+
+    @SuppressWarnings("unused")
+    public Fortune() {}
+
+    public Fortune(String message) {
+        this.message = message;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    @Override
+    public int compareTo(Fortune o) {
+        return message.compareTo(o.message);
+    }
+}

+ 29 - 0
dropwizard/src/main/java/com/example/helloworld/db/model/World.java

@@ -0,0 +1,29 @@
+package com.example.helloworld.db.model;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "World")
+public class World {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private long id;
+
+    @Column(name = "randomNumber", nullable = false)
+    private long randomNumber;
+
+    public World() {}
+
+    public long getId() {
+        return id;
+    }
+
+    public long getRandomNumber() {
+        return randomNumber;
+    }
+
+    public void setRandomNumber(long randomNumber) {
+        this.randomNumber = randomNumber;
+    }
+}

+ 37 - 0
dropwizard/src/main/java/com/example/helloworld/resources/FortuneResource.java

@@ -0,0 +1,37 @@
+package com.example.helloworld.resources;
+
+import com.example.helloworld.db.FortuneDAO;
+import com.example.helloworld.db.model.Fortune;
+import com.example.helloworld.resources.views.FortuneView;
+import com.google.common.collect.Lists;
+import io.dropwizard.hibernate.UnitOfWork;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.Collections;
+import java.util.List;
+
+@Path("/fortunes")
+@Produces(MediaType.TEXT_HTML + ";charset=UTF-8")
+public class FortuneResource {
+
+    private final FortuneDAO fortuneDAO;
+
+    public FortuneResource(FortuneDAO fortuneDAO) {
+        this.fortuneDAO = fortuneDAO;
+    }
+
+    @GET
+    @UnitOfWork
+    public FortuneView dbTest() {
+        final List<Fortune> fortunes = Lists.newArrayListWithExpectedSize(32);
+
+        fortunes.addAll(fortuneDAO.list());
+        fortunes.add(new Fortune("Additional fortune added at request time."));
+
+        Collections.sort(fortunes);
+        return new FortuneView(fortunes);
+    }
+}

+ 6 - 18
dropwizard/src/main/java/com/example/helloworld/resources/JsonResource.java

@@ -1,8 +1,6 @@
-
 package com.example.helloworld.resources;
 
-import java.util.HashMap;
-import java.util.Map;
+import com.example.helloworld.resources.api.HelloMessage;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -11,20 +9,10 @@ import javax.ws.rs.core.MediaType;
 
 @Path("/json")
 @Produces(MediaType.APPLICATION_JSON)
-public class JsonResource
-{
-  // Response message class (copied from 'servlet' test)
-  public final static class HelloMessage {
-    public final String message;
-
-    public HelloMessage(String m) { message = m; }
-  }
-
-  public JsonResource() { }
+public class JsonResource {
 
-  @GET
-  public HelloMessage sayHello()
-  {
-    return new HelloMessage("Hello, World!");
-  }
+    @GET
+    public HelloMessage sayHello() {
+        return new HelloMessage("Hello, World!");
+    }
 }

+ 16 - 0
dropwizard/src/main/java/com/example/helloworld/resources/TextResource.java

@@ -0,0 +1,16 @@
+package com.example.helloworld.resources;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/plaintext")
+@Produces(MediaType.TEXT_PLAIN)
+public class TextResource {
+
+    @GET
+    public String sayHello() {
+        return "Hello, World!";
+    }
+}

+ 47 - 28
dropwizard/src/main/java/com/example/helloworld/resources/WorldResource.java

@@ -1,41 +1,60 @@
 package com.example.helloworld.resources;
 
-import java.util.Random;
+import com.example.helloworld.db.WorldDAO;
+import com.example.helloworld.db.model.World;
+import com.google.common.base.Optional;
+import io.dropwizard.hibernate.UnitOfWork;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
-
-import com.example.helloworld.core.World;
-import com.example.helloworld.db.WorldDAO;
-import com.google.common.base.Optional;
-import com.yammer.dropwizard.hibernate.UnitOfWork;
+import java.util.Random;
 
 @Path("/db")
 @Produces(MediaType.APPLICATION_JSON)
-public class WorldResource
-{
-  private WorldDAO worldDAO = null;
-
-  public WorldResource(WorldDAO worldDAO)
-  {
-    this.worldDAO = worldDAO;
-  }
-
-  @GET
-  @UnitOfWork
-  public World[] dbTest(@QueryParam("queries") Optional<Integer> queries)
-  {
-    final int totalQueries = queries.or(1);
-    final World[] worlds = new World[queries.or(1)];
-    final Random random = new Random(System.currentTimeMillis());
-
-    for (int i = 0; i < totalQueries; i++)
-    {
-      worlds[i] = this.worldDAO.findById((long)(random.nextInt(10000) + 1)).orNull();
+public class WorldResource {
+
+    private static final Random RANDOM = new Random();
+
+    private final WorldDAO worldDAO;
+
+    public WorldResource(WorldDAO worldDAO) {
+        this.worldDAO = worldDAO;
+    }
+
+    @GET
+    @UnitOfWork
+    public World[] dbTest(@QueryParam("queries") Optional<Integer> queries) {
+        final int totalQueries = queries.or(1); // TODO: Should be bound [1,500]
+        final World[] worlds = new World[totalQueries];
+
+        // TODO: Is parallelising this cheating?
+        for (int i = 0; i < totalQueries; i++) {
+            final long worldId = RANDOM.nextInt(10_000) + 1;
+            worlds[i] = worldDAO.findById(worldId).orNull();
+        }
+
+        return worlds;
+    }
+
+    @GET
+    @Path("/update")
+    @UnitOfWork
+    public World[] updateTest(@QueryParam("queries") Optional<Integer> queries) {
+        final int totalQueries = queries.or(1); // TODO: Should be bound [1,500]
+        final World[] worlds = new World[totalQueries];
+
+        // TODO: Is parallelising this cheating?
+        for (int i = 0; i < totalQueries; i++) {
+            final long worldId = RANDOM.nextInt(10_000) + 1;
+
+            final World world = worldDAO.findById(worldId).orNull();
+            world.setRandomNumber(RANDOM.nextInt(10_000) + 1);
+            worlds[i] = worldDAO.update(world);
+        }
+
+        return worlds;
     }
-    return worlds;
-  }
 }

+ 17 - 0
dropwizard/src/main/java/com/example/helloworld/resources/api/HelloMessage.java

@@ -0,0 +1,17 @@
+package com.example.helloworld.resources.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public final class HelloMessage {
+
+    @JsonProperty
+    private final String message;
+
+    public HelloMessage(String m) {
+        message = m;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

+ 23 - 0
dropwizard/src/main/java/com/example/helloworld/resources/views/FortuneView.java

@@ -0,0 +1,23 @@
+package com.example.helloworld.resources.views;
+
+import com.example.helloworld.db.model.Fortune;
+import io.dropwizard.views.View;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+public class FortuneView extends View {
+
+    private final List<Fortune> fortunes;
+
+    public FortuneView(List<Fortune> fortunes) {
+        super("/fortunes.mustache", StandardCharsets.UTF_8);
+
+        this.fortunes = fortunes;
+    }
+
+    @SuppressWarnings("unused")
+    public List<Fortune> getFortunes() {
+        return fortunes;
+    }
+}

+ 14 - 0
dropwizard/src/main/resources/fortunes.mustache

@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+        <table>
+            <tr><th>id</th><th>message</th></tr>
+{{#fortunes}}
+                <tr><td>{{id}}</td><td>{{message}}</td></tr>
+{{/fortunes}}
+        </table>
+    </body>
+</html>

+ 20 - 0
falcon/gunicorn_conf.py

@@ -0,0 +1,20 @@
+import multiprocessing
+import sys
+
+_is_pypy = hasattr(sys, 'pypy_version_info')
+
+# falcon only implements json and plain. Not wait DB.
+workers = multiprocessing.cpu_count()
+bind = "0.0.0.0:8080"
+keepalive = 120
+
+if _is_pypy:
+    worker_class = "tornado"
+else:
+    worker_class = "meinheld.gmeinheld.MeinheldWorker"
+
+    def post_fork(server, worker):
+        # Disalbe access log
+        import meinheld.server
+        meinheld.server.set_access_logger(None)
+

+ 8 - 7
falcon/setup.py

@@ -1,9 +1,7 @@
 import subprocess
-import multiprocessing
 import os
 
 bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py2/bin')
-NCPU = multiprocessing.cpu_count()
 
 proc = None
 
@@ -13,19 +11,22 @@ def start(args, logfile, errfile):
     proc = subprocess.Popen([
         bin_dir + "/gunicorn",
         "app:app",
-        "-k", "meinheld.gmeinheld.MeinheldWorker",
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU*3),
-        "--log-level=critical"],
+        "-c", "gunicorn_conf.py"],
         cwd="falcon", stderr=errfile, stdout=logfile)
     return 0
 
 
 def stop(logfile, errfile):
+    global proc
+    if proc:
+        proc.terminate()
+        proc = None
+
     p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
     out, err = p.communicate()
     for line in out.splitlines():
       if 'FrameworkBenchmarks/installs/py2/bin/' in line:
-        pid = int(line.split(None,2)[1])
+        errfile.write("Killing: " + line + "\n")
+        pid = int(line.split()[1])
         os.kill(pid, 15)
     return 0

+ 2 - 6
falcon/setup_py3.py

@@ -1,9 +1,7 @@
 import subprocess
-import multiprocessing
 import os
 
 bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py3/bin')
-NCPU = multiprocessing.cpu_count()
 
 proc = None
 
@@ -13,13 +11,11 @@ def start(args, logfile, errfile):
     proc = subprocess.Popen([
         bin_dir + "/gunicorn",
         "app:app",
-        "-k", "meinheld.gmeinheld.MeinheldWorker",
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU*3),
-        "--log-level=critical"],
+        "-c", "gunicorn_conf.py"],
         cwd="falcon", stderr=errfile, stdout=logfile)
     return 0
 
+
 def stop(logfile, errfile):
     global proc
     if proc is None:

+ 12 - 10
falcon/setup_pypy.py

@@ -1,9 +1,7 @@
 import subprocess
-import multiprocessing
 import os
 
 bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/pypy/bin')
-NCPU = multiprocessing.cpu_count()
 
 proc = None
 
@@ -13,17 +11,21 @@ def start(args, logfile, errfile):
     proc = subprocess.Popen([
         bin_dir + "/gunicorn",
         "app:app",
-        '-k', 'tornado',
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU*3),
-        "--log-level=critical"],
+        "-c", "gunicorn_conf.py"],
         cwd="falcon", stderr=errfile, stdout=logfile)
     return 0
 
 def stop(logfile, errfile):
     global proc
-    if proc is None:
-        return 0
-    proc.terminate()
-    proc = None
+    if proc:
+        proc.terminate()
+        proc = None
+
+    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+    out, err = p.communicate()
+    for line in out.splitlines():
+      if 'installs/pypy/bin/' in line:
+        errfile.write("Killing: " + line + "\n")
+        pid = int(line.split()[1])
+        os.kill(pid, 15)
     return 0

+ 28 - 16
flask/app.py

@@ -22,10 +22,10 @@ except ImportError:
 # setup
 
 app = Flask(__name__)
-app.config['SQLALCHEMY_DATABASE_URI'] = mysql_schema + '//benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world?charset=utf8'
+app.config['SQLALCHEMY_DATABASE_URI'] = mysql_schema + '//benchmarkdbuser:benchmarkdbpass@localhost:3306/hello_world?charset=utf8'
 app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
 db = SQLAlchemy(app)
-dbraw_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])
+dbraw_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'], connect_args={'autocommit': True}, pool_reset_on_return=None)
 
 # models
 
@@ -110,7 +110,9 @@ def get_fortunes():
 
 @app.route("/fortunesraw")
 def get_forutens_raw():
-    fortunes = list(dbraw_engine.execute("SELECT * FROM Fortune"))
+    res = dbraw_engine.execute("SELECT * FROM Fortune")
+    fortunes = res.fetchall()
+    res.close()
     fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
     fortunes.sort(key=attrgetter('message'))
     return render_template('fortunes.html', fortunes=fortunes)
@@ -138,19 +140,22 @@ def updates():
 @app.route("/raw-updates")
 def raw_updates():
     """Test 5: Database Updates"""
-    num_queries = request.args.get('queries', 1, type=int)
-    if num_queries > 500:
-        num_queries = 500
-
-    worlds = []
-    rp = partial(randint, 1, 10000)
-    for i in xrange(num_queries):
-        world = dbraw_engine.execute("SELECT * FROM World WHERE id=%s", (rp(),)).fetchone()
-        randomNumber = rp()
-        worlds.append({'id': world['id'], 'randomNumber': randomNumber})
-        dbraw_engine.execute("UPDATE World SET randomNumber=%s WHERE id=%s",
-                             (randomNumber, world['id']))
-    return json_response(worlds)
+    connection = dbraw_engine.connect()
+    try:
+        num_queries = request.args.get('queries', 1, type=int)
+        if num_queries > 500:
+            num_queries = 500
+
+        worlds = []
+        rp = partial(randint, 1, 10000)
+        for i in xrange(num_queries):
+            world = connection.execute("SELECT * FROM World WHERE id=%s", (rp(),)).fetchone()
+            randomNumber = rp()
+            worlds.append({'id': world['id'], 'randomNumber': randomNumber})
+            connection.execute("UPDATE World SET randomNumber=%s WHERE id=%s", (randomNumber, world['id']))
+        return json_response(worlds)
+    finally:
+        connection.close()
 
 
 @app.route('/plaintext')
@@ -161,6 +166,13 @@ def plaintext():
     return response
 
 
+try:
+    import meinheld
+    meinheld.server.set_access_logger(None)
+    meinheld.set_keepalive(120)
+except ImportError:
+    pass
+
 # entry point for debugging
 if __name__ == "__main__":
     app.run(debug=True)

+ 7 - 7
flask/benchmark_config

@@ -16,7 +16,7 @@
       "framework": "flask",
       "language": "Python",
       "orm": "Full",
-      "platform": "Gunicorn/Meinheld",
+      "platform": "Meinheld",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
@@ -37,7 +37,7 @@
       "framework": "flask",
       "language": "Python",
       "orm": "Raw",
-      "platform": "Gunicorn/Meinheld",
+      "platform": "Meinheld",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
@@ -60,7 +60,7 @@
       "framework": "flask",
       "language": "Python",
       "orm": "Full",
-      "platform": "Gunicorn/Meinheld",
+      "platform": "Meinheld",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
@@ -83,12 +83,12 @@
       "framework": "flask",
       "language": "Python",
       "orm": "Full",
-      "platform": "Gunicorn/Tornado",
+      "platform": "Tornado",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "flask-pypy",
-      "notes": "PyPy 2.2",
+      "notes": "PyPy 2.3",
       "versus": "wsgi"
     },
     "pypy-mysql-raw": {
@@ -104,12 +104,12 @@
       "framework": "flask",
       "language": "Python",
       "orm": "Raw",
-      "platform": "Gunicorn/Tornado",
+      "platform": "Tornado",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "flask-pypy-raw",
-      "notes": "PyPy 2.2",
+      "notes": "PyPy 2.3",
       "versus": "wsgi"
     },
     "nginx-uwsgi": {

+ 1 - 0
flask/requirements.txt

@@ -0,0 +1 @@
+Chaussette

+ 28 - 14
flask/setup.py

@@ -6,24 +6,38 @@ import os
 bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py2/bin')
 NCPU = multiprocessing.cpu_count()
 
+CIRCUS_INI = """\
+[watcher:app]
+cmd = {BIN}/chaussette --fd=$(circus.sockets.app) --backend=meinheld app.app
+use_sockets = True
+numprocesses = {PROCS}
+
+[socket:app]
+host = 0.0.0.0
+port = 8080
+"""
+
+proc = None
 
 def start(args, logfile, errfile):
+    global proc
+
+    subprocess.check_call(bin_dir + "/pip install -r requirements.txt",
+                          cwd="flask", stderr=errfile, stdout=logfile, shell=True)
+
+    with open("flask/circus.ini", "w") as f:
+        f.write(CIRCUS_INI.format(BIN=bin_dir, PROCS=NCPU*3))
+
     setup_util.replace_text("flask/app.py", "DBHOSTNAME", args.database_host)
-    subprocess.Popen([
-        bin_dir + "/gunicorn",
-        "app:app",
-        "-k", "meinheld.gmeinheld.MeinheldWorker",
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU*3),
-        "--log-level=critical"],
-        cwd="flask", stderr=errfile, stdout=logfile)
+    proc = subprocess.Popen([bin_dir + "/circusd", "circus.ini"],
+		            cwd="flask", stderr=errfile, stdout=logfile)
     return 0
 
 def stop(logfile, errfile):
-    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
-    out, err = p.communicate()
-    for line in out.splitlines():
-      if 'FrameworkBenchmarks/installs/py2/bin/' in line:
-        pid = int(line.split(None,2)[1])
-        os.kill(pid, 15)
+    global proc
+    if proc is None:
+        return 0
+    proc.terminate()
+    proc.wait()
+    proc = None
     return 0

+ 24 - 9
flask/setup_py3.py

@@ -3,21 +3,36 @@ import setup_util
 import multiprocessing
 import os
 
-bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py3/bin')
+PY2BIN = os.path.expanduser('~/FrameworkBenchmarks/installs/py2/bin')
+PY3BIN = os.path.expanduser('~/FrameworkBenchmarks/installs/py3/bin')
 NCPU = multiprocessing.cpu_count()
 
+CIRCUS_INI = """\
+[watcher:app]
+cmd = {BIN}/chaussette --fd=$(circus.sockets.app) --backend=meinheld app.app
+use_sockets = True
+numprocesses = {PROCS}
+
+[socket:app]
+host = 0.0.0.0
+port = 8080
+"""
+
+proc = None
+
 
 def start(args, logfile, errfile):
     global proc
+
+    subprocess.check_call(PY3BIN + "/pip3 install -r requirements.txt",
+                          cwd="flask", stderr=errfile, stdout=logfile, shell=True)
+
+    with open("flask/circus.ini", "w") as f:
+        f.write(CIRCUS_INI.format(BIN=PY3BIN, PROCS=NCPU*3))
+
     setup_util.replace_text("flask/app.py", "DBHOSTNAME", args.database_host)
-    proc = subprocess.Popen([
-        bin_dir + "/gunicorn",
-        "app:app",
-        "-k", "meinheld.gmeinheld.MeinheldWorker",
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU*3),
-        "--log-level=critical"],
-        cwd="flask", stderr=errfile, stdout=logfile)
+    proc = subprocess.Popen([PY2BIN + "/circusd", "circus.ini"],
+		            cwd="flask", stderr=errfile, stdout=logfile)
     return 0
 
 def stop(logfile, errfile):

+ 1 - 1
flask/setup_pypy.py

@@ -15,7 +15,7 @@ def start(args, logfile, errfile):
     proc = subprocess.Popen([
         bin_dir + "/gunicorn",
         "app:app",
-        '-k', 'tornado',
+        "-k", "tornado",
         "-b", "0.0.0.0:8080",
         '-w', str(NCPU*3),
         "--log-level=critical"],

+ 2 - 2
netty/README.md

@@ -8,8 +8,8 @@ This is the netty portion of a [benchmarking test suite](../) comparing a variet
 ## Versions
 
 * [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
-* [Netty 4.0.16](http://netty.io/)
-* [Jackson 2.3.1](http://wiki.fasterxml.com/JacksonHome)
+* [Netty 4.0.21](http://netty.io/)
+* [Jackson 2.4.1](http://wiki.fasterxml.com/JacksonHome)
 
 ## References
 * https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example/http/snoop

+ 5 - 4
netty/pom.xml

@@ -13,22 +13,23 @@
 		<dependency>
 			<groupId>io.netty</groupId>
 			<artifactId>netty-codec-http</artifactId>
-			<version>4.0.17.Final</version>
+			<version>4.0.21.Final</version>
 		</dependency>
 		<dependency>
 			<groupId>io.netty</groupId>
 			<artifactId>netty-transport-native-epoll</artifactId>
-			<version>4.0.17.Final</version>
+			<version>4.0.21.Final</version>
+			<classifier>linux-x86_64</classifier>
 		</dependency>
 		<dependency>
 			<groupId>com.fasterxml.jackson.core</groupId>
 			<artifactId>jackson-databind</artifactId>
-			<version>2.3.1</version>
+			<version>RELEASE</version>
 		</dependency>
 		<dependency>
 			<groupId>com.fasterxml.jackson.module</groupId>
 			<artifactId>jackson-module-afterburner</artifactId>
-			<version>2.3.1</version>
+			<version>RELEASE</version>
 		</dependency>
 		<dependency>
 			<groupId>javassist</groupId>

+ 57 - 66
netty/src/main/java/hello/HelloServerHandler.java

@@ -3,7 +3,6 @@ package hello;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
@@ -13,6 +12,7 @@ import io.netty.handler.codec.http.HttpRequest;
 import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.HttpVersion;
 import io.netty.util.CharsetUtil;
+import io.netty.util.concurrent.FastThreadLocal;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
@@ -23,20 +23,16 @@ import java.util.concurrent.TimeUnit;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
 
[email protected]
 public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
-	private static final ThreadLocal<DateFormat> FORMAT = new ThreadLocal<DateFormat>() {
-        @Override
-        protected DateFormat initialValue() {
-            return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
-        }
+    private static final FastThreadLocal<DateFormat> FORMAT = new FastThreadLocal<DateFormat>() {
+	@Override
+	protected DateFormat initialValue() {
+	    return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
+	}
     };
 
-
-    private static final ByteBuf CONTENT_BUFFER = Unpooled.unreleasableBuffer(
-            Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8)));
-    private static final CharSequence contentLength = HttpHeaders.newEntity(
-            String.valueOf(CONTENT_BUFFER.readableBytes()));
+    private static final ByteBuf CONTENT_BUFFER = Unpooled.unreleasableBuffer(Unpooled.directBuffer().writeBytes("Hello, World!".getBytes(CharsetUtil.UTF_8)));
+    private static final CharSequence contentLength = HttpHeaders.newEntity(String.valueOf(CONTENT_BUFFER.readableBytes()));
 
     private static final CharSequence TYPE_PLAIN = HttpHeaders.newEntity("text/plain; charset=UTF-8");
     private static final CharSequence TYPE_JSON = HttpHeaders.newEntity("application/json; charset=UTF-8");
@@ -46,77 +42,72 @@ public class HelloServerHandler extends SimpleChannelInboundHandler<Object> {
     private static final CharSequence CONTENT_LENGTH_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.CONTENT_LENGTH);
     private static final CharSequence SERVER_ENTITY = HttpHeaders.newEntity(HttpHeaders.Names.SERVER);
     private static final ObjectMapper MAPPER;
-    
-    static{
-    	MAPPER = new ObjectMapper();
-    	MAPPER.registerModule(new AfterburnerModule());
+
+    static {
+	MAPPER = new ObjectMapper();
+	MAPPER.registerModule(new AfterburnerModule());
     }
-    
+
     private volatile CharSequence date = HttpHeaders.newEntity(FORMAT.get().format(new Date()));
 
     HelloServerHandler(ScheduledExecutorService service) {
-        service.scheduleWithFixedDelay(new Runnable() {
-            private final DateFormat format = FORMAT.get();
-            @Override
-            public void run() {
-                date = HttpHeaders.newEntity(format.format(new Date()));
-            }
-        }, 1000, 1000, TimeUnit.MILLISECONDS);
+	service.scheduleWithFixedDelay(new Runnable() {
+	    private final DateFormat format = FORMAT.get();
+
+	    @Override
+	    public void run() {
+		date = HttpHeaders.newEntity(format.format(new Date()));
+	    }
+	}, 1000, 1000, TimeUnit.MILLISECONDS);
 
     }
 
     @Override
     public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
-        if (msg instanceof HttpRequest) {
-            HttpRequest request = (HttpRequest) msg;
-            String uri = request.getUri();
-            switch (uri) {
-                case "/plaintext":
-                    writeResponse(ctx, request, CONTENT_BUFFER.duplicate(), TYPE_PLAIN, contentLength);
-                    return;
-                case "/json":
-                    byte[] json = MAPPER.writeValueAsBytes(new Message("Hello, World!"));
-                    writeResponse(ctx, request, Unpooled.wrappedBuffer(json), TYPE_JSON,
-                            String.valueOf(json.length));
-                    return;
-            }
-            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, Unpooled.EMPTY_BUFFER, false);
-            ctx.write(response).addListener(ChannelFutureListener.CLOSE);
-        }
+	if (msg instanceof HttpRequest) {
+	    HttpRequest request = (HttpRequest) msg;
+	    String uri = request.getUri();
+	    switch (uri) {
+	    case "/plaintext":
+		writeResponse(ctx, request, CONTENT_BUFFER.duplicate(), TYPE_PLAIN, contentLength);
+		return;
+	    case "/json":
+		byte[] json = MAPPER.writeValueAsBytes(new Message("Hello, World!"));
+		writeResponse(ctx, request, Unpooled.wrappedBuffer(json), TYPE_JSON, String.valueOf(json.length));
+		return;
+	    }
+	    FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND, Unpooled.EMPTY_BUFFER, false);
+	    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
+	}
     }
 
-    private void writeResponse(ChannelHandlerContext ctx, HttpRequest request, ByteBuf buf,
-                               CharSequence contentType, CharSequence contentLength) {
-        // Decide whether to close the connection or not.
-        boolean keepAlive = HttpHeaders.isKeepAlive(request);
-        // Build the response object.
-        FullHttpResponse response = new DefaultFullHttpResponse(
-                HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf, false);
-        HttpHeaders headers = response.headers();
-        headers.set(CONTENT_TYPE_ENTITY, contentType);
-        headers.set(SERVER_ENTITY, SERVER_NAME);
-        headers.set(DATE_ENTITY, date);
-
-        if (keepAlive) {
-            headers.set(CONTENT_LENGTH_ENTITY, contentLength);
-        }
-
-        // Close the non-keep-alive connection after the write operation is done.
-        if (!keepAlive) {
-            ctx.write(response).addListener(ChannelFutureListener.CLOSE);
-        } else {
-            ctx.write(response, ctx.voidPromise());
-        }
+    private void writeResponse(ChannelHandlerContext ctx, HttpRequest request, ByteBuf buf, CharSequence contentType, CharSequence contentLength) {
+	// Decide whether to close the connection or not.
+	boolean keepAlive = HttpHeaders.isKeepAlive(request);
+	// Build the response object.
+	FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf, false);
+	HttpHeaders headers = response.headers();
+	headers.set(CONTENT_TYPE_ENTITY, contentType);
+	headers.set(SERVER_ENTITY, SERVER_NAME);
+	headers.set(DATE_ENTITY, date);
+	headers.set(CONTENT_LENGTH_ENTITY, contentLength);
+
+	// Close the non-keep-alive connection after the write operation is
+	// done.
+	if (!keepAlive) {
+	    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
+	} else {
+	    ctx.write(response, ctx.voidPromise());
+	}
     }
 
     @Override
-    public void exceptionCaught(
-            ChannelHandlerContext ctx, Throwable cause) throws Exception {
-        ctx.close();
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+	ctx.close();
     }
 
     @Override
     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
-        ctx.flush();
+	ctx.flush();
     }
 }

+ 9 - 7
netty/src/main/java/hello/HelloServerInitializer.java

@@ -1,6 +1,5 @@
 package hello;
 
-import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
 import io.netty.channel.socket.SocketChannel;
@@ -10,15 +9,18 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
 import java.util.concurrent.ScheduledExecutorService;
 
 public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
-    private final ChannelHandler httpHandler;
+
+    private ScheduledExecutorService service;
+
     public HelloServerInitializer(ScheduledExecutorService service) {
-        this.httpHandler = new HelloServerHandler(service);
+	this.service = service;
     }
+
     @Override
     public void initChannel(SocketChannel ch) throws Exception {
-        ChannelPipeline p = ch.pipeline();
-        p.addLast("encoder", new HttpResponseEncoder());
-        p.addLast("decoder", new HttpRequestDecoder(4096, 8192, 8192, false));
-        p.addLast("handler", httpHandler);
+	ChannelPipeline p = ch.pipeline();
+	p.addLast("encoder", new HttpResponseEncoder());
+	p.addLast("decoder", new HttpRequestDecoder(4096, 8192, 8192, false));
+	p.addLast("handler", new HelloServerHandler(service));
     }
 }

+ 33 - 39
netty/src/main/java/hello/HelloWebServer.java

@@ -6,6 +6,7 @@ import io.netty.channel.Channel;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.ServerChannel;
+import io.netty.channel.epoll.Epoll;
 import io.netty.channel.epoll.EpollEventLoopGroup;
 import io.netty.channel.epoll.EpollServerSocketChannel;
 import io.netty.channel.nio.NioEventLoopGroup;
@@ -13,60 +14,53 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.util.ResourceLeakDetector;
 import io.netty.util.ResourceLeakDetector.Level;
 
-
 public class HelloWebServer {
-	private static int IO_THREADS = Runtime.getRuntime().availableProcessors() * 2;
+
     static {
-        ResourceLeakDetector.setLevel(Level.DISABLED);
+	ResourceLeakDetector.setLevel(Level.DISABLED);
     }
 
     private final int port;
 
     public HelloWebServer(int port) {
-        this.port = port;
+	this.port = port;
     }
 
     public void run() throws Exception {
-		// Configure the server.
+	// Configure the server.
 
-		String os = System.getProperty("os.name").toLowerCase();
-
-		boolean is_linux = os.contains("linux");
-		
-		if (is_linux) {
-			doRun( new EpollEventLoopGroup(), EpollServerSocketChannel.class);
-		}
-		else {
-			doRun(new NioEventLoopGroup(), NioServerSocketChannel.class);
-		} 
+	if (Epoll.isAvailable()) {
+	    doRun(new EpollEventLoopGroup(), EpollServerSocketChannel.class);
+	} else {
+	    doRun(new NioEventLoopGroup(), NioServerSocketChannel.class);
+	}
     }
-    
-	private void doRun(EventLoopGroup loupGroup, Class<? extends ServerChannel> serverChannelClass) throws InterruptedException	{
-		try {
-			ServerBootstrap b = new ServerBootstrap();
-			b.option(ChannelOption.SO_BACKLOG, 1024);
-			b.option(ChannelOption.SO_REUSEADDR, true);
-			b.group(loupGroup).channel(serverChannelClass).childHandler(new HelloServerInitializer(loupGroup.next()));			
-            b.option(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
-            b.childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(true, IO_THREADS, IO_THREADS, 8192, 11));
-            b.childOption(ChannelOption.SO_REUSEADDR, true);
-            b.childOption(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
 
-			Channel ch = b.bind(port).sync().channel();
-			ch.closeFuture().sync();
-		}
-		finally {
-			loupGroup.shutdownGracefully().sync();
-		}
+    private void doRun(EventLoopGroup loupGroup, Class<? extends ServerChannel> serverChannelClass) throws InterruptedException {
+	try {
+	    ServerBootstrap b = new ServerBootstrap();
+	    b.option(ChannelOption.SO_BACKLOG, 1024);
+	    b.option(ChannelOption.SO_REUSEADDR, true);
+	    b.group(loupGroup).channel(serverChannelClass).childHandler(new HelloServerInitializer(loupGroup.next()));
+	    b.option(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
+	    b.childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(true));
+	    b.childOption(ChannelOption.SO_REUSEADDR, true);
+	    b.childOption(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE);
+
+	    Channel ch = b.bind(port).sync().channel();
+	    ch.closeFuture().sync();
+	} finally {
+	    loupGroup.shutdownGracefully().sync();
 	}
+    }
 
     public static void main(String[] args) throws Exception {
-        int port;
-        if (args.length > 0) {
-            port = Integer.parseInt(args[0]);
-        } else {
-            port = 8080;
-        }
-        new HelloWebServer(port).run();
+	int port;
+	if (args.length > 0) {
+	    port = Integer.parseInt(args[0]);
+	} else {
+	    port = 8080;
+	}
+	new HelloWebServer(port).run();
     }
 }

+ 9 - 9
netty/src/main/java/hello/Message.java

@@ -1,15 +1,15 @@
 package hello;
 
 public class Message {
-	
-	private final String message;
 
-	public Message(String message) {
-		super();
-		this.message = message;
-	}
+    private final String message;
 
-	public String getMessage() {
-		return message;
-	}
+    public Message(String message) {
+	super();
+	this.message = message;
+    }
+
+    public String getMessage() {
+	return message;
+    }
 }

+ 3 - 5
plack/README.md

@@ -11,8 +11,7 @@ Plack
 # Requirements
 
 * Plack
-* Monoceros or Starman
-* EV
+* Starlet
 * HTTP::Parser::XS
 * JSON::XS
 * DBI
@@ -20,6 +19,5 @@ Plack
 
 # Deployment
 
-    plackup -E production -s Starman --workers=2 -l :8080 app.psgi
-    - or -
-    plackup -E production -s Monoceros --max-workers=2 -l :8080 app.psgi
+    plackup -E production -s Starlet --max-keepalive-reqs 5000 \
+      --max-reqs-per-child 50000 --min-reqs-per-child 40000 --workers=2 -l :8080 app.psgi

+ 24 - 14
plack/app.psgi

@@ -1,24 +1,34 @@
+use strict;
 use v5.16;
-use Plack::Builder;
-use Plack::Request;
-use JSON::XS 'encode_json';
+use utf8;
+use JSON::XS qw(encode_json);
 use DBI;
 
 my $dbh = DBI->connect_cached(
     'dbi:mysql:database=hello_world;host=localhost;port=3306', 
-    qw(benchmarkdbuser benchmarkdbpass)
+    'benchmarkdbuser',
+    'benchmarkdbpass',
+    { AutoInactiveDestroy => 1, mysql_enable_utf8 => 1 }
 ) || die $!;
 
-my $sth = $dbh->prepare_cached('SELECT randomNumber FROM World WHERE id = ?');
+my $query = 'SELECT id, randomNumber FROM World WHERE id = ?';
 my $header = [qw(Content-Type application/json)];
+my $message = { message => 'Hello, World!' };
 
-builder {
-    mount '/json' => sub { [ 200, $header, [ encode_json({ message => 'Hello, World!' })] ] },
-    mount '/db' => sub {
-        my @rs = map { id => $_->[0] + 0, randomNumber => $_->[1] },
-            grep exists $_->[1],
-            map [$_, $sth->execute($_) && $sth->fetchrow_array],
-            map int rand 10000 + 1,
-            1..Plack::Request->new(shift)->param('queries')//1;
-        [ 200, $header, [ encode_json( @rs > 1 ? \@rs : $rs[0] ) ] ] } };
+my $app = sub {
+    my $env = shift;
+    if ( $env->{PATH_INFO} eq '/json' ) {
+        return [ 200, $header, [ encode_json($message) ]];
+    }
+    elsif ( $env->{PATH_INFO} eq '/db' ) {
+        my ($n) = ($env->{QUERY_STRING} || "" ) =~ m!queries=(\d+)!;
+        $n //= 1;
+        my @rs = map {{id=>$_->[0]+0,randomNumber=>$_->[1]+0}} 
+            map { $dbh->selectrow_arrayref($query,{},int rand 10000 + 1) } 1..$n;
+        return [ 200, $header, [ '{}' ]] unless @rs;
+        return [ 200, $header, [ encode_json( @rs > 1 ? \@rs : $rs[0] ) ]];
+    }
+    [ 404, [], ['not found']];
+};
 
+$app;

+ 2 - 2
plack/benchmark_config

@@ -12,8 +12,8 @@
       "framework": "plack",
       "language": "Perl",
       "orm": "Raw",
-      "platform": "Plack",
-      "webserver": "Starman",
+      "platform": "Starlet",
+      "webserver": "nginx",
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "plack",

+ 6 - 1
plack/cpanfile

@@ -1 +1,6 @@
-map requires($_), qw(JSON::XS EV HTTP::Parser::XS Plack DBI DBD::mysql DBI Monoceros Starman);
+requires 'JSON::XS', '3.01';
+requires 'HTTP::Parser::XS', '0.16';
+requires 'Plack', '1.0030';
+requires 'DBI', '1.631';
+requires 'DBD::mysql', '4.027';
+requires 'Starlet', '0.24';

+ 31 - 0
plack/nginx.conf

@@ -0,0 +1,31 @@
+error_log stderr error;
+pid        /tmp/nginx.pid;
+worker_processes 4;
+
+events {
+  worker_connections  4096;
+  multi_accept on;
+}
+
+http {
+  access_log       off;
+  tcp_nodelay      on;
+  keepalive_requests 50000;
+  etag off;
+
+  upstream backendurl {
+    server unix:/home/tfb/FrameworkBenchmarks/plack/app.sock;
+    keepalive 8;
+  }
+
+  server {
+    listen 8080;
+    server_name localhost;
+    location / {
+      proxy_http_version 1.1;
+      proxy_set_header Connection "";
+      proxy_pass http://backendurl;
+    }
+  }
+}
+

+ 12 - 4
plack/setup.py

@@ -1,21 +1,29 @@
 import subprocess
 import sys
 import setup_util
+from os.path import expanduser
 import os
+import getpass
+
+home = expanduser("~")
 
 def start(args, logfile, errfile):
   setup_util.replace_text("plack/app.psgi", "localhost", ""+ args.database_host +"")
+  setup_util.replace_text("plack/nginx.conf", "USR", getpass.getuser())
+  setup_util.replace_text("plack/nginx.conf", "server unix:.*\/FrameworkBenchmarks", "server unix:" + home + "/FrameworkBenchmarks")
   try:
     subprocess.check_call("curl -L http://cpanmin.us | perl - App::cpanminus", shell=True, cwd="plack", stderr=errfile, stdout=logfile)
-    subprocess.check_call("cpanm --installdeps .", shell=True, cwd="plack", stderr=errfile, stdout=logfile)
-    pid = subprocess.Popen("plackup -E production -s Monoceros -l :8080 --max-workers=" + str(args.max_threads) + " app.psgi", shell=True, cwd="plack", stderr=errfile, stdout=logfile).pid
-    open('plack/app.pid', 'w').write(str(pid))
+    subprocess.check_call("cpanm --notest --no-man-pages --installdeps "+home+"/FrameworkBenchmarks/plack", shell=True, cwd="plack", stderr=errfile, stdout=logfile)
+    subprocess.Popen("start_server --backlog=16384 --pid-file="+home+"/FrameworkBenchmarks/plack/app.pid --path="+home+"/FrameworkBenchmarks/plack/app.sock -- plackup -E production -s Starlet --max-keepalive-reqs 1000 --max-reqs-per-child 50000 --min-reqs-per-child 40000 --max-workers=" + str(args.max_threads+4) + " -a "+home+"/FrameworkBenchmarks/plack/app.psgi", shell=True, cwd="plack", stderr=errfile, stdout=logfile)
+    subprocess.check_call("/usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/plack/nginx.conf", shell=True,stderr=errfile, stdout=logfile)
     return 0
   except subprocess.CalledProcessError:
     return 1
 def stop(logfile, errfile):
   try:
-    subprocess.Popen("kill -TERM $(ps --ppid `cat app.pid` -o pid --no-header)", shell=True, cwd="plack", stderr=errfile, stdout=logfile)
+    subprocess.call('kill -TERM $(cat '+home+"/FrameworkBenchmarks/plack/app.pid)", shell=True, stderr=errfile, stdout=logfile)
+    subprocess.call("/usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/plack/nginx.conf -s stop", shell=True, stderr=errfile, stdout=logfile)
     return 0
   except subprocess.CalledProcessError:
     return 1
+

+ 2 - 0
plack/source_code

@@ -1,2 +1,4 @@
 ./plack/app.psgi
 ./plack/cpanfile
+./plack/nginx.conf
+

+ 4 - 4
spring/README.md

@@ -61,8 +61,8 @@ Check out [SampleApplication, the main Application file](src/main/java/com/teche
 ## Infrastructure Software Versions
 The tests were run with:
 
-* [Spring 4.0.2.RELEASE](http://projects.spring.io/spring-framework/)
-* [Spring Boot 1.0.0.RC4](http://projects.spring.io/spring-boot/)
-* [Spring Data JPA 1.5.0.RELEASE](http://projects.spring.io/spring-data-jpa/)
+* [Spring 4.0.5.RELEASE](http://projects.spring.io/spring-framework/)
+* [Spring Boot 1.1.3.RELEASE](http://projects.spring.io/spring-boot/)
+* [Spring Data JPA 1.6.0.RELEASE](http://projects.spring.io/spring-data-jpa/)
 * [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
-* [Tomcat 8.0.3](https://tomcat.apache.org/)
+* [Tomcat 8.0.8](https://tomcat.apache.org/)

+ 12 - 18
spring/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>1.0.0.RC4</version>
+        <version>1.1.3.RELEASE</version>
     </parent>
 
     <groupId>com.techempower</groupId>
@@ -19,7 +19,7 @@
 
     <properties>
         <java.version>1.7</java.version>
-        <tomcat.version>8.0.3</tomcat.version>
+        <tomcat.version>8.0.9</tomcat.version>
     </properties>
 
     <dependencies>
@@ -32,9 +32,19 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.zaxxer</groupId>
+            <artifactId>HikariCP</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-jpa</artifactId>
+			<exclusions>
+				<exclusion>
+					<groupId>org.apache.tomcat</groupId>
+					<artifactId>tomcat-jdbc</artifactId>
+				</exclusion>
+			</exclusions>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -43,16 +53,11 @@
         <dependency>
         	<groupId>org.springframework.boot</groupId>
         	<artifactId>spring-boot-starter-tomcat</artifactId>
-        	<scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.thymeleaf</groupId>
             <artifactId>thymeleaf-spring4</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.yaml</groupId>
-            <artifactId>snakeyaml</artifactId>
-        </dependency>
     </dependencies>
 
     <build>
@@ -66,10 +71,6 @@
     </build>
 
     <repositories>
-        <repository>
-            <id>spring-milestones</id>
-            <url>http://repo.spring.io/milestone</url>
-        </repository>
         <repository>
             <id>bintray</id>
             <name>bintray</name>
@@ -77,11 +78,4 @@
         </repository>
     </repositories>
 
-    <pluginRepositories>
-        <pluginRepository>
-            <id>spring-milestones</id>
-            <url>http://repo.spring.io/milestone</url>
-        </pluginRepository>
-    </pluginRepositories>
-
 </project>

+ 1 - 1
spring/src/main/java/com/techempower/spring/web/FortuneController.java

@@ -19,7 +19,7 @@ final class FortuneController {
     private FortuneRepository fortuneRepository;
 
     @RequestMapping(value = "/fortunes")
-     String fortunes(ModelMap modelMap) {
+    String fortunes(ModelMap modelMap) {
         List<Fortune> fortunes = this.fortuneRepository.findAll();
         fortunes.add(new Fortune(0, "Additional fortune added at request time."));
         Collections.sort(fortunes);

+ 1 - 1
spring/src/main/java/com/techempower/spring/web/WorldDatabaseController.java

@@ -58,7 +58,7 @@ final class WorldDatabaseController {
 		return worlds;
 	}
 
-	private Integer boundQueryCount(Integer raw) {
+	private Integer boundQueryCount(final Integer raw) {
 		if (raw == null || raw < 1) {
 			return 1;
 		} else if (raw > 500) {

+ 0 - 2
spring/src/main/resources/application.yml

@@ -6,8 +6,6 @@ spring:
     url: jdbc:mysql://${database.host: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
     username: benchmarkdbuser
     password: benchmarkdbpass
-    maxActive: 256
-    maxIdle: 256    
   jpa:
     show_sql: false
     hibernate:

+ 0 - 4
spring/src/main/resources/schema.sql → spring/src/main/resources/import.sql

@@ -1,7 +1,3 @@
-
-
--- Uncomment the following lines to import sample data
-
 -- Fortunes
 insert into Fortune(message) values ('43rd Law of Computing: Anything that can go wr fortune: Segmentation violation -- Core dumped');
 insert into Fortune(message) values ('The proof of the pudding is in the eating. -- Miguel de Cervantes');

+ 2 - 3
toolset/setup/linux/frameworks/wt.sh

@@ -10,6 +10,7 @@ sudo apt-get -y install libboost1.54-all-dev
 
 fw_get http://downloads.sourceforge.net/witty/wt-3.3.3.tar.gz -O wt.tar.gz
 fw_untar wt.tar.gz
+rm wt.tar.gz
 
 mv wt-* wt
 cd wt
@@ -17,6 +18,4 @@ mkdir -p build
 cd build
 cmake .. -DWT_CPP_11_MODE=-std=c++0x -DCMAKE_BUILD_TYPE=Release
 make
-sudo make install
-
-rm wt.tar.gz
+sudo make install

+ 2 - 2
toolset/setup/linux/languages/php.sh

@@ -17,13 +17,13 @@ cd php-5.4.13
 ./configure --with-pdo-mysql --with-mysql --with-mcrypt --enable-intl --enable-mbstring --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data --with-openssl
 make
 sudo make install
+cd ..
 
 sudo cp $FWROOT/config/php.ini /usr/local/lib/php.ini
 sudo cp $FWROOT/config/php-fpm.conf /usr/local/lib/php-fpm.conf
 
-cd ..
 RETCODE=$(fw_exists /usr/local/lib/php/extensions/no-debug-non-zts-20100525/apc.so)
 [ ! "$RETCODE" == 0 ] || { return 0; }
 
 cd php-5.4.13
-printf "\n" | sudo pecl install apc-beta
+printf "\n" | sudo pecl install apc-beta

+ 5 - 5
toolset/setup/linux/prerequisites.sh

@@ -37,12 +37,12 @@ sudo apt-get install -y gcc-4.8 g++-4.8
 
 # Stop permanently overwriting people's files just for 
 # trying out our software!
-fw_exists ~/.bash_profile.bak
-[ $? -eq 0 ] || { \
+RETCODE=$(fw_exists ~/.bash_profile.bak)
+[ ! "$RETCODE" == 0 ] || { \
   echo "Backing up your original ~/.bash_profile, ~/.profile, ~/.bashrc"
-  mv ~/.bash_profile ~/.bash_profile.bak
-  mv ~/.bash_profile ~/.bash_profile.bak
-  mv ~/.bash_profile ~/.bash_profile.bak
+  mv ~/.bash_profile ~/.bash_profile.bak || true
+  mv ~/.profile ~/.profile.bak || true
+  mv ~/.bashrc ~/.bashrc.bak || true
 }
 
 sudo sh -c "echo '*               -    nofile          65535' >> /etc/security/limits.conf"

+ 11 - 11
tornado/benchmark_config

@@ -22,16 +22,16 @@
       "notes": "CPython 2.7",
       "versus": ""
     },
-    "py3": {
-      "setup_file": "setup_py3",
+    "postgresql-raw": {
+      "setup_file": "setup_pg",
       "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
+      "db_url": "/dbraw",
+      "query_url": "/queriesraw?queries=",
       "plaintext_url": "/plaintext",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
-      "database": "MongoDB",
+      "database": "Postgres",
       "framework": "tornado",
       "language": "Python",
       "orm": "Raw",
@@ -39,12 +39,12 @@
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "tornado-py3",
-      "notes": "CPython 3.3",
+      "display_name": "tornado",
+      "notes": "CPython 2.7",
       "versus": ""
     },
-    "pypy": {
-      "setup_file": "setup_pypy",
+    "py3": {
+      "setup_file": "setup_py3",
       "json_url": "/json",
       "db_url": "/db",
       "query_url": "/queries?queries=",
@@ -60,8 +60,8 @@
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "tornado-pypy",
-      "notes": "PyPy 2.2",
+      "display_name": "tornado-py3",
+      "notes": "CPython 3.3",
       "versus": ""
     }
   }]

+ 50 - 1
tornado/server.py

@@ -4,6 +4,7 @@ import sys
 import json
 from random import randint
 
+import momoko
 import motor
 import tornado.ioloop
 import tornado.web
@@ -19,6 +20,7 @@ if sys.version_info[0] == 3:
 
 tornado.options.define('port', default=8888, type=int, help="Server port")
 tornado.options.define('mongo', default='localhost', type=str, help="MongoDB host")
+tornado.options.define('postgres', default=None, type=str, help="PostgreSQL host")
 
 
 class BaseHandler(tornado.web.RequestHandler):
@@ -72,11 +74,54 @@ class QueryTestHandler(BaseHandler):
         self.write(response)
 
 
+class QueryPostgresRawTestHandler(BaseHandler):
+    @gen.coroutine
+    def get(self):
+        sql = "SELECT id, randomNumber FROM World WHERE id=%s"
+
+        random_id = randint(1, 10000)
+        cursor = yield momoko.Op(
+            self.application.db.execute, sql, (random_id,)
+        )
+        row = cursor.fetchone()
+        response = json.dumps({"id": row[0], "randomNumber": row[1]})
+
+        self.set_header("Content-Type", "application/json; charset=UTF-8")
+        self.write(response)
+
+
+class MultipleQueriesPostgresRawTestHandler(BaseHandler):
+    @gen.coroutine
+    def get(self):
+        queries = self.get_argument("queries", "1")
+        try:
+            queries = int(queries.strip())
+        except ValueError:
+            queries = 1
+
+        queries = min(max(1, queries), 500)
+
+        sql = "SELECT id, randomNumber FROM World WHERE id=%s"
+
+        worlds = []
+        for i in xrange(int(queries)):
+            random_id = randint(1, 10000)
+            cursor = yield momoko.Op(
+                self.application.db.execute, sql, (random_id,)
+            )
+            row = cursor.fetchone()
+            worlds.append({"id": row[0], "randomNumber": row[1]})
+        response = json.dumps(worlds)
+        self.set_header("Content-Type", "application/json; charset=UTF-8")
+        self.write(response)
+
 application = tornado.web.Application([
     (r"/json", JsonSerializeTestHandler),
     (r"/plaintext", PlaintextHandler),
     (r"/db", DBTestHandler),
     (r"/queries", QueryTestHandler),
+    (r"/dbraw", QueryPostgresRawTestHandler),
+    (r"/queriesraw", MultipleQueriesPostgresRawTestHandler)
 ])
 
 
@@ -85,5 +130,9 @@ if __name__ == "__main__":
     server = tornado.httpserver.HTTPServer(application)
     server.bind(options.port)
     server.start(0)
-    db = motor.MotorClient(options.mongo).hello_world
+    if options.postgres:
+        dsn = "user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world host=%s" % options.postgres
+        application.db = momoko.Pool(dsn, size=1)
+    else:
+        db = motor.MotorClient(options.mongo).hello_world
     tornado.ioloop.IOLoop.instance().start()

+ 32 - 0
tornado/setup_pg.py

@@ -0,0 +1,32 @@
+import os
+import subprocess
+import sys
+import time
+
+
+bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py2/bin')
+python = os.path.expanduser(os.path.join(bin_dir, 'python'))
+pip = os.path.expanduser(os.path.join(bin_dir, 'pip'))
+cwd = os.path.expanduser('~/FrameworkBenchmarks/tornado')
+
+
+def start(args, logfile, errfile):
+    subprocess.Popen(
+        python + ' server.py --port=8080 --postgres=%s --logging=error' % (args.database_host,),
+        shell=True, cwd=cwd, stderr=errfile, stdout=logfile)
+    return 0
+
+
+def stop(logfile, errfile):
+    for line in subprocess.check_output(['ps', 'aux']).splitlines():
+        if 'server.py --port=8080' in line:
+            pid = int(line.split(None, 2)[1])
+            os.kill(pid, 9)
+    return 0
+
+if __name__ == '__main__':
+    class DummyArg:
+        database_host = 'localhost'
+    start(DummyArg(), sys.stderr, sys.stderr)
+    time.sleep(1)
+    stop(sys.stderr, sys.stderr)

+ 0 - 30
tornado/setup_pypy.py

@@ -1,30 +0,0 @@
-from os.path import expanduser
-from os import kill
-import subprocess
-import sys
-import time
-
-
-python = expanduser('~/FrameworkBenchmarks/installs/pypy/bin/pypy')
-cwd = expanduser('~/FrameworkBenchmarks/tornado')
-
-
-def start(args, logfile, errfile):
-    subprocess.Popen(
-        python + " server.py --port=8080 --mongo=%s --logging=error" % (args.database_host,),
-        shell=True, cwd=cwd, stderr=errfile, stdout=logfile)
-    return 0
-
-def stop(logfile, errfile):
-    for line in subprocess.check_output(["ps", "aux"]).splitlines():
-        if 'server.py --port=8080' in line:
-            pid = int(line.split(None,2)[1])
-            kill(pid, 9)
-    return 0
-
-if __name__ == '__main__':
-    class DummyArg:
-        database_host = 'localhost'
-    start(DummyArg(), sys.stderr, sys.stderr)
-    time.sleep(1)
-    stop(sys.stderr, sys.stderr)

+ 2 - 2
undertow-edge/pom.xml

@@ -18,7 +18,7 @@
         <dependency>
             <groupId>io.undertow</groupId>
             <artifactId>undertow-core</artifactId>
-            <version>1.0.0.Beta31</version>
+            <version>1.0.13.Final</version>
             <exclusions>
                 <exclusion>
                     <groupId>org.jboss.xnio</groupId>
@@ -29,7 +29,7 @@
         <dependency>
             <groupId>org.jboss.xnio</groupId>
             <artifactId>xnio-api</artifactId>
-            <version>3.2.0.Beta4</version>
+            <version>3.2.1.Final</version>
         </dependency>
         <dependency>
             <groupId>org.jboss.xnio</groupId>

+ 4 - 2
undertow-edge/src/main/java/hello/HelloWebServer.java

@@ -13,6 +13,7 @@ import io.undertow.Handlers;
 import io.undertow.Undertow;
 import io.undertow.UndertowOptions;
 import io.undertow.util.Headers;
+import org.xnio.Options;
 
 import javax.sql.DataSource;
 import java.io.IOException;
@@ -115,10 +116,11 @@ public final class HelloWebServer {
     }
     Undertow.builder()
         .addListener(
-            Integer.parseInt(properties.getProperty("web.port")),
-            properties.getProperty("web.host"))
+                Integer.parseInt(properties.getProperty("web.port")),
+                properties.getProperty("web.host"))
         .setBufferSize(1024 * 16)
         .setIoThreads(Runtime.getRuntime().availableProcessors() * 2) //this seems slightly faster in some configurations
+        .setSocketOption(Options.BACKLOG, 10000)
         .setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, false) //don't send a keep-alive header for HTTP/1.1 requests, as it is not required
         .setHandler(Handlers.date(Handlers.header(Handlers.path()
             .addPrefixPath("/json",

+ 3 - 3
undertow-edge/src/main/resources/hello/server.properties

@@ -1,14 +1,14 @@
 web.port = 8080
 web.host = 0.0.0.0
-mysql.uri = jdbc:mysql://DATABASE_HOST: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
+mysql.uri = 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
 mysql.user = benchmarkdbuser
 mysql.password = benchmarkdbpass
 #
 # TODO: Audit this postgresql connection string.
 # It looks copy & pasted from MySQL.  Do these parameters even do anything?
 #
-postgresql.uri = jdbc:postgresql://DATABASE_HOST:5432/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
+postgresql.uri = jdbc:postgresql://localhost:5432/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
 postgresql.user = benchmarkdbuser
 postgresql.password = benchmarkdbpass
-mongodb.host = DATABASE_HOST:27017
+mongodb.host = localhost:27017
 mongodb.name = hello_world

+ 12 - 10
undertow/pom.xml

@@ -7,34 +7,36 @@
     <groupId>com.techempower</groupId>
     <artifactId>undertow-example</artifactId>
     <version>0.1</version>
-
+     <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
     <dependencies>
         <!-- Web server -->
         <dependency>
             <groupId>io.undertow</groupId>
             <artifactId>undertow-core</artifactId>
-            <version>1.0.0.Beta31</version>
+            <version>1.0.14.Final</version>
         </dependency>
         <dependency>
             <groupId>org.jboss.xnio</groupId>
             <artifactId>xnio-api</artifactId>
-            <version>3.2.0.Beta4</version>
+            <version>3.2.2.Final</version>
         </dependency>
         <dependency>
             <groupId>org.jboss.xnio</groupId>
             <artifactId>xnio-nio</artifactId>
-            <version>3.2.0.Beta4</version>
+            <version>3.2.2.Final</version>
         </dependency>
         <!-- Database drivers -->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
-            <version>5.1.25</version>
+            <version>5.1.30</version>
         </dependency>
         <dependency>
             <groupId>postgresql</groupId>
             <artifactId>postgresql</artifactId>
-            <version>9.0-801.jdbc4</version>
+            <version>9.1-901-1.jdbc4</version>
         </dependency>
         <dependency>
             <groupId>org.mongodb</groupId>
@@ -51,23 +53,23 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <version>14.0.1</version>
+            <version>16.0.1</version>
         </dependency>
         <!-- JSON encoding -->
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
-            <version>2.3.0</version>
+            <version>2.3.3</version>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-annotations</artifactId>
-            <version>2.3.0</version>
+            <version>2.3.3</version>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-core</artifactId>
-            <version>2.3.0</version>
+            <version>2.3.3</version>
         </dependency>
         <!-- HTML templates -->
         <dependency>

+ 6 - 3
undertow/src/main/java/hello/HelloWebServer.java

@@ -13,6 +13,7 @@ import io.undertow.Handlers;
 import io.undertow.Undertow;
 import io.undertow.UndertowOptions;
 import io.undertow.util.Headers;
+import org.xnio.Options;
 
 import javax.sql.DataSource;
 import java.io.IOException;
@@ -114,13 +115,15 @@ public final class HelloWebServer {
       }
     }
     Undertow.builder()
-        .addListener(
+        .addHttpListener(
             Integer.parseInt(properties.getProperty("web.port")),
             properties.getProperty("web.host"))
         .setBufferSize(1024 * 16)
         .setIoThreads(Runtime.getRuntime().availableProcessors() * 2) //this seems slightly faster in some configurations
+        .setSocketOption(Options.BACKLOG, 10000)
         .setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, false) //don't send a keep-alive header for HTTP/1.1 requests, as it is not required
-        .setHandler(Handlers.date(Handlers.header(Handlers.path()
+        .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true)
+        .setHandler(Handlers.header(Handlers.path()
             .addPrefixPath("/json",
                 new JsonHandler(objectMapper))
             .addPrefixPath("/db/mysql",
@@ -151,7 +154,7 @@ public final class HelloWebServer {
                 new PlaintextHandler())
             .addPrefixPath("/cache",
                 new CacheHandler(objectMapper, worldCache)),
-            Headers.SERVER_STRING, "U-tow")))
+            Headers.SERVER_STRING, "U-tow"))
         .setWorkerThreads(200)
         .build()
         .start();

+ 3 - 3
undertow/src/main/resources/hello/server.properties

@@ -1,14 +1,14 @@
 web.port = 8080
 web.host = 0.0.0.0
-mysql.uri = jdbc:mysql://DATABASE_HOST: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
+mysql.uri = 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
 mysql.user = benchmarkdbuser
 mysql.password = benchmarkdbpass
 #
 # TODO: Audit this postgresql connection string.
 # It looks copy & pasted from MySQL.  Do these parameters even do anything?
 #
-postgresql.uri = jdbc:postgresql://DATABASE_HOST:5432/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
+postgresql.uri = jdbc:postgresql://localhost:5432/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
 postgresql.user = benchmarkdbuser
 postgresql.password = benchmarkdbpass
-mongodb.host = DATABASE_HOST:27017
+mongodb.host = localhost:27017
 mongodb.name = hello_world

+ 1 - 1
wsgi/benchmark_config

@@ -12,7 +12,7 @@
       "framework": "wsgi",
       "language": "Python",
       "orm": "Raw",
-      "platform": "Gunicorn/Meinheld",
+      "platform": "Meinheld",
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",

+ 10 - 2
wsgi/hello.py

@@ -15,7 +15,7 @@ def json(environ, start_response):
         ('Content-type', 'application/json'),
         ('Content-Length', str(len(data)))
     ]
-    start_response('200 OK', response_headers)
+    start_response(b'200 OK', response_headers)
     return [data]
 
 def plaintext(environ, start_response):
@@ -24,7 +24,7 @@ def plaintext(environ, start_response):
         ('Content-type', 'text/plain'),
         ('Content-Length', str(len(data)))
     ]
-    start_response('200 OK', response_headers)
+    start_response(b'200 OK', response_headers)
     return [data]
 
 def app(environ, start_response):
@@ -33,3 +33,11 @@ def app(environ, start_response):
         return json(environ, start_response)
     else:
         return plaintext(environ, start_response)
+
+
+try:
+    import meinheld
+    meinheld.server.set_access_logger(None)
+    meinheld.set_keepalive(120)
+except ImportError:
+    pass

+ 2 - 0
wsgi/requirements.txt

@@ -1 +1,3 @@
 ujson
+circus
+Chaussette

+ 20 - 8
wsgi/setup.py

@@ -6,19 +6,31 @@ import os
 bin_dir = os.path.expanduser('~/FrameworkBenchmarks/installs/py2/bin')
 NCPU = multiprocessing.cpu_count()
 
+CIRCUS_INI = """\
+[watcher:app]
+cmd = {BIN}/chaussette --fd=$(circus.sockets.app) --backend=meinheld hello.app
+use_sockets = True
+numprocesses = {PROCS}
+
+[socket:app]
+host = 0.0.0.0
+port = 8080
+"""
+
 proc = None
 
 
 def start(args, logfile, errfile):
     global proc
-    proc = subprocess.Popen([
-        bin_dir + "/gunicorn",
-        "hello:app",
-        "-k", "meinheld.gmeinheld.MeinheldWorker",
-        "-b", "0.0.0.0:8080",
-        '-w', str(NCPU),
-        "--log-level=critical"],
-        cwd="wsgi", stderr=errfile, stdout=logfile)
+
+    subprocess.check_call(bin_dir + "/pip install -r requirements.txt",
+                          cwd="wsgi", stderr=errfile, stdout=logfile, shell=True)
+
+    with open("wsgi/circus.ini", "w") as f:
+        f.write(CIRCUS_INI.format(BIN=bin_dir, PROCS=NCPU*2))
+
+    proc = subprocess.Popen([bin_dir + "/circusd", "circus.ini"],
+		            cwd="wsgi", stderr=errfile, stdout=logfile)
     return 0
 
 def stop(logfile, errfile):