Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,13 @@ cache
*.iml

# MacOS Finder
**/.DS_Store
**/.DS_Store

# Local benchmarks
out_benchmark.json
out_storage.json
local_deployment.json
experiments.json

# Editors
.vscode
6 changes: 6 additions & 0 deletions benchmarks/000.microbenchmarks/010.sleep/bun/function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const timer = ms => new Promise( res => setTimeout(res, ms));

exports.handler = async function(event) {
var sleep = event.sleep;
return timer(sleep*1000);
};
9 changes: 9 additions & 0 deletions benchmarks/000.microbenchmarks/010.sleep/bun/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "",
"version": "1.0.0",
"description": "",
"author": "",
"license": "",
"dependencies": {
}
}
6 changes: 5 additions & 1 deletion benchmarks/000.microbenchmarks/010.sleep/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"timeout": 120,
"memory": 128,
"languages": ["python", "nodejs"],
"languages": [
"python",
"nodejs",
"bun"
],
"modules": []
}
29 changes: 29 additions & 0 deletions benchmarks/100.webapps/110.dynamic-html/bun/function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const Mustache = require('mustache'),
fs = require('fs'),
path = require('path');

function random(b, e) {
return Math.round(Math.random() * (e - b) + b);
}

exports.handler = async function(event) {
var random_numbers = new Array(event.random_len);
for(var i = 0; i < event.random_len; ++i) {
random_numbers[i] = random(0, 100);
}
var input = {
cur_time: new Date().toLocaleString(),
username: event.username,
random_numbers: random_numbers
};

var file = path.resolve(__dirname, 'templates', 'template.html');
return new Promise((resolve, reject) => {
fs.readFile(file, "utf-8",
function(err, data) {
if(err) reject(err);
resolve(Mustache.render(data, input));
}
);
});
};
10 changes: 10 additions & 0 deletions benchmarks/100.webapps/110.dynamic-html/bun/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

DIR=$1
VERBOSE=$2
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
path="${SCRIPT_DIR}/templates/"
if [ "$VERBOSE" = true ]; then
echo "Update ${DIR} with static templates ${path}"
fi
cp -r ${SCRIPT_DIR}/templates ${DIR}
10 changes: 10 additions & 0 deletions benchmarks/100.webapps/110.dynamic-html/bun/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "",
"version": "1.0.0",
"description": "",
"author": "",
"license": "",
"dependencies": {
"mustache": "^3.2.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<title>Randomly generated data.</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
<style type="text/css">
.container {
max-width: 500px;
padding-top: 100px;
}
</style>
</head>
<body>
<div class="container">
<p>Welcome {{username}}!</p>
<p>Data generated at: {{cur_time}}!</p>
<p>Requested random numbers:</p>
<ul>
{{#random_numbers}}
<li>{{.}}</li>
{{/random_numbers}}
</ul>
</div>
</body>
</html>
6 changes: 5 additions & 1 deletion benchmarks/100.webapps/110.dynamic-html/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"timeout": 10,
"memory": 128,
"languages": ["python", "nodejs"],
"languages": [
"python",
"nodejs",
"bun"
],
"modules": []
}
36 changes: 36 additions & 0 deletions benchmarks/100.webapps/120.uploader/bun/function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const fs = require('fs'),
path = require('path'),
request = require('request'),
storage = require('./storage');

let storage_handler = new storage.storage();

function streamToPromise(stream) {
return new Promise(function(resolve, reject) {
stream.on("close", () => {
resolve();
});
stream.on("error", reject);
})
}

exports.handler = async function(event) {
let bucket = event.bucket.bucket
let output_prefix = event.bucket.output
let url = event.object.url
let upload_key = path.basename(url)
let download_path = path.join('/tmp', upload_key)

var file = fs.createWriteStream(download_path);
request(url).pipe(file);
let promise = streamToPromise(file);
var keyName;
let upload = promise.then(
async () => {
[keyName, promise] = storage_handler.upload(bucket, path.join(output_prefix, upload_key), download_path);
await promise;
}
);
await upload;
return {bucket: bucket, url: url, key: keyName}
};
10 changes: 10 additions & 0 deletions benchmarks/100.webapps/120.uploader/bun/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "",
"version": "1.0.0",
"description": "",
"author": "",
"license": "",
"dependencies": {
"request": "^2.88.0"
}
}
10 changes: 8 additions & 2 deletions benchmarks/100.webapps/120.uploader/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"timeout": 30,
"memory": 128,
"languages": ["python", "nodejs"],
"modules": ["storage"]
"languages": [
"python",
"nodejs",
"bun"
],
"modules": [
"storage"
]
}
28 changes: 28 additions & 0 deletions benchmarks/200.multimedia/210.thumbnailer/bun/function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const sharp = require('sharp'),
path = require('path'),
storage = require('./storage');

let storage_handler = new storage.storage();

exports.handler = async function(event) {

bucket = event.bucket.bucket
input_prefix = event.bucket.input
output_prefix = event.bucket.output
let key = event.object.key
width = event.object.width
height = event.object.height
let pos = key.lastIndexOf('.');
let upload_key = key.substr(0, pos < 0 ? key.length : pos) + '.png';

const sharp_resizer = sharp().resize(width, height).png();
let read_promise = storage_handler.downloadStream(bucket, path.join(input_prefix, key));
let [writeStream, promise, uploadName] = storage_handler.uploadStream(bucket, path.join(output_prefix, upload_key));
read_promise.then(
(input_stream) => {
input_stream.pipe(sharp_resizer).pipe(writeStream);
}
);
await promise;
return {bucket: output_prefix, key: uploadName}
};
10 changes: 10 additions & 0 deletions benchmarks/200.multimedia/210.thumbnailer/bun/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "",
"version": "1.0.0",
"description": "",
"author": "",
"license": "",
"dependencies": {
"sharp": "0.32.6"
}
}
10 changes: 8 additions & 2 deletions benchmarks/200.multimedia/210.thumbnailer/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"timeout": 60,
"memory": 256,
"languages": ["python", "nodejs"],
"modules": ["storage"]
"languages": [
"python",
"nodejs",
"bun"
],
"modules": [
"storage"
]
}
47 changes: 47 additions & 0 deletions benchmarks/wrappers/aws/bun/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

const path = require('path'), fs = require('fs');

function process_output(data, http_trigger) {
if(http_trigger)
return JSON.stringify(data);
else
return data;
}

exports.handler = async function(event, context) {
var begin = Date.now()/1000;
var start = process.hrtime();
var http_trigger = "body" in event;
var input_data = http_trigger ? JSON.parse(event.body) : event
var func = require('./function/function')
var ret = func.handler(input_data);
return ret.then(
(result) => {
var elapsed = process.hrtime(start);
var end = Date.now()/1000;
var micro = elapsed[1] / 1e3 + elapsed[0] * 1e6;

var is_cold = false;
var fname = path.join('/tmp','cold_run');
if(!fs.existsSync(fname)) {
is_cold = true;
fs.closeSync(fs.openSync(fname, 'w'));
}
return {
statusCode: 200,
body: process_output({
begin: begin,
end: end,
compute_time: micro,
results_time: 0,
result: {output: result},
is_cold: is_cold,
request_id: context.awsRequestId
}, http_trigger)
};
},
(error) => {
throw(error);
}
);
}
40 changes: 40 additions & 0 deletions benchmarks/wrappers/aws/bun/runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Custom runtime while loop for AWS lambda.
* Listens for function events, executes handler, and returns results.
*
* ENV variables based on https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime
* API endpoints based on https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html
*/

import { handler } from "./handler.js";

const RUNTIME_API = process.env.AWS_LAMBDA_RUNTIME_API;
const API_BASE = `http://${RUNTIME_API}/2018-06-01/runtime`;

while (true) {
const nextResponse = await fetch(`${API_BASE}/invocation/next`);
const event = await nextResponse.json();
const requestId = nextResponse.headers.get("Lambda-Runtime-Aws-Request-Id");

// NOTE: If more context is needed inside the handler, they can be added here
const context = { awsRequestId: requestId };

try {
const response = await handler(event, context);

await fetch(`${API_BASE}/invocation/${requestId}/response`, {
method: "POST",
body: JSON.stringify(response),
});
} catch (error) {
console.error(error);
await fetch(`${API_BASE}/invocation/${requestId}/error`, {
method: "POST",
body: JSON.stringify({
errorMessage: error.message,
errorType: "Runtime.UserCodeError",
stackTrace: error.stack ? error.stack.split("\n") : [],
}),
});
}
}
50 changes: 50 additions & 0 deletions benchmarks/wrappers/aws/bun/storage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

const aws = require('aws-sdk'),
fs = require('fs'),
path = require('path'),
uuid = require('uuid'),
util = require('util'),
stream = require('stream');

class aws_storage {

constructor() {
this.S3 = new aws.S3();
}

unique_name(file) {
let name = path.parse(file);
let uuid_name = uuid.v4().split('-')[0];
return path.join(name.dir, util.format('%s.%s%s', name.name, uuid_name, name.ext));
}

upload(bucket, file, filepath) {
var upload_stream = fs.createReadStream(filepath);
let uniqueName = this.unique_name(file);
let params = {Bucket: bucket, Key: uniqueName, Body: upload_stream};
var upload = this.S3.upload(params);
return [uniqueName, upload.promise()];
};

download(bucket, file, filepath) {
var file = fs.createWriteStream(filepath);
this.S3.getObject( {Bucket: bucket, Key: file} ).createReadStream().pipe(file);
};

uploadStream(bucket, file) {
var write_stream = new stream.PassThrough();
let uniqueName = this.unique_name(file);
// putObject won't work correctly for streamed data (length has to be known before)
// https://stackoverflow.com/questions/38442512/difference-between-upload-and-putobject-for-uploading-a-file-to-s3
var upload = this.S3.upload( {Bucket: bucket, Key: uniqueName, Body: write_stream} );
return [write_stream, upload.promise(), uniqueName];
};

// We return a promise to match the API for other providers
downloadStream(bucket, file) {
// AWS.Request -> read stream
let downloaded = this.S3.getObject( {Bucket: bucket, Key: file} ).createReadStream();
return Promise.resolve(downloaded);
};
};
exports.storage = aws_storage;
Loading