View
@@ -1,26 +1,63 @@
# Vertx Benchmarking Test
# Vertx 2.x Benchmarking Test
This is the vertx portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
This is the vertx 2.x portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
### Plaintext Test
* [Plaintext test source](WebServer.java)
### JSON Serialization Test
### JSON Encoding Test
* [JSON test source](WebServer.java)
### Data-Store/Database Mapping Test
### Database Single query Test
* [Database Single query test source](WebServer.java)
### Database Multiple queries Test
* [Database Multiple queries test source](WebServer.java)
### Database Data updates Test
* [Database Data updates test source](WebServer.java)
### Fortunes Test
* [Database test source](WebServer.java)
* [Fortunes test source](WebServer.java)
## Versions
* [Java OpenJDK 1.7.0_09](http://openjdk.java.net/)
* [vertx 1.3.1](http://vertx.io/)
* [Java OpenJDK 1.7.0_79](http://openjdk.java.net/)
* [vertx 2.1.5](http://vertx.io/)
## Test URLs
### Plaintext Test
http://localhost:8080/plaintext
### JSON Encoding Test
http://localhost:8080/json
### Database Mapping Test
http://localhost:8080/db?queries=5
http://localhost:8080/db?queries=5
### Database Single query Test
http://localhost:8080/db
### Database Multiple queries Test
http://localhost:8080/queries?queries=5
### Database Data updates Test
http://localhost:8080/updates?queries=3
### Fortunes Test
http://localhost:8080/fortunes
View
@@ -15,15 +15,67 @@
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import freemarker.template.Template;
import freemarker.template.Configuration;
import java.io.StringReader;
import java.io.Writer;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
public class WebServer extends Verticle implements Handler<HttpServerRequest> {
private Buffer helloWorldBuffer = new Buffer("Hello, World!");
private String helloWorldContentLength = String.valueOf(helloWorldBuffer.length());
private DateFormat DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyyy HH:mm:ss z");
private final Buffer helloWorldBuffer = new Buffer("Hello, World!");
private final String helloWorldContentLength = String.valueOf(helloWorldBuffer.length());
private final DateFormat DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyyy HH:mm:ss z");
private final Random random = ThreadLocalRandom.current();
private String dateString;
private static final String PATH_PLAINTEXT = "/plaintext";
private static final String PATH_JSON = "/json";
private static final String PATH_DB = "/db";
private static final String PATH_QUERIES = "/queries";
private static final String PATH_UPDATES = "/updates";
private static final String PATH_FORTUNES = "/fortunes";
private static final String RESPONSE_TYPE_PLAIN = "text/plain";
private static final String RESPONSE_TYPE_HTML = "text/html";
private static final String RESPONSE_TYPE_JSON = "application/json";
private static final String HEADER_CONTENT_TYPE = "Content-Type";
private static final String HEADER_CONTENT_LENGTH = "Content-Length";
private static final String HEADER_SERVER = "Server";
private static final String HEADER_SERVER_VERTX = "vert.x";
private static final String HEADER_DATE = "Date";
private static final String MONGO_ADDRESS = "hello.persistor";
private static final String FREEMARKER_ADDRESS = "vertx.freemarker";
private static final String UNDERSCORE_ID = "_id";
private static final String TEXT_ID = "id";
private static final String RANDOM_NUMBER = "randomNumber";
private static final String TEXT_RESULT = "result";
private static final String TEXT_RESULTS = "results";
private static final String TEXT_QUERIES = "queries";
private static final String TEXT_MESSAGE = "message";
private static final String TEXT_MESSAGES = "messages";
private static final String ADD_FORTUNE_MESSAGE = "Additional fortune added at request time.";
private static final String HELLO_WORLD = "Hello, world!";
private static final String TEXT_ACTION = "action";
private static final String TEXT_CRITERIA = "criteria";
private static final String TEXT_UPDATE = "update";
private static final String TEXT_OBJ_NEW = "objNew";
private static final String TEXT_FINDONE = "findone";
private static final String TEXT_FIND = "find";
private static final String TEXT_COLLECTION = "collection";
private static final String TEXT_WORLD = "World";
private static final String TEXT_FORTUNE = "Fortune";
private static final String TEXT_MATCHER = "matcher";
private static final String TEMPLATE_FORTUNE = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr><#list messages as message><tr><td>${message.id?html}</td><td>${message.message?html}</td></tr></#list></table></body></html>";
private Template ftlTemplate;
@Override
public void start() {
try { ftlTemplate = new Template(TEXT_FORTUNE, new StringReader(TEMPLATE_FORTUNE), new Configuration(Configuration.VERSION_2_3_22)); } catch (Exception ex) { ex.printStackTrace(); }
vertx.createHttpServer().requestHandler(WebServer.this).listen(8080);
vertx.setPeriodic(1000, new Handler<Long>() {
@Override
@@ -36,19 +88,24 @@ public void handle(Long timerID) {
@Override
public void handle(HttpServerRequest req) {
String path = req.path();
switch (path) {
case "/plaintext":
switch (req.path()) {
case PATH_PLAINTEXT:
handlePlainText(req);
break;
case "/json":
case PATH_JSON:
handleJson(req);
break;
case "/db":
case PATH_DB:
handleDbMongo(req);
break;
case "/queries":
handleQueriesMongo(req);
case PATH_QUERIES:
handleDBMongo(req,false);
break;
case PATH_UPDATES:
handleDBMongo(req,true);
break;
case PATH_FORTUNES:
handleFortunes(req);
break;
default:
req.response().setStatusCode(404);
@@ -60,21 +117,55 @@ private void formatDate() {
dateString = DATE_FORMAT.format(new Date());
}
private void handleFortunes(HttpServerRequest req) {
final HttpServerResponse resp = req.response();
vertx.eventBus().send(
MONGO_ADDRESS,
new JsonObject()
.putString(TEXT_ACTION, TEXT_FIND)
.putString(TEXT_COLLECTION, TEXT_FORTUNE),
new Handler<Message<JsonObject>>() {
@Override
public void handle(Message<JsonObject> reply) {
JsonArray results = reply.body().getArray(TEXT_RESULTS);
List<Fortune> fortunes = new ArrayList<>();
for (Object fortune: results) {
fortunes.add(new Fortune(
((JsonObject)fortune).getNumber(TEXT_ID).intValue(),
((JsonObject)fortune).getString(TEXT_MESSAGE)));
}
fortunes.add(new Fortune(0, ADD_FORTUNE_MESSAGE));
Collections.sort(fortunes);
Map model = new HashMap();
model.put(TEXT_MESSAGES, fortunes);
Writer writer = new StringWriter();
try { ftlTemplate.process(model, writer); } catch (Exception ex) { ex.printStackTrace(); }
Buffer buff = new Buffer(writer.toString());
setHeaders(resp, RESPONSE_TYPE_HTML, String.valueOf(buff.length()));
resp.end(buff);
}
});
}
private void handlePlainText(HttpServerRequest req) {
HttpServerResponse resp = req.response();
setHeaders(resp, "text/plain", helloWorldContentLength);
setHeaders(resp, RESPONSE_TYPE_PLAIN, helloWorldContentLength);
resp.end(helloWorldBuffer);
}
private void handleJson(HttpServerRequest req) {
Buffer buff = new Buffer(Json.encode(Collections.singletonMap("message", "Hello, world!")));
Buffer buff = new Buffer(Json.encode(Collections.singletonMap(TEXT_MESSAGE, HELLO_WORLD)));
HttpServerResponse resp = req.response();
setHeaders(resp, "application/json", String.valueOf(buff.length()));
setHeaders(resp, RESPONSE_TYPE_JSON, String.valueOf(buff.length()));
resp.end(buff);
}
private void handleDbMongo(final HttpServerRequest req) {
findRandom(ThreadLocalRandom.current(), new Handler<Message<JsonObject>>() {
findRandom(new Handler<Message<JsonObject>>() {
@Override
public void handle(Message<JsonObject> reply) {
JsonObject world = getResultFromReply(reply);
@@ -86,72 +177,86 @@ public void handle(Message<JsonObject> reply) {
private JsonObject getResultFromReply(Message<JsonObject> reply) {
JsonObject body = reply.body();
JsonObject world = body.getObject("result");
Object id = world.removeField("_id");
world.putValue("id", id);
JsonObject world = body.getObject(TEXT_RESULT);
Object id = world.removeField(UNDERSCORE_ID);
world.putValue(TEXT_ID, Integer.valueOf(((Double)id).intValue()));
return world;
}
private void handleQueriesMongo(final HttpServerRequest req) {
private void handleDBMongo(final HttpServerRequest req, boolean randomUpdates) {
int queriesParam = 1;
try {
queriesParam = Integer.parseInt(req.params().get("queries"));
queriesParam = Integer.parseInt(req.params().get(TEXT_QUERIES));
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (queriesParam < 1)
{
queriesParam = 1;
}
if (queriesParam > 500)
{
if (queriesParam < 1) {
queriesParam = 1;
} else if (queriesParam > 500) {
queriesParam = 500;
}
final MongoHandler dbh = new MongoHandler(req, queriesParam);
final Random random = ThreadLocalRandom.current();
final MongoHandler dbh = new MongoHandler(req, queriesParam, randomUpdates);
for (int i = 0; i < queriesParam; i++) {
findRandom(random, dbh);
findRandom(dbh);
}
}
private void findRandom(Random random, Handler<Message<JsonObject>> handler) {
private void findRandom(Handler<Message<JsonObject>> handler) {
vertx.eventBus().send(
"hello.persistor",
MONGO_ADDRESS,
new JsonObject()
.putString("action", "findone")
.putString("collection", "World")
.putObject("matcher", new JsonObject().putNumber("_id", (random.nextInt(10000) + 1))),
.putString(TEXT_ACTION, TEXT_FINDONE)
.putString(TEXT_COLLECTION, TEXT_WORLD)
.putObject(TEXT_MATCHER, new JsonObject().putNumber(UNDERSCORE_ID, (random.nextInt(10000) + 1))),
handler);
}
private void updateRandom(JsonObject json) {
vertx.eventBus().send(
MONGO_ADDRESS,
new JsonObject()
.putString(TEXT_ACTION, TEXT_UPDATE)
.putString(TEXT_COLLECTION, TEXT_WORLD)
.putObject(TEXT_CRITERIA, new JsonObject().putValue(UNDERSCORE_ID, json.getValue(TEXT_ID)))
.putObject(TEXT_OBJ_NEW, json)
);
}
private void sendResponse(HttpServerRequest req, String result) {
Buffer buff = new Buffer(result);
HttpServerResponse resp = req.response();
setHeaders(resp, "application/json", String.valueOf(buff.length()));
setHeaders(resp, RESPONSE_TYPE_JSON, String.valueOf(buff.length()));
resp.end(buff);
}
private void setHeaders(HttpServerResponse resp, String contentType, String contentLength) {
resp.putHeader("Content-Type", contentType);
resp.putHeader("Content-Length", contentLength);
resp.putHeader("Server", "vert.x");
resp.putHeader("Date", dateString);
resp.putHeader(HEADER_CONTENT_TYPE, contentType);
resp.putHeader(HEADER_CONTENT_LENGTH, contentLength);
resp.putHeader(HEADER_SERVER, HEADER_SERVER_VERTX );
resp.putHeader(HEADER_DATE, dateString);
}
private class MongoHandler implements Handler<Message<JsonObject>> {
private final class MongoHandler implements Handler<Message<JsonObject>> {
private final HttpServerRequest req;
private final int queries;
private final JsonArray worlds;
private final Random random;
private final boolean randomUpdates;
public MongoHandler(HttpServerRequest request, int queriesParam) {
public MongoHandler(HttpServerRequest request, int queriesParam, boolean performRandomUpdates) {
req = request;
queries = queriesParam;
randomUpdates = performRandomUpdates;
random = ThreadLocalRandom.current();
worlds = new JsonArray();
}
@Override
public void handle(Message<JsonObject> reply) {
JsonObject world = getResultFromReply(reply);
if (randomUpdates) {
world.putValue(RANDOM_NUMBER, (random.nextInt(10000) + 1));
updateRandom(world);
}
worlds.add(world);
if (worlds.size() == this.queries) {
// All queries have completed; send the response.
@@ -160,6 +265,25 @@ public void handle(Message<JsonObject> reply) {
}
}
}
public final class Fortune implements Comparable<Fortune> {
public int id;
public String message;
public int getId() {
return id;
}
public String getMessage() {
return message;
}
public Fortune(int id, String message) {
this.id = id;
this.message = message;
}
@Override
public int compareTo(Fortune other) {
return message.compareTo(other.message);
}
}
}
View
3 frameworks/Java/vertx/app.js 100644 → 100755
@@ -3,7 +3,8 @@ var container = require('vertx/container')
var persistorConf = {
address: 'hello.persistor',
db_name: 'hello_world',
host: 'localhost'
host: '127.0.0.1',
pool_size: 100
}
container.deployModule('io.vertx~mod-mongo-persistor~2.1.1', persistorConf, function (err, dep_id) {
View
@@ -7,6 +7,8 @@
"db_url": "/db",
"plaintext_url": "/plaintext",
"query_url": "/queries?queries=",
"update_url": "/updates?queries=",
"fortune_url": "/fortunes",
"port": 8080,
"approach": "Realistic",
"classification": "Platform",
View
@@ -1,3 +1,11 @@
#!/bin/bash
fw_depends java7 vertx
fw_depends java7
RETCODE=$(fw_exists ${IROOT}/vert.x-2.1.5.installed)
[ ! "$RETCODE" == 0 ] || { return 0; }
fw_get http://dl.bintray.com/vertx/downloads/vert.x-2.1.5.tar.gz?direct=true -O vert.x-2.1.5.tar.gz
fw_untar vert.x-2.1.5.tar.gz
wget http://central.maven.org/maven2/org/freemarker/freemarker/2.3.22/freemarker-2.3.22.jar -O ${IROOT}/vert.x-2.1.5/lib/freemarker-2.3.22.jar
touch ${IROOT}/vert.x-2.1.5.installed
View
@@ -4,4 +4,4 @@ source $IROOT/java7.installed
sed -i 's|host: \x27.*\x27|host: \x27'"${DBHOST}"'\x27|g' app.js
${IROOT}/vert.x-2.1.1/bin/vertx run app.js &
${IROOT}/vert.x-2.1.5/bin/vertx run app.js &
View
@@ -1,2 +1,2 @@
./vertx/App.groovy
./vertx/app.js
./vertx/WebServer.java
View
@@ -12,8 +12,8 @@ This is the Express portion of a [benchmarking test suite](../) comparing a vari
## Infrastructure Software Versions
The tests were run with:
* [Node.js v0.10.0](http://nodejs.org/)
* [Express 3.1](http://expressjs.com/)
* [Node.js v0.12.2](http://nodejs.org/)
* [Express 4.12.3](http://expressjs.com/)
## Resources
* http://nodejs.org/api/cluster.html
View
@@ -5,28 +5,56 @@
var cluster = require('cluster')
, numCPUs = require('os').cpus().length
, windows = require('os').platform() == 'win32'
, express = require('express')
, Sequelize = require('sequelize')
, mongoose = require('mongoose')
, async = require('async')
, conn = mongoose.connect('mongodb://localhost/hello_world')
, connMap = { user: 'benchmarkdbuser', password: 'benchmarkdbpass', database: 'hello_world', host: 'localhost', charset: 'utf8' };
, async = require('async');
// Middleware
var bodyParser = require('body-parser')
, methodOverride = require('method-override')
, errorHandler = require('errorhandler');
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
var WorldSchema = new Schema({
id : Number
, randomNumber : Number
}, { collection : 'world' });
var MWorld = conn.model('World', WorldSchema);
if (!windows) {
var Mapper = require('mapper');
Mapper.connect(connMap, {verbose: false, strict: false});
var World = Mapper.map("World", "id", "randomNumber");
var Fortune = Mapper.map("Fortune", "id", "message");
}
var WorldSchema = new mongoose.Schema({
id : Number,
randomNumber: Number
}, {
collection: 'world'
}),
MWorld = conn.model('World', WorldSchema);
var sequelize = new Sequelize('hello_world', 'benchmarkdbuser', 'benchmarkdbpass', {
host: 'localhost',
dialect: 'mysql',
logging: false
});
var World = sequelize.define('World', {
id: {
type: 'Sequelize.INTEGER'
},
randomNumber: {
type: 'Sequelize.INTEGER'
}
}, {
timestamps: false,
freezeTableName: true
});
var Fortune = sequelize.define('Fortune', {
id: {
type: 'Sequelize.INTEGER'
},
message: {
type: 'Sequelize.STRING'
}
}, {
timestamps: false,
freezeTableName: true
});
if (cluster.isMaster) {
// Fork workers.
@@ -41,95 +69,104 @@ if (cluster.isMaster) {
var app = module.exports = express();
// Configuration
app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
// https://github.com/expressjs/method-override#custom-logic
app.use(bodyParser.urlencoded({extended: true}));
app.use(methodOverride(function(req, res){
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
// look in urlencoded POST bodies and delete it
var method = req.body._method
delete req.body._method
return method
}
}));
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
// Set headers for all routes
app.use(function(req, res, next) {
res.setHeader("Server", "Express");
return next();
});
app.configure('development', function() {
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.configure('production', function() {
app.use(express.errorHandler());
});
// Check Node env.
var env = process.env.NODE_ENV || 'development';
if ('development' == env) {
app.use(errorHandler({ dumpExceptions: true, showStack: true }));
}
if ('production' == env) {
app.use(errorHandler());
}
// Routes
app.get('/json', function(req, res) {
res.send({ message: 'Hello, World!' })
res.send({ message: 'Hello, World!' });
});
app.get('/plaintext', function(req, res) {
res.header('Content-Type', 'text/plain').send('Hello, World!');
});
app.get('/mongoose', function(req, res) {
var queries = req.query.queries || 1,
worlds = [],
queryFunctions = [];
var queries = isNaN(req.query.queries) ? 1 : parseInt(req.query.queries, 10)
, queryFunctions = [];
queries = Math.min(Math.max(queries, 1), 500);
for (var i = 1; i <= queries; i++ ) {
queryFunctions.push(function(callback) {
MWorld.findOne({ id: (Math.floor(Math.random() * 10000) + 1 )}).exec(function (err, world) {
worlds.push(world);
callback(null, 'success');
});
MWorld.findOne({ id: (Math.floor(Math.random() * 10000) + 1) }).exec(callback);
});
}
async.parallel(queryFunctions, function(err, results) {
if (queries == 1) {
worlds = worlds[0];
if (!req.query.queries) {
results = results[0];
}
res.send(worlds);
res.send(results);
});
});
app.get('/mysql-orm', function(req, res) {
if (windows) return res.send(501, 'Not supported on windows');
app.get('/mysql-orm', function(req, res) {
var queries = isNaN(req.query.queries) ? 1 : parseInt(req.query.queries, 10)
, worlds = []
, queryFunctions = [];
queries = Math.min(Math.max(queries, 1), 500);
for (var i = 1; i <= queries; i++ ) {
queryFunctions.push(function(callback) {
World.findById(Math.floor(Math.random()*10000) + 1, function (err, world) {
worlds.push(world);
callback(null, 'success');
});
World.findOne({
where: {
id: Math.floor(Math.random() * 10000) + 1}
}
).complete(callback);
});
}
async.parallel(queryFunctions, function(err, results) {
if (!req.query.queries) {
worlds = worlds[0];
results = results[0];
}
res.send(worlds);
res.setHeader("Content-Type", "application/json");
res.send(results);
});
});
app.get('/fortune', function(req, res) {
if (windows) return res.send(501, 'Not supported on windows');
Fortune.all(function (err, fortunes) {
Fortune.findAll().complete(function (err, fortunes) {
var newFortune = {id: 0, message: "Additional fortune added at request time."};
fortunes.push(newFortune);
fortunes.sort(sortFortunes);
fortunes.sort(function (a, b) {
return (a.message < b.message) ? -1 : 1;
});
res.render('fortunes', {fortunes: fortunes});
});
});
function sortFortunes(a, b) {
return (a.message < b.message) ? -1 : (a.message > b.message) ? 1 : 0;
}
app.get('/mongoose-update', function(req, res) {
var queries = req.query.queries || 1
var queries = isNaN(req.query.queries) ? 1 : parseInt(req.query.queries, 10)
, selectFunctions = [];
queries = Math.min(queries, 500);
@@ -163,16 +200,18 @@ if (cluster.isMaster) {
});
app.get('/mysql-orm-update', function(req, res) {
if (windows) return res.send(501, 'Not supported on windows');
var queries = req.query.queries || 1
var queries = isNaN(req.query.queries) ? 1 : parseInt(req.query.queries, 10)
, selectFunctions = [];
queries = Math.min(queries, 500);
queries = Math.max(Math.min(queries, 500), 1);
for (var i = 1; i <= queries; i++ ) {
selectFunctions.push(function(callback) {
World.findById(Math.floor(Math.random() * 10000) + 1, callback);
World.findOne({
where: {
id: Math.floor(Math.random() * 10000) + 1}
}
).complete(callback);
});
}
@@ -183,15 +222,16 @@ if (cluster.isMaster) {
(function(i){
updateFunctions.push(function(callback){
worlds[i].randomNumber = Math.ceil(Math.random() * 10000);
World.save(worlds[i], callback);
worlds[i].save().complete(callback);
});
})(i);
}
async.parallel(updateFunctions, function(err, updates) {
res.send(worlds);
});
});
});
});
app.listen(8080);
View
@@ -4,6 +4,7 @@
"default": {
"setup_file": "setup",
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
View
@@ -3,11 +3,14 @@
, "version": "0.0.1"
, "private": true
, "dependencies": {
"express": "3.1.0"
, "mongoose": "3.5.5"
, "async": "0.2.5"
, "mysql-libmysqlclient": "1.5.2"
, "mapper": "0.2.4-pre"
"express": "4.12.3"
, "body-parser": "1.12.3"
, "method-override": "2.3.2"
, "errorhandler": "1.3.5"
, "mongoose": "4.0.1"
, "async": "0.9.0"
, "jade": "0.29.0"
, "sequelize": "2.0.6"
, "mysql": "2.6.2"
}
}
View
@@ -7,8 +7,8 @@ export NVM_HOME=${IROOT}/nvm
# Used to avoid nvm's return 2 error.
# Sourcing this functions if 0 is returned.
source $NVM_HOME/nvm.sh || 0
nvm install 0.10.8
nvm use 0.10.8
nvm install 0.12.2
nvm use 0.12.2
# update npm before app init
npm install -g npm
View
@@ -12,8 +12,8 @@ This is the Hapi portion of a [benchmarking test suite](../) comparing a variety
## Infrastructure Software Versions
The tests were run with:
* [Node.js v0.10.0](http://nodejs.org/)
* [Hapi 1.2.0](http://spumko.github.io/)
* [Node.js v0.12.2](http://nodejs.org/)
* [Hapi 8.4.0](http://hapijs.com/)
## Resources
* http://nodejs.org/api/cluster.html
View
@@ -4,12 +4,11 @@
var cluster = require('cluster'),
numCPUs = require('os').cpus().length,
windows = require('os').platform() == 'win32',
Hapi = require('hapi'),
Sequelize = require('sequelize'),
mongoose = require('mongoose'),
async = require('async'),
conn = mongoose.connect('mongodb://localhost/hello_world'),
connMap = { user: 'benchmarkdbuser', password: 'benchmarkdbpass', database: 'hello_world', host: 'localhost', charset: 'utf8' };
async = require('async');
var WorldSchema = new mongoose.Schema({
id : Number,
@@ -19,12 +18,34 @@ var WorldSchema = new mongoose.Schema({
}),
MWorld = conn.model('World', WorldSchema);
if (!windows) {
var Mapper = require('mapper');
Mapper.connect(connMap, {verbose: false, strict: false});
var World = Mapper.map('World', 'id', 'randomNumber');
var Fortune = Mapper.map('Fortune', 'id', 'message');
}
var sequelize = new Sequelize('hello_world', 'benchmarkdbuser', 'benchmarkdbpass', {
host: 'localhost',
dialect: 'mysql',
logging: false
});
var World = sequelize.define('World', {
id: {
type: 'Sequelize.INTEGER'
},
randomNumber: {
type: 'Sequelize.INTEGER'
}
}, {
timestamps: false,
freezeTableName: true
});
var Fortune = sequelize.define('Fortune', {
id: {
type: 'Sequelize.INTEGER'
},
message: {
type: 'Sequelize.STRING'
}
}, {
timestamps: false,
freezeTableName: true
});
if (cluster.isMaster) {
// Fork workers.
@@ -36,28 +57,38 @@ if (cluster.isMaster) {
console.log('worker ' + worker.pid + ' died');
});
} else {
var server = module.exports = Hapi.createServer(null, 8080, {
views: {
engines: {
handlebars: 'handlebars'
},
path: __dirname + '/views'
}
var server = module.exports = new Hapi.Server();
server.connection({port: 8080});
server.views({
engines: {
html: require('handlebars')
},
path: __dirname + '/views'
});
server.route({
method: 'GET',
path: '/json',
handler: function(req) {
req.reply({ message: 'Hello, World!' })
handler: function(req, reply) {
reply({ message: 'Hello, World!' }).header('Server', 'hapi');
}
});
server.route({
method: 'GET',
path: '/plaintext',
handler: function(req, reply) {
reply('Hello, World!')
.header('Server', 'hapi')
.header('Content-Type', 'text/plain');
}
});
server.route({
method: 'GET',
path: '/mongoose/{queries?}',
handler: function(req){
var queries = req.params.queries || 1,
handler: function(req, reply){
var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
queryFunctions = [];
queries = Math.min(Math.max(queries, 1), 500);
@@ -69,10 +100,10 @@ if (cluster.isMaster) {
}
async.parallel(queryFunctions, function(err, results){
if (queries == 1) {
if (!req.params.queries) {
results = results[0];
}
req.reply(results).header('Server', 'hapi');
reply(results).header('Server', 'hapi');
});
}
});
@@ -81,16 +112,18 @@ if (cluster.isMaster) {
method: 'GET',
path: '/mysql-orm/{queries?}',
handler: function(req, reply){
if (windows) return req.reply(Hapi.error.internal('Not supported on windows'));
var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
queryFunctions = [];
queries = Math.min(Math.max(queries, 1), 500);
for (var i = 1; i <= queries; i++) {
queryFunctions.push(function(callback){
World.findById(Math.floor(Math.random() * 10000) + 1, callback);
World.findOne({
where: {
id: Math.floor(Math.random() * 10000) + 1}
}
).complete(callback);
});
}
@@ -106,10 +139,8 @@ if (cluster.isMaster) {
server.route({
method: 'GET',
path: '/fortune',
handler: function(req){
if (windows) return req.reply(Hapi.error.internal('Not supported on windows'));
Fortune.all(function(err, fortunes){
handler: function(req,reply){
Fortune.findAll().complete(function(err, fortunes){
fortunes.push({
id: 0,
message: 'Additional fortune added at request time.'
@@ -118,7 +149,7 @@ if (cluster.isMaster) {
return (a.message < b.message) ? -1 : 1;
});
req.reply.view('fortunes.handlebars', {
reply.view('fortunes', {
fortunes: fortunes
}).header('Server', 'hapi');
});
@@ -128,8 +159,8 @@ if (cluster.isMaster) {
server.route({
method: 'GET',
path: '/mongoose-update/{queries?}',
handler: function(req){
var queries = req.params.queries || 1,
handler: function(req, reply){
var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
selectFunctions = [];
queries = Math.max(Math.min(queries, 500), 1);
@@ -157,7 +188,7 @@ if (cluster.isMaster) {
}
async.parallel(updateFunctions, function(err, updates) {
req.reply(worlds).header('Server', 'hapi');
reply(worlds).header('Server', 'hapi');
});
});
}
@@ -166,15 +197,19 @@ if (cluster.isMaster) {
server.route({
method: 'GET',
path: '/mysql-orm-update/{queries?}',
handler: function(req){
var queries = req.params.queries || 1,
handler: function(req,reply){
var queries = isNaN(req.params.queries) ? 1 : parseInt(req.params.queries, 10),
selectFunctions = [];
queries = Math.max(Math.min(queries, 500), 1);
for (var i = 1; i <= queries; i++) {
selectFunctions.push(function(callback){
World.findById(Math.floor(Math.random() * 10000) + 1, callback);
World.findOne({
where: {
id: Math.floor(Math.random() * 10000) + 1}
}
).complete(callback);
});
}
@@ -185,13 +220,13 @@ if (cluster.isMaster) {
(function(i){
updateFunctions.push(function(callback){
worlds[i].randomNumber = Math.ceil(Math.random() * 10000);
World.save(worlds[i], callback);
worlds[i].save().complete(callback);
});
})(i);
}
async.parallel(updateFunctions, function(err, updates) {
req.reply(worlds).header('Server', 'hapi');
reply(worlds).header('Server', 'hapi');
});
});
}
View
@@ -4,6 +4,7 @@
"default": {
"setup_file": "setup",
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
View
@@ -3,10 +3,11 @@
"version": "0.0.1",
"private": true,
"dependencies": {
"hapi": "1.2.0",
"mongoose": "3.5.5",
"async": "0.2.5",
"mapper": "0.2.4-pre",
"handlebars": "1.0.11"
"hapi": "8.4.0",
"mongoose": "4.0.1",
"async": "0.9.0",
"handlebars": "3.0.1",
"sequelize": "2.0.6",
"mysql": "2.6.2"
}
}
View
@@ -6,8 +6,8 @@ export NVM_HOME=${IROOT}/nvm
# Used to avoid nvm's return 2 error.
# Sourcing this functions if 0 is returned.
source $NVM_HOME/nvm.sh || 0
nvm install 0.10.8
nvm use 0.10.8
nvm install 0.12.2
nvm use 0.12.2
# update npm before app init
npm install -g npm
View
File renamed without changes.
View
@@ -80,16 +80,19 @@ if (cluster.isMaster) {
// Route handlers
function *jsonHandler() {
this.set('Server', 'Koa');
this.body = {
message: "Hello, world!"
}
}
function *dbHandler() {
this.set('Server', 'Koa');
this.body = yield worldQuery;
}
function *queriesHandler() {
this.set('Server', 'Koa');
var numOfQueries = validateParam(this.query.queries);
var queries = [];
for (var i = 0; i < numOfQueries; i++) {
@@ -112,6 +115,7 @@ if (cluster.isMaster) {
}
function *updateHandler() {
this.set('Server', 'Koa');
var numOfUpdates = validateParam(this.query.queries);
var queries = [];
for (var i = 0; i < numOfUpdates; i++) {
@@ -121,6 +125,7 @@ if (cluster.isMaster) {
}
function *textHandler() {
this.set('Server', 'Koa');
this.body = 'Hello, world!';
}
View
@@ -6,8 +6,8 @@ export NVM_HOME=${IROOT}/nvm
# Used to avoid nvm's return 2 error.
# Sourcing this functions if 0 is returned.
source $NVM_HOME/nvm.sh || 0
nvm install 0.11.16
nvm use 0.11.16
nvm install 0.12.2
nvm use 0.12.2
# update npm before app init
npm install -g npm
View
@@ -12,23 +12,31 @@ This is the NodeJS portion of a [benchmarking test suite](../) comparing a varie
## Infrastructure Software Versions
The tests were run with:
* [Node.js v0.10.0](http://nodejs.org/)
* [Mongoose 3.5.5](http://mongoosejs.com/)
* [Mapper 0.2.4-pre](https://github.com/mgutz/mapper)
* [MySQL 5.5.29](https://dev.mysql.com/)
* [Node.js v0.12.2](http://nodejs.org/)
* [Mongoose 4.0.1](http://mongoosejs.com/)
* [Sequelize 2.0.6](https://github.com/sequelize/sequelize)
* [Node MySQL 2.6.2](https://github.com/felixge/node-mysql/)
* [Node MongoDB Driver 2.0.27](https://github.com/mongodb/node-mongodb-native)
## Test URLs
### JSON Encoding Test
http://localhost:8080/json
### Plaintext Test
http://localhost:8080/plaintext
### Data-Store/Database Mapping Test
MongoDB:
http://localhost:8080/mongoose
MongoDB Raw:
http://localhost:8080/mongodb
MySQL:
http://localhost:8080/sequelize
http://localhost:8080/mysql-orm
MySQL Raw:
http://localhost:8080/mysql
@@ -38,6 +46,9 @@ http://localhost:8080/mysql
MongoDB:
http://localhost:8080/mongoose?queries=2
MongoDB Raw:
http://localhost:8080/mongodb?queries=2
MySQL:
http://localhost:8080/mysql-orm?queries=2
View
@@ -24,6 +24,7 @@
"setup_file": "setup",
"db_url": "/mongoose",
"query_url": "/mongoose?queries=",
"update_url": "/mongoose-update?queries=",
"port": 8080,
"approach": "Realistic",
"classification": "Platform",
@@ -41,9 +42,9 @@
},
"mongodb-raw": {
"setup_file": "setup",
"db_url": "/mongodbdriver",
"query_url": "/mongodbdriver?queries=",
"update_url": "/update-mongodb?queries=",
"db_url": "/mongodb",
"query_url": "/mongodb?queries=",
"update_url": "/mongodb-update?queries=",
"port": 8080,
"approach": "Realistic",
"classification": "Platform",
@@ -63,6 +64,7 @@
"setup_file": "setup",
"db_url": "/mysql-orm",
"query_url": "/mysql-orm?queries=",
"update_url": "/mysql-orm-update?queries=",
"port": 8080,
"approach": "Realistic",
"classification": "Platform",
@@ -82,7 +84,7 @@
"setup_file": "setup",
"db_url": "/mysql",
"query_url": "/mysql?queries=",
"update_url": "/update?queries=",
"update_url": "/mysql-update?queries=",
"port": 8080,
"approach": "Realistic",
"classification": "Platform",
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -3,11 +3,11 @@
, "version": "0.0.1"
, "private": true
, "dependencies": {
"mongoose": "3.5.5"
, "async": "0.2.5"
, "mysql-libmysqlclient": "1.5.2"
, "mapper": "0.2.4-pre"
, "mongodb": "1.3.0"
"mongoose": "4.0.1"
, "async": "0.9.0"
, "mongodb": "2.0.27"
, "sequelize": "2.0.6"
, "mysql": "2.6.2"
}
, "main": "hello.js"
}
View
@@ -7,8 +7,8 @@ export NVM_HOME=${IROOT}/nvm
# Used to avoid nvm's return 2 error.
# Sourcing this functions if 0 is returned.
source $NVM_HOME/nvm.sh || 0
nvm install 0.10.8
nvm use 0.10.8
nvm install 0.12.2
nvm use 0.12.2
# update npm before app init
npm install -g npm
View
@@ -1,18 +1,19 @@
local config
do
local _obj_0 = require("lapis.config")
config = _obj_0.config
end
config = require("lapis.config").config
config("development", function() end)
return config("production", function()
return config({
"production",
"development"
}, function()
port(80)
num_workers(4)
lua_code_cache("on")
return postgres({
backend = "pgmoon",
database = "hello_world",
user = "benchmarkdbuser",
password = "benchmarkdbpass",
host = "DBHOSTNAME"
})
logging(false)
return postgres(function()
backend("pgmoon")
database("hello_world")
user("benchmarkdbuser")
password("benchmarkdbpass")
return host("DBHOSTNAME")
end)
end)
View
@@ -2,14 +2,14 @@ import config from require "lapis.config"
config "development", ->
config "production", ->
config {"production", "development"}, ->
port 80
num_workers 4
lua_code_cache "on"
postgres {
backend: "pgmoon"
database: "hello_world"
user: "benchmarkdbuser"
password: "benchmarkdbpass"
host: "DBHOSTNAME"
}
logging false
postgres ->
backend "pgmoon"
database "hello_world"
user "benchmarkdbuser"
password "benchmarkdbpass"
host "DBHOSTNAME"
View
@@ -1,6 +1,6 @@
worker_processes auto;
# pid /tmp/nginx.pid;
error_log stderr crit;
error_log stderr notice;
#error_log /tmp/test.log error;
env LAPIS_ENVIRONMENT;
daemon off;
@@ -26,7 +26,6 @@
location / {
default_type text/html;
set $_url "";
content_by_lua_file "loader.lua";
}
View
@@ -3,6 +3,12 @@ local mysql = mysql
local encode = encode
local random = math.random
local min = math.min
local insert = table.insert
local sort = table.sort
local template = require'resty.template'
template.caching(false)
-- Compile template, disable cache, enable plain text view to skip filesystem loading
local view = template.compile([[<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{% for _,f in ipairs(fortunes) do %}<tr><td>{{ f.id }}</td><td>{{ f.message }}</td></tr>{% end %}</table></body></html>]], nil, true)
local mysqlconn = {
host = "DBHOSTNAME",
@@ -11,24 +17,48 @@ local mysqlconn = {
user = "benchmarkdbuser",
password = "benchmarkdbpass"
}
return function(ngx)
local db = mysql:new()
assert(db:connect(mysqlconn))
local num_queries = tonumber(ngx.var.arg_queries) or 1
-- May seem like a stupid branch, but since we know that
-- at a benchmark it will always be taken one way,
-- it doesn't matter. For me, after a small warmup, the performance
-- is identical to a version without the branch
-- http://wiki.luajit.org/Numerical-Computing-Performance-Guide
if num_queries == 1 then
ngx.print(encode(db:query('SELECT * FROM World WHERE id = '..random(1,10000))[1]))
else
local worlds = {}
num_queries = min(500, num_queries)
for i=1, num_queries do
worlds[#worlds+1] = db:query('SELECT * FROM World WHERE id = '..random(1,10000))[1]
end
ngx.print( encode(worlds) )
end
db:set_keepalive(0, 256)
end
return {
db = function(ngx)
local db = mysql:new()
assert(db:connect(mysqlconn))
ngx.print(encode(db:query('SELECT * FROM World WHERE id = '..random(1,10000))[1]))
db:set_keepalive(0, 256)
end,
queries = function(ngx)
local db = mysql:new()
assert(db:connect(mysqlconn))
local num_queries = tonumber(ngx.var.arg_queries) or 1
-- May seem like a stupid branch, but since we know that
-- at a benchmark it will always be taken one way,
-- it doesn't matter. For me, after a small warmup, the performance
-- is identical to a version without the branch
-- http://wiki.luajit.org/Numerical-Computing-Performance-Guide
if num_queries < 2 then
ngx.print(encode({db:query('SELECT * FROM World WHERE id = '..random(1,10000))[1]}))
else
local worlds = {}
num_queries = min(500, num_queries)
for i=1, num_queries do
worlds[#worlds+1] = db:query('SELECT * FROM World WHERE id = '..random(1,10000))[1]
end
ngx.print( encode(worlds) )
end
db:set_keepalive(0, 256)
end,
fortunes = function(ngx)
local db = mysql:new()
assert(db:connect(mysqlconn))
local fortunes = db:query('SELECT * FROM Fortune')
insert(fortunes, {
id = 0,
message = "Additional fortune added at request time."
})
sort(fortunes, function(a, b)
return a.message < b.message
end)
local res = view{fortunes=fortunes}
ngx.header['Content-Length'] = #res
ngx.print(res)
db:set_keepalive(0, 256)
end
}
View
@@ -5,7 +5,8 @@
"setup_file": "setup",
"json_url": "/json",
"db_url": "/db",
"query_url": "/db?queries=",
"query_url": "/queries?queries=",
"fortune_url": "/fortunes",
"plaintext_url": "/plaintext",
"port": 8080,
"approach": "Realistic",
View
@@ -1,3 +1,5 @@
#!/bin/bash
fw_depends lua nginx openresty
fw_depends lua openresty
sudo luarocks install --server=http://rocks.moonscript.org lua-resty-template
View
@@ -9,7 +9,7 @@ http {
resolver 127.0.0.1;
access_log off;
lua_package_path 'CWD/?.lua;;';
init_by_lua 'jit.opt.start("minstitch=10"); require "resty.core" encode = require("cjson").encode mysql = require("resty.mysql")';
init_by_lua 'jit.opt.start("minstitch=10"); require "resty.core" encode = require("cjson").encode mysql = require("resty.mysql") app = require("app")';
server {
listen 8080;
location /plaintext {
@@ -21,8 +21,17 @@ http {
default_type "application/json";
content_by_lua 'ngx.print(encode({message = "Hello, World!"}))';
}
location /fortunes {
default_type "text/html; charset=UTF-8";
content_by_lua 'app.fortunes(ngx)';
}
location /db {
default_type "application/json";
content_by_lua 'app.db(ngx)';
}
location / {
content_by_lua 'require("app")(ngx)';
default_type "application/json";
content_by_lua 'app.queries(ngx)';
}
}
}
View
@@ -16,7 +16,7 @@
|
*/
'driver' => 'file',
'driver' => 'array',
/*
|--------------------------------------------------------------------------
View
@@ -1,16 +1,37 @@
worker_processes 8;
events {
worker_connections 1024;
worker_connections 2048;
multi_accept on;
use epoll;
}
http {
include /home/vagrant/FrameworkBenchmarks/installs/nginx/conf/mime.types;
default_type application/octet-stream;
access_log off;
sendfile on;
keepalive_timeout 65;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
open_file_cache max=2000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 5;
open_file_cache_errors off;
#FastCGI optimizations
fastcgi_buffers 256 16k;
fastcgi_buffer_size 128k;
fastcgi_connect_timeout 30s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
reset_timedout_connection on;
server_names_hash_bucket_size 100;
upstream fastcgi_backend {
server 127.0.0.1:9001;
@@ -39,4 +60,4 @@ http {
include /home/vagrant/FrameworkBenchmarks/installs/nginx/conf/fastcgi_params;
}
}
}
}
View
@@ -8,4 +8,5 @@ fw_depends php nginx composer
${PHP_HOME}/bin/php ${COMPOSER_HOME}/composer.phar install \
--no-interaction --working-dir ${TROOT} \
--no-progress --optimize-autoloader
php artisan optimize --force
View
@@ -0,0 +1,38 @@
# Twisted Klein Benchmark Test
This is the Klein portion of a [benchmarking tests suite](../../)
comparing a variety of web development platforms.
The information below is specific to Klein. For further guidance,
review the [documentation](http://frameworkbenchmarks.readthedocs.org/en/latest/).
Also note that there is additional information provided in
the [Python README](../).
## Description
Klein framework (https://github.com/twisted/klein)
## Infrastructure Software
### Server
* gunicorn+meinheld on CPython
* Tornado on PyPy
## Test Paths & Sources
All of the test implementations are located within a single file ([app.py](app.py)).
* [JSON Serialization](app.py): "/json"
* [Single Database Query](app.py): "/db"
* [Multiple Database Queries](app.py): "/queries?queries=5"
* [Fortunes](app.py): "/fortune"
* [Database Updates](app.py): "/updates?queries=5"
* [Plaintext](app.py): "/plaintext"
## Get Help
### Resources
* [Klein Source Code](https://github.com/twisted/klein)
View
@@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
import os
import sys
import json
import bleach
from random import randint
from functools import partial
from operator import attrgetter
from klein import Klein, run, route
from jinja2 import Environment, PackageLoader
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Column
from sqlalchemy.types import String, Integer, Unicode
from sqlalchemy.orm import sessionmaker
if sys.version_info[0] == 3:
xrange = range
DBDRIVER = 'mysql'
DBHOSTNAME = os.environ.get('DBHOST', 'localhost')
DATABASE_URI = '%s://benchmarkdbuser:benchmarkdbpass@%s:3306/hello_world?charset=utf8' % (DBDRIVER, DBHOSTNAME)
Base = declarative_base()
db_engine = create_engine(DATABASE_URI)
Session = sessionmaker(bind=db_engine)
db_session = Session()
env = Environment(loader=PackageLoader("app", "templates"))
app = Klein()
class Fortune(Base):
__tablename__ = "Fortune"
id = Column(Integer, primary_key=True)
message = Column(String)
def serialize(self):
return {
'id': self.id,
'randomNumber': self.randomNumber,
}
class World(Base):
__tablename__ = "World"
id = Column(Integer, primary_key=True)
randomNumber = Column(Integer)
def serialize(self):
return {
'id': self.id,
'randomNumber': self.randomNumber,
}
def getQueryNum(queryString):
try:
num_queries = int(queryString)
if num_queries < 1:
return 1
if num_queries > 500:
return 500
return num_queries
except ValueError:
return 1
@app.route("/plaintext")
def plaintext(request):
request.setHeader("Content-Type", "text/plain; charset=UTF-8")
return "Hello, World!"
@app.route("/json")
def jsonHandler(request):
request.setHeader("Content-Type", "application/json; charset=UTF-8")
return json.dumps({"message": "Hello, World!"})
@app.route("/db")
def db(request):
request.setHeader("Content-Type", "application/json; charset=UTF-8")
wid = randint(1, 10000)
world = db_session.query(World).get(wid).serialize()
return json.dumps(world)
@app.route("/queries")
def queries(request):
request.setHeader("Content-Type", "application/json; charset=UTF-8")
num_queries = getQueryNum(request.args.get("queries")[0])
rp = partial(randint, 1, 10000)
get = db_session.query(World).get
worlds = [get(rp()).serialize() for _ in xrange(num_queries)]
return json.dumps(worlds)
@app.route("/updates")
def updates(request):
request.setHeader("Content-Type", "application/json; charset=UTF-8")
num_queries = getQueryNum(request.args.get("queries")[0])
worlds = []
rp = partial(randint, 1, 10000)
ids = [rp() for _ in xrange(num_queries)]
ids.sort()
for id in ids:
world = db_session.query(World).get(id)
world.randomNumber = rp()
worlds.append(world.serialize())
db_session.commit()
return json.dumps(worlds)
@app.route("/fortune")
def fortune(request):
request.setHeader("Content-Type", "text/html; charset=UTF-8")
fortunes = db_session.query(Fortune).all()
fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
fortunes.sort(key=attrgetter("message"))
for f in fortunes:
f.message = bleach.clean(f.message)
template = env.get_template("fortunes.html")
return template.render(fortunes=fortunes)
if __name__ == "__main__":
app.run("0.0.0.0", 8080)
View
@@ -0,0 +1,27 @@
{
"framework": "klein",
"tests": [{
"default": {
"setup_file": "setup",
"json_url": "/json",
"db_url": "/db",
"query_url": "/queries?queries=",
"fortune_url": "/fortune",
"update_url": "/updates?queries=",
"plaintext_url": "/plaintext",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "MySQL",
"framework": "Twisted Klein",
"language": "Python",
"orm": "Full",
"platform": "Twisted Web",
"webserver": "None",
"os": "Linux",
"database_os": "Linux",
"display_name": "Twisted Klein",
"notes": "CPython 2.7"
}
}]
}
View
@@ -0,0 +1,19 @@
#!/bin/bash
export PY2_ROOT=$IROOT/py2
export PY2=$PY2_ROOT/bin/python
export PY2_PIP=$PY2_ROOT/bin/pip
export PY3_ROOT=$IROOT/py3
export PY3=$PY3_ROOT/bin/python3
export PY3_PIP=$PY3_ROOT/bin/pip3
mkdir -p $IROOT/.pip_cache
export PIP_DOWNLOAD_CACHE=$IROOT/.pip_cache
fw_depends python2 python3
$PY2_PIP install --install-option="--prefix=${PY2_ROOT}" -r $TROOT/requirements.txt
$PY3_PIP install --install-option="--prefix=${PY3_ROOT}" -r $TROOT/requirements.txt
View
@@ -0,0 +1,6 @@
klein==15.0.0
bleach==1.4.1
mysqlclient==1.3.6
SQLAlchemy==0.9.9
jinja2==2.7.3
View
@@ -0,0 +1,6 @@
#!/bin/bash
export PY2_ROOT=$IROOT/py2
export PY2=$PY2_ROOT/bin/python
$PY2 app.py &
View
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Fortunes</title>
</head>
<body>
<table>
<tr>
<th>id</th>
<th>message</th>
</tr>
{%for fortune in fortunes %}
<tr>
<td>{{ fortune.id }}</td>
<td>{{ fortune.message }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
View
@@ -1,11 +1,16 @@
import codecs
import os
from frameworkbenchmarks.models import DBSession
FWROOT = os.environ.get('FWROOT', '../../..')
if __name__ == "__main__":
"""
Initialize database
"""
with codecs.open('../config/create-postgres.sql', 'r', encoding='utf-8') as fp:
with codecs.open('%s/config/create-postgres.sql' % FWROOT,
'r',
encoding='utf-8') as fp:
sql = fp.read()
DBSession.execute(sql)
DBSession.commit()
View
@@ -56,7 +56,7 @@ def test_queries_999(self):
res = self._get('/queries?queries=999')
self.assertEqual(len(json.loads(self._str_compat(res.body))), 500)
def test_queries_999(self):
def test_queries_10(self):
"""
/queries?queries=10 objects
"""
View
@@ -5,6 +5,7 @@
from random import randint
from pyramid.view import view_config
from pyramid.response import Response
from frameworkbenchmarks.models import DBSession, World, Fortune
@@ -91,7 +92,8 @@ def test_6(request):
"""
Test type 6: Plaintext
"""
response = request.response
response.text = u"Hello, World!" # py2k/3k
response.content_type = "text/plain"
response = Response(
body=b'Hello, World!',
content_type='text/plain',
)
return response
View
@@ -84,7 +84,7 @@ def fortune(self):
fortunes.sort(key=attrgetter("message"))
for f in fortunes:
f.message = bleach.clean(f.message)
template = env.get_template("fortunes.html")
template = env.get_template("fortunes.html")
return template.render(fortunes=fortunes)
config = AppConfig(minimal=True, root_controller=RootController())
View
@@ -0,0 +1,8 @@
target/
project/target
bin/
logs/
.cache
.classpath
.project
/bin/
View
@@ -0,0 +1,30 @@
#colossus Benchmarking Test
### JSON Encoding Test
* [JSON test source](src/main/scala/example/Main.scala)
### Plaintext Test
* [JSON test source](src/main/scala/example/Main.scala)
## Infrastructure Software Versions
The tests were run with:
* [Java Oracle 1.8.0_25](http://www.oracle.com/technetwork/java/javase)
* [colossus 0.6.1](http://tumblr.github.io/colossus/)
## Test URLs
### JSON Encoding Test
http://localhost:9007/json
### Plaintext Test
http://localhost:9007/plaintext
## How to run
sbt 'oneJar'
java -jar target/scala-2.11/colossus*one-jar.jar
View
@@ -0,0 +1,23 @@
{
"framework": "colossus",
"tests": [{
"default": {
"orm": "Raw",
"database_os": "Linux",
"setup_file": "setup",
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 9007,
"approach": "Realistic",
"classification": "Micro",
"database": "None",
"framework": "colossus",
"language": "Scala",
"platform": "Akka",
"webserver": "None",
"os": "Linux",
"display_name": "colossus",
"notes": ""
}
}]
}
View
@@ -0,0 +1,14 @@
name := """colossus-example"""
version := "0.1.0"
scalaVersion := "2.11.5"
com.github.retronym.SbtOneJar.oneJarSettings
mainClass in oneJar := Some("example.Main")
libraryDependencies ++= Seq(
"com.tumblr" %% "colossus" % "0.6.1",
"net.liftweb" %% "lift-json" % "2.6-RC1"
)
View
@@ -0,0 +1,3 @@
#!/bin/bash
fw_depends java8 sbt
View
@@ -0,0 +1 @@
addSbtPlugin("org.scala-sbt.plugins" % "sbt-onejar" % "0.8")
View
@@ -0,0 +1,9 @@
#!/bin/bash
source $IROOT/java8.installed
export SBT_HOME=${IROOT}/sbt
${SBT_HOME}/bin/sbt 'oneJar'
java -jar target/scala-2.11/colossus*one-jar.jar
View
@@ -0,0 +1,38 @@
package example
import java.util.Date
import java.text.SimpleDateFormat
import colossus._
import service._
import protocols.http._
import UrlParsing._
import HttpMethod._
import net.liftweb.json._
import JsonDSL._
object Main extends App {
implicit val io_system = IOSystem()
Service.become[Http]("sample", 9007) {
case request @ Get on Root / "json" => {
val json = ("message" -> "Hello, World!")
val sdf = new SimpleDateFormat("EEE, MMM d yyyy HH:MM:ss z")
val v = request.ok(compact(render(json)))
.withHeader("Content-Type", "application/json")
.withHeader("Server", "Colossus")
.withHeader("Date", sdf.format(new Date()))
Callback.successful(v)
}
case request @ Get on Root / "plaintext" => {
val sdf = new SimpleDateFormat("EEE, MMM d yyyy HH:MM:ss z")
val res = request.ok("Hello, World!")
.withHeader("Content-Type", "text/plain")
.withHeader("Server", "Colossus")
.withHeader("Date", sdf.format(new Date()))
Callback.successful(res)
}
}
}
View
@@ -0,0 +1,3 @@
target
projet/target
.cache
View
@@ -0,0 +1,26 @@
#http4s Benchmarking Test
### JSON Encoding Test
* [JSON test source](src/main/scala/code/lib/WebServer.scala)
## Infrastructure Software Versions
The tests were run with:
* [Java Oracle 1.8.0_25](http://www.oracle.com/technetwork/java/javase)
* [http4s 0.6.2](http://http4s.org/)
* [blaze 0.6.2](https://github.com/http4s/blaze/)
## Test URLs
### JSON Encoding Test
http://localhost:8080/json
### Plaintext Test
http://localhost:8080/plaintext
## How to run
sbt 'oneJar'
java -jar target/scala-2.11/http4s_2.11-1.0-SNAPSHOT-one-jar.jar
View
@@ -0,0 +1,23 @@
{
"framework": "http4s",
"tests": [{
"default": {
"orm": "Raw",
"database_os": "Linux",
"setup_file": "setup",
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "None",
"framework": "http4s",
"language": "Scala",
"platform": "NIO2",
"webserver": "blaze",
"os": "Linux",
"display_name": "http4s",
"notes": ""
}
}]
}
View
@@ -0,0 +1,17 @@
name := "http4s"
version := "1.0-SNAPSHOT"
scalaVersion := "2.11.6"
com.github.retronym.SbtOneJar.oneJarSettings
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-blazeserver" % "0.6.2",
"org.http4s" %% "http4s-dsl" % "0.6.2",
"org.http4s" %% "http4s-argonaut" % "0.6.2"
)
mainClass in oneJar := Some("WebServer")
resolvers += "Bintray" at "http://dl.bintray.com/pchiusano/maven/"
View
@@ -0,0 +1,3 @@
#!/bin/bash
fw_depends java8 sbt
View
@@ -0,0 +1 @@
addSbtPlugin("org.scala-sbt.plugins" % "sbt-onejar" % "0.8")
View
@@ -0,0 +1,9 @@
#!/bin/bash
source $IROOT/java8.installed
export SBT_HOME=${IROOT}/sbt
#${SBT_HOME}/bin/sbt compile
${SBT_HOME}/bin/sbt 'oneJar'
java -jar target/scala-2.11/http4s*one-jar.jar
View
@@ -0,0 +1,29 @@
import org.http4s._
import org.http4s.server._
import org.http4s.dsl._
import org.http4s.argonaut._
import org.http4s.server.blaze.BlazeBuilder
import headers._
import _root_.argonaut._, Argonaut._
object WebServer extends App {
val service = HttpService {
case GET -> Root / "json" =>
val dateHeader = Date(DateTime(4))
Ok(Json("message" -> jString("Hello, World!")).asJson)
.withHeaders(dateHeader)
.withContentType(Some(`Content-Type`(MediaType.`application/json`)))
case GET -> Root / "plaintext" =>
val dateHeader = Date(DateTime(4))
Ok("Hello, World!")
.withHeaders(dateHeader)
.withContentType(Some(`Content-Type`(MediaType.`text/plain`)))
}
BlazeBuilder.bindHttp(8080)
.mountService(service, "/")
.run
.awaitShutdown()
}
View
@@ -18,7 +18,8 @@
"notes": "",
"versus": "netty",
"port": "9000",
"json_url": "/json"
"json_url": "/json",
"plaintext_url": "/plaintext"
},
"activate": {
"display_name": "play2-scala-activate",
View
@@ -9,4 +9,14 @@ object Application extends Controller {
Ok(Json.obj("message" -> "Hello, World!"))
}
def plaintext() = Action {
import java.util.Date
import java.text.SimpleDateFormat
val sdf = new SimpleDateFormat("EEE, MMM d yyyy HH:MM:ss z")
Ok("Hello, World!")
.withHeaders(
DATE -> sdf.format(new Date()),
SERVER -> "Play Framework 2.3.3")
}
}
View
@@ -4,6 +4,7 @@
# Home page
GET /json controllers.Application.json
GET /plaintext controllers.Application.plaintext
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
View
@@ -1,6 +1,6 @@
#!/bin/bash
VERSION=20150103
VERSION=20150412
COMPILER=${IROOT}/urweb
RETCODE=$(fw_exists $COMPILER)
View
@@ -715,13 +715,14 @@ def is_port_bound(self, port):
# shutdown properly.
############################################################
def __is_port_bound(self, port):
port = int(port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Try to bind to all IP addresses, this port
s.bind(("", port))
# If we get here, we were able to bind successfully,
# which means the port is free.
except Exception:
except socket.error:
# If we get an exception, it might be because the port is still bound
# which would be bad, or maybe it is a privileged port (<1024) and we
# are not running as root, or maybe the server is gone, but sockets are
@@ -732,7 +733,7 @@ def __is_port_bound(self, port):
# If we get here, we were able to connect to something, which means
# that the port is still bound.
return True
except Exception:
except socket.error:
# An exception means that we couldn't connect, so a server probably
# isn't still running on the port.
pass
View
@@ -256,7 +256,7 @@ def tee_output(prefix, line):
"%s: %s.sh and framework processes have terminated" % (self.name, self.setup_file))
# Set a limit on total execution time of setup.sh
timeout = datetime.now() + timedelta(minutes = 20)
timeout = datetime.now() + timedelta(minutes = 105)
time_remaining = timeout - datetime.now()
# Need to print to stdout once every 10 minutes or Travis-CI will abort
@@ -274,9 +274,9 @@ def tee_output(prefix, line):
# output to the pipes.
#
prefix = "Setup %s: " % self.name
while not (p.poll()
or self.benchmarker.is_port_bound(self.port)
or time_remaining.total_seconds() < 0):
while (p.poll() is None
and not self.benchmarker.is_port_bound(self.port)
and not time_remaining.total_seconds() < 0):
# The conditions above are slow to check, so
# we will delay output substantially if we only
@@ -301,6 +301,8 @@ def tee_output(prefix, line):
if (travis_timeout - datetime.now()).total_seconds() < 0:
sys.stdout.write(prefix + 'Printing so Travis-CI does not time out\n')
sys.stdout.write(prefix + "Status: Poll: %s, Port %s bound: %s, Time Left: %s\n" % (
p.poll(), self.port, self.benchmarker.is_port_bound(self.port), time_remaining))
sys.stdout.flush()
travis_timeout = datetime.now() + timedelta(minutes = 5)
@@ -313,8 +315,10 @@ def tee_output(prefix, line):
# What's our return code?
# If setup.sh has terminated, use that code
# Otherwise, detect if the port was bound
retcode = (p.poll() or 0 if self.benchmarker.is_port_bound(self.port) else 1)
if p.poll():
tee_output(prefix, "Status: Poll: %s, Port %s bound: %s, Time Left: %s\n" % (
p.poll(), self.port, self.benchmarker.is_port_bound(self.port), time_remaining))
retcode = (p.poll() if p.poll() is not None else 0 if self.benchmarker.is_port_bound(self.port) else 1)
if p.poll() is not None:
tee_output(prefix, "%s.sh process exited naturally with %s\n" % (self.setup_file, p.poll()))
elif self.benchmarker.is_port_bound(self.port):
tee_output(prefix, "Bound port detected on %s\n" % self.port)
View

This file was deleted.

Oops, something went wrong.