Skip to content

Commit 0c0f34e

Browse files
committed
benchmark: add script for creating scatter plot
Previously this a tool in `plot.R`. It is now are more complete tool which executes the benchmarks many times and creates a boxplot. PR-URL: #7094 Reviewed-By: Trevor Norris <[email protected]> Reviewed-By: Jeremiah Senkpiel <[email protected]> Reviewed-By: Brian White <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 855009a commit 0c0f34e

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

benchmark/scatter.R

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env Rscript
2+
library(ggplot2);
3+
library(plyr);
4+
5+
# get __dirname and load ./_cli.R
6+
args = commandArgs(trailingOnly = F);
7+
dirname = dirname(sub("--file=", "", args[grep("--file", args)]));
8+
source(paste0(dirname, '/_cli.R'), chdir=T);
9+
10+
if (is.null(args.options$xaxis) || is.null(args.options$category) ||
11+
(!is.null(args.options$plot) && args.options$plot == TRUE)) {
12+
stop("usage: cat file.csv | Rscript scatter.R [variable=value ...]
13+
--xaxis variable variable name to use as xaxis (required)
14+
--category variable variable name to use as colored category (required)
15+
--plot filename save plot to filename
16+
--log use a log-2 scale for xaxis in the plot");
17+
}
18+
19+
plot.filename = args.options$plot;
20+
21+
# parse options
22+
x.axis.name = args.options$xaxis;
23+
category.name = args.options$category;
24+
use.log2 = !is.null(args.options$log);
25+
26+
# parse data
27+
dat = read.csv(file('stdin'), strip.white=TRUE);
28+
dat = data.frame(dat);
29+
30+
# List of aggregated variables
31+
aggregate = names(dat);
32+
aggregate = aggregate[
33+
! aggregate %in% c('rate', 'time', 'filename', x.axis.name, category.name)
34+
];
35+
# Variables that don't change aren't aggregated
36+
for (aggregate.key in aggregate) {
37+
if (length(unique(dat[[aggregate.key]])) == 1) {
38+
aggregate = aggregate[aggregate != aggregate.key];
39+
}
40+
}
41+
42+
# Print out aggregated variables
43+
for (aggregate.variable in aggregate) {
44+
cat(sprintf('aggregating variable: %s\n', aggregate.variable));
45+
}
46+
if (length(aggregate) > 0) {
47+
cat('\n');
48+
}
49+
50+
# Calculate statistics
51+
stats = ddply(dat, c(x.axis.name, category.name), function(subdat) {
52+
rate = subdat$rate;
53+
54+
# calculate standard error of the mean
55+
se = sqrt(var(rate)/length(rate));
56+
57+
# calculate mean and 95 % confidence interval
58+
r = list(
59+
rate = mean(rate),
60+
confidence.interval = se * qt(0.975, length(rate) - 1)
61+
);
62+
63+
return(data.frame(r));
64+
});
65+
66+
print(stats, row.names=F);
67+
68+
if (!is.null(plot.filename)) {
69+
p = ggplot(stats, aes_string(x=x.axis.name, y='mean', colour=category.name));
70+
if (use.log2) {
71+
p = p + scale_x_continuous(trans='log2');
72+
}
73+
p = p + geom_errorbar(aes(ymin=mean-confidence.interval, ymax=mean+confidence.interval), width=.1);
74+
p = p + geom_point();
75+
p = p + ylab("rate of operations (higher is better)");
76+
p = p + ggtitle(dat[1, 1]);
77+
ggsave(plot.filename, p);
78+
}

benchmark/scatter.js

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use strict';
2+
3+
const fork = require('child_process').fork;
4+
const path = require('path');
5+
const CLI = require('./_cli.js');
6+
7+
//
8+
// Parse arguments
9+
//
10+
const cli = CLI(`usage: ./node scatter.js [options] [--] <filename>
11+
Run the benchmark script <filename> many times and output the rate (ops/s)
12+
together with the benchmark variables as a csv.
13+
14+
--runs 30 number of samples
15+
--set variable=value set benchmark variable (can be repeated)
16+
`, {
17+
arrayArgs: ['set']
18+
});
19+
20+
if (cli.items.length !== 1) {
21+
cli.abort(cli.usage);
22+
return;
23+
}
24+
25+
// Create queue from the benchmarks list such both node versions are tested
26+
// `runs` amount of times each.
27+
const filepath = path.resolve(cli.items[0]);
28+
const name = filepath.slice(__dirname.length + 1);
29+
const runs = cli.optional.runs ? parseInt(cli.optional.runs, 10) : 30;
30+
31+
let printHeader = true;
32+
33+
function csvEncodeValue(value) {
34+
if (typeof value === 'number') {
35+
return value.toString();
36+
} else {
37+
return '"' + value.replace(/"/g, '""') + '"';
38+
}
39+
}
40+
41+
(function recursive(i) {
42+
const child = fork(path.resolve(__dirname, filepath), cli.optional.set);
43+
44+
child.on('message', function(data) {
45+
// print csv header
46+
if (printHeader) {
47+
const confHeader = Object.keys(data.conf)
48+
.map(csvEncodeValue)
49+
.join(', ');
50+
console.log(`"filename", ${confHeader}, "rate", "time"`);
51+
printHeader = false;
52+
}
53+
54+
// print data row
55+
const confData = Object.keys(data.conf)
56+
.map((key) => csvEncodeValue(data.conf[key]))
57+
.join(', ');
58+
59+
console.log(`"${name}", ${confData}, ${data.rate}, ${data.time}`);
60+
});
61+
62+
child.once('close', function(code) {
63+
if (code) {
64+
process.exit(code);
65+
return;
66+
}
67+
68+
// If there are more benchmarks execute the next
69+
if (i + 1 < runs) {
70+
recursive(i + 1);
71+
}
72+
});
73+
})(0);

0 commit comments

Comments
 (0)