Browse Source

Merge branch 'master' into update-node-frameworks

Edward Bramanti 10 years ago
parent
commit
8eb8de0087
29 changed files with 767 additions and 190 deletions
  1. 1 0
      .travis.yml
  2. 1 0
      frameworks/Clojure/compojure/benchmark_config.json
  3. 1 2
      frameworks/Clojure/compojure/hello/project.clj
  4. 137 49
      frameworks/Clojure/compojure/hello/src/hello/handler.clj
  5. 12 7
      frameworks/Clojure/compojure/setup.sh
  6. 6 3
      frameworks/Clojure/http-kit/benchmark_config.json
  7. 10 2
      frameworks/Clojure/http-kit/hello/project.clj
  8. 182 47
      frameworks/Clojure/http-kit/hello/src/hello/handler.clj
  9. 9 5
      frameworks/Clojure/http-kit/setup.sh
  10. 1 0
      frameworks/Clojure/luminus/benchmark_config.json
  11. 4 0
      frameworks/Clojure/luminus/hello/src/hello/handler.clj
  12. 44 22
      frameworks/Clojure/luminus/hello/src/hello/models/db.clj
  13. 68 12
      frameworks/Clojure/luminus/hello/src/hello/routes/home.clj
  14. 5 2
      frameworks/Clojure/luminus/setup.sh
  15. 36 28
      frameworks/Clojure/pedestal/src/pedestal/service.clj
  16. 2 6
      frameworks/PHP/limonade/index.php
  17. 1 1
      frameworks/PHP/php-laravel/app/config/session.php
  18. 1 0
      frameworks/Python/cherrypy/app.py
  19. 38 0
      frameworks/Python/klein/README.md
  20. 123 0
      frameworks/Python/klein/app.py
  21. 27 0
      frameworks/Python/klein/benchmark_config.json
  22. 19 0
      frameworks/Python/klein/install.sh
  23. 6 0
      frameworks/Python/klein/requirements.txt
  24. 6 0
      frameworks/Python/klein/setup.sh
  25. 20 0
      frameworks/Python/klein/templates/fortunes.html
  26. 1 0
      frameworks/Python/turbogears/app.py
  27. 4 2
      frameworks/Python/web2py/app/app/controllers/default.py
  28. 1 0
      frameworks/Python/wheezyweb/app.py
  29. 1 2
      toolset/benchmark/test_types/framework_test_type.py

+ 1 - 0
.travis.yml

@@ -126,6 +126,7 @@ env:
     - "TESTDIR=Python/django"
     - "TESTDIR=Python/falcon"
     - "TESTDIR=Python/flask"
+    - "TESTDIR=Python/klein"
     - "TESTDIR=Python/pyramid"
     - "TESTDIR=Python/tornado"
     - "TESTDIR=Python/turbogears"

+ 1 - 0
frameworks/Clojure/compojure/benchmark_config.json

@@ -6,6 +6,7 @@
       "json_url": "/compojure/json",
       "db_url": "/compojure/db",
       "query_url": "/compojure/db/",
+      "update_url": "/compojure/updates/",
       "fortune_url": "/compojure/fortune-hiccup",
       "plaintext_url": "/compojure/plaintext",
       "port": 8080,

+ 1 - 2
frameworks/Clojure/compojure/hello/project.clj

@@ -9,8 +9,7 @@
                  [mysql/mysql-connector-java "5.1.6"]
                  [org.clojure/java.jdbc "0.3.0-alpha1"]
                  [c3p0/c3p0 "0.9.1.2"]
-                 [hiccup "1.0.4"]
-                 ]
+                 [hiccup "1.0.4"]]
   :plugins [[lein-ring "0.8.10"]]
   :ring {:handler hello.handler/app}
   :profiles

+ 137 - 49
frameworks/Clojure/compojure/hello/src/hello/handler.clj

@@ -13,6 +13,7 @@
             [clojure.java.jdbc :as jdbc]
             [clojure.java.jdbc.sql :as sql]))
 
+
 ; Database connection
 (defdb db (mysql {:subname "//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"
                   :user "benchmarkdbuser"
@@ -22,6 +23,7 @@
                   :maximum-pool-size 256
                   }))
 
+
 ; Set up entity World and the database representation
 (defentity world
   (pk :id)
@@ -29,19 +31,23 @@
   (entity-fields :id :randomNumber)
   (database db))
 
-; Query a random World record from the database
-(defn get-world []
+
+(defn get-world
+  "Query a random World record from the database"
+  []
   (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
     (select world
             (fields :id :randomNumber)
             (where {:id id }))))
 
-; Run the specified number of queries, return the results
-(defn run-queries [queries]
-   (flatten ; Make it a list of maps
-    (take
-     queries ; Number of queries to run
-     (repeatedly get-world))))
+
+(defn run-queries
+  "Run the specified number of queries, return the results"
+  [queries]
+  (flatten ; Make it a list of maps
+    (take queries ; Number of queries to run
+          (repeatedly get-world))))
+
 
 ; Database connection for java.jdbc "raw"
 ; https://github.com/clojure/java.jdbc/blob/master/doc/clojure/java/jdbc/ConnectionPooling.md
@@ -52,6 +58,7 @@
    :user "benchmarkdbuser"
    :password "benchmarkdbpass"})
 
+
 (defn pool
   [spec]
   (let [cpds (doto (ComboPooledDataSource.)
@@ -65,35 +72,42 @@
                (.setMaxIdleTime (* 3 60 60)))]
     {:datasource cpds}))
 
+
 (def pooled-db (delay (pool db-spec-mysql-raw)))
 
+
 (defn db-raw [] @pooled-db)
 
