Browse Source

Merge branch 'methane-python-update'

Patrick Falls 12 years ago
parent
commit
b97c08906b
13 changed files with 169 additions and 22 deletions
  1. 19 1
      flask/README.md
  2. 38 3
      flask/app.py
  3. 19 0
      flask/benchmark_config
  4. 14 0
      flask/run_pypy.py
  5. 24 0
      flask/setup_pypy.py
  6. 18 0
      flask/templates/fortunes.html
  7. 5 0
      framework_test.py
  8. 24 9
      installer.py
  9. 1 1
      restexpress/benchmark_config
  10. 1 1
      run-tests.py
  11. 3 4
      setup_util.py
  12. 0 1
      tornado/setup.py
  13. 3 2
      wsgi/setup.py

+ 19 - 1
flask/README.md

@@ -2,6 +2,24 @@
 
 Single file test, [app.py](app.py)
 
+## Description
+
+Flask + Flask-SQLAlchemy
+
+### Interpreter
+
+* CPython 2.7.4
+* PyPy 2.0
+
+### Database
+
+MySQL (MySQL-python on CPython, PyMySQL on PyPy)
+
+### Server
+
+* gunicorn+meinheld on CPython
+* Tornado on PyPy
+
 
 ## Test URLs
 ### JSON Encoding 
@@ -22,4 +40,4 @@ With ORM:
     http://localhost:8080/db?queries=2
 
 Without ORM (raw):
-    http://localhost:8080/dbraw?queries=2
+    http://localhost:8080/dbraw?queries=2

+ 38 - 3
flask/app.py

@@ -1,13 +1,25 @@
-from flask import Flask, jsonify, request
+#!/usr/bin/env python
+from flask import Flask, jsonify, request, render_template
 from flask.ext.sqlalchemy import SQLAlchemy
 from sqlalchemy import create_engine
 from random import randint
+from operator import attrgetter
+
+try:
+    import MySQLdb
+    mysql_schema = "mysql:"
+except ImportError:
+    mysql_schema = "mysql+pymysql:"
+
+# setup
 
 app = Flask(__name__)
-app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world'
+app.config['SQLALCHEMY_DATABASE_URI'] = mysql_schema + '//benchmarkdbuser:benchmarkdbpass@DBHOSTNAME:3306/hello_world?charset=utf8'
 db = SQLAlchemy(app)
 dbraw_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])
 
+# models
+
 class World(db.Model):
   __tablename__ = "World"
   id = db.Column(db.Integer, primary_key=True)
@@ -22,6 +34,14 @@ class World(db.Model):
          'randomNumber': self.randomNumber
      }
 
+class Fortune(db.Model):
+    __tablename__ = "Fortune"
+    id = db.Column(db.Integer, primary_key=True)
+    message = db.Column(db.String)
+
+
+# views
+
 @app.route("/json")
 def hello():
   resp = {"message": "Hello, World!"}
@@ -63,5 +83,20 @@ def get_random_world_single_raw():
   connection.close()
   return jsonify(worlds=worlds)
 
[email protected]("/fortunes")
+def get_fortunes():
+    fortunes = list(Fortune.query.all())
+    fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
+    fortunes.sort(key=attrgetter('message'))
+    return render_template('fortunes.html', fortunes=fortunes)
+
[email protected]("/fortunesraw")
+def get_forutens_raw():
+    fortunes = list(dbraw_engine.execute("SELECT * FROM Fortune"))
+    fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
+    fortunes.sort(key=attrgetter('message'))
+    return render_template('fortunes.html', fortunes=fortunes)
+
+# entry point for debugging
 if __name__ == "__main__":
-    app.run()
+    app.run(debug=True)

+ 19 - 0
flask/benchmark_config

@@ -6,6 +6,7 @@
       "json_url": "/json",
       "db_url": "/dbs",
       "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
       "port": 8080,
       "sort": 31
     },
@@ -13,8 +14,26 @@
       "setup_file": "setup",
       "db_url": "/dbsraw",
       "query_url": "/dbraw?queries=",
+      "fortune_url": "/fortunesraw",
       "port": 8080,
       "sort": 84
+    },
+    "pypy": {
+      "setup_file": "setup_pypy",
+      "json_url": "/json",
+      "db_url": "/dbs",
+      "query_url": "/db?queries=",
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "sort": 110
+    },
+    "pypy-mysql-raw": {
+      "setup_file": "setup_pypy",
+      "db_url": "/dbsraw",
+      "query_url": "/dbraw?queries=",
+      "fortune_url": "/fortunesraw",
+      "port": 8080,
+      "sort": 111
     }
   }]
 }

+ 14 - 0
flask/run_pypy.py

