Browse Source

Added more rack tests for other web servers

Richard Nienaber 11 years ago
parent
commit
e684b548bc

+ 17 - 0
frameworks/Ruby/rack/Gemfile

@@ -0,0 +1,17 @@
+source 'http://rubygems.org'
+
+platforms :jruby do
+  gem "jdbc-mysql", "5.1.31", :require => 'jdbc/mysql'
+  gem 'torqbox', '0.1.7'
+  gem "trinidad", "1.4.6"
+end
+
+platforms :ruby do
+  gem 'mysql2', '0.3.16'
+  gem "unicorn", "4.8.3"
+  gem "thin", "~> 1.6.2"
+end
+
+gem 'rack', '1.5.2'
+gem 'json', '1.8.1'
+gem "puma", "~> 2.9.0"

+ 0 - 8
frameworks/Ruby/rack/Gemfile-jruby

@@ -1,8 +0,0 @@
-source 'http://rubygems.org'
-
-gem 'rack', '1.5.2'
-gem 'json', '1.8.1'
-
-group :server do
-  gem 'torqbox', '0.1.7', :require => false
-end

+ 0 - 9
frameworks/Ruby/rack/Gemfile-ruby

@@ -1,9 +0,0 @@
-source 'http://rubygems.org'
-
-gem 'rack', '1.5.2'
-gem 'json', '1.8.1'
-
-group :server do
-  gem 'passenger', '4.0.44', :require => false
-  gem 'unicorn', '4.8.3', :require => false
-end

+ 2 - 0
frameworks/Ruby/rack/README.md

@@ -14,6 +14,8 @@ The tests were run with:
 * [Rack 1.5.2](http://rack.github.com/)
 * [Rack 1.5.2](http://rack.github.com/)
 * [Unicorn 4.8.3](http://unicorn.bogomips.org/)
 * [Unicorn 4.8.3](http://unicorn.bogomips.org/)
 * [TorqBox 0.1.7](http://torquebox.org/torqbox/)
 * [TorqBox 0.1.7](http://torquebox.org/torqbox/)
+* [Puma 2.9.0](http://puma.io/)
+* [Thin 1.6.2](http://code.macournoyer.com/thin/)
 
 
 ## References
 ## References
 * https://github.com/FooBarWidget/passenger/pull/71
 * https://github.com/FooBarWidget/passenger/pull/71

+ 91 - 0
frameworks/Ruby/rack/app/jruby_impl.rb

@@ -0,0 +1,91 @@
+require 'java'
+Jdbc::MySQL.load_driver
+Java::com.mysql.jdbc.Driver
+
+host, database     = DB_CONFIG[:host], DB_CONFIG[:database]
+username, password = DB_CONFIG[:username], DB_CONFIG[:password]
+JDBC_CONFIG = "jdbc:mysql://#{host}/#{database}?user=#{username}&password=#{password}"
+
+module App
+  JRuby = lambda do |env| 
+    content_type, body = case env['PATH_INFO']
+      when '/plaintext'
+        ['text/plain; charset=utf-8', "Hello, World!"] 
+      when '/json'
+        ['application/json; charset=utf-8', {:message => "Hello, World!"}.to_json]
+      when '/db'
+        id = Random.rand(10000) + 1
+        query = "SELECT * FROM World WHERE id = " + id.to_s
+
+        connection = java.sql.DriverManager.get_connection(JDBC_CONFIG)
+        results = begin
+          statement = connection.create_statement
+          begin
+            rs = statement.execute_query(query)
+            rs.next
+            {id: rs.getObject('id'), randomNumber: rs.getObject('randomNumber')}
+          ensure
+            statement.close
+          end
+        ensure
+          connection.close
+        end
+        ['application/json; charset=utf-8', results.to_json]
+      when '/queries'
+        query_string = Rack::Utils.parse_query(env['QUERY_STRING'])
+        queries = query_string['queries'].to_i
+        queries = 1 if queries < 1
+        queries = 500 if queries > 500
+
+        connection = java.sql.DriverManager.get_connection(JDBC_CONFIG)
+        results = begin
+          statement = connection.create_statement
+          begin
+            (1..queries).map do
+              id = Random.rand(10000) + 1
+              rs = statement.execute_query("SELECT * FROM World WHERE id = " + id.to_s)
+              rs.next
+              {id: rs.getObject('id'), randomNumber: rs.getObject('randomNumber')}
+            end
+          ensure
+            statement.close
+          end
+        ensure
+          connection.close
+        end
+        ['application/json; charset=utf-8', results.to_json] 
+      when '/updates'
+        query_string = Rack::Utils.parse_query(env['QUERY_STRING'])
+        queries = query_string['queries'].to_i
+        queries = 1 if queries < 1
+        queries = 500 if queries > 500
+
+        connection = java.sql.DriverManager.get_connection(JDBC_CONFIG)
+        results = begin
+          statement = connection.create_statement
+          begin
+            results = (1..queries).map do
+              id = Random.rand(10000) + 1
+              rs = statement.execute_query("SELECT * FROM World WHERE id = " + id.to_s)
+              rs.next
+              {id: rs.getObject('id'), randomNumber: rs.getObject('randomNumber')}
+            end
+
+            #mass update
+            values = results.map { |h| ['(', h[:id], ',' ,Random.rand(10000) + 1, ')', ','] }.flatten[0..-2].join
+            sql = "INSERT INTO `World` (`id`,`randomNumber`) VALUES #{values} ON DUPLICATE KEY UPDATE `World`.`randomNumber` = VALUES(`randomNumber`)"
+            rs = statement.execute_update(sql)
+
+            results
+          ensure
+            statement.close
+          end
+        ensure
+          connection.close
+        end
+
+        ['application/json; charset=utf-8', results.to_json] 
+      end
+    [200, { 'Content-Type' => content_type }, [body]]
+  end 
+end

+ 61 - 0
frameworks/Ruby/rack/app/ruby_impl.rb

@@ -0,0 +1,61 @@
+module App
+  Ruby = lambda do |env| 
+    content_type, body = case env['PATH_INFO']
+      when '/plaintext'
+        ['text/plain; charset=utf-8', "Hello, World!"] 
+      when '/json'
+        ['application/json; charset=utf-8', {:message => "Hello, World!"}.to_json]
+      when '/db'
+        id = Random.rand(10000) + 1
+        query = "SELECT * FROM World WHERE id = " + id.to_s
+
+        client = Mysql2::Client.new(DB_CONFIG)
+        results = begin
+          client.query(query)
+        ensure
+          client.close
+        end
+        ['application/json; charset=utf-8', results.first.to_json]
+      when '/queries'
+        query_string = Rack::Utils.parse_query(env['QUERY_STRING'])
+        queries = query_string['queries'].to_i
+        queries = 1 if queries < 1
+        queries = 500 if queries > 500
+
+        client = Mysql2::Client.new(DB_CONFIG)
+        results = begin
+          (1..queries).map do
+            id = Random.rand(10000) + 1
+            client.query("SELECT * FROM World WHERE id = " + id.to_s).first
+          end
+        ensure
+          client.close
+        end
+        ['application/json; charset=utf-8', results.to_json] 
+      when '/updates'
+        query_string = Rack::Utils.parse_query(env['QUERY_STRING'])
+        queries = query_string['queries'].to_i
+        queries = 1 if queries < 1
+        queries = 500 if queries > 500
+
+        client = Mysql2::Client.new(DB_CONFIG)
+        results = begin
+          results = (1..queries).map do
+            id = Random.rand(10000) + 1
+            client.query("SELECT * FROM World WHERE id = " + id.to_s).first
+          end
+
+          #mass update
+          values = results.map { |h| ['(', h['id'], ',' ,Random.rand(10000) + 1, ')', ','] }.flatten[0..-2].join
+          sql = "INSERT INTO `World` (`id`,`randomNumber`) VALUES #{values} ON DUPLICATE KEY UPDATE `World`.`randomNumber` = VALUES(`randomNumber`)"
+          client.query(sql)
+
+          results
+        ensure
+          client.close
+        end
+        ['application/json; charset=utf-8', results.to_json] 
+      end
+    [200, { 'Content-Type' => content_type }, [body]]
+  end 
+end

+ 103 - 15
frameworks/Ruby/rack/benchmark_config

@@ -1,43 +1,131 @@
 {
 {
   "framework": "rack",
   "framework": "rack",
   "tests": [{
   "tests": [{
-    "ruby": {
-      "setup_file": "setup_ruby",
+    "puma-jruby": {
+      "setup_file": "run_jruby_puma",
       "json_url": "/json",
       "json_url": "/json",
+      "db_url": "/db", 
+      "query_url": "/queries?queries=", 
+      "update_url": "/updates?queries=", 
       "plaintext_url": "/plaintext",
       "plaintext_url": "/plaintext",
       "port": 8080,
       "port": 8080,
-      "approach": "Realistic",
+      "approach": "Stripped",
       "classification": "Platform",
       "classification": "Platform",
-      "database": "None",
+      "database": "MySQL",
       "framework": "rack",
       "framework": "rack",
       "language": "Ruby",
       "language": "Ruby",
-      "orm": "Full",
+      "orm": "Raw",
+      "platform": "JRuby",
+      "webserver": "Puma",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "rack",
+      "notes": ""
+    },
+    "puma": {
+      "setup_file": "run_mri_puma",
+      "json_url": "/json",
+      "db_url": "/db", 
+      "query_url": "/queries?queries=", 
+      "update_url": "/updates?queries=", 
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "rack",
+      "language": "Ruby",
+      "orm": "Raw",
       "platform": "Rack",
       "platform": "Rack",
-      "webserver": "Unicorn",
+      "webserver": "Puma",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "rack",
+      "notes": ""
+    },
+    "thin": {
+      "setup_file": "run_thin",
+      "json_url": "/json",
+      "db_url": "/db", 
+      "query_url": "/queries?queries=", 
+      "update_url": "/updates?queries=", 
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "rack",
+      "language": "Ruby",
+      "orm": "Raw",
+      "platform": "Rack",
+      "webserver": "Thin",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "rack",
       "display_name": "rack",
-      "notes": "",
-      "versus": ""
+      "notes": ""
     },
     },
-    "jruby": {
-      "setup_file": "setup_jruby",
+    "torqbox": {
+      "setup_file": "run_torqbox",
       "json_url": "/json",
       "json_url": "/json",
+      "db_url": "/db", 
+      "query_url": "/queries?queries=", 
+      "update_url": "/updates?queries=", 
       "plaintext_url": "/plaintext",
       "plaintext_url": "/plaintext",
       "port": 8080,
       "port": 8080,
-      "approach": "Realistic",
+      "approach": "Stripped",
       "classification": "Platform",
       "classification": "Platform",
-      "database": "None",
+      "database": "MySQL",
       "framework": "rack",
       "framework": "rack",
       "language": "Ruby",
       "language": "Ruby",
-      "orm": "Full",
+      "orm": "Raw",
       "platform": "JRuby",
       "platform": "JRuby",
       "webserver": "TorqBox",
       "webserver": "TorqBox",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "rack",
       "display_name": "rack",
-      "notes": "",
-      "versus": ""
+      "notes": ""
+    },
+    "trinidad": {
+      "setup_file": "run_trinidad",
+      "json_url": "/json",
+      "db_url": "/db", 
+      "query_url": "/queries?queries=", 
+      "update_url": "/updates?queries=", 
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "rack",
+      "language": "Ruby",
+      "orm": "Raw",
+      "platform": "JRuby",
+      "webserver": "Trinidad",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "rack",
+      "notes": ""
+    },
+    "unicorn": {
+      "setup_file": "run_unicorn",
+      "json_url": "/json",
+      "db_url": "/db", 
+      "query_url": "/queries?queries=", 
+      "update_url": "/updates?queries=", 
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Stripped",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "rack",
+      "language": "Ruby",
+      "orm": "Raw",
+      "platform": "Rack",
+      "webserver": "Unicorn",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "rack",
+      "notes": ""
     }
     }
   }]
   }]
 }
 }

+ 12 - 17
frameworks/Ruby/rack/config.ru

@@ -1,19 +1,14 @@
-require 'json'
+Bundler.require :default
+require 'erb'
 
 
-app = lambda do |env| 
-  if env['PATH_INFO'] == "/plaintext"
-    [
-      200,
-      { 'Content-Type' => 'text/plain' },
-      ["Hello, World!"]
-    ]
-  else
-    [
-      200,
-      { 'Content-Type' => 'application/json' },
-      [{:message => "Hello, World!"}.to_json]
-    ]
-  end
-end 
-run app 
+$: << "."
 
 
+DB_CONFIG = YAML.load(ERB.new(File.read("config/database.yml")).result)
+
+if RUBY_PLATFORM == 'java'
+ require 'app/jruby_impl'
+ run App::JRuby
+else
+ require 'app/ruby_impl'
+ run App::Ruby
+end

+ 8 - 0
frameworks/Ruby/rack/config/database.yml

@@ -0,0 +1,8 @@
+---
+  :encoding: utf8
+  :host: localhost
+  :database: hello_world
+  :username: benchmarkdbuser
+  :password: benchmarkdbpass
+  :pool: 256
+  :timeout: 5000

+ 10 - 0
frameworks/Ruby/rack/config/thin.yml

@@ -0,0 +1,10 @@
+--- 
+timeout: 30
+wait: 30
+max_conns: 1024
+max_persistent_conns: 512
+environment: production
+port: 8080
+servers: 8
+log: /tmp/thin.log
+quiet: true

+ 9 - 0
frameworks/Ruby/rack/config/trinidad.yml

@@ -0,0 +1,9 @@
+---
+  port: 8080
+  threadsafe: true
+  environment: production
+  http:
+    address: '*'
+  logging:
+    level: SEVERE
+  java_lib: lib

+ 33 - 0
frameworks/Ruby/rack/helper.py

@@ -0,0 +1,33 @@
+import os
+import subprocess
+from collections import namedtuple
+
+import setup_util
+
+Command = namedtuple('Command', ['command', 'wait_for_exit'])
+
+def set_database_host(args):
+  database_host = args.database_host or 'localhost'
+  database_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config/database.yml')
+  setup_util.replace_text(database_file, "  host:.*", "  host: " + database_host)
+
+def run(commands, logfile, errfile):
+  cwd = os.path.basename(os.path.normpath(os.path.dirname(os.path.realpath(__file__))))
+  try:
+    for command in commands:      
+      if command.wait_for_exit:
+        subprocess.check_call(command.command, shell=True, cwd=cwd, stderr=errfile, stdout=logfile)
+      else:
+        subprocess.Popen(command.command, shell=True, cwd=cwd, stderr=errfile, stdout=logfile)
+  except subprocess.CalledProcessError:
+    return 1
+  return 0
+
+def stop(partial_command, logfile, errfile):
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if partial_command in line and 'run-tests' not in line:
+      pid = int(line.split(None, 2)[1])
+      os.kill(pid, 15)
+  return 0

+ 1 - 1
frameworks/Ruby/rack/install.sh

@@ -6,4 +6,4 @@ rvm install ruby-2.0.0-p0
 rvm ruby-2.0.0-p0 do bundle install --gemfile=$TROOT/Gemfile-ruby
 rvm ruby-2.0.0-p0 do bundle install --gemfile=$TROOT/Gemfile-ruby
 
 
 rvm install jruby-1.7.8
 rvm install jruby-1.7.8
-rvm jruby-1.7.8 do bundle install --gemfile=$TROOT/Gemfile-jruby
+rvm jruby-1.7.8 do bundle install --gemfile=$TROOT/Gemfile-jruby

BIN
frameworks/Ruby/rack/lib/mysql-connector-java-5.1.28-bin.jar


+ 14 - 0
frameworks/Ruby/rack/run_jruby_puma.py

@@ -0,0 +1,14 @@
+import helper
+from helper import Command
+
+def start(args, logfile, errfile):
+  helper.set_database_host(args)
+  commands = [
+    Command("rvm jruby-1.7.8 do bundle", True),
+    Command("rvm jruby-1.7.8 do bundle exec puma -b tcp://0.0.0.0:8080 -e production", False)
+  ]
+
+  return helper.run(commands, logfile, errfile)
+
+def stop(logfile, errfile):
+  return helper.stop('puma', logfile, errfile)

+ 14 - 0
frameworks/Ruby/rack/run_mri_puma.py

@@ -0,0 +1,14 @@
+import helper
+from helper import Command
+
+def start(args, logfile, errfile):
+  helper.set_database_host(args)
+  commands = [
+    Command("rvm ruby-2.0.0-p0 do bundle", True),
+    Command("rvm ruby-2.0.0-p0 do bundle exec puma -t 8:32 -w 8 --preload -b tcp://0.0.0.0:8080 -e production", False)
+  ]
+
+  return helper.run(commands, logfile, errfile)
+
+def stop(logfile, errfile):
+  return helper.stop('puma', logfile, errfile)

+ 15 - 0
frameworks/Ruby/rack/run_thin.py

@@ -0,0 +1,15 @@
+import helper
+from helper import Command
+
+def start(args, logfile, errfile):
+  helper.set_database_host(args)
+  commands = [
+    Command("rvm ruby-2.0.0-p0 do bundle", True),
+    Command("rvm ruby-2.0.0-p0 do bundle exec thin start -C config/thin.yml", False)
+  ]
+
+  return helper.run(commands, logfile, errfile)
+
+def stop(logfile, errfile):
+  helper.run([Command('rm -rf tmp/*', True)], logfile, errfile)  
+  return helper.stop('thin', logfile, errfile)

+ 14 - 0
frameworks/Ruby/rack/run_torqbox.py

@@ -0,0 +1,14 @@
+import helper
+from helper import Command
+
+def start(args, logfile, errfile):
+  helper.set_database_host(args)
+  commands = [
+    Command("rvm jruby-1.7.8 do bundle", True),
+    Command("rvm jruby-1.7.8 do bundle exec torqbox -b 0.0.0.0 -E production", False)
+  ]
+
+  return helper.run(commands, logfile, errfile)
+
+def stop(logfile, errfile):
+  return helper.stop('torqbox', logfile, errfile)

+ 14 - 0
frameworks/Ruby/rack/run_trinidad.py

@@ -0,0 +1,14 @@
+import helper
+from helper import Command
+
+def start(args, logfile, errfile):
+  helper.set_database_host(args)
+  commands = [
+    Command("rvm jruby-1.7.8 do bundle", True),
+    Command("rvm jruby-1.7.8 do bundle exec trinidad --config config/trinidad.yml", False)
+  ]
+
+  return helper.run(commands, logfile, errfile)
+
+def stop(logfile, errfile):
+  return helper.stop('trinidad', logfile, errfile)

+ 19 - 0
frameworks/Ruby/rack/run_unicorn.py

@@ -0,0 +1,19 @@
+import helper
+from helper import Command
+
+from os.path import expanduser
+home = expanduser("~")
+
+def start(args, logfile, errfile):
+  helper.set_database_host(args)
+  commands = [
+    Command("rvm ruby-2.0.0-p0 do bundle", True),
+    Command("sudo /usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/frameworks/Ruby/rack/config/nginx.conf", True),
+    Command("rvm ruby-2.0.0-p0 do bundle exec unicorn -E production -c config/unicorn.rb", False)
+  ]
+
+  return helper.run(commands, logfile, errfile)
+
+def stop(logfile, errfile):
+  helper.run([Command("sudo /usr/local/nginx/sbin/nginx -s stop", True)], logfile, errfile)
+  return helper.stop('unicorn', logfile, errfile)

+ 0 - 28
frameworks/Ruby/rack/setup_jruby.py

@@ -1,28 +0,0 @@
-
-import subprocess
-import sys
-import re
-import os
-
-def start(args, logfile, errfile):
-
-  try:
-    subprocess.check_call("cp Gemfile-jruby Gemfile", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    subprocess.check_call("cp Gemfile-jruby.lock Gemfile.lock", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    subprocess.Popen("rvm jruby-1.7.8 do bundle exec torqbox -b 0.0.0.0 -E production", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    return 0
-  except subprocess.CalledProcessError:
-    return 1
-def stop(logfile, errfile):
-  try:
-    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
-    out, err = p.communicate()
-    for line in out.splitlines():
-      if 'torqbox' in line:
-        pid = int(line.split(None, 2)[1])
-        os.kill(pid, 15)
-    subprocess.check_call("rm -f Gemfile", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    subprocess.check_call("rm -f Gemfile.lock", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    return 0
-  except subprocess.CalledProcessError:
-    return 1

+ 0 - 30
frameworks/Ruby/rack/setup_ruby.py

@@ -1,30 +0,0 @@
-
-import subprocess
-import sys
-import re
-import os
-
-def start(args, logfile, errfile):
-
-  try:
-    subprocess.check_call("cp Gemfile-ruby Gemfile", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    subprocess.check_call("cp Gemfile-ruby.lock Gemfile.lock", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c $TROOT/config/nginx.conf", shell=True, stderr=errfile, stdout=logfile)
-    subprocess.Popen("rvm ruby-2.0.0-p0 do bundle exec unicorn -E production -c $TROOT/config/unicorn.rb", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    return 0
-  except subprocess.CalledProcessError:
-    return 1
-def stop(logfile, errfile):
-  subprocess.call("sudo /usr/local/nginx/sbin/nginx -c $TROOT/config/nginx.conf -s stop", shell=True, stderr=errfile, stdout=logfile)
-  try:
-    p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
-    out, err = p.communicate()
-    for line in out.splitlines():
-      if 'unicorn' in line and 'master' in line:
-        pid = int(line.split(None, 2)[1])
-        os.kill(pid, 15)
-    subprocess.check_call("rm -f Gemfile", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    subprocess.check_call("rm -f Gemfile.lock", shell=True, cwd="rack", stderr=errfile, stdout=logfile)
-    return 0
-  except subprocess.CalledProcessError:
-    return 1

+ 3 - 3
frameworks/Ruby/rack/source_code

@@ -1,3 +1,3 @@
-./rack/config/unicorn.rb
-./rack/setup_jruby.py
-./rack/setup_ruby.py
+./app/jruby_impl.rb
+./app/ruby_impl.rb
+./config.ru