-; Query a random World record from the database
-(defn get-world-raw []
-  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
+
+(defn get-world-raw
+  "Query a random World record from the database"
+  []
+  (let [id (inc (rand-int 9999))]
     (jdbc/with-connection (db-raw)
       ; Set a naming strategy to preserve column name case
       (jdbc/with-naming-strategy {:keyword identity}
         (jdbc/with-query-results rs [(str "select * from world where id = ?") id]
           (doall rs))))))
 
-; Run the specified number of queries, return the results
-(defn run-queries-raw [queries]
-   (flatten ; Make it a list of maps
-    (take
-     queries ; Number of queries to run
-     (repeatedly get-world-raw))))
 
-(defn get-query-count [queries]
+(defn run-queries-raw
+  "Run the specified number of queries, return the results"
+  [queries]
+  (flatten ; Make it a list of maps
+    (take queries
+          (repeatedly get-world-raw))))
+
+
+(defn get-query-count
   "Parse provided string value of query count, clamping values to between 1 and 500."
-  (let [q (try (Integer/parseInt queries)
+  [queries]
+  (let [n (try (Integer/parseInt queries)
                (catch Exception e 1))] ; default to 1 on parse failure
-    (if (> q 500)
-      500 ; clamp to 500 max
-      (if (< q 1)
-        1 ; clamp to 1 min
-        q)))) ; otherwise use provided value
+    (cond
+      (< n 1) 1
+      (> n 500) 500
+      :else n)))
+
 
 ; Set up entity World and the database representation
 (defentity fortune
@@ -102,19 +116,27 @@
   (entity-fields :id :message)
   (database db))
 
-(defn get-all-fortunes []
+
+(defn get-all-fortunes
   "Query all Fortune records from the database."
-    (select fortune
-            (fields :id :message)))
+  []
+  (select fortune
+          (fields :id :message)))
+
 
-(defn get-fortunes []
+(defn get-fortunes
   "Fetch the full list of Fortunes from the database, sort them by the fortune
-message text, and then return the results."
-  (let [fortunes (conj (get-all-fortunes) {:id 0 :message "Additional fortune added at request time."} )]
+  message text, and then return the results."
+  []
+  (let [fortunes (conj (get-all-fortunes)
+                       {:id 0
+                        :message "Additional fortune added at request time."})]
     (sort-by #(:message %) fortunes)))
 
-(defn fortunes-hiccup [fortunes]
+
+(defn fortunes-hiccup
   "Render the given fortunes to simple HTML using Hiccup."
+  [fortunes]
   (html5
    [:head
     [:title "Fortunes"]]
@@ -129,27 +151,93 @@ message text, and then return the results."
         [:td (escape-html (:message x))]])
      ]]))
 
-(defn fortunes-enlive [fortunes]
-  "Render the given fortunes to simple HTML using Enlive."
-  "todo")
 
-; Define route handlers
+(defn update-and-persist
+  "Changes the :randomNumber of a number of world entities.
+  Persists the changes to sql then returns the updated entities"
+  [queries]
+  (let [results (run-queries queries)]
+    (for [w results]
+      (update-in w [:randomNumber (inc (rand-int 9999))]
+        (update world
+                (set-fields {:randomNumber (:randomNumber w)})
+                (where {:id [:id w]}))))
+    results))
+
+
+(def json-serialization
+  "Test 1: JSON serialization"
+  (response {:message "Hello, World!"}))
+
+
+(def single-query-test
+  "Test 2: Single database query"
+  (-> 1
+      (run-queries)
+      (first)
+      (response)))
+
+
+(defn multiple-query-test
+  "Test 3: Multiple database queries"
+  [queries]
+  (-> queries
+      (get-query-count)
+      (run-queries)
+      (response)))
+
+
+(def single-query-test-raw
+  "Test 2: Single database query (raw)"
+  (-> 1
+      (run-queries-raw)
+      (first)
+      (response)))
+
+
+(defn multiple-query-test-raw
+  "Test 3: Multiple database queries (raw)"
+  [queries]
+  (-> queries
+      (get-query-count)
+      (run-queries-raw)
+      (response)))
+
+
+(def fortune-test
+  "Test 4: Fortunes"
+  (response (fortunes-hiccup (get-fortunes))))
+
+
+(defn db-updates
+  "Test 5: Database updates"
+  [queries]
+  (-> queries
+      (get-query-count)
+      (update-and-persist)
+      (response)))
+
+(def plaintext
+  "Test 6: Plaintext"
+  {:status 200
+   :headers {"Content-Type" "text/plain; charset=utf-8"}
+   :body "Hello, World!"})
+
+
 (defroutes app-routes
-  (GET "/" [] "Hello, World!")
-  (GET "/plaintext" []
-       {:status 200
-        :headers {"Content-Type" "text/plain; charset=utf-8"}
-        :body "Hello, World!"})
-  (GET "/json" [] (response {:message "Hello, World!"}))
-  (GET "/db" [] (response (first (run-queries 1))))
-  (GET "/db/:queries" [queries] (response (run-queries (get-query-count queries))))
-  (GET "/dbraw" [] (response (first (run-queries-raw 1))))
-  (GET "/dbraw/:queries" [queries] (response (run-queries-raw (get-query-count queries))))
-  (GET "/fortune" [] (response (get-fortunes)))
-  (GET "/fortune-hiccup" [] (fortunes-hiccup (get-fortunes)))
-  (GET "/fortune-enlive" [] (fortunes-enlive (get-fortunes)))
+  (GET "/"                 [] "Hello, World!")
+  (GET "/json"             [] json-serialization)
+  (GET "/db"               [] single-query-test)
+  (GET "/db/:queries"      [queries] (multiple-query-test queries))
+  (GET "/dbraw"            [] single-query-test-raw)
+  (GET "/dbraw/:queries"   [queries] (multiple-query-test-raw queries))
+  (GET "/fortunes"         [] (response (get-fortunes))) ; Raw json of fortunes
+  (GET "/fortune-hiccup"   [] fortune-test)
+  (GET "/updates/:queries" [queries] (db-updates queries))
+  (GET "/plaintext"        [] plaintext)
   (route/not-found "Not Found"))
 
-; Format responses as JSON
+
 (def app
+  "Format responses as JSON"
   (wrap-json-response app-routes))

+ 12 - 7
frameworks/Clojure/compojure/setup.sh

@@ -2,17 +2,22 @@
 
 source $IROOT/java7.installed
 
-export RESIN_HOME=${IROOT}/resin-4.0.41
-export LEIN_HOME=$IROOT/lein
+source $IROOT/lein.installed
 
-# Path vars must be set here
-export PATH="$JAVA_HOME/bin:$PATH"
+export RESIN_HOME=${IROOT}/resin-4.0.41
 
 sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/handler.clj
 
 cd hello
-$LEIN_HOME/bin/lein clean
-$LEIN_HOME/bin/lein ring uberwar
+lein clean
+lein ring uberwar
 rm -rf $RESIN_HOME/webapps/*
 cp target/hello-compojure-standalone.war $RESIN_HOME/webapps/compojure.war
-$RESIN_HOME/bin/resinctl start
+
+$RESIN_HOME/bin/resinctl start
+
+# preform an initial request to warm up the server
+# initial requests were taking >15 seconds, causing fails in the tests
+echo "Sleeping, then executing an initial request to ensure server is in a responsive state"
+sleep 30
+curl -m 60 http://localhost:8080/compojure/ > /dev/null 2>&1

+ 6 - 3
frameworks/Clojure/http-kit/benchmark_config.json

@@ -3,9 +3,12 @@
   "tests": [{
     "default": {
       "setup_file": "setup",
-      "json_url": "/http-kit/json",
-      "db_url": "/http-kit/db",
-      "query_url": "/http-kit/db/",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates/",
+      "plaintext_url": "/plaintext",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",

+ 10 - 2
frameworks/Clojure/http-kit/hello/project.clj

@@ -6,9 +6,17 @@
                  [ring/ring-json "0.2.0"]
                  [org.clojure/tools.cli "0.2.1"]
                  [http-kit/dbcp "0.1.0"]
-                 [http-kit "2.0.1"]
+                 [http-kit "2.1.18"]
                  [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]
-                 [mysql/mysql-connector-java "5.1.6"]]
+                 ; [ch.qos.logback/logback-classic "1.1.2" :exclusions [org.slf4j/slf4j-api]]
+                 ; [org.slf4j/jul-to-slf4j "1.7.7"]
+                 ; [org.slf4j/jcl-over-slf4j "1.7.7"]
+                 ; [org.slf4j/log4j-over-slf4j "1.7.7"]
+                 [org.clojure/data.json "0.2.5"]
+                 [org.clojure/java.jdbc "0.3.6"]
+                 [korma "0.4.0"]
+                 [mysql/mysql-connector-java "5.1.6"]
+                 [hiccup "1.0.4"]]
   :main hello.handler
   :aot [hello.handler]
   :uberjar-name "http-kit-standalone.jar"

+ 182 - 47
frameworks/Clojure/http-kit/hello/src/hello/handler.clj

@@ -1,72 +1,207 @@
 (ns hello.handler
   (:gen-class)
+  (:import com.mchange.v2.c3p0.ComboPooledDataSource)
   (:use compojure.core
         ring.middleware.json
         org.httpkit.server
         [clojure.tools.cli :only [cli]]
-        ring.util.response)
+        korma.db
+        korma.core
+        hiccup.core
+        hiccup.util
+        hiccup.page)
   (:require [compojure.handler :as handler]
-            [org.httpkit.dbcp :as db]
-            [compojure.route :as route]))
-
-;;; convert to int
-(defn to-int [s] (cond
-                  (string? s) (Integer/parseInt s)
-                  (instance? Integer s) s
-                  (instance? Long s) (.intValue ^Long s)
-                  :else 0))
-
-;; Query a random World record from the database
-(defn get-world []
-  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
-    ; Set a naming strategy to preserve column name case
-    (clojure.java.jdbc/with-naming-strategy {:keyword identity}
-      (db/query "select * from world where id = ?" id))))
-
-;; Run the specified number of queries, return the results
-(defn run-queries [queries]
-   (flatten ; Make it a list of maps
-    (take
-     queries ; Number of queries to run
-     (repeatedly get-world))))
-
-(defn get-query-count [queries]
-  "Parse provided string value of query count, clamping values to between 1 and 500."
-  (let [q (try (Integer/parseInt queries)
+            [compojure.route :as route]
+            [ring.util.response :as ring-resp]
+            [clojure.data.json :as json]
+            [clojure.java.jdbc :as jdbc]))
+
+
+(defn parse-port [s] 
+  "Convert stringy port number int. Defaults to 8080."
+  (cond
+    (string? s) (Integer/parseInt s)
+    (instance? Integer s) s
+    (instance? Long s) (.intValue ^Long s)
+    :else 8080))
+
+
+;; MySQL connection
+(defdb mysql-db
+  (mysql {
+    :classname "com.mysql.jdbc.Driver"
+    :subprotocol "mysql"
+    :subname "//127.0.0.1:3306/hello_world"
+    :user "benchmarkdbuser"
+    :password "benchmarkdbpass"
+    ;;OPTIONAL KEYS
+    :delimiters "" ;; remove delimiters
+    :maximum-pool-size 256}))
+
+
+;; Set up entity World and the database representation
+(defentity world
+  (pk :id)
+  (table :world)
+  (entity-fields :id :randomNumber) ;; Default fields for select
+  (database mysql-db))
+
+
+(defn sanitize-queries-param
+  "Sanitizes the `queries` parameter. Caps the value between 1 and 500.
+  Invalid (stringy) values become 1"
+  [queries]
+  (let [n (try (Integer/parseInt queries)
                (catch Exception e 1))] ; default to 1 on parse failure
-    (if (> q 500)
-      500 ; clamp to 500 max
-      (if (< q 1)
-        1 ; clamp to 1 min
-        q)))) ; otherwise use provided value
+    (cond
+      (< n 1) 1
+      (> n 500) 500
+      :else n)))
+
+
+(defn random-world
+  "Query a random World record from the database"
+  []
+  (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
+    (select world
+            (where {:id id }))))
+
+
+(defn run-queries
+  "Run query repeatedly -- Always returns an array"
+  [queries]
+  (flatten (take queries (repeatedly random-world))))
+
+; Set up entity Fortune and the database representation
+(defentity fortune
+  (pk :id)
+  (table :fortune)
+  (entity-fields :id :message)
+  (database mysql-db))
+
+
+(defn get-all-fortunes
+  "Query all Fortune records from the database."
+  []
+  (select fortune
+          (fields :id :message)))
+
+
+(defn get-fortunes
+  "Fetch the full list of Fortunes from the database, sort them by the fortune
+  message text, and then return the results."
+  []
+  (sort-by #(:message %)
+    (conj
+      (get-all-fortunes)
+      { :id 0 :message "Additional fortune added at request time." })))
+
+
+(defn fortunes-hiccup
+  "Render the given fortunes to simple HTML using Hiccup."
+  [fortunes]
+  (html5
+   [:head
+    [:title "Fortunes"]]
+   [:body
+    [:table
+     [:tr
+      [:th "id"]
+      [:th "message"]]
+     (for [x fortunes]
+       [:tr
+        [:td (:id x)]
+        [:td (escape-html (:message x))]])
+     ]]))
+
+
+(defn update-and-persist
+  "Changes the :randomNumber of a number of world entities.
+  Persists the changes to sql then returns the updated entities"
+  [queries]
+  (let [results (-> queries
+                    (sanitize-queries-param)
+                    (run-queries))]
+    (for [w results]
+      (update-in w [:randomNumber (inc (rand-int 9999))]
+        (update world
+                (set-fields {:randomNumber (:randomNumber w)})
+                (where {:id [:id w]}))))
+    results))
+
+
+(def json-serialization
+  "Test 1: JSON serialization"
+  (ring-resp/response {:message "Hello, World!"}))
+
+
+(def single-query-test
+  "Test 2: Single database query"
+  (ring-resp/response (first (run-queries 1))))
+
+
+(defn multiple-queries-test
+  "Test 3: Multiple database queries"
+  [queries]
+  (-> queries
+      (sanitize-queries-param)
+      (run-queries)
+      (ring-resp/response)
+      (ring-resp/content-type "application/json")))
+
+
+(def fortune-test
+  "Test 4: Fortunes"
+  (->
+    (get-fortunes)
+    (fortunes-hiccup)
+    (ring-resp/response)
+    (ring-resp/content-type "text/html")))
+
+
+(defn db-updates
+  "Test 5: Database updates"
+  [queries]
+  (-> queries
+      (update-and-persist)
+      (ring-resp/response)))
+
+
+(def plaintext
+  "Test 6: Plaintext"
+  (->
+    (ring-resp/response "Hello, World!")
+    (ring-resp/content-type "text/plain")))
+
 
 ;; Define route handlers
 (defroutes app-routes
-  (GET "/http-kit/" [] "Hello, World!")
-  (GET "/http-kit/json" [] (response {:message "Hello, World!"}))
-  (GET "/http-kit/db" []
-       (response (first (run-queries 1))))
-  (GET "/http-kit/db/:queries" [queries]
-       (response (run-queries (get-query-count queries))))
+  (GET "/"                 [] "Hello, World!")
+  (GET "/json"             [] json-serialization)
+  (GET "/db"               [] single-query-test)
+  (GET "/queries/:queries" [queries] (multiple-queries-test queries))
+  (GET "/fortunes"         [] fortune-test)
+  (GET "/updates/:queries" [queries] (db-updates queries))
+  (GET "/plaintext"        [] plaintext)
   (route/not-found "Not Found"))
 
 
-(defn start-server [{:keys [port db-host]}]
-  (db/use-database! (str "jdbc:mysql://" db-host "/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")
-                    "benchmarkdbuser"
-                    "benchmarkdbpass")
+(defn start-server [{:keys [port]}]
   ;; Format responses as JSON
   (let [handler (wrap-json-response app-routes)
         cpu (.availableProcessors (Runtime/getRuntime))]
     ;; double worker threads should increase database access performance
-    (run-server handler {:port port :thread (* 2 cpu)})
+    (run-server handler {:port port
+                         :thread (* 2 cpu)})
     (println (str "http-kit server listens at :" port))))
 
+
 (defn -main [& args]
   (let [[options _ banner]
         (cli args
-             ["-p" "--port" "Port to listen" :default 8080 :parse-fn to-int]
-             ["--db-host" "MySQL database host" :default "localhost"]
+             ["-p" "--port" "Port to listen" :default 8080 :parse-fn parse-port]
              ["--[no-]help" "Print this help"])]
-    (when (:help options) (println banner) (System/exit 0))
+    (when (:help options)
+          (println banner)
+          (System/exit 0))
     (start-server options)))

+ 9 - 5
frameworks/Clojure/http-kit/setup.sh

@@ -1,13 +1,17 @@
 #!/bin/bash
 source $IROOT/java7.installed
-export LEIN_HOME=$IROOT/lein
+source $IROOT/lein.installed
+
+
+# Update db host in the source file
+sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/handler.clj
 
 cd hello
-$LEIN_HOME/bin/lein clean
-$LEIN_HOME/bin/lein deps
+lein clean
+lein deps
 rm -rf target
 # pack all dependencies into a single jar: target/http-kit-standalone.jar
-$LEIN_HOME/bin/lein uberjar
+lein uberjar
 # -server is much faster
 # 'lein run' passes '-client -XX:+TieredCompilation -XX:TieredStopAtLevel=1' which make it starts fast, but runs slow
-$JAVA_HOME/bin/java -server -jar target/http-kit-standalone.jar --db-host ${DBHOST} &
+java -server -jar target/http-kit-standalone.jar  &

+ 1 - 0
frameworks/Clojure/luminus/benchmark_config.json

@@ -7,6 +7,7 @@
       "db_url": "/luminus/db",
       "query_url": "/luminus/db/",
       "fortune_url": "/luminus/fortune",
+      "update_url": "/luminus/update/",
       "plaintext_url": "/luminus/plaintext",
       "port": 8080,
       "approach": "Realistic",

+ 4 - 0
frameworks/Clojure/luminus/hello/src/hello/handler.clj

@@ -6,13 +6,16 @@
             [taoensso.timbre :as timbre]
             [taoensso.timbre.appenders.rotor :as rotor]))
 
+
 (defroutes app-routes
   (route/resources "/")
   (route/not-found "Not Found"))
 
+
 (defn destroy []
   (timbre/info "picture-gallery is shutting down"))
 
+
 (defn init
   "init will be called once when
    app is deployed as a servlet on
@@ -33,6 +36,7 @@
 
   (timbre/info "hello started successfully"))
 
+
 (defn destroy
   "destroy will be called when your application
    shuts down, put any clean up code here"

+ 44 - 22
frameworks/Clojure/luminus/hello/src/hello/models/db.clj

@@ -12,15 +12,19 @@
   (entity-fields :id :randomNumber)
   (database db))
 
-; Query a random World record from the database
-(defn get-world []
+
+(defn get-world
+  "Query a random World record from the database"
+  []
   (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
     (select world
             (fields :id :randomNumber)
             (where {:id id }))))
 
-; Query a random World record from the database
-(defn get-world-raw []
+
+(defn get-world-raw
+  "Query a random World record from the database"
+  []
   (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
     (jdbc/with-connection (db-raw)
       ; Set a naming strategy to preserve column name case
@@ -28,19 +32,21 @@
         (jdbc/with-query-results rs [(str "select * from world where id = ?") id]
           (doall rs))))))
 
-; Run the specified number of queries, return the results
-(defn run-queries [queries]
-   (flatten ; Make it a list of maps
-    (take
-     queries ; Number of queries to run
-     (repeatedly get-world))))
 
-; Run the specified number of queries, return the results
+(defn run-queries
+  "Run the specified number of queries, return the results"
+  [queries]
+  (flatten ; Make it a list of maps
+    (take queries
+          (repeatedly get-world))))
+
+
 (defn run-queries-raw [queries]
-   (flatten ; Make it a list of maps
-    (take
-     queries ; Number of queries to run
-     (repeatedly get-world-raw))))
+  "Run the specified number of queries, return the results"
+  (flatten ; Make it a list of maps
+    (take queries
+          (repeatedly get-world-raw))))
+
 
 (defn get-query-count [queries]
   "Parse provided string value of query count, clamping values to between 1 and 500."
@@ -60,13 +66,29 @@
   (entity-fields :id :message)
   (database db))
 
-(defn get-all-fortunes []
+
+(def get-all-fortunes
   "Query all Fortune records from the database."
-    (select fortune
-            (fields :id :message)))
+  (select fortune
+          (fields :id :message)))
+
 
-(defn get-fortunes []
-  "Fetch the full list of Fortunes from the database, sort them by the fortune
-   message text, and then return the results."
-  (let [fortunes (conj (get-all-fortunes) {:id 0 :message "Additional fortune added at request time."} )]
+(def get-fortunes
+  "Fetch the full list of Fortunes from the database. Insert an additional fortune at runtime.
+  Then sort all by fortune message text. Return the results."
+  (let [fortunes (conj get-all-fortunes
+                       {:id 0 :message "Additional fortune added at request time."})]
     (sort-by :message fortunes)))
+
+
+(defn update-and-persist
+  "Changes the :randomNumber of a number of world entities.
+  Persists the changes to sql then returns the updated entities"
+  [queries]
+  (let [results (run-queries queries)]
+    (for [w results]
+      (update-in w [:randomNumber (inc (rand-int 9999))]
+        (update world
+                (set-fields {:randomNumber (:randomNumber w)})
+                (where {:id [:id w]}))))
+    results))

+ 68 - 12
frameworks/Clojure/luminus/hello/src/hello/routes/home.clj

@@ -4,16 +4,72 @@
   (:require [hello.views.layout :as layout]
             [noir.response :as response]))
 
-(defroutes home-routes
-  (GET "/" [] "Hello, World!")
-  (GET "/plaintext" []
-       {:status 200
-        :headers {"Content-Type" "text/plain; charset=utf-8"}
-        :body "Hello, World!"})
-  (GET "/json" [] (response/json {:message "Hello, World!"}))
-  (GET "/db" [] (response/json (first (run-queries 1))))
-  (GET "/db/:queries" [queries] (response/json (run-queries (get-query-count queries))))
-  (GET "/dbraw" [] (response/json (first (run-queries-raw 1))))
-  (GET "/dbraw/:queries" [queries] (response/json (run-queries-raw (get-query-count queries))))  
-  (GET "/fortune" [] (layout/render "home.html" {:messages (get-fortunes)})))
 
+(def json-serialization
+  "Test 1: JSON serialization"
+  (response/json {:message "Hello, World!"}))
+
+
+(def single-query-test
+  "Test 2: Single database query"
+  (response/json (first (run-queries 1))))
+
+
+(defn multiple-query-test
+  "Test 3: Multiple database query"
+  [queries]
+  (-> queries
+      (get-query-count)
+      (run-queries)
+      (response/json)))
+
+
+(def single-query-test-raw
+  "Test 2: Single database query (raw)"
+  (-> 1
+      (run-queries-raw)
+      (first)
+      (response/json)))
+
+
+(defn multiple-query-test-raw
+  "Test 3: Multiple database query (raw)"
+  [queries]
+  (-> queries
+      (get-query-count)
+      (run-queries-raw)
+      (response/json)))
+
+
+(def fortunes
+  "Test 4: Fortunes"
+  (layout/render "home.html"
+                 {:messages get-fortunes}))
+
+
+(defn db-update
+  "Test 5: Database updates"
+  [queries]
+  (-> queries
+      (get-query-count)
+      (update-and-persist)
+      (response/json)))
+
+
+(def plaintext
+  "Test 6: Plaintext"
+  {:status 200
+   :headers {"Content-Type" "text/plain; charset=utf-8"}
+   :body "Hello, World!"})
+
+
+(defroutes home-routes
+  (GET "/"                [] "Hello, World!")
+  (GET "/plaintext"       [] plaintext)
+  (GET "/json"            [] json-serialization)
+  (GET "/db"              [] single-query-test)
+  (GET "/db/:queries"     [queries] (multiple-query-test queries))
+  (GET "/dbraw"           [] single-query-test-raw)
+  (GET "/dbraw/:queries"  [queries] (multiple-query-test-raw queries))
+  (GET "/fortune"         [] fortunes)
+  (GET "/update/:queries" [queries] (db-update queries)))

+ 5 - 2
frameworks/Clojure/luminus/setup.sh

@@ -1,6 +1,9 @@
 #!/bin/bash
 
 source $IROOT/java7.installed
+
+source $IROOT/lein.installed
+
 export RESIN_HOME=${IROOT}/resin-4.0.41
 
 # Path vars must be set here
@@ -9,8 +12,8 @@ export PATH="$JAVA_HOME/bin:$PATH"
 sed -i 's|:subname "//.*:3306|:subname "//'"${DBHOST}"':3306|g' hello/src/hello/models/schema.clj
 
 cd hello
-$IROOT/lein/bin/lein clean
-$IROOT/lein/bin/lein ring uberwar
+lein clean
+lein ring uberwar
 rm -rf $RESIN_HOME/webapps/*
 cp target/hello-luminus-standalone.war $RESIN_HOME/webapps/luminus.war
 $RESIN_HOME/bin/resinctl start

+ 36 - 28
frameworks/Clojure/pedestal/src/pedestal/service.clj

@@ -41,11 +41,12 @@
   (database mysql-db))
 
 
-(defn random-world []
+(defn random-world
   "Query a random World record from the database"
+  []
   (let [id (inc (rand-int 9999))] ; Num between 1 and 10,000
     (select world
-      (where {:id id }))))
+            (where {:id id }))))
 
 
 (defn run-queries
@@ -62,26 +63,27 @@
 
 (defn sanitizeQueriesParam
   "Sanitizes the `queries` parameter. Caps the value between 1 and 500.
-Invalid (stringy) values become 1"
+  Invalid (stringy) values become 1"
   [request]
-  (let [queries (-> request :params :queries)]
-    (let [n
-      (if (= (re-find #"\A-?\d+" queries) nil)
-        1
-        (Integer/parseInt queries))]
-    (cond
-      (< n 1) 1
-      (> n 500) 500
-      :else n))))
+  (let [queries (-> request
+                    :params
+                    :queries)]
+    (if-let [n (if (= (re-find #"\A-?\d+" queries) nil)
+                   1
+                   (Integer/parseInt queries))]
+      (cond
+        (< n 1) 1
+        (> n 500) 500
+        :else n))))
 
 
 (defn multiple-query-test
   "Test 3: Multiple database queries"
   [request]
   (-> request
-    (sanitizeQueriesParam)
-    (run-queries)
-    (bootstrap/json-response)))
+      (sanitizeQueriesParam)
+      (run-queries)
+      (bootstrap/json-response)))
 
 
 ; Set up entity Fortune and the database representation
@@ -92,23 +94,26 @@ Invalid (stringy) values become 1"
   (database mysql-db))
 
 
-(defn get-all-fortunes []
+(defn get-all-fortunes
   "Query all Fortune records from the database."
+  []
   (select fortune
-    (fields :id :message)))
+          (fields :id :message)))
 
 
-(defn get-fortunes []
+(defn get-fortunes
   "Fetch the full list of Fortunes from the database, sort them by the fortune
-message text, and then return the results."
+  message text, and then return the results."
+  []
   (sort-by #(:message %)
     (conj
       (get-all-fortunes)
       { :id 0 :message "Additional fortune added at request time." })))
 
 
-(defn fortunes-hiccup [fortunes]
+(defn fortunes-hiccup
   "Render the given fortunes to simple HTML using Hiccup."
+  [fortunes]
   (html5
    [:head
     [:title "Fortunes"]]
@@ -124,8 +129,9 @@ message text, and then return the results."
      ]]))
 
 
-(defn fortune-test [request]
+(defn fortune-test
   "Test 4: Fortunes"
+  [request]
   (->
     (get-fortunes)
     (fortunes-hiccup)
@@ -136,23 +142,25 @@ message text, and then return the results."
 
 (defn update-and-persist
   "Changes the :randomNumber of a number of world entities.
-Persists the changes to sql then returns the updated entities"
+  Persists the changes to sql then returns the updated entities"
   [request]
-  (let [results (-> request (sanitizeQueriesParam) (run-queries))]
+  (let [results (-> request
+                    (sanitizeQueriesParam)
+                    (run-queries))]
     (for [w results]
       (update-in w [:randomNumber (inc (rand-int 9999))]
         (update world
-          (set-fields {:randomNumber (:randomNumber w)})
-          (where {:id [:id w]}))))
-  results))
+                (set-fields {:randomNumber (:randomNumber w)})
+                (where {:id [:id w]}))))
+    results))
 
 
 (defn db-updates
   "Test 5: Database updates"
   [request]
   (-> request
-    (update-and-persist)
-    (bootstrap/json-response)))
+      (update-and-persist)
+      (bootstrap/json-response)))
 
 
 (defn plaintext

+ 2 - 6
frameworks/PHP/limonade/index.php

@@ -54,10 +54,6 @@ function queries() {
 
 }
 
-function update_world(&$world, $key) {
-	$world["randomnumber"] = mt_rand(1, 10000);
-}
-
 dispatch("/updates/:queries", "updates");
 function updates() {
 	header('Content-Type: application/json; charset=utf-8');
@@ -74,11 +70,11 @@ function updates() {
 	for ($i = 0; $i < $query_count; $i++) {
 		$id = mt_rand(1, 10000);
 		$world = World::find($id);
+                $world->randomnumber = mt_rand(1, 10000);
+		$world->save();
 		$worlds[] = $world->to_array();
 	}
 
-	array_walk($worlds, "update_world");
-
 	return json($worlds);
 }
 

+ 1 - 1
frameworks/PHP/php-laravel/app/config/session.php

@@ -16,7 +16,7 @@ return array(
 	|
 	*/
 
-	'driver' => 'file',
+	'driver' => 'array',
 
 	/*
 	|--------------------------------------------------------------------------

+ 1 - 0
frameworks/Python/cherrypy/app.py

@@ -101,6 +101,7 @@ class CherryPyBenchmark(object):
             world = cherrypy.request.db.query(World).get(id)
             world.randomNumber = rp()
             worlds.append(world.serialize())
+        cherrypy.request.db.commit()
         return worlds
 
     @cherrypy.expose

+ 38 - 0
frameworks/Python/klein/README.md

@@ -0,0 +1,38 @@
+# Twisted Klein Benchmark Test
+
+This is the Klein portion of a [benchmarking tests suite](../../) 
+comparing a variety of web development platforms.
+
+The information below is specific to Klein. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information provided in 
+the [Python README](../).
+
+## Description
+
+Klein framework (https://github.com/twisted/klein)
+
+## Infrastructure Software
+
+### Server
+
+* gunicorn+meinheld on CPython
+* Tornado on PyPy
+
+## Test Paths & Sources
+
+All of the test implementations are located within a single file ([app.py](app.py)).
+
+* [JSON Serialization](app.py): "/json"
+* [Single Database Query](app.py): "/db"
+* [Multiple Database Queries](app.py): "/queries?queries=5"
+* [Fortunes](app.py): "/fortune"
+* [Database Updates](app.py): "/updates?queries=5"
+* [Plaintext](app.py): "/plaintext"
+
+## Get Help
+
+### Resources
+
+* [Klein Source Code](https://github.com/twisted/klein)
+

+ 123 - 0
frameworks/Python/klein/app.py

@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+import json
+
+import bleach
+
+from random import randint
+from functools import partial
+from operator import attrgetter
+
+from klein import Klein, run, route
+
+from jinja2 import Environment, PackageLoader
+
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import create_engine, Column
+from sqlalchemy.types import String, Integer, Unicode
+from sqlalchemy.orm import sessionmaker
+
+if sys.version_info[0] == 3:
+    xrange = range
+
+DBDRIVER = 'mysql'
+DBHOSTNAME = os.environ.get('DBHOST', 'localhost')
+DATABASE_URI = '%s://benchmarkdbuser:benchmarkdbpass@%s:3306/hello_world?charset=utf8' % (DBDRIVER, DBHOSTNAME)
+
+Base = declarative_base()
+db_engine = create_engine(DATABASE_URI)
+Session = sessionmaker(bind=db_engine)
+db_session = Session()
+
+env = Environment(loader=PackageLoader("app", "templates"))
+
+app = Klein()
+
+class Fortune(Base):
+    __tablename__ = "Fortune"
+    id = Column(Integer, primary_key=True)
+    message = Column(String)
+
+    def serialize(self):
+        return {
+            'id': self.id,
+            'randomNumber': self.randomNumber,
+        }
+
+class World(Base):
+    __tablename__ = "World"
+    id = Column(Integer, primary_key=True)
+    randomNumber = Column(Integer)
+    def serialize(self):
+        return {
+            'id': self.id,
+            'randomNumber': self.randomNumber,
+        }
+
+def getQueryNum(queryString):
+    try:
+        num_queries = int(queryString)
+        if num_queries < 1:
+            return 1
+        if num_queries > 500:
+            return 500
+        return num_queries
+    except ValueError:
+         return 1
+
[email protected]("/plaintext")
+def plaintext(request):
+	request.setHeader("Content-Type", "text/plain; charset=UTF-8")
+	return "Hello, World!"
+
[email protected]("/json")
+def jsonHandler(request):
+	request.setHeader("Content-Type", "application/json; charset=UTF-8")
+	return json.dumps({"message": "Hello, World!"})
+
[email protected]("/db")
+def db(request):
+	request.setHeader("Content-Type", "application/json; charset=UTF-8")	
+	wid = randint(1, 10000)
+	world = db_session.query(World).get(wid).serialize() 
+	return json.dumps(world)
+
[email protected]("/queries")
+def queries(request):
+	request.setHeader("Content-Type", "application/json; charset=UTF-8")	
+	num_queries = getQueryNum(request.args.get("queries")[0])
+	rp = partial(randint, 1, 10000)
+	get = db_session.query(World).get
+	worlds = [get(rp()).serialize() for _ in xrange(num_queries)]
+	return json.dumps(worlds)
+
[email protected]("/updates")
+def updates(request):
+	request.setHeader("Content-Type", "application/json; charset=UTF-8")
+	num_queries = getQueryNum(request.args.get("queries")[0])
+	worlds = []
+	rp = partial(randint, 1, 10000)
+	ids = [rp() for _ in xrange(num_queries)]
+	ids.sort()
+	for id in ids:
+		world = db_session.query(World).get(id)
+		world.randomNumber = rp()
+		worlds.append(world.serialize())
+	db_session.commit()
+	return json.dumps(worlds)
+
[email protected]("/fortune")
+def fortune(request):
+	request.setHeader("Content-Type", "text/html; charset=UTF-8")
+	fortunes = db_session.query(Fortune).all()
+	fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
+	fortunes.sort(key=attrgetter("message"))
+	for f in fortunes:
+		f.message = bleach.clean(f.message)
+	template = env.get_template("fortunes.html")
+	return template.render(fortunes=fortunes)
+
+if __name__ == "__main__":
+    app.run("0.0.0.0", 8080)

+ 27 - 0
frameworks/Python/klein/benchmark_config.json

@@ -0,0 +1,27 @@
+{
+  "framework": "klein",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/updates?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "MySQL",
+      "framework": "Twisted Klein",
+      "language": "Python",
+      "orm": "Full",
+      "platform": "Twisted Web",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Twisted Klein",
+      "notes": "CPython 2.7"
+    }
+  }]
+}

+ 19 - 0
frameworks/Python/klein/install.sh

@@ -0,0 +1,19 @@
+#!/bin/bash
+
+export PY2_ROOT=$IROOT/py2
+export PY2=$PY2_ROOT/bin/python
+export PY2_PIP=$PY2_ROOT/bin/pip
+
+export PY3_ROOT=$IROOT/py3
+export PY3=$PY3_ROOT/bin/python3
+export PY3_PIP=$PY3_ROOT/bin/pip3
+
+mkdir -p $IROOT/.pip_cache
+export PIP_DOWNLOAD_CACHE=$IROOT/.pip_cache
+
+fw_depends python2 python3
+
+$PY2_PIP install --install-option="--prefix=${PY2_ROOT}" -r $TROOT/requirements.txt
+
+$PY3_PIP install --install-option="--prefix=${PY3_ROOT}" -r $TROOT/requirements.txt
+

+ 6 - 0
frameworks/Python/klein/requirements.txt

@@ -0,0 +1,6 @@
+klein==15.0.0
+
+bleach==1.4.1
+mysqlclient==1.3.6
+SQLAlchemy==0.9.9
+jinja2==2.7.3

+ 6 - 0
frameworks/Python/klein/setup.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+export PY2_ROOT=$IROOT/py2
+export PY2=$PY2_ROOT/bin/python
+
+$PY2 app.py &

+ 20 - 0
frameworks/Python/klein/templates/fortunes.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Fortunes</title>
+    </head>
+    <body>
+        <table>
+            <tr>
+                <th>id</th>
+                <th>message</th>
+            </tr>
+            {%for fortune in fortunes %}
+                <tr>
+                    <td>{{ fortune.id }}</td>
+                    <td>{{ fortune.message }}</td>
+                </tr>
+            {% endfor %}
+        </table>
+    </body>
+</html>

+ 1 - 0
frameworks/Python/turbogears/app.py

@@ -65,6 +65,7 @@ class RootController(TGController):
             world = db_session.query(World).get(id)
             world.randomNumber = rp()
             worlds.append(world.serialize())
+        db_session.commit()
         return json.dumps(worlds)
 
     @expose("json")

+ 4 - 2
frameworks/Python/web2py/app/app/controllers/default.py

@@ -55,8 +55,10 @@ def updates():
     ids = [rp() for _ in xrange(num_queries)]
     ids.sort() # To avoid deadlock
     for id in ids:
-        world = DATABASE(DATABASE.world.id==id).select()[0]
-        world.randomNumber = rp()
+        world = DATABASE.world[id]
+        newNumber = rp()
+        DATABASE(DATABASE.world.id==id).update(randomNumber=newNumber)
+        world.randomNumber = newNumber
         worlds.append(serializeWorld(world))
     return jsonOut.dumps(worlds)
 

+ 1 - 0
frameworks/Python/wheezyweb/app.py

@@ -106,6 +106,7 @@ class UpdatesHandler(BaseHandler):
             world = db_session.query(World).get(id)
             world.randomNumber = rp()
             worlds.append(world.serialize())
+        db_session.commit()
         return self.json_response(worlds)
 
 class FortuneHandler(BaseHandler):

+ 1 - 2
toolset/benchmark/test_types/framework_test_type.py

@@ -77,9 +77,8 @@ class FrameworkTestType:
   def _curl_body(self, url):
     '''Downloads a URL and returns the HTTP body'''
     # Use -m 15 to make curl stop trying after 15sec.
-    # Use -i to output response with headers
     # Don't use -f so that the HTTP response code is ignored.
-    # Use -sS to hide progress bar, but show errors.
+    # Use -s to hide progress bar
     # Get response body
     p = subprocess.Popen(["curl", "-m", "15", "-s", url], stdout=PIPE, stderr=PIPE)
     (out, err) = p.communicate()