@@ -0,0 +1,14 @@
+import tornado.options
+import tornado.wsgi
+import tornado.httpserver
+from tornado.options import options
+
+tornado.options.define('port', default=8080, type=int, help=("Server port"))
+tornado.options.parse_command_line()
+
+import app
+container = tornado.wsgi.WSGIContainer(app.app)
+server = tornado.httpserver.HTTPServer(container)
+server.bind(options.port)
+server.start(8)
+tornado.ioloop.IOLoop.instance().start()

+ 24 - 0
flask/setup_pypy.py

@@ -0,0 +1,24 @@
+import subprocess
+import sys
+import setup_util
+import os
+
+proc = None
+
+def start(args):
+  global proc
+  setup_util.replace_text("flask/app.py", "DBHOSTNAME", args.database_host)
+  proc = subprocess.Popen("~/FrameworkBenchmarks/installs/pypy-2.0/bin/pypy run_pypy.py --port=8080 --logging=error", shell=True, cwd="flask")
+  return 0
+
+def stop():
+  p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  out, err = p.communicate()
+  for line in out.splitlines():
+    if 'pypy' in line and 'run-tests' not in line:
+      try:
+        pid = int(line.split(None, 2)[1])
+        os.kill(pid, 9)
+      except OSError:
+        pass
+  return 0 

+ 18 - 0
flask/templates/fortunes.html

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

+ 5 - 0
framework_test.py

@@ -201,6 +201,7 @@ class FrameworkTest:
     try:
       if self.json_url_passed and (self.benchmarker.type == "all" or self.benchmarker.type == "json"):
         sys.stdout.write("BENCHMARKING JSON ... ") 
+        sys.stdout.flush()
         remote_script = self.__generate_concurrency_script(self.json_url, self.port)
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'json'))
         results = self.__parse_test('json')
@@ -214,6 +215,7 @@ class FrameworkTest:
     try:
       if self.db_url_passed and (self.benchmarker.type == "all" or self.benchmarker.type == "db"):
         sys.stdout.write("BENCHMARKING DB ... ") 
+        sys.stdout.flush()
         remote_script = self.__generate_concurrency_script(self.db_url, self.port)
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'db'))
         results = self.__parse_test('db')
@@ -227,6 +229,7 @@ class FrameworkTest:
     try:
       if self.query_url_passed and (self.benchmarker.type == "all" or self.benchmarker.type == "query"):
         sys.stdout.write("BENCHMARKING Query ... ") 
+        sys.stdout.flush()
         remote_script = self.__generate_query_script(self.query_url, self.port)
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'query'))
         results = self.__parse_test('query')
@@ -239,6 +242,7 @@ class FrameworkTest:
     try:
       if self.fortune_url_passed and (self.benchmarker.type == "all" or self.benchmarker.type == "fortune"):
         sys.stdout.write("BENCHMARKING Fortune ... ") 
+        sys.stdout.flush()
         remote_script = self.__generate_concurrency_script(self.fortune_url, self.port)
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'fortune'))
         results = self.__parse_test('fortune')
@@ -251,6 +255,7 @@ class FrameworkTest:
     try:
       if self.update_url_passed and (self.benchmarker.type == "all" or self.benchmarker.type == "update"):
         sys.stdout.write("BENCHMARKING Update ... ") 
+        sys.stdout.flush()
         remote_script = self.__generate_query_script(self.update_url, self.port)
         self.__run_benchmark(remote_script, self.benchmarker.output_file(self.name, 'update'))
         results = self.__parse_test('update')

+ 24 - 9
installer.py

@@ -46,13 +46,18 @@ class Installer:
     # Python
     #
 
-    self.__run_command("curl http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz | tar xvz")
-    self.__run_command("./configure", cwd="Python-2.7.3")
-    self.__run_command("sudo make install", cwd="Python-2.7.3")
-    self.__run_command("curl http://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz | tar xvz")
-    self.__run_command("sudo python setup.py install", cwd="setuptools-0.6c11")
-    self.__run_command("curl http://pypi.python.org/packages/source/p/pip/pip-1.1.tar.gz | tar xvz")
-    self.__run_command("sudo python setup.py install", cwd="pip-1.1")
+    self.__run_command("curl -L http://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux64.tar.bz2 | tar xvj")
+    self.__run_command("curl http://www.python.org/ftp/python/2.7.4/Python-2.7.4.tgz | tar xvz")
+    self.__run_command("./configure", cwd="Python-2.7.4")
+    self.__run_command("make -j", cwd="Python-2.7.4")
+    self.__run_command("sudo make install", cwd="Python-2.7.4")
+    self.__run_command("curl https://pypi.python.org/packages/source/d/distribute/distribute-0.6.38.tar.gz | tar xvz")
+    # run pypy before python. (`setup.py install` fails after `sudo setup.py install`)
+    self.__run_command("../pypy-2.0/bin/pypy setup.py install", cwd="distribute-0.6.38")
+    self.__run_command("sudo python setup.py install", cwd="distribute-0.6.38")
+    self.__run_command("curl https://pypi.python.org/packages/source/p/pip/pip-1.3.1.tar.gz | tar xvz")
+    self.__run_command("../pypy-2.0/bin/pypy setup.py install", cwd="pip-1.3.1")
+    self.__run_command("sudo python setup.py install", cwd="pip-1.3.1")
     self.__run_command("sudo pip install MySQL-python==1.2.4")
     self.__run_command("sudo pip install simplejson==3.0.7")
     self.__run_command("curl http://initd.org/psycopg/tarballs/PSYCOPG-2-5/psycopg2-2.5.tar.gz | tar xvz")
@@ -60,6 +65,7 @@ class Installer:
     self.__run_command("git clone https://github.com/iiilx/django-psycopg2-pool.git")
     self.__run_command("sudo python setup.py install", cwd="django-psycopg2-pool")
     self.__run_command("sudo pip install --upgrade numpy==1.7.1")
+    self.__run_command("pypy-2.0/bin/pip install PyMySQL==0.5")
 
     #
     # nodejs
@@ -253,6 +259,13 @@ class Installer:
     #
     ##############################################################
 
+    ##############################
+    # Tornado
+    ##############################
+    packages = "tornado==3.0.1 motor==0.1 pymongo==2.5"
+    self.__run_command("sudo pip install " + packages)
+    self.__run_command("pypy-2.0/bin/pip install " + packages)
+
     ##############################
     # Django
     ##############################
@@ -272,7 +285,9 @@ class Installer:
     ##############################
     # Flask
     ##############################
-    self.__run_command("sudo pip install flask flask-sqlalchemy")
+    packages = "flask==0.9 flask-sqlalchemy==0.16 sqlalchemy==0.8.1 jinja2==2.6 werkzeug==0.8.3"
+    self.__run_command("sudo pip install " + packages)
+    self.__run_command("pypy-2.0/bin/pip install " + packages)
 
     ##############################
     # Bottle
@@ -396,7 +411,7 @@ class Installer:
     ##############################
     # MongoDB
     ##############################
-    sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10
+    sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
     sudo cp 10gen.list /etc/apt/sources.list.d/10gen.list
     sudo apt-get update
     yes | sudo apt-get install mongodb-10gen

+ 1 - 1
restexpress/benchmark_config

@@ -22,4 +22,4 @@
       "sort": 109
     }
   }]
-}
+}

+ 1 - 1
run-tests.py

@@ -17,7 +17,7 @@ parser.add_argument('-d', '--database-host')
 parser.add_argument('-i', dest='identity_file', help='ssh key to ssh from the server instance to the client instance.')
 parser.add_argument('-p', dest='password_prompt', action='store_true')
 parser.add_argument('--install-software', action='store_true', help='runs the installation script before running the rest of the commands')
-parser.add_argument('--install', choices=['clinet', 'server', 'all'], default='all', help='Allows you to only install the server or client software')
+parser.add_argument('--install', choices=['client', 'server', 'all'], default='all', help='Allows you to only install the server or client software')
 parser.add_argument('--test', nargs='+', help='names of tests to run')
 parser.add_argument('--exclude', nargs='+', help='names of tests to exclude')
 parser.add_argument('--type', choices=['all', 'json', 'db', 'query', 'fortune', 'update'], default='all', help='which type of test to run')

+ 3 - 4
setup_util.py

@@ -4,7 +4,6 @@ import re
 def replace_text(file, to_replace, replacement):
   with open(file, "r") as conf:
     contents = conf.read()
-    replaced_text = re.sub(to_replace, replacement, contents)
-  f = open(file, "w")
-  f.write(replaced_text)
-  f.close()
+  replaced_text = re.sub(to_replace, replacement, contents)
+  with open(file, "w") as f:
+    f.write(replaced_text)

+ 0 - 1
tornado/setup.py

@@ -12,7 +12,6 @@ def start(args):
     setup_util.replace_text(
         cwd + "/server.py", "localhost", args.database_host)
 
-    subprocess.check_call("sudo pip install -r requirements.txt", cwd=cwd, shell=True)
     subprocess.Popen("python %s/FrameworkBenchmarks/tornado/server.py --port=8080 --logging=error" % home, shell=True, cwd=cwd)
     return 0
 

+ 3 - 2
wsgi/setup.py

@@ -5,7 +5,8 @@ import setup_util
 import os
 
 def start(args):
-  subprocess.Popen("gunicorn hello:app -b 0.0.0.0:8080 -w " + str((args.max_threads * 2)) + " --log-level=critical", shell=True, cwd="wsgi")
+  subprocess.Popen('gunicorn hello:app --worker-class="egg:meinheld#gunicorn_worker" -b 0.0.0.0:8080 -w '
+                   + str((args.max_threads * 2)) + " --log-level=critical", shell=True, cwd="wsgi")
   return 0
 def stop():
   p = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
@@ -18,4 +19,4 @@ def stop():
       except OSError:
         pass
 
-  return 0
+  return 0