Skip to content

Commit

Permalink
Adding ES4X to the JavaScript frameworks (#4039)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmlopes authored and michaelhixson committed Sep 15, 2018
1 parent dd87c72 commit cffabe9
Show file tree
Hide file tree
Showing 7 changed files with 431 additions and 0 deletions.
41 changes: 41 additions & 0 deletions frameworks/JavaScript/es4x/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# ES4X Benchmarking Test

### Test Type Implementation Source Code

* [JSON](index.js#L24-L30)
* [PLAINTEXT](index.js#L233-L239)
* [DB](index.js#L50-L71)
* [QUERY](index.js#L78-L108)
* [UPDATE](index.js#L171-L225)
* [FORTUNES](index.js#L114-L164)

## Important Libraries
The tests were run with:
* [Eclipse Vert.x](https://vertx.io/)
* [GraalVM 1.0.0 rc6](https://graalvm.org/)
* [ES4X](https://reactiverse.io/es4x/)

## Test URLs
### JSON

http://localhost:8080/json

### PLAINTEXT

http://localhost:8080/plaintext

### DB

http://localhost:8080/db

### QUERY

http://localhost:8080/queries?queries=

### UPDATE

http://localhost:8080/updates?queries=

### FORTUNES

http://localhost:8080/fortunes
30 changes: 30 additions & 0 deletions frameworks/JavaScript/es4x/benchmark_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"framework": "es4x",
"tests": [
{
"default": {
"json_url": "/json",
"plaintext_url": "/plaintext",
"db_url": "/db",
"query_url": "/queries?queries=",
"fortune_url": "/fortunes",
"update_url": "/updates?queries=",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "Postgres",
"framework": "ES4X",
"language": "JavaScript",
"flavor": "None",
"orm": "Raw",
"platform": "Vert.x",
"webserver": "None",
"os": "Linux",
"database_os": "Linux",
"display_name": "ES4X",
"notes": "",
"versus": "nodejs"
}
}
]
}
48 changes: 48 additions & 0 deletions frameworks/JavaScript/es4x/es4x.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
FROM ubuntu:18.04

ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update && \
apt-get -y install curl && \
rm -rf /var/lib/apt/lists/*

ENV GRAALVM_VERSION=1.0.0-rc6

# Get GraalVM CE
RUN echo "Pulling graalvm ${GRAALVM_VERSION} binary from Github." \
&& curl -sSLf https://github.com/oracle/graal/releases/download/vm-${GRAALVM_VERSION}/graalvm-ce-${GRAALVM_VERSION}-linux-amd64.tar.gz > /tmp/graalvm-ce-${GRAALVM_VERSION}-linux-amd64.tar.gz \
&& mkdir -p /opt/java \
&& tar -zxf /tmp/graalvm-ce-${GRAALVM_VERSION}-linux-amd64.tar.gz -C /opt/java \
&& rm /tmp/graalvm-ce-${GRAALVM_VERSION}-linux-amd64.tar.gz

ENV GRAALVM_HOME=/opt/java/graalvm-ce-${GRAALVM_VERSION}
ENV JAVA_HOME=${GRAALVM_HOME}
ENV PATH=${PATH}:${JAVA_HOME}/bin

# Set working dir
RUN mkdir /app
WORKDIR /app

COPY ./ /app

# Get dependencies
RUN npm --unsafe-perm install
# Generate a runtime blog
RUN npm run package

CMD ${GRAALVM_HOME}/bin/java \
-server \
-XX:+UseNUMA \
-XX:+UseParallelGC \
-XX:+AggressiveOpts \
-Dvertx.disableMetrics=true \
-Dvertx.disableH2c=true \
-Dvertx.disableWebsockets=true \
-Dvertx.flashPolicyHandler=false \
-Dvertx.threadChecks=false \
-Dvertx.disableContextTimings=true \
-Dvertx.disableTCCL=true \
-jar \
target/es4x-0.0.1-fat.jar \
--instances \
`grep --count ^processor /proc/cpuinfo`
246 changes: 246 additions & 0 deletions frameworks/JavaScript/es4x/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
/// <reference types="@vertx/core/runtime" />
// @ts-check

import {Router} from '@vertx/web';

import {PgClient, Tuple} from '@reactiverse/reactive-pg-client';
import {PgPoolOptions} from '@reactiverse/reactive-pg-client/options';

const util = require('./util');
const HandlebarsTemplateEngine = Java.type('io.vertx.ext.web.templ.HandlebarsTemplateEngine');

const SERVER = 'vertx.js';

const app = Router.router(vertx);
const template = HandlebarsTemplateEngine.create();
let date = new Date().toString();

vertx.setPeriodic(1000, t => date = new Date().toUTCString());

/*
* This test exercises the framework fundamentals including keep-alive support, request routing, request header
* parsing, object instantiation, JSON serialization, response header generation, and request count throughput.
*/
app.get("/json").handler(ctx => {
ctx.response()
.putHeader("Server", SERVER)
.putHeader("Date", date)
.putHeader("Content-Type", "application/json")
.end(JSON.stringify({message: 'Hello, World!'}));
});

const UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2";
const SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1";
const SELECT_FORTUNE = "SELECT id, message from FORTUNE";

let client = PgClient.pool(
vertx,
new PgPoolOptions()
.setCachePreparedStatements(true)
.setMaxSize(1)
.setHost('tfb-database')
.setUser('benchmarkdbuser')
.setPassword('benchmarkdbpass')
.setDatabase('hello_world'));

/*
* This test exercises the framework's object-relational mapper (ORM), random number generator, database driver,
* and database connection pool.
*/
app.get("/db").handler(ctx => {
client.preparedQuery(SELECT_WORLD, Tuple.of(util.randomWorld()), res => {
if (res.succeeded()) {
let resultSet = res.result().iterator();

if (!resultSet.hasNext()) {
ctx.fail(404);
return;
}

let row = resultSet.next();

ctx.response()
.putHeader("Server", SERVER)
.putHeader("Date", date)
.putHeader("Content-Type", "application/json")
.end(JSON.stringify({id: row.getInteger(0), randomNumber: row.getInteger(1)}));
} else {
ctx.fail(res.cause());
}
})
});

/*
* This test is a variation of Test #2 and also uses the World table. Multiple rows are fetched to more dramatically
* punish the database driver and connection pool. At the highest queries-per-request tested (20), this test
* demonstrates all frameworks' convergence toward zero requests-per-second as database activity increases.
*/
app.get("/queries").handler(ctx => {
let failed = false;
let worlds = [];

const queries = util.getQueries(ctx.request());

for (let i = 0; i < queries; i++) {
client.preparedQuery(SELECT_WORLD, Tuple.of(util.randomWorld()), ar => {
if (!failed) {
if (ar.failed()) {
failed = true;
ctx.fail(ar.cause());
return;
}

// we need a final reference
const row = ar.result().iterator().next();
worlds.push({id: row.getInteger(0), randomNumber: row.getInteger(1)});

// stop condition
if (worlds.length === queries) {
ctx.response()
.putHeader("Server", SERVER)
.putHeader("Date", date)
.putHeader("Content-Type", "application/json")
.end(JSON.stringify(worlds));
}
}
});
}
});

/*
* This test exercises the ORM, database connectivity, dynamic-size collections, sorting, server-side templates,
* XSS countermeasures, and character encoding.
*/
app.get("/fortunes").handler(ctx => {
client.preparedQuery(SELECT_FORTUNE, ar => {

if (ar.failed()) {
ctx.fail(ar.cause());
return;
}

let fortunes = [];
let resultSet = ar.result().iterator();

if (!resultSet.hasNext()) {
ctx.fail(404);
return;
}

while (resultSet.hasNext()) {
let row = resultSet.next();
fortunes.push({id: row.getInteger(0), message: row.getString(1)});
}

fortunes.push({id: 0, message: "Additional fortune added at request time."});

fortunes.sort((a, b) => {
let messageA = a.message;
let messageB = b.message;
if (messageA < messageB) {
return -1;
}
if (messageA > messageB) {
return 1;
}
return 0;
});

ctx.put("fortunes", fortunes);

// and now delegate to the engine to render it.
template.render(ctx, "templates", "/fortunes.hbs", res => {
if (res.succeeded()) {
ctx.response()
.putHeader("Server", SERVER)
.putHeader("Date", date)
.putHeader("Content-Type", "text/html; charset=UTF-8")
.end(res.result());
} else {
ctx.fail(res.cause());
}
});
});
});

/*
* This test is a variation of Test #3 that exercises the ORM's persistence of objects and the database driver's
* performance at running UPDATE statements or similar. The spirit of this test is to exercise a variable number of
* read-then-write style database operations.
*/
app.route("/updates").handler(ctx => {
let failed = false;
let queryCount = 0;
let worlds = [];

const queries = util.getQueries(ctx.request());

for (let i = 0; i < queries; i++) {
const id = util.randomWorld();
const index = i;

client.preparedQuery(SELECT_WORLD, Tuple.of(id), ar => {
if (!failed) {
if (ar.failed()) {
failed = true;
ctx.fail(ar.cause());
return;
}

const row = ar.result().iterator().next();

worlds[index] = {id: row.getInteger(0), randomNumber: util.randomWorld()};
if (++queryCount === queries) {
worlds.sort((a, b) => {
return a.id - b.id;
});

let batch = [];

worlds.forEach(world => {
batch.push(Tuple.of(world.randomNumber, world.id));
});

client.preparedBatch(UPDATE_WORLD, batch, ar => {
if (ar.failed()) {
ctx.fail(ar.cause());
return;
}

let json = [];
worlds.forEach(world => {
json.push({id: world.id, randomNumber: world.randomNumber});
});

ctx.response()
.putHeader("Server", SERVER)
.putHeader("Date", date)
.putHeader("Content-Type", "application/json")
.end(JSON.stringify(json));
});
}
}
});
}
});

/*
* This test is an exercise of the request-routing fundamentals only, designed to demonstrate the capacity of
* high-performance platforms in particular. Requests will be sent using HTTP pipelining. The response payload is
* still small, meaning good performance is still necessary in order to saturate the gigabit Ethernet of the test
* environment.
*/
app.get("/plaintext").handler(ctx => {
ctx.response()
.putHeader("Server", SERVER)
.putHeader("Date", date)
.putHeader("Content-Type", "text/plain")
.end('Hello, World!');
});

vertx
.createHttpServer()
.requestHandler(req => app.accept(req))
.listen(8080);

console.log('Server listening at: http://localhost:8080/');
26 changes: 26 additions & 0 deletions frameworks/JavaScript/es4x/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "es4x",
"version": "0.0.1",
"private": true,
"main": "index.js",
"scripts": {
"postinstall": "vertx-scripts init",
"package": "vertx-scripts package"
},
"devDependencies": {
"vertx-scripts": "latest",
"@vertx/unit": "latest"
},
"dependencies": {
"@vertx/core": "3.5.3",
"@vertx/web": "3.5.3",
"@reactiverse/reactive-pg-client": "0.10.3"
},
"mvnDependencies": {
"io.vertx:vertx-web-templ-handlebars": "3.5.3"
},
"files": [
"util.js",
"templates/fortunes.hbs"
]
}
Loading

0 comments on commit cffabe9

Please sign in to comment.