Browse Source

resolve .travis.yml conflict

Gelin Luo 8 years ago
parent
commit
ae2d204f9c
100 changed files with 1271 additions and 507 deletions
  1. 180 1
      .travis.yml
  2. 76 0
      frameworks/Python/aiohttp/README.md
  3. 0 0
      frameworks/Python/aiohttp/app/__init__.py
  4. 6 0
      frameworks/Python/aiohttp/app/gunicorn.py
  5. 80 0
      frameworks/Python/aiohttp/app/main.py
  6. 20 0
      frameworks/Python/aiohttp/app/models.py
  7. 20 0
      frameworks/Python/aiohttp/app/templates/fortune.jinja
  8. 179 0
      frameworks/Python/aiohttp/app/views.py
  9. 50 0
      frameworks/Python/aiohttp/benchmark_config.json
  10. 14 0
      frameworks/Python/aiohttp/gunicorn_conf.py
  11. 10 0
      frameworks/Python/aiohttp/requirements.txt
  12. 7 0
      frameworks/Python/aiohttp/setup.sh
  13. 0 0
      frameworks/Python/api_hour/.gitignore
  14. 2 2
      frameworks/Python/api_hour/README.md
  15. 0 0
      frameworks/Python/api_hour/aiohttp.web/.gitignore
  16. 0 0
      frameworks/Python/api_hour/aiohttp.web/LICENSE
  17. 0 0
      frameworks/Python/api_hour/aiohttp.web/README.rst
  18. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/default/hello
  19. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/gunicorn_conf.py
  20. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/logging.ini
  21. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/hello/main/main.yaml
  22. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/init.d/hello
  23. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/logrotate.d/hello
  24. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/monit/conf.d/hello
  25. 0 0
      frameworks/Python/api_hour/aiohttp.web/etc/rsyslog.conf
  26. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/__init__.py
  27. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/endpoints/__init__.py
  28. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/endpoints/world.py
  29. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/services/__init__.py
  30. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/services/mysql.py
  31. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/services/redis.py
  32. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/services/world.py
  33. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/templates/fortunes.html.j2
  34. 0 0
      frameworks/Python/api_hour/aiohttp.web/hello/utils/__init__.py
  35. 0 0
      frameworks/Python/api_hour/aiohttp.web/setup-mysql.sh
  36. 0 0
      frameworks/Python/api_hour/aiohttp.web/setup-postgresql.sh
  37. 0 0
      frameworks/Python/api_hour/aiohttp.web/setup.sh
  38. 0 0
      frameworks/Python/api_hour/aiohttp.web/source_code
  39. 6 11
      frameworks/Python/api_hour/benchmark_config.json
  40. 1 2
      frameworks/Python/api_hour/requirements.txt
  41. 0 0
      frameworks/Python/api_hour/yocto_http/.gitignore
  42. 0 0
      frameworks/Python/api_hour/yocto_http/LICENSE
  43. 0 0
      frameworks/Python/api_hour/yocto_http/README.rst
  44. 0 0
      frameworks/Python/api_hour/yocto_http/etc/default/hello
  45. 0 0
      frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/gunicorn_conf.py
  46. 0 0
      frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/logging.ini
  47. 0 0
      frameworks/Python/api_hour/yocto_http/etc/hello/main/main.yaml
  48. 0 0
      frameworks/Python/api_hour/yocto_http/etc/init.d/hello
  49. 0 0
      frameworks/Python/api_hour/yocto_http/etc/logrotate.d/hello
  50. 0 0
      frameworks/Python/api_hour/yocto_http/etc/monit/conf.d/hello
  51. 0 0
      frameworks/Python/api_hour/yocto_http/etc/rsyslog.conf
  52. 0 0
      frameworks/Python/api_hour/yocto_http/hello/__init__.py
  53. 0 0
      frameworks/Python/api_hour/yocto_http/hello/endpoints/__init__.py
  54. 0 0
      frameworks/Python/api_hour/yocto_http/hello/endpoints/world.py
  55. 0 0
      frameworks/Python/api_hour/yocto_http/hello/servers/__init__.py
  56. 0 0
      frameworks/Python/api_hour/yocto_http/hello/servers/yocto_http.py
  57. 0 0
      frameworks/Python/api_hour/yocto_http/hello/services/__init__.py
  58. 0 0
      frameworks/Python/api_hour/yocto_http/hello/services/redis.py
  59. 0 0
      frameworks/Python/api_hour/yocto_http/hello/services/world.py
  60. 0 0
      frameworks/Python/api_hour/yocto_http/hello/templates/fortunes.html.j2
  61. 0 0
      frameworks/Python/api_hour/yocto_http/hello/utils/__init__.py
  62. 0 0
      frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/__init__.py
  63. 0 0
      frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/application.py
  64. 0 0
      frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/request.py
  65. 0 0
      frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/utils.py
  66. 0 0
      frameworks/Python/api_hour/yocto_http/setup.sh
  67. 0 0
      frameworks/Python/api_hour/yocto_http/source_code
  68. 1 1
      frameworks/Python/wsgi/setup.sh
  69. 3 2
      frameworks/Ruby/sinatra/.gitignore
  70. 18 20
      frameworks/Ruby/sinatra/Gemfile
  71. 0 88
      frameworks/Ruby/sinatra/Gemfile.lock
  72. 2 0
      frameworks/Ruby/sinatra/Makefile
  73. 23 17
      frameworks/Ruby/sinatra/README.md
  74. 142 71
      frameworks/Ruby/sinatra/benchmark_config.json
  75. 8 0
      frameworks/Ruby/sinatra/benchmark_config.rb
  76. 86 0
      frameworks/Ruby/sinatra/benchmark_config.yaml
  77. 64 0
      frameworks/Ruby/sinatra/boot.rb
  78. 3 2
      frameworks/Ruby/sinatra/config.ru
  79. 41 0
      frameworks/Ruby/sinatra/config/auto_tune.rb
  80. 6 0
      frameworks/Ruby/sinatra/config/bundle_install.sh
  81. 13 0
      frameworks/Ruby/sinatra/config/common_run.sh
  82. 24 0
      frameworks/Ruby/sinatra/config/java_tune.sh
  83. 7 0
      frameworks/Ruby/sinatra/config/mri_puma.rb
  84. 6 0
      frameworks/Ruby/sinatra/config/mri_unicorn.rb
  85. 0 158
      frameworks/Ruby/sinatra/config/nginx.conf
  86. 0 3
      frameworks/Ruby/sinatra/config/puma.rb
  87. 0 10
      frameworks/Ruby/sinatra/config/thin.yml
  88. 0 8
      frameworks/Ruby/sinatra/config/trinidad.yml
  89. 0 7
      frameworks/Ruby/sinatra/config/unicorn.rb
  90. 94 81
      frameworks/Ruby/sinatra/hello_world.rb
  91. 0 1
      frameworks/Ruby/sinatra/public/500.html
  92. 13 0
      frameworks/Ruby/sinatra/run_jruby_puma.sh
  93. 13 0
      frameworks/Ruby/sinatra/run_jruby_torquebox.sh
  94. 20 0
      frameworks/Ruby/sinatra/run_mri_passenger.sh
  95. 7 3
      frameworks/Ruby/sinatra/run_mri_puma.sh
  96. 11 0
      frameworks/Ruby/sinatra/run_mri_unicorn.sh
  97. 0 7
      frameworks/Ruby/sinatra/run_thin.sh
  98. 0 11
      frameworks/Ruby/sinatra/run_unicorn.sh
  99. 3 1
      frameworks/Ruby/sinatra/source_code
  100. 12 0
      frameworks/Ruby/sinatra/views/fortunes.erb

+ 180 - 1
.travis.yml

@@ -10,8 +10,187 @@ python:
 
 
 env:
 env:
   matrix:
   matrix:
+    - "TESTDIR=C/libreactor"
+    - "TESTDIR=C/lwan"
+    - "TESTDIR=C/duda"
+    - "TESTDIR=C/haywire"
+    - "TESTDIR=C/onion"
+    - "TESTDIR=C/h2o"
+    - "TESTDIR=C/octane"
+    - "TESTDIR=CSharp/aspnet"
+    - "TESTDIR=CSharp/aspnetcore"
+    ## - "TESTDIR=CSharp/aspnet-stripped"
+    - "TESTDIR=CSharp/evhttp-sharp"
+    ## - "TESTDIR=CSharp/HttpListener"
+    - "TESTDIR=CSharp/nancy"
+    - "TESTDIR=CSharp/revenj"
+    - "TESTDIR=CSharp/servicestack"
+    - "TESTDIR=C++/cpoll_cppsp"
+    - "TESTDIR=C++/cutelyst"
+    - "TESTDIR=C++/silicon"
+    - "TESTDIR=C++/treefrog"
+    - "TESTDIR=C++/ulib"
+    - "TESTDIR=C++/wt"
+    - "TESTDIR=C++/ffead-cpp"
+    - "TESTDIR=C++/poco"
+    - "TESTDIR=Clojure/compojure"
+    - "TESTDIR=Clojure/http-kit"
+    - "TESTDIR=Clojure/luminus"
+    - "TESTDIR=Clojure/pedestal"
+    - "TESTDIR=Clojure/aleph"
+    - "TESTDIR=Crystal/crystal"
+    - "TESTDIR=Crystal/kemal"
+    - "TESTDIR=D/vibed"
+    - "TESTDIR=Dart/dart-raw"
+    - "TESTDIR=Dart/redstone"
+    - "TESTDIR=Dart/start"
+    - "TESTDIR=Dart/stream"
+    - "TESTDIR=Elixir/phoenix"
+    - "TESTDIR=Elixir/cowboy"
+    - "TESTDIR=Erlang/chicagoboss"
+    - "TESTDIR=Erlang/cowboy"
+    - "TESTDIR=Erlang/elli"
+    - "TESTDIR=Erlang/mochiweb"
+    - "TESTDIR=Go/beego"
+    - "TESTDIR=Go/echo"
+    - "TESTDIR=Go/falcore"
+    - "TESTDIR=Go/fasthttp"
+    - "TESTDIR=Go/gin"
+    - "TESTDIR=Go/goji"
+    - "TESTDIR=Go/go-std"
+    - "TESTDIR=Go/revel"
+    - "TESTDIR=Go/webgo"
+    - "TESTDIR=Groovy/grails"
+    - "TESTDIR=Groovy/hot"
+    - "TESTDIR=Haskell/snap"
+    - "TESTDIR=Haskell/wai"
+    - "TESTDIR=Haskell/yesod"
+    - "TESTDIR=Haskell/servant"
+    - "TESTDIR=Haskell/spock"
     - "TESTDIR=Java/act"
     - "TESTDIR=Java/act"
-
+    - "TESTDIR=Java/activeweb"
+    - "TESTDIR=Java/baratine"
+    - "TESTDIR=Java/bayou"
+    - "TESTDIR=Java/comsat-servlet"
+    - "TESTDIR=Java/comsat-webactors"
+    - "TESTDIR=Java/curacao"
+    - "TESTDIR=Java/dropwizard"
+    - "TESTDIR=Java/gemini"
+    - "TESTDIR=Java/grizzly-bm"
+    - "TESTDIR=Java/grizzly-jersey"
+    - "TESTDIR=Java/jawn"
+    - "TESTDIR=Java/jetty-servlet"
+    - "TESTDIR=Java/jetty"
+    - "TESTDIR=Java/jlhttp"
+    - "TESTDIR=Java/jooby"
+    - "TESTDIR=Java/netty"
+    - "TESTDIR=Java/ninja-standalone"
+    - "TESTDIR=Java/officefloor"
+    - "TESTDIR=Java/permeagility"
+    - "TESTDIR=Java/play1"
+    - "TESTDIR=Java/play2-java"
+    - "TESTDIR=Java/rapidoid"
+    - "TESTDIR=Java/restexpress"
+    - "TESTDIR=Java/revenj-jvm"
+    - "TESTDIR=Java/servlet"
+    - "TESTDIR=Java/spark"
+    - "TESTDIR=Java/spring"
+    - "TESTDIR=Java/tapestry"
+    - "TESTDIR=Java/undertow"
+    - "TESTDIR=Java/undertow-jersey-c3p0"
+    - "TESTDIR=Java/undertow-jersey-hikaricp"
+    - "TESTDIR=Java/vertx"
+    - "TESTDIR=Java/vertx-web"
+    - "TESTDIR=Java/wicket"
+    - "TESTDIR=Java/beyondj"
+    - "TESTDIR=Java/wildfly-ee7"
+    - "TESTDIR=JavaScript/express"
+    - "TESTDIR=JavaScript/hapi"
+    - "TESTDIR=JavaScript/koa"
+    - "TESTDIR=JavaScript/nodejs"
+    - "TESTDIR=JavaScript/ringojs"
+    - "TESTDIR=JavaScript/ringojs-convenient"
+    - "TESTDIR=JavaScript/sailsjs"
+    - "TESTDIR=Kotlin/hexagon"
+    - "TESTDIR=Lua/lapis"
+    - "TESTDIR=Lua/octopus"
+    - "TESTDIR=Lua/openresty"
+    - "TESTDIR=Nim/jester"
+    - "TESTDIR=Perl/dancer"
+    - "TESTDIR=Perl/kelp"
+    - "TESTDIR=Perl/mojolicious"
+    - "TESTDIR=Perl/plack"
+    - "TESTDIR=Perl/web-simple"
+    - "TESTDIR=PHP/cakephp"
+    - "TESTDIR=PHP/hhvm"
+    - "TESTDIR=PHP/php"
+    - "TESTDIR=PHP/cygnite"
+    - "TESTDIR=PHP/codeigniter"
+    - "TESTDIR=PHP/clancats"
+    - "TESTDIR=PHP/fat-free"
+    - "TESTDIR=PHP/fuel"
+    - "TESTDIR=PHP/kohana"
+    - "TESTDIR=PHP/laravel"
+    - "TESTDIR=PHP/limonade"
+    - "TESTDIR=PHP/lithium"
+    - "TESTDIR=PHP/lumen"
+    - "TESTDIR=PHP/phalcon"
+    - "TESTDIR=PHP/phalcon-micro"
+    - "TESTDIR=PHP/phpixie"
+    - "TESTDIR=PHP/silex"
+    - "TESTDIR=PHP/silex-orm"
+    - "TESTDIR=PHP/slim"
+    - "TESTDIR=PHP/symfony2"
+    - "TESTDIR=PHP/symfony2-stripped"
+    - "TESTDIR=PHP/yaf"
+    - "TESTDIR=PHP/yii2"
+    - "TESTDIR=PHP/zend"
+    - "TESTDIR=PHP/zend1"
+    - "TESTDIR=PHP/phreeze"
+    - "TESTDIR=Python/aiohttp"
+    - "TESTDIR=Python/api_hour"
+    - "TESTDIR=Python/bottle"
+    - "TESTDIR=Python/cherrypy"
+    - "TESTDIR=Python/django"
+    - "TESTDIR=Python/falcon"
+    - "TESTDIR=Python/flask"
+    - "TESTDIR=Python/historical"
+    - "TESTDIR=Python/klein"
+    - "TESTDIR=Python/pyramid"
+    - "TESTDIR=Python/tornado"
+    - "TESTDIR=Python/turbogears"
+    - "TESTDIR=Python/uwsgi"
+    - "TESTDIR=Python/web2py"
+    - "TESTDIR=Python/weppy"
+    - "TESTDIR=Python/wheezyweb"
+    - "TESTDIR=Python/wsgi"
+    - "TESTDIR=Ruby/grape"
+    - "TESTDIR=Ruby/ngx_mruby"
+    - "TESTDIR=Ruby/padrino"
+    - "TESTDIR=Ruby/rack"
+    - "TESTDIR=Ruby/rack-sequel"
+    - "TESTDIR=Ruby/rails"
+    - "TESTDIR=Ruby/rails-stripped"
+    - "TESTDIR=Ruby/roda-sequel"
+    - "TESTDIR=Ruby/sinatra"
+    - "TESTDIR=Ruby/sinatra-sequel"
+    - "TESTDIR=Rust/iron"
+    - "TESTDIR=Rust/nickel"
+    - "TESTDIR=Rust/hyper"
+    - "TESTDIR=Rust/tokio-minihttp"
+    - "TESTDIR=Scala/akka-http"
+    - "TESTDIR=Scala/blaze"
+    - "TESTDIR=Scala/colossus"
+    - "TESTDIR=Scala/finagle"
+    - "TESTDIR=Scala/finatra"
+    - "TESTDIR=Scala/fintrospect"
+    - "TESTDIR=Scala/play2-scala"
+    - "TESTDIR=Scala/scruffy"
+    - "TESTDIR=Scala/spray"
+    - "TESTDIR=Scala/s-server"
+    - "TESTDIR=Scala/http4s"
+    - "TESTDIR=Scala/finch"
+    - "TESTDIR=Ur/urweb"
 
 
 before_script:
 before_script:
 
 

+ 76 - 0
frameworks/Python/aiohttp/README.md

@@ -0,0 +1,76 @@
+# [aiohttp](http://aiohttp.readthedocs.io/) Benchmark Test
+
+The information below is specific to aiohttp. For further guidance, 
+review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
+Also note that there is additional information that's provided in 
+the [Python README](../).
+
+This is the Python aiohttp portion of a [benchmarking tests suite](../../) 
+comparing a variety of frameworks.
+
+All test implementations are located within ([./app](app)).
+
+## Description
+
+aiohttp with [aiopg + sqlalchemy](http://aiopg.readthedocs.io/en/stable/sa.html) and 
+separately [asyncpg](https://magicstack.github.io/asyncpg/current/) for database access.
+ 
+[uvloop](https://github.com/MagicStack/uvloop) is used for a more performant event loop.
+
+### Database
+
+PostgreSQL
+
+### Server
+
+gunicorn+uvloop on CPython
+
+## Test URLs
+
+### Test 1: JSON Encoding 
+
+    http://localhost:8080/json
+
+### Test 2: Single Row Query
+
+With ORM:
+
+    http://localhost:8080/db
+
+Without ORM (raw):
+
+    http://localhost:8080/raw/db
+
+### Test 3: Multi Row Query 
+
+With ORM:
+
+    http://localhost:8080/queries?queries=20
+
+Without ORM (raw):
+
+    http://localhost:8080/raw/queries?queries=20
+
+### Test 4: Fortunes (Template rendering)
+
+With ORM:
+
+    http://localhost:8080/fortunes
+
+Without ORM (raw):
+
+    http://localhost:8080/raw/fortunes
+
+### Test 5: Update Query
+
+With ORM:
+
+    http://localhost:8080/updates?queries=20
+
+Without ORM (raw):
+
+    http://localhost:8080/raw/updates?queries=20
+
+### Test6: Plaintext
+
+    http://localhost:8080/plaintext

+ 0 - 0
frameworks/Ruby/sinatra/public/.gitkeep → frameworks/Python/aiohttp/app/__init__.py


+ 6 - 0
frameworks/Python/aiohttp/app/gunicorn.py

@@ -0,0 +1,6 @@
+import asyncio
+
+from .main import create_app
+
+loop = asyncio.get_event_loop()
+app = create_app(loop)

+ 80 - 0
frameworks/Python/aiohttp/app/main.py

@@ -0,0 +1,80 @@
+import os
+from pathlib import Path
+
+import aiohttp_jinja2
+import aiopg.sa
+import asyncpg
+import jinja2
+from aiohttp import web
+from sqlalchemy.engine.url import URL
+
+from .views import (
+    json,
+    single_database_query_orm,
+    multiple_database_queries_orm,
+    fortunes,
+    updates,
+    plaintext,
+
+    single_database_query_raw,
+    multiple_database_queries_raw,
+    fortunes_raw,
+    updates_raw,
+)
+
+THIS_DIR = Path(__file__).parent
+
+
+def pg_dsn() -> str:
+    """
+    :return: DSN url suitable for sqlalchemy and aiopg.
+    """
+    return str(URL(
+        database='hello_world',
+        password=os.getenv('PGPASS', 'benchmarkdbpass'),
+        host=os.getenv('DBHOST', 'localhost'),
+        port='5432',
+        username=os.getenv('PGUSER', 'benchmarkdbuser'),
+        drivername='postgres',
+    ))
+
+
+async def startup(app: web.Application):
+    dsn = pg_dsn()
+    app.update(
+        aiopg_engine=await aiopg.sa.create_engine(dsn=dsn, minsize=10, maxsize=20, loop=app.loop),
+        asyncpg_pool=await asyncpg.create_pool(dsn=dsn, min_size=10, max_size=20, loop=app.loop),
+    )
+
+
+async def cleanup(app: web.Application):
+    app['aiopg_engine'].close()
+    await app['aiopg_engine'].wait_closed()
+    await app['asyncpg_pool'].close()
+
+
+def setup_routes(app):
+    app.router.add_get('/json', json)
+    app.router.add_get('/db', single_database_query_orm)
+    app.router.add_get('/queries', multiple_database_queries_orm)
+    app.router.add_get('/fortunes', fortunes)
+    app.router.add_get('/updates', updates)
+    app.router.add_get('/plaintext', plaintext)
+
+    app.router.add_get('/raw/db', single_database_query_raw)
+    app.router.add_get('/raw/queries', multiple_database_queries_raw)
+    app.router.add_get('/raw/fortunes', fortunes_raw)
+    app.router.add_get('/raw/updates', updates_raw)
+
+
+def create_app(loop):
+    app = web.Application(loop=loop)
+
+    jinja2_loader = jinja2.FileSystemLoader(str(THIS_DIR / 'templates'))
+    aiohttp_jinja2.setup(app, loader=jinja2_loader)
+
+    app.on_startup.append(startup)
+    app.on_cleanup.append(cleanup)
+
+    setup_routes(app)
+    return app

+ 20 - 0
frameworks/Python/aiohttp/app/models.py

@@ -0,0 +1,20 @@
+from sqlalchemy import Column, Integer, String
+from sqlalchemy.ext.declarative import declarative_base
+
+Base = declarative_base()
+
+
+class World(Base):
+    __tablename__ = 'world'
+    id = Column(Integer, primary_key=True)
+    randomnumber = Column(Integer)
+
+sa_worlds = World.__table__
+
+
+class Fortune(Base):
+    __tablename__ = 'fortune'
+    id = Column(Integer, primary_key=True)
+    message = Column(String)
+
+sa_fortunes = Fortune.__table__

+ 20 - 0
frameworks/Python/aiohttp/app/templates/fortune.jinja

@@ -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|escape }}</td>
+</tr>
+{% endfor %}
+</table>
+</body>
+</html>

+ 179 - 0
frameworks/Python/aiohttp/app/views.py

@@ -0,0 +1,179 @@
+from operator import attrgetter, itemgetter
+from random import randint
+
+from aiohttp_jinja2 import template
+from aiohttp.web import Response
+import ujson
+
+from sqlalchemy import select
+
+from .models import sa_fortunes, sa_worlds, Fortune
+
+
+def json_response(data):
+    body = ujson.dumps(data)
+    return Response(body=body.encode(), content_type='application/json')
+
+
+def get_num_queries(request):
+    try:
+        num_queries = int(request.GET.get('queries', 1))
+    except ValueError:
+        return 1
+    if num_queries < 1:
+        return 1
+    if num_queries > 500:
+        return 500
+    return num_queries
+
+
+async def json(request):
+    """
+    Test 1
+    """
+    return json_response({'message': 'Hello, World!'})
+
+
+async def single_database_query_orm(request):
+    """
+    Test 2 ORM
+    """
+    id_ = randint(1, 10000)
+    async with request.app['aiopg_engine'].acquire() as conn:
+        cur = await conn.execute(select([sa_worlds.c.randomnumber]).where(sa_worlds.c.id == id_))
+        r = await cur.first()
+    return json_response({'id': id_, 'randomNumber': r[0]})
+
+
+async def single_database_query_raw(request):
+    """
+    Test 2 RAW
+    """
+    id_ = randint(1, 10000)
+
+    async with request.app['asyncpg_pool'].acquire() as conn:
+        r = await conn.fetchval('SELECT randomnumber FROM world WHERE id = $1', id_)
+    return json_response({'id': id_, 'randomNumber': r})
+
+
+async def multiple_database_queries_orm(request):
+    """
+    Test 3 ORM
+    """
+    num_queries = get_num_queries(request)
+
+    ids = [randint(1, 10000) for _ in range(num_queries)]
+    ids.sort()
+
+    result = []
+    async with request.app['aiopg_engine'].acquire() as conn:
+        for id_ in ids:
+            cur = await conn.execute(select([sa_worlds.c.randomnumber]).where(sa_worlds.c.id == id_))
+            r = await cur.first()
+            result.append({'id': id_, 'randomNumber': r[0]})
+    return json_response(result)
+
+
+async def multiple_database_queries_raw(request):
+    """
+    Test 3 RAW
+    """
+    num_queries = get_num_queries(request)
+
+    ids = [randint(1, 10000) for _ in range(num_queries)]
+    ids.sort()
+
+    result = []
+    async with request.app['asyncpg_pool'].acquire() as conn:
+        stmt = await conn.prepare('SELECT randomnumber FROM world WHERE id = $1')
+        for id_ in ids:
+            result.append({
+                'id': id_,
+                'randomNumber': await stmt.fetchval(id_),
+            })
+    return json_response(result)
+
+
+@template('fortune.jinja')
+async def fortunes(request):
+    """
+    Test 4 ORM
+    """
+    async with request.app['aiopg_engine'].acquire() as conn:
+        cur = await conn.execute(select([sa_fortunes.c.id, sa_fortunes.c.message]))
+        fortunes = list(await cur.fetchall())
+    fortunes.append(Fortune(id=0, message='Additional fortune added at request time.'))
+    fortunes.sort(key=attrgetter('message'))
+    return {'fortunes': fortunes}
+
+
+@template('fortune.jinja')
+async def fortunes_raw(request):
+    """
+    Test 4 RAW
+    """
+    async with request.app['asyncpg_pool'].acquire() as conn:
+        fortunes = await conn.fetch('SELECT * FROM Fortune')
+    fortunes.append(dict(id=0, message='Additional fortune added at request time.'))
+    fortunes.sort(key=itemgetter('message'))
+    return {'fortunes': fortunes}
+
+
+async def updates(request):
+    """
+    Test 5 ORM
+    """
+    num_queries = get_num_queries(request)
+    result = []
+
+    ids = [randint(1, 10000) for _ in range(num_queries)]
+    ids.sort()
+
+    async with request.app['aiopg_engine'].acquire() as conn:
+        for id_ in ids:
+            cur = await conn.execute(
+                select([sa_worlds.c.randomnumber])
+                .where(sa_worlds.c.id == id_)
+            )
+            r = await cur.first()
+            await conn.execute(
+                sa_worlds.update()
+                .where(sa_worlds.c.id == id_)
+                .values(randomnumber=randint(1, 10000))
+            )
+            result.append({'id': id_, 'randomNumber': r.randomnumber})
+
+    return json_response(result)
+
+
+async def updates_raw(request):
+    """
+    Test 5 RAW
+    """
+    num_queries = get_num_queries(request)
+
+    ids = [randint(1, 10000) for _ in range(num_queries)]
+    ids.sort()
+
+    result = []
+    updates = []
+    async with request.app['asyncpg_pool'].acquire() as conn:
+        stmt = await conn.prepare('SELECT randomnumber FROM world WHERE id = $1')
+
+        for id_ in ids:
+            result.append({
+                'id': id_,
+                'randomNumber': await stmt.fetchval(id_)
+            })
+
+            updates.append((randint(1, 10000), id_))
+        await conn.executemany('UPDATE world SET randomnumber=$1 WHERE id=$2', updates)
+
+    return json_response(result)
+
+
+async def plaintext(request):
+    """
+    Test 6
+    """
+    return Response(body=b'Hello, World!', content_type='text/plain')

+ 50 - 0
frameworks/Python/aiohttp/benchmark_config.json

@@ -0,0 +1,50 @@
+{
+  "framework": "aiohttp",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates?queries=",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "Postgres",
+      "framework": "aiohttp",
+      "language": "Python",
+      "flavor": "Python3",
+      "orm": "Full",
+      "platform": "asyncio",
+      "webserver": "gunicorn",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aiohttp",
+      "notes": "uses aiopg with sqlalchemy for database access"
+    },
+    "pg-raw": {
+      "setup_file": "setup",
+      "db_url": "/raw/db",
+      "query_url": "/raw/queries?queries=",
+      "fortune_url": "/raw/fortunes",
+      "update_url": "/raw/updates?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "Postgres",
+      "framework": "aiohttp",
+      "language": "Python",
+      "flavor": "Python3",
+      "orm": "Raw",
+      "platform": "asyncio",
+      "webserver": "gunicorn",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aiohttp-pg-raw",
+      "notes": "uses asyncpg for database access",
+      "versus": "default"
+    }
+  }]
+}

+ 14 - 0
frameworks/Python/aiohttp/gunicorn_conf.py

@@ -0,0 +1,14 @@
+import multiprocessing
+import os
+
+if os.environ.get('TRAVIS') == 'true':
+    workers = 2
+else:
+    workers = multiprocessing.cpu_count()
+
+bind = '0.0.0.0:8080'
+keepalive = 120
+errorlog = '-'
+pidfile = 'gunicorn.pid'
+
+worker_class = 'aiohttp.worker.GunicornUVLoopWebWorker'

+ 10 - 0
frameworks/Python/aiohttp/requirements.txt

@@ -0,0 +1,10 @@
+aiohttp==1.2.0
+aiohttp-jinja2==0.13.0
+aiopg==0.13.0
+asyncpg==0.8.4
+cchardet==1.1.2
+gunicorn==19.6.0
+psycopg2==2.6.2
+SQLAlchemy==1.1.5
+ujson==1.35
+uvloop==0.7.2

+ 7 - 0
frameworks/Python/aiohttp/setup.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+fw_depends postgresql python3
+
+pip3 install --install-option="--prefix=${PY3_ROOT}" -r $TROOT/requirements.txt
+
+gunicorn app.gunicorn:app -c gunicorn_conf.py &

+ 0 - 0
frameworks/Python/asyncio/.gitignore → frameworks/Python/api_hour/.gitignore


+ 2 - 2
frameworks/Python/asyncio/README.md → frameworks/Python/api_hour/README.md

@@ -1,6 +1,6 @@
-# AsyncIO/API-Hour Benchmark Test
+# AsyncIO/aiohttp/API-Hour Benchmark Test
 
 
-This is the AsyncIO/API-Hour portion of a [benchmarking tests suite](../../) 
+This is the AsyncIO/aiohttp/API-Hour portion of a [benchmarking tests suite](../../) 
 comparing a variety of web development platforms.
 comparing a variety of web development platforms.
 
 
 The information below is specific to AsyncIO/API-Hour. For further guidance, 
 The information below is specific to AsyncIO/API-Hour. For further guidance, 

+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/.gitignore → frameworks/Python/api_hour/aiohttp.web/.gitignore


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/LICENSE → frameworks/Python/api_hour/aiohttp.web/LICENSE


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/README.rst → frameworks/Python/api_hour/aiohttp.web/README.rst


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/default/hello → frameworks/Python/api_hour/aiohttp.web/etc/default/hello


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/hello/api_hour/gunicorn_conf.py → frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/gunicorn_conf.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/hello/api_hour/logging.ini → frameworks/Python/api_hour/aiohttp.web/etc/hello/api_hour/logging.ini


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/hello/main/main.yaml → frameworks/Python/api_hour/aiohttp.web/etc/hello/main/main.yaml


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/init.d/hello → frameworks/Python/api_hour/aiohttp.web/etc/init.d/hello


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/logrotate.d/hello → frameworks/Python/api_hour/aiohttp.web/etc/logrotate.d/hello


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/monit/conf.d/hello → frameworks/Python/api_hour/aiohttp.web/etc/monit/conf.d/hello


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/etc/rsyslog.conf → frameworks/Python/api_hour/aiohttp.web/etc/rsyslog.conf


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/__init__.py → frameworks/Python/api_hour/aiohttp.web/hello/__init__.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/endpoints/__init__.py → frameworks/Python/api_hour/aiohttp.web/hello/endpoints/__init__.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/endpoints/world.py → frameworks/Python/api_hour/aiohttp.web/hello/endpoints/world.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/services/__init__.py → frameworks/Python/api_hour/aiohttp.web/hello/services/__init__.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/services/mysql.py → frameworks/Python/api_hour/aiohttp.web/hello/services/mysql.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/services/redis.py → frameworks/Python/api_hour/aiohttp.web/hello/services/redis.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/services/world.py → frameworks/Python/api_hour/aiohttp.web/hello/services/world.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/templates/fortunes.html.j2 → frameworks/Python/api_hour/aiohttp.web/hello/templates/fortunes.html.j2


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/hello/utils/__init__.py → frameworks/Python/api_hour/aiohttp.web/hello/utils/__init__.py


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/setup-mysql.sh → frameworks/Python/api_hour/aiohttp.web/setup-mysql.sh


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/setup-postgresql.sh → frameworks/Python/api_hour/aiohttp.web/setup-postgresql.sh


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/setup.sh → frameworks/Python/api_hour/aiohttp.web/setup.sh


+ 0 - 0
frameworks/Python/asyncio/aiohttp.web/source_code → frameworks/Python/api_hour/aiohttp.web/source_code


+ 6 - 11
frameworks/Python/asyncio/benchmark_config.json → frameworks/Python/api_hour/benchmark_config.json

@@ -1,5 +1,5 @@
 {
 {
-  "framework": "asyncio",
+  "framework": "api_hour",
   "tests": [{
   "tests": [{
     "default": {
     "default": {
       "setup_file": "aiohttp.web/setup-postgresql",
       "setup_file": "aiohttp.web/setup-postgresql",
@@ -22,8 +22,7 @@
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "Asyncio",
       "display_name": "Asyncio",
-      "notes": "Python 3 + API-Hour + AsyncIO + aiohttp.web + PostgreSQL",
-      "versus": "asyncio"
+      "notes": "Python 3 + API-Hour + AsyncIO + aiohttp.web + PostgreSQL"
     },
     },
     "mysql": {
     "mysql": {
       "setup_file": "aiohttp.web/setup-mysql",
       "setup_file": "aiohttp.web/setup-mysql",
@@ -44,8 +43,7 @@
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "Asyncio",
       "display_name": "Asyncio",
-      "notes": "Python 3 + API-Hour + AsyncIO + aiohttp.web + MySQL",
-      "versus": "asyncio"
+      "notes": "Python 3 + API-Hour + AsyncIO + aiohttp.web + MySQL"
     },
     },
     "json": {
     "json": {
       "setup_file": "yocto_http/setup",
       "setup_file": "yocto_http/setup",
@@ -63,8 +61,7 @@
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "Asyncio",
       "display_name": "Asyncio",
-      "notes": "Python 3 + API-Hour + AsyncIO",
-      "versus": "asyncio"
+      "notes": "Python 3 + API-Hour + AsyncIO"
     },
     },
     "dbs": {
     "dbs": {
       "setup_file": "yocto_http/setup",
       "setup_file": "yocto_http/setup",
@@ -84,8 +81,7 @@
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "Asyncio",
       "display_name": "Asyncio",
-      "notes": "Python 3 + API-Hour + AsyncIO",
-      "versus": "asyncio"
+      "notes": "Python 3 + API-Hour + AsyncIO"
     },
     },
     "plaintext": {
     "plaintext": {
       "setup_file": "yocto_http/setup",
       "setup_file": "yocto_http/setup",
@@ -103,8 +99,7 @@
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "Asyncio",
       "display_name": "Asyncio",
-      "notes": "Python 3 + API-Hour + AsyncIO",
-      "versus": "asyncio"
+      "notes": "Python 3 + API-Hour + AsyncIO"
     }
     }
   }]
   }]
 }
 }

+ 1 - 2
frameworks/Python/asyncio/requirements.txt → frameworks/Python/api_hour/requirements.txt

@@ -14,7 +14,6 @@ PyYAML==3.11
 requests==2.7.0
 requests==2.7.0
 requests-futures==0.9.5
 requests-futures==0.9.5
 setproctitle==1.1.8
 setproctitle==1.1.8
-six==1.9.0
 ujson==1.33
 ujson==1.33
 aiomysql==0.0.7
 aiomysql==0.0.7
-PyMySQL==0.6.7
+PyMySQL==0.6.7

+ 0 - 0
frameworks/Python/asyncio/yocto_http/.gitignore → frameworks/Python/api_hour/yocto_http/.gitignore


+ 0 - 0
frameworks/Python/asyncio/yocto_http/LICENSE → frameworks/Python/api_hour/yocto_http/LICENSE


+ 0 - 0
frameworks/Python/asyncio/yocto_http/README.rst → frameworks/Python/api_hour/yocto_http/README.rst


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/default/hello → frameworks/Python/api_hour/yocto_http/etc/default/hello


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/hello/api_hour/gunicorn_conf.py → frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/gunicorn_conf.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/hello/api_hour/logging.ini → frameworks/Python/api_hour/yocto_http/etc/hello/api_hour/logging.ini


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/hello/main/main.yaml → frameworks/Python/api_hour/yocto_http/etc/hello/main/main.yaml


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/init.d/hello → frameworks/Python/api_hour/yocto_http/etc/init.d/hello


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/logrotate.d/hello → frameworks/Python/api_hour/yocto_http/etc/logrotate.d/hello


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/monit/conf.d/hello → frameworks/Python/api_hour/yocto_http/etc/monit/conf.d/hello


+ 0 - 0
frameworks/Python/asyncio/yocto_http/etc/rsyslog.conf → frameworks/Python/api_hour/yocto_http/etc/rsyslog.conf


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/__init__.py → frameworks/Python/api_hour/yocto_http/hello/__init__.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/endpoints/__init__.py → frameworks/Python/api_hour/yocto_http/hello/endpoints/__init__.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/endpoints/world.py → frameworks/Python/api_hour/yocto_http/hello/endpoints/world.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/servers/__init__.py → frameworks/Python/api_hour/yocto_http/hello/servers/__init__.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/servers/yocto_http.py → frameworks/Python/api_hour/yocto_http/hello/servers/yocto_http.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/services/__init__.py → frameworks/Python/api_hour/yocto_http/hello/services/__init__.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/services/redis.py → frameworks/Python/api_hour/yocto_http/hello/services/redis.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/services/world.py → frameworks/Python/api_hour/yocto_http/hello/services/world.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/templates/fortunes.html.j2 → frameworks/Python/api_hour/yocto_http/hello/templates/fortunes.html.j2


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/utils/__init__.py → frameworks/Python/api_hour/yocto_http/hello/utils/__init__.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/utils/yocto_http/__init__.py → frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/__init__.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/utils/yocto_http/application.py → frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/application.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/utils/yocto_http/request.py → frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/request.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/hello/utils/yocto_http/utils.py → frameworks/Python/api_hour/yocto_http/hello/utils/yocto_http/utils.py


+ 0 - 0
frameworks/Python/asyncio/yocto_http/setup.sh → frameworks/Python/api_hour/yocto_http/setup.sh


+ 0 - 0
frameworks/Python/asyncio/yocto_http/source_code → frameworks/Python/api_hour/yocto_http/source_code


+ 1 - 1
frameworks/Python/wsgi/setup.sh

@@ -2,6 +2,6 @@
 
 
 fw_depends python3
 fw_depends python3
 
 
-pip install --install-option="--prefix=${PY3_ROOT}" -r $TROOT/requirements.txt
+pip3 install --install-option="--prefix=${PY3_ROOT}" -r $TROOT/requirements.txt
 
 
 gunicorn hello:app -c gunicorn_conf.py &
 gunicorn hello:app -c gunicorn_conf.py &

+ 3 - 2
frameworks/Ruby/sinatra/.gitignore

@@ -1,3 +1,4 @@
 .bundle
 .bundle
-/vendor/
-/tmp/
+vendor/bundle
+passenger.*
+Gemfile.lock

+ 18 - 20
frameworks/Ruby/sinatra/Gemfile

@@ -1,24 +1,22 @@
-source 'http://rubygems.org'
+source 'https://rubygems.org'
 
 
-platforms :jruby do
-  gem "activerecord-jdbcmysql-adapter", "~> 1.3.9", :require => false
-  gem 'torqbox', '0.1.7'
-  gem "trinidad", '1.4.6'
-end
+gem 'activerecord', '~> 5.0', :require=>'active_record'
+gem 'activerecord-jdbc-adapter', '>= 5.0.pre1', '< 6.0', :platforms=>:jruby
+gem 'json', '~> 2.0'
+gem 'passenger', '~> 5.1', :platforms=>[:ruby, :mswin], :require=>false
+gem 'puma', '~> 3.6', :require=>false
+gem 'sinatra', '>= 2.0.0.beta2', '< 3.0', :require=>'sinatra/base',
+  :git=>'https://github.com/sinatra/sinatra.git', :branch=>'master'
+gem 'sysrandom', '~> 1.0', :require=>'sysrandom/securerandom'
+gem 'torquebox-web', '>= 4.0.0.beta3', '< 5', :platforms=>:jruby, :require=>false
+gem 'unicorn', '~> 5.2', :platforms=>[:ruby, :mswin], :require=>false
 
 
-platforms :ruby do
-  gem 'mysql2', '0.3.16'
-  gem "unicorn", '4.8.3'
-  gem "thin", '1.6.2'
+group :mysql do
+  gem 'jdbc-mysql', '~> 5.1', :platforms=>:jruby, :require=>'jdbc/mysql'
+  gem 'mysql2', '~> 0.4', :platforms=>[:ruby, :mswin]
 end
 end
 
 
-gem "puma", '2.9.0'
-
-gem "activerecord-import", '0.5.0'
-gem 'activerecord', '4.1.4', :require => 'active_record'
-
-gem "sinatra-activerecord", '2.0.2'
-gem 'sinatra', '1.4.5'
-gem 'sinatra-contrib', '1.4.2'
-
-gem 'slim', '2.0.3'
+group :postgresql do
+  gem 'jdbc-postgres', '~> 9.4', :platforms=>:jruby, :require=>'jdbc/postgres'
+  gem 'pg', '~> 0.19', :platforms=>[:ruby, :mswin]
+end

+ 0 - 88
frameworks/Ruby/sinatra/Gemfile.lock

@@ -1,88 +0,0 @@
-GEM
-  remote: http://rubygems.org/
-  specs:
-    activemodel (4.1.4)
-      activesupport (= 4.1.4)
-      builder (~> 3.1)
-    activerecord (4.1.4)
-      activemodel (= 4.1.4)
-      activesupport (= 4.1.4)
-      arel (~> 5.0.0)
-    activerecord-import (0.5.0)
-      activerecord (>= 3.0)
-    activesupport (4.1.4)
-      i18n (~> 0.6, >= 0.6.9)
-      json (~> 1.7, >= 1.7.7)
-      minitest (~> 5.1)
-      thread_safe (~> 0.1)
-      tzinfo (~> 1.1)
-    arel (5.0.1.20140414130214)
-    backports (3.6.8)
-    builder (3.2.2)
-    daemons (1.2.4)
-    eventmachine (1.2.0.1)
-    i18n (0.7.0)
-    json (1.8.3)
-    kgio (2.10.0)
-    minitest (5.9.0)
-    multi_json (1.12.1)
-    mysql2 (0.3.16)
-    puma (2.9.0)
-      rack (>= 1.1, < 2.0)
-    rack (1.6.4)
-    rack-protection (1.5.3)
-      rack
-    rack-test (0.6.3)
-      rack (>= 1.0)
-    raindrops (0.17.0)
-    sinatra (1.4.5)
-      rack (~> 1.4)
-      rack-protection (~> 1.4)
-      tilt (~> 1.3, >= 1.3.4)
-    sinatra-activerecord (2.0.2)
-      activerecord (>= 3.2)
-      sinatra (~> 1.0)
-    sinatra-contrib (1.4.2)
-      backports (>= 2.0)
-      multi_json
-      rack-protection
-      rack-test
-      sinatra (~> 1.4.0)
-      tilt (~> 1.3)
-    slim (2.0.3)
-      temple (~> 0.6.6)
-      tilt (>= 1.3.3, < 2.1)
-    temple (0.6.10)
-    thin (1.6.2)
-      daemons (>= 1.0.9)
-      eventmachine (>= 1.0.0)
-      rack (>= 1.0.0)
-    thread_safe (0.3.5)
-    tilt (1.4.1)
-    tzinfo (1.2.2)
-      thread_safe (~> 0.1)
-    unicorn (4.8.3)
-      kgio (~> 2.6)
-      rack
-      raindrops (~> 0.7)
-
-PLATFORMS
-  ruby
-
-DEPENDENCIES
-  activerecord (= 4.1.4)
-  activerecord-import (= 0.5.0)
-  activerecord-jdbcmysql-adapter (~> 1.3.9)
-  mysql2 (= 0.3.16)
-  puma (= 2.9.0)
-  sinatra (= 1.4.5)
-  sinatra-activerecord (= 2.0.2)
-  sinatra-contrib (= 1.4.2)
-  slim (= 2.0.3)
-  thin (= 1.6.2)
-  torqbox (= 0.1.7)
-  trinidad (= 1.4.6)
-  unicorn (= 4.8.3)
-
-BUNDLED WITH
-   1.13.1

+ 2 - 0
frameworks/Ruby/sinatra/Makefile

@@ -0,0 +1,2 @@
+json: benchmark_config.yaml
+	ruby benchmark_config.rb benchmark_config.yaml >benchmark_config.json

+ 23 - 17
frameworks/Ruby/sinatra/README.md

@@ -1,24 +1,30 @@
-# Ruby [Sinatra](http://www.sinatrarb.com/) Benchmarking Test
+# Ruby [Sinatra](http://www.sinatrarb.com) Benchmarking Test
 
 
-The information below contains information specific to Sinatra. 
-For further guidance, review the 
-[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/). 
-Also note the additional information provided in the [Ruby README](../).
+The information below contains information specific to the Sinatra benchmarking
+test. For further guidance, review the
+[documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/).  Also
+note the additional information provided in the [Ruby README](../).
 
 
-This is the Ruby Sinatra portion of a [benchmarking test suite](../../) 
+This is the Ruby Sinatra portion of a [benchmarking test suite](../../)
 comparing a variety of web platforms.
 comparing a variety of web platforms.
 
 
 ## Infrastructure Software Versions
 ## Infrastructure Software Versions
-The tests were run with:
-* [Ruby 2.0.0-p0](http://www.ruby-lang.org/)
-* [JRuby 1.7.8](http://jruby.org/)
-* [Rubinius 2.2.10](http://rubini.us/)
-* [Sinatra 1.3.4](http://www.sinatrarb.com/)
-* [Unicorn 4.6.2](http://unicorn.bogomips.org/)
-* [TorqBox 0.1.7](http://torquebox.org/torqbox/)
-* [Puma 2.9.0](http://puma.io/)
-* [Thin 1.6.2](http://code.macournoyer.com/thin/)
-* [MySQL 5.5.29](https://dev.mysql.com/)
+
+The tests will be run with:
+
+* [Ruby 2.4](http://www.ruby-lang.org)
+* [JRuby 9.1](http://jruby.org)\*
+* [Rubinius 3](https://rubinius.com)\*
+* [Puma 3.6](http://puma.io)
+* [Passenger 5.1](https://www.phusionpassenger.com)
+* [Unicorn 5.2](https://bogomips.org/unicorn/)
+* [TorqueBox 4.0](http://torquebox.org)\*
+* [Sinatra 2.0](http://www.sinatrarb.com)
+* [ActiveRecord 5.0](https://github.com/rails/rails/tree/master/activerecord)
+* [MySQL 5.5](https://www.mysql.com)
+* [Postgres 9.3](https://www.postgresql.org)
+
+\* - Tests are developed but currently disabled due to compatibility issues.
 
 
 ## Paths & Source for Tests
 ## Paths & Source for Tests
 
 
@@ -39,8 +45,8 @@ _No experts listed, yet. If you're an expert, add yourself!_
 
 
 * [Sinatra Google Group](https://groups.google.com/forum/#!forum/sinatrarb)
 * [Sinatra Google Group](https://groups.google.com/forum/#!forum/sinatrarb)
 * `#sinatra` IRC Channel ([irc.freenode.net](http://freenode.net/))
 * `#sinatra` IRC Channel ([irc.freenode.net](http://freenode.net/))
+* `#sinatrarb` on the [Sinatra and Friends](http://sinatra-slack.herokuapp.com) Slack
 
 
 ### Resources
 ### Resources
 
 
 * [Sinatra Source Code](https://github.com/sinatra/sinatra)
 * [Sinatra Source Code](https://github.com/sinatra/sinatra)
-* [PR: passenger-install-apache2-module doesn't work on ruby 2.0](https://github.com/FooBarWidget/passenger/pull/71)

+ 142 - 71
frameworks/Ruby/sinatra/benchmark_config.json

@@ -1,74 +1,145 @@
 {
 {
   "framework": "sinatra",
   "framework": "sinatra",
-  "tests": [{
-    "default": {
-      "setup_file": "run_mri_puma",
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?queries=", 
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Micro",
-      "database": "MySQL",
-      "framework": "sinatra",
-      "language": "Ruby",
-      "orm": "Full",
-      "platform": "Rack",
-      "webserver": "Puma",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "sinatra-puma-mri",
-      "notes": "",
-      "versus": "rack-puma-mri"
-    },
-    "thin": {
-      "setup_file": "run_thin",
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?queries=", 
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Micro",
-      "database": "MySQL",
-      "framework": "sinatra",
-      "language": "Ruby",
-      "orm": "Full",
-      "platform": "Rack",
-      "webserver": "Thin",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "sinatra-thin",
-      "notes": "",
-      "versus": "rack-thin"
-    },
-    "unicorn": {
-      "setup_file": "run_unicorn",
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/queries?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?queries=", 
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Micro",
-      "database": "MySQL",
-      "framework": "sinatra",
-      "language": "Ruby",
-      "orm": "Full",
-      "platform": "Rack",
-      "webserver": "Unicorn",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "sinatra-unicorn",
-      "notes": "",
-      "versus": "rack-unicorn"
-    }    
-  }]
+  "tests": [
+    {
+      "default": {
+        "setup_file": "run_mri_puma",
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "MySQL",
+        "framework": "sinatra",
+        "language": "Ruby",
+        "orm": "Full",
+        "platform": "Rack",
+        "webserver": "Puma",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "sinatra-puma-mri",
+        "versus": "rack-puma-mri",
+        "notes": ""
+      },
+      "postgres": {
+        "setup_file": "run_mri_puma",
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "sinatra",
+        "language": "Ruby",
+        "orm": "Full",
+        "platform": "Rack",
+        "webserver": "Puma",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "sinatra-postgres-puma-mri",
+        "versus": "rack-postgres-puma-mri",
+        "notes": ""
+      },
+      "passenger-mri": {
+        "setup_file": "run_mri_passenger",
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "MySQL",
+        "framework": "sinatra",
+        "language": "Ruby",
+        "orm": "Full",
+        "platform": "Rack",
+        "webserver": "Passenger Standalone",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "sinatra-passenger-mri",
+        "versus": "rack-passenger-mri",
+        "notes": ""
+      },
+      "postgres-passenger-mri": {
+        "setup_file": "run_mri_passenger",
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "sinatra",
+        "language": "Ruby",
+        "orm": "Full",
+        "platform": "Rack",
+        "webserver": "Passenger Standalone",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "sinatra-postgres-passenger-mri",
+        "versus": "rack-postgres-passenger-mri",
+        "notes": ""
+      },
+      "unicorn-mri": {
+        "setup_file": "run_mri_unicorn",
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "MySQL",
+        "framework": "sinatra",
+        "language": "Ruby",
+        "orm": "Full",
+        "platform": "Rack",
+        "webserver": "Unicorn",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "sinatra-unicorn-mri",
+        "versus": "rack-unicorn-mri",
+        "notes": ""
+      },
+      "postgres-unicorn-mri": {
+        "setup_file": "run_mri_unicorn",
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "sinatra",
+        "language": "Ruby",
+        "orm": "Full",
+        "platform": "Rack",
+        "webserver": "Unicorn",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "sinatra-postgres-unicorn-mri",
+        "versus": "rack-postgres-unicorn-mri",
+        "notes": ""
+      }
+    }
+  ]
 }
 }

+ 8 - 0
frameworks/Ruby/sinatra/benchmark_config.rb

@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'json'
+require 'yaml'
+
+yaml = YAML.load(ARGF.read)
+yaml["tests"][0].delete_if { |_, v| v["disabled"] }
+puts JSON.pretty_generate(yaml)

+ 86 - 0
frameworks/Ruby/sinatra/benchmark_config.yaml

@@ -0,0 +1,86 @@
+---
+framework: sinatra
+tests:
+  - default: &default
+      setup_file: run_mri_puma
+      json_url: /json
+      db_url: /db
+      query_url: /queries?queries=
+      fortune_url: /fortunes
+      update_url: /updates?queries=
+      plaintext_url: /plaintext
+      port: 8080
+      approach: Realistic
+      classification: Micro
+      database: MySQL
+      framework: sinatra
+      language: Ruby
+      orm: Full
+      platform: Rack
+      webserver: Puma
+      os: Linux
+      database_os: Linux
+      display_name: sinatra-puma-mri
+      versus: rack-puma-mri
+      notes: ""
+    postgres:
+      <<: *default
+      database: Postgres
+      display_name: sinatra-postgres-puma-mri
+      versus: rack-postgres-puma-mri
+    puma-jruby:
+      <<: *default
+      setup_file: run_jruby_puma
+      platform: JRuby
+      display_name: sinatra-puma-jruby
+      versus: rack-puma-jruby
+      disabled: true
+    postgres-puma-jruby:
+      <<: *default
+      setup_file: run_jruby_puma
+      database: Postgres
+      platform: JRuby
+      display_name: sinatra-postgres-puma-jruby
+      versus: rack-postgres-puma-jruby
+      disabled: true
+    passenger-mri:
+      <<: *default
+      setup_file: run_mri_passenger
+      webserver: Passenger Standalone
+      display_name: sinatra-passenger-mri
+      versus: rack-passenger-mri
+    postgres-passenger-mri:
+      <<: *default
+      setup_file: run_mri_passenger
+      database: Postgres
+      webserver: Passenger Standalone
+      display_name: sinatra-postgres-passenger-mri
+      versus: rack-postgres-passenger-mri
+    unicorn-mri:
+      <<: *default
+      setup_file: run_mri_unicorn
+      webserver: Unicorn
+      display_name: sinatra-unicorn-mri
+      versus: rack-unicorn-mri
+    postgres-unicorn-mri:
+      <<: *default
+      setup_file: run_mri_unicorn
+      database: Postgres
+      webserver: Unicorn
+      display_name: sinatra-postgres-unicorn-mri
+      versus: rack-postgres-unicorn-mri
+    torquebox-jruby:
+      <<: *default
+      setup_file: run_jruby_torquebox
+      platform: JRuby
+      display_name: sinatra-torquebox-jruby
+      versus: rack-torquebox-jruby
+      disabled: true
+    postgres-torquebox-jruby:
+      <<: *default
+      setup_file: run_jruby_torquebox
+      database: Postgres
+      platform: JRuby
+      display_name: sinatra-postgres-torquebox-jruby
+      versus: rack-postgres-torquebox-jruby
+      disabled: true

+ 64 - 0
frameworks/Ruby/sinatra/boot.rb

@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+require 'bundler'
+require 'time'
+
+MAX_PK = 10_000
+QUERIES_MIN = 1
+QUERIES_MAX = 500
+
+Bundler.require(:default) # Load core modules
+
+def connect(dbtype)
+  Bundler.require(dbtype) # Load database-specific modules
+
+  opts = {
+    :adapter=>(dbtype == :mysql ? 'mysql2' : 'postgresql'),
+    :username=>'benchmarkdbuser',
+    :password=>'benchmarkdbpass',
+    :host=>ENV.fetch('DBHOST', '127.0.0.1'),
+    :database=>'hello_world'
+  }
+
+  # Determine threading/thread pool size and timeout
+  if defined?(JRUBY_VERSION)
+    opts[:pool] = Integer(ENV.fetch('MAX_CONCURRENCY'))
+    opts[:check_timeout] = 10
+  elsif defined?(Puma)
+    opts[:pool] = Puma.cli_config.options.fetch(:max_threads)
+    opts[:check_timeout] = 10
+  else
+    # TODO: ActiveRecord doesn't have a single-threaded mode?
+    opts[:pool] = 1
+    opts[:check_timeout] = 0
+  end
+
+  ActiveRecord::Base.establish_connection(opts)
+end
+
+connect ENV.fetch('DBTYPE').to_sym
+
+# Define ORM models
+class World < ActiveRecord::Base
+  self.table_name = name
+
+  alias_attribute(:randomnumber, :randomNumber) \
+    if ActiveRecord::Base.connection.adapter_name.downcase.start_with?('mysql')
+end
+
+class Fortune < ActiveRecord::Base
+  self.table_name = name
+end
+
+ActiveRecord::Base.clear_active_connections!
+
+SERVER_STRING =
+  if defined?(PhusionPassenger)
+    [
+      PhusionPassenger::SharedConstants::SERVER_TOKEN_NAME,
+      PhusionPassenger::VERSION_STRING
+    ].join('/').freeze
+  elsif defined?(Puma)
+    Puma::Const::PUMA_SERVER_STRING
+  elsif defined?(Unicorn)
+    Unicorn::HttpParser::DEFAULTS['SERVER_SOFTWARE']
+  end

+ 3 - 2
frameworks/Ruby/sinatra/config.ru

@@ -1,2 +1,3 @@
-require './hello_world'
-run Sinatra::Application
+require_relative 'boot'
+require_relative 'hello_world'
+run HelloWorld.new

+ 41 - 0
frameworks/Ruby/sinatra/config/auto_tune.rb

@@ -0,0 +1,41 @@
+#!/usr/bin/env ruby
+# Instantiate about one process per X MiB of available memory, scaling up to as
+# close to MAX_THREADS as possible while observing an upper bound based on the
+# number of virtual/logical CPUs. If there are fewer processes than
+# MAX_THREADS, add threads per process to reach MAX_THREADS.
+require 'etc'
+
+KB_PER_WORKER = 96 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k)
+MIN_WORKERS = 2
+MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical
+MIN_THREADS_PER_WORKER = 4
+MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256)
+
+def meminfo(arg)
+  File.open('/proc/meminfo') do |f|
+    f.each_line do |line|
+      key, value = line.split(/:\s+/)
+      return value.split(/\s+/).first.to_i if key == arg
+    end
+  end
+
+  fail "Unable to find `#{arg}' in /proc/meminfo!"
+end
+
+def auto_tune
+  avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024
+
+  workers = [
+    [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max,
+    (Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil
+  ].min
+
+  threads_per_worker = [
+    workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY,
+    MIN_THREADS_PER_WORKER
+  ].max
+
+  [workers, threads_per_worker]
+end
+
+p auto_tune if $0 == __FILE__

+ 6 - 0
frameworks/Ruby/sinatra/config/bundle_install.sh

@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# Ensure we don't accidentally (try to) use gems for the wrong platform.
+rm -f $TROOT/Gemfile.lock
+
+bundle install --jobs=4 --gemfile=$TROOT/Gemfile --path=vendor/bundle

+ 13 - 0
frameworks/Ruby/sinatra/config/common_run.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+
+if [[ $LOGDIR == *postgres* ]] ; then
+  DBTYPE=postgresql
+else
+  DBTYPE=mysql
+fi
+
+export DBTYPE
+
+if [[ $LOGDIR == *jruby* ]] ; then
+  . $(dirname $0)/config/java_tune.sh
+fi

+ 24 - 0
frameworks/Ruby/sinatra/config/java_tune.sh

@@ -0,0 +1,24 @@
+#!/bin/sh
+stack_size=1
+cache_size=240
+meta_size=192
+
+# Factor in Ruby's per-thread overhead...
+avail_mem=$(awk '/^MemAvailable/ { print int(0.7 * $2 / 1024) - ( \
+  $ENVIRON["MAX_CONCURRENCY"] * $ENVIRON["THREAD_FACTOR"] \
+); exit }' /proc/meminfo)
+
+# ...as well as Java's per-thread stack size.
+heap_size=$(( avail_mem - meta_size - cache_size - (
+  stack_size * MAX_CONCURRENCY * THREAD_FACTOR
+) ))
+
+JRUBY_OPTS="-J-server -J-XX:+AggressiveOpts -J-Djava.net.preferIPv4Stack=true"
+JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseSerialGC"
+#JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=100"
+JRUBY_OPTS="$JRUBY_OPTS -J-Xms${heap_size}m -J-Xmx${heap_size}m"
+JRUBY_OPTS="$JRUBY_OPTS -J-Xss${stack_size}m"
+JRUBY_OPTS="$JRUBY_OPTS -J-XX:MaxMetaspaceSize=${meta_size}m"
+JRUBY_OPTS="$JRUBY_OPTS -J-XX:ReservedCodeCacheSize=${cache_size}m"
+
+export JRUBY_OPTS

+ 7 - 0
frameworks/Ruby/sinatra/config/mri_puma.rb

@@ -0,0 +1,7 @@
+require_relative 'auto_tune'
+
+# FWBM only... use the puma_auto_tune gem in production!
+num_workers, num_threads = auto_tune
+
+workers num_workers
+threads num_threads, num_threads

+ 6 - 0
frameworks/Ruby/sinatra/config/mri_unicorn.rb

@@ -0,0 +1,6 @@
+require_relative 'auto_tune'
+
+# FWBM only...
+num_workers, = auto_tune
+
+worker_processes num_workers

+ 0 - 158
frameworks/Ruby/sinatra/config/nginx.conf

@@ -1,158 +0,0 @@
-# This is example contains the bare mininum to get nginx going with
-# Unicorn or Rainbows! servers.  Generally these configuration settings
-# are applicable to other HTTP application servers (and not just Ruby
-# ones), so if you have one working well for proxying another app
-# server, feel free to continue using it.
-#
-# The only setting we feel strongly about is the fail_timeout=0
-# directive in the "upstream" block.  max_fails=0 also has the same
-# effect as fail_timeout=0 for current versions of nginx and may be
-# used in its place.
-#
-# Users are strongly encouraged to refer to nginx documentation for more
-# details and search for other example configs.
-
-# you generally only need one nginx worker unless you're serving
-# large amounts of static files which require blocking disk reads
-worker_processes 8;
-
-# # drop privileges, root is needed on most systems for binding to port 80
-# # (or anything < 1024).  Capability-based security may be available for
-# # your system and worth checking out so you won't need to be root to
-# # start nginx to bind on 80
-# user nobody nogroup; # for systems with a "nogroup"
-#user nobody nobody; # for systems with "nobody" as a group instead
-
-# Feel free to change all paths to suite your needs here, of course
-pid /tmp/nginx.pid;
-#error_log /tmp/nginx.error.log;
-error_log /dev/null error;
-
-events {
-  worker_connections 4096; # increase if you have lots of clients
-  accept_mutex off; # "on" if nginx worker_processes > 1
-  use epoll; # enable for Linux 2.6+
-  # use kqueue; # enable for FreeBSD, OSX
-}
-
-http {
-  # nginx will find this file in the config directory set at nginx build time
-  include /usr/local/nginx/conf/mime.types;
-
-  # fallback in case we can't determine a type
-  default_type application/octet-stream;
-
-  # click tracking!
-  #access_log /tmp/nginx.access.log combined;
-  access_log off;
-
-  # you generally want to serve static files with nginx since neither
-  # Unicorn nor Rainbows! is optimized for it at the moment
-  sendfile on;
-
-  tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
-  tcp_nodelay off; # on may be better for some Comet/long-poll stuff
-
-  # we haven't checked to see if Rack::Deflate on the app server is
-  # faster or not than doing compression via nginx.  It's easier
-  # to configure it all in one place here for static files and also
-  # to disable gzip for clients who don't get gzip/deflate right.
-  # There are other gzip settings that may be needed used to deal with
-  # bad clients out there, see http://wiki.nginx.org/NginxHttpGzipModule
-  #gzip on;
-  #gzip_http_version 1.0;
-  #gzip_proxied any;
-  #gzip_min_length 500;
-  #gzip_disable "MSIE [1-6]\.";
-  #gzip_types text/plain text/html text/xml text/css
-  #           text/comma-separated-values
-  #           text/javascript application/x-javascript
-  #           application/atom+xml;
-
-  # this can be any application server, not just Unicorn/Rainbows!
-  upstream app_server {
-    # fail_timeout=0 means we always retry an upstream even if it failed
-    # to return a good HTTP response (in case the Unicorn master nukes a
-    # single worker for timing out).
-
-    # for UNIX domain socket setups:
-    server unix:/tmp/.sock fail_timeout=0;
-
-    # for TCP setups, point these to your backend servers
-    # server 192.168.0.7:8080 fail_timeout=0;
-    # server 192.168.0.8:8080 fail_timeout=0;
-    # server 192.168.0.9:8080 fail_timeout=0;
-  }
-
-  server {
-    # enable one of the following if you're on Linux or FreeBSD
-    listen 8080 default deferred; # for Linux
-    # listen 80 default accept_filter=httpready; # for FreeBSD
-
-    # If you have IPv6, you'll likely want to have two separate listeners.
-    # One on IPv4 only (the default), and another on IPv6 only instead
-    # of a single dual-stack listener.  A dual-stack listener will make
-    # for ugly IPv4 addresses in $remote_addr (e.g ":ffff:10.0.0.1"
-    # instead of just "10.0.0.1") and potentially trigger bugs in
-    # some software.
-    # listen [::]:80 ipv6only=on; # deferred or accept_filter recommended
-
-    client_max_body_size 4G;
-    server_name _;
-
-    # ~2 seconds is often enough for most folks to parse HTML/CSS and
-    # retrieve needed images/icons/frames, connections are cheap in
-    # nginx so increasing this is generally safe...
-    keepalive_timeout 10;
-
-    # path for static files
-    root /path/to/app/current/public;
-
-    # Prefer to serve static files directly from nginx to avoid unnecessary
-    # data copies from the application server.
-    #
-    # try_files directive appeared in in nginx 0.7.27 and has stabilized
-    # over time.  Older versions of nginx (e.g. 0.6.x) requires
-    # "if (!-f $request_filename)" which was less efficient:
-    # http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127
-    try_files $uri/index.html $uri.html $uri @app;
-
-    location @app {
-      # an HTTP header important enough to have its own Wikipedia entry:
-      #   http://en.wikipedia.org/wiki/X-Forwarded-For
-      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
-      # enable this if you forward HTTPS traffic to unicorn,
-      # this helps Rack set the proper URL scheme for doing redirects:
-      # proxy_set_header X-Forwarded-Proto $scheme;
-
-      # pass the Host: header from the client right along so redirects
-      # can be set properly within the Rack application
-      proxy_set_header Host $http_host;
-
-      # we don't want nginx trying to do something clever with
-      # redirects, we set the Host: header above already.
-      proxy_redirect off;
-
-      # set "proxy_buffering off" *only* for Rainbows! when doing
-      # Comet/long-poll/streaming.  It's also safe to set if you're using
-      # only serving fast clients with Unicorn + nginx, but not slow
-      # clients.  You normally want nginx to buffer responses to slow
-      # clients, even with Rails 3.1 streaming because otherwise a slow
-      # client can become a bottleneck of Unicorn.
-      #
-      # The Rack application may also set "X-Accel-Buffering (yes|no)"
-      # in the response headers do disable/enable buffering on a
-      # per-response basis.
-      # proxy_buffering off;
-
-      proxy_pass http://app_server;
-    }
-
-    # Rails error pages
-    error_page 500 502 503 504 /500.html;
-    location = /500.html {
-      root /path/to/app/current/public;
-    }
-  }
-}

+ 0 - 3
frameworks/Ruby/sinatra/config/puma.rb

@@ -1,3 +0,0 @@
-environment 'production'
-threads 8, 32
-bind 'tcp://0.0.0.0:8080'

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

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

+ 0 - 8
frameworks/Ruby/sinatra/config/trinidad.yml

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

+ 0 - 7
frameworks/Ruby/sinatra/config/unicorn.rb

@@ -1,7 +0,0 @@
-worker_processes 8
-listen "/tmp/.sock", :backlog => 256
-preload_app true
-GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true
-
-before_fork { |server, worker| }
-after_fork { |server, worker| }

+ 94 - 81
frameworks/Ruby/sinatra/hello_world.rb

@@ -1,97 +1,110 @@
-require 'active_record'
-Bundler.require :default
-
-set :logging, false
-ActiveRecord::Base.logger = nil
-set :activerecord_logger, nil
-set :static, false
-set :template_engine, :slim
-Slim::Engine.set_default_options format: :html5, sort_attrs: false
-
-# Specify the encoder - otherwise, sinatra/json inefficiently
-# attempts to load one of several on each request
-set :json_encoder => :to_json
-
-# Don't prefix JSON results with { "world": {...} }
-ActiveRecord::Base.include_root_in_json = false
-
-db_config = { :database => 'hello_world', :username => 'benchmarkdbuser', :password => 'benchmarkdbpass', :pool => 256, :timeout => 5000 }
-adapter = RUBY_PLATFORM == 'java' ? 'jdbcmysql' : 'mysql2'
-set :database, db_config.merge(:adapter => adapter, :host => ENV['DB_HOST'])
-
-# The sinatra-activerecord gem registers before and after filters that
-# call expensive synchronized ActiveRecord methods on every request to
-# verify every connection in the pool, even for routes that don't use
-# the database. Clear those filters and handle connection management
-# ourselves, which is what applications seeking high throughput with
-# ActiveRecord need to do anyway.
-settings.filters[:before].clear
-settings.filters[:after].clear
-
-after do
-  # Add mandatory HTTP headers to every response
-  response['Server'] ||= ENV['WEB_SERVER'].freeze
-  response['Date'] ||= Time.now.to_s
-end
+# frozen_string_literal: true
 
 
-class World < ActiveRecord::Base
-  self.table_name = "World"
-end
+# Our Rack application to be executed by rackup
+class HelloWorld < Sinatra::Base
+  configure do
+    # Static file serving is ostensibly disabled in modular mode but Sinatra
+    # still calls an expensive Proc on every request...
+    disable :static
 
 
-class Fortune < ActiveRecord::Base
-  self.table_name = "Fortune"
-end
+    # XSS, CSRF, IP spoofing, etc. protection are not explicitly required
+    disable :protection
 
 
-get '/json' do
-  json :message => 'Hello, World!'
-end
+    # Only add the charset parameter to specific content types per the requirements
+    set :add_charset, [mime_type(:html)]
+  end
 
 
-get '/plaintext' do
-  response['Content-type'] = 'text/plain'
-  'Hello, World!'
-end
+  helpers do
+    def bounded_queries
+      queries = params[:queries].to_i
+      return QUERIES_MIN if queries < QUERIES_MIN
+      return QUERIES_MAX if queries > QUERIES_MAX
+      queries
+    end
 
 
-get '/db' do
-  worlds = ActiveRecord::Base.connection_pool.with_connection do
-    World.find(Random.rand(10000) + 1)
+    def json(data)
+      content_type :json
+      JSON.fast_generate(data)
+    end
+
+    # Return a random number between 1 and MAX_PK
+    def rand1
+      Random.rand(MAX_PK).succ
+    end
+
+    # Return an array of `n' unique random numbers between 1 and MAX_PK
+    def randn(n)
+      (1..MAX_PK).to_a.shuffle!.take(n)
+    end
+  end
+
+  after do
+    response['Date'] = Time.now.httpdate
   end
   end
-  json(worlds)
-end
 
 
-get '/queries' do
-  queries = (params[:queries] || 1).to_i
-  queries = 1 if queries < 1
-  queries = 500 if queries > 500
+  after do
+    response['Server'] = SERVER_STRING
+  end if SERVER_STRING
 
 
-  worlds = ActiveRecord::Base.connection_pool.with_connection do
-    (1..queries).map do
-      World.find(Random.rand(10000) + 1)
+  # Test type 1: JSON serialization
+  get '/json' do
+     json :message=>'Hello, World!'
+  end
+
+  # Test type 2: Single database query
+  get '/db' do
+    world = ActiveRecord::Base.connection_pool.with_connection do
+      World.find(rand1)
     end
     end
+
+    json world.attributes
   end
   end
-  json(worlds)
-end
 
 
-get '/fortunes' do
-  @fortunes = Fortune.all
-  @fortunes << Fortune.new(:id => 0, :message => "Additional fortune added at request time.")
-  @fortunes = @fortunes.sort_by { |x| x.message }
+  # Test type 3: Multiple database queries
+  get '/queries' do
+    worlds = ActiveRecord::Base.connection_pool.with_connection do
+      # Benchmark requirements explicitly forbid a WHERE..IN here, so be good
+      randn(bounded_queries).map! { |id| World.find(id) }
+    end
 
 
-  slim :fortunes
-end
+    json worlds.map!(&:attributes)
+  end
 
 
-get '/updates' do
-  queries = (params[:queries] || 1).to_i
-  queries = 1 if queries < 1
-  queries = 500 if queries > 500
-
-  worlds = ActiveRecord::Base.connection_pool.with_connection do
-    worlds = (1..queries).map do
-      world = World.find(Random.rand(10000) + 1)
-      world.randomNumber = Random.rand(10000) + 1
-      World.update(world.id, :randomNumber => world.randomNumber)
-      world
+  # Test type 4: Fortunes
+  get '/fortunes' do
+    @fortunes = ActiveRecord::Base.connection_pool.with_connection do
+      Fortune.all.to_a
     end
     end
-    worlds
+    @fortunes << Fortune.new(
+      :id=>0,
+      :message=>'Additional fortune added at request time.'
+    )
+    @fortunes.sort_by!(&:message)
+
+    erb :fortunes, :layout=>true
+  end
+
+  # Test type 5: Database updates
+  get '/updates' do
+    worlds = ActiveRecord::Base.connection_pool.with_connection do |conn|
+      # Benchmark requirements explicitly forbid a WHERE..IN here, transactions
+      # are optional, batch updates are allowed (but each transaction can only
+      # read and write a single record?), so... be good
+      randn(bounded_queries).map! do |id|
+        conn.transaction do
+          world = World.lock.find(id)
+          world.update(:randomnumber=>rand1)
+          world
+        end
+      end
+    end
+
+    json worlds.map!(&:attributes)
+  end
+
+  # Test type 6: Plaintext
+  get '/plaintext' do
+    content_type :text
+    'Hello, World!'
   end
   end
-  json(worlds)
 end
 end

+ 0 - 1
frameworks/Ruby/sinatra/public/500.html

@@ -1 +0,0 @@
- 

+ 13 - 0
frameworks/Ruby/sinatra/run_jruby_puma.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+
+THREAD_FACTOR=1
+
+. $(dirname $0)/config/common_run.sh
+
+fw_depends $DBTYPE rvm jruby-9.1
+
+rvm use jruby-$JRUBY_VERSION
+
+. $(dirname $0)/config/bundle_install.sh
+
+bundle exec puma -t $MAX_CONCURRENCY:$MAX_CONCURRENCY -b tcp://0.0.0.0:8080 -e production &

+ 13 - 0
frameworks/Ruby/sinatra/run_jruby_torquebox.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+
+THREAD_FACTOR=2
+
+. $(dirname $0)/config/common_run.sh
+
+fw_depends $DBTYPE rvm jruby-9.1
+
+rvm use jruby-$JRUBY_VERSION
+
+. $(dirname $0)/config/bundle_install.sh
+
+bundle exec torquebox run --io-threads $MAX_CONCURRENCY --worker-threads $MAX_CONCURRENCY -b 0.0.0.0 -p 8080 -e production &

+ 20 - 0
frameworks/Ruby/sinatra/run_mri_passenger.sh

@@ -0,0 +1,20 @@
+#!/bin/bash
+
+. $(dirname $0)/config/common_run.sh
+
+fw_depends $DBTYPE rvm ruby-2.4
+
+rvm use ruby-$MRI_VERSION
+
+. $(dirname $0)/config/bundle_install.sh
+
+# TODO: https://github.com/phusion/passenger/issues/1916
+export _PASSENGER_FORCE_HTTP_SESSION=true
+
+# FWBM only... Passenger will auto-tune itself in production!
+instances=$(ruby -r$(dirname $0)/config/auto_tune -e 'puts auto_tune.first')
+
+bundle exec passenger start --log-level 1 \
+  --engine builtin --disable-turbocaching --disable-security-update-check \
+  --spawn-method direct --max-pool-size $instances --min-instances $instances --max-request-queue-size 1024 \
+  --address 0.0.0.0 --port 8080 --environment production &

+ 7 - 3
frameworks/Ruby/sinatra/run_mri_puma.sh

@@ -1,7 +1,11 @@
 #!/bin/bash
 #!/bin/bash
 
 
-fw_depends mysql rvm ruby-2.0
+. $(dirname $0)/config/common_run.sh
 
 
-rvm ruby-$MRI_VERSION do bundle install --jobs=4 --gemfile=$TROOT/Gemfile --path=vendor/bundle
+fw_depends $DBTYPE rvm ruby-2.4
 
 
-WEB_SERVER=Puma DB_HOST=${DBHOST} rvm ruby-$MRI_VERSION do bundle exec puma -C config/puma.rb -w 8 --preload &
+rvm use ruby-$MRI_VERSION
+
+. $(dirname $0)/config/bundle_install.sh
+
+bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production &

+ 11 - 0
frameworks/Ruby/sinatra/run_mri_unicorn.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+
+. $(dirname $0)/config/common_run.sh
+
+fw_depends $DBTYPE rvm ruby-2.4
+
+rvm use ruby-$MRI_VERSION
+
+. $(dirname $0)/config/bundle_install.sh
+
+bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production &

+ 0 - 7
frameworks/Ruby/sinatra/run_thin.sh

@@ -1,7 +0,0 @@
-#!/bin/bash
-
-fw_depends mysql rvm ruby-2.0
-
-rvm ruby-$MRI_VERSION do bundle install --jobs=4 --gemfile=$TROOT/Gemfile --path=vendor/bundle
-
-WEB_SERVER=Thin DB_HOST=${DBHOST} rvm ruby-$MRI_VERSION do bundle exec thin start -C config/thin.yml &

+ 0 - 11
frameworks/Ruby/sinatra/run_unicorn.sh

@@ -1,11 +0,0 @@
-#!/bin/bash
-
-fw_depends mysql rvm ruby-2.0 nginx
-
-sed -i 's|/usr/local/nginx/|'"${IROOT}"'/nginx/|g' config/nginx.conf
-
-rvm ruby-$MRI_VERSION do bundle install --jobs=4 --gemfile=$TROOT/Gemfile --path=vendor/bundle
-
-nginx -c $TROOT/config/nginx.conf
-
-WEB_SERVER=Unicorn DB_HOST=${DBHOST} rvm ruby-$MRI_VERSION do bundle exec unicorn -E production -c config/unicorn.rb &

+ 3 - 1
frameworks/Ruby/sinatra/source_code

@@ -1 +1,3 @@
-./hello_world.rb
+./sinatra/config.ru
+./sinatra/boot.rb
+./sinatra/hello_world.rb

+ 12 - 0
frameworks/Ruby/sinatra/views/fortunes.erb

@@ -0,0 +1,12 @@
+<table>
+<tr>
+  <th>id</th>
+  <th>message</th>
+</tr>
+<% @fortunes.each do |fortune| %>
+<tr>
+  <td><%= Rack::Utils.escape_html(fortune.id) %></td>
+  <td><%= Rack::Utils.escape_html(fortune.message) %></td>
+</tr>
+<% end %>
+</table>

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