2012-04-09 15:39:57 +00:00
|
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
|
|
<title>Exp Series Performance Tests</title>
|
|
|
|
<!-- http://code.google.com/p/flot/ -->
|
|
|
|
<!--[if lte IE 8]><script language="javascript" type="text/javascript" src="excanvas.min.js"></script><![endif]-->
|
|
|
|
<script language="javascript" type="text/javascript" src="jquery.js"></script>
|
|
|
|
<script language="javascript" type="text/javascript" src="jquery.flot.js"></script>
|
|
|
|
<script language="javascript" type="text/javascript" src="exp_series.js"></script>
|
|
|
|
<style type="text/css">
|
|
|
|
body {
|
|
|
|
font-family: sans-serif;
|
|
|
|
font-size: 16px;
|
|
|
|
margin: 50px;
|
|
|
|
}
|
2012-05-04 21:16:57 +00:00
|
|
|
.graph {
|
2012-04-09 15:39:57 +00:00
|
|
|
width:800px;
|
|
|
|
height:400px;
|
|
|
|
}
|
2012-05-04 21:16:57 +00:00
|
|
|
.note {
|
|
|
|
|
|
|
|
}
|
|
|
|
.show_hide {
|
|
|
|
padding: 1px;
|
|
|
|
line-height: 200%;
|
|
|
|
margin: 20px;
|
|
|
|
cursor: pointer;
|
|
|
|
background-color: LightGray;
|
|
|
|
}
|
|
|
|
.hidden {
|
|
|
|
display: none; //visibility: hidden; // to collapse, use display: none
|
2012-05-03 20:43:12 +00:00
|
|
|
}
|
2012-04-09 15:39:57 +00:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Exp Series Performance Tests</h1>
|
2012-05-04 21:16:57 +00:00
|
|
|
x-axis is power of 2, log base 2 of size<br/>
|
|
|
|
y-axis is "document" operations per second, ex., total document insertions per second<br/>
|
|
|
|
<br/>
|
|
|
|
For measuring Ruby driver performance, we are interested primarily in the "user" CPU time.<br/>
|
|
|
|
The "user" time is the time used by the Ruby driver, typically much less than real time.<br/>
|
|
|
|
<br/>
|
|
|
|
<hr/>
|
|
|
|
<h2>Issues</h2><div id="array_slow"></div>
|
|
|
|
<hr/>
|
|
|
|
<h2>Nested Structures</h2><div id="nested"></div>
|
|
|
|
<hr/>
|
|
|
|
<h2>C versus Ruby</h2><div id="c_vs_ruby"></div>
|
|
|
|
<hr/>
|
2012-04-09 15:39:57 +00:00
|
|
|
|
|
|
|
<script type="text/javascript">
|
2012-04-16 21:28:48 +00:00
|
|
|
function genOpXY(a, xMax, plotSpec, xKey, yKey) {
|
|
|
|
var genOpA = $.grep(a, function(e, i){
|
|
|
|
if (e.exp2 > xMax) return false;
|
|
|
|
for (var key in plotSpec) {
|
|
|
|
if (e[key] != plotSpec[key]) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
2012-04-09 15:39:57 +00:00
|
|
|
return $.map(genOpA, function(e, i){return [[e[xKey], e[yKey]]];});
|
|
|
|
}
|
2012-04-17 13:25:11 +00:00
|
|
|
function flotSeries(expSeries, xMax, labelSpec, plotSpecs) {
|
2012-04-16 21:28:48 +00:00
|
|
|
return $.map(plotSpecs, function(plotSpec, i){
|
2012-04-09 15:39:57 +00:00
|
|
|
return {
|
2012-04-17 13:25:11 +00:00
|
|
|
label: labelSpec + ': ' + plotSpec[labelSpec],
|
2012-05-03 20:43:12 +00:00
|
|
|
data: genOpXY(expSeries, xMax, plotSpec, 'exp2', 'ut_ops'),
|
2012-04-09 15:39:57 +00:00
|
|
|
lines: { show: true },
|
|
|
|
points: { show: true }
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
$(function () {
|
|
|
|
|
|
|
|
function xExpTicks(axis) {
|
|
|
|
var res = [];
|
|
|
|
for (var i = axis.min; i <= axis.max; i++) {
|
|
|
|
res.push([i, i + ':' + Math.pow(2,i)]);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2012-05-04 21:16:57 +00:00
|
|
|
function doPlot(section, title, series, classes, notes) {
|
2012-04-09 15:39:57 +00:00
|
|
|
var id = title.replace(/\W/g,'_');
|
2012-05-04 21:16:57 +00:00
|
|
|
$(section).append('<hr/><h3>' + title + '</h3>' +
|
|
|
|
'<div id="note_' + id + '" class="note"></div>' +
|
|
|
|
'<span id="show_hide_' + id + '" class="show_hide">Show/Hide</span>' +
|
|
|
|
'<div id="' + id + '" class="graph"></div>');
|
|
|
|
$('#note_' + id).text(notes);
|
2012-05-03 20:43:12 +00:00
|
|
|
var e = $('#' + id);
|
|
|
|
$.plot(e, series, {
|
|
|
|
xaxis:{ ticks:xExpTicks },
|
|
|
|
yaxes:[
|
|
|
|
{ min:0 }
|
|
|
|
],
|
|
|
|
legend:{ position:'ne' },
|
|
|
|
grid:{ hoverable:true }
|
|
|
|
});
|
|
|
|
e.addClass(classes);
|
2012-04-09 15:39:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// comment pending
|
|
|
|
var graph = [
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#array_slow', 'array_size_fixnum slow versus hash_size_fixnum insert C', '', 12, 'generator',
|
2012-04-16 21:28:48 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' }
|
|
|
|
],
|
|
|
|
'Array insertion is significantly slower than hash insertion. ' +
|
|
|
|
'Investigation shows that there is an extra malloc/free for each array index key. '
|
2012-04-09 15:39:57 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#array_slow', 'array_size_fixnum slow versus fast insert C', '', 12, 'tag',
|
2012-04-16 21:28:48 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
|
|
|
],
|
|
|
|
'Pending: Array insertion is now faster.'
|
2012-04-09 15:39:57 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#array_slow', 'array_size_fixnum fast versus hash_size_fixnum insert C', '', 12, 'generator',
|
2012-04-16 21:28:48 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' },
|
|
|
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' }
|
|
|
|
],
|
|
|
|
'Pending: Array insertion is now as fast as hash insertion.'
|
2012-04-09 15:39:57 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#array_slow', 'array_nest_fixnum slow versus hash_nest_fixnum insert C base 2', '', 12, 'generator',
|
2012-04-16 21:28:48 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' }
|
|
|
|
],
|
|
|
|
'Nested array insertion is significantly slower than nested hash insertion.'
|
2012-04-17 13:25:11 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#array_slow', 'array_nest_fixnum slow versus fast insert C base 2', 'hidden', 12, 'tag',
|
2012-04-17 13:25:11 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
|
|
|
],
|
|
|
|
'Pending: Nested array insertion is now faster.'
|
2012-04-17 13:25:11 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#array_slow', 'array_nest_fixnum fast versus hash_nest_fixnum insert C base 2', 'hidden', 12, 'generator',
|
2012-04-17 13:25:11 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' },
|
|
|
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' }
|
|
|
|
],
|
|
|
|
'Pending: Nested array insertion is now as fast as nested hash insertion.'
|
2012-04-09 15:39:57 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#nested', 'array_nest_fixnum insert C by base', 'hidden', 12, 'base',
|
2012-04-16 21:28:48 +00:00
|
|
|
[
|
2012-05-03 20:43:12 +00:00
|
|
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:4, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:8, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:16, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:32, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' }
|
2012-05-04 21:16:57 +00:00
|
|
|
],
|
|
|
|
'The deeper binary nested array is slower than broader structures with the same number of leaves.'
|
2012-04-09 15:39:57 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#nested', 'hash_nest_fixnum insert C by base', 'hidden', 12, 'base',
|
2012-04-16 21:28:48 +00:00
|
|
|
[
|
2012-05-03 20:43:12 +00:00
|
|
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:4, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:8, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:16, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
|
|
|
{ base:32, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' }
|
2012-05-04 21:16:57 +00:00
|
|
|
],
|
|
|
|
'The deeper binary nested hash is slower than broader structures with the same number of leaves.'
|
2012-04-09 15:39:57 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#c_vs_ruby', 'value_string_size insert C versus Ruby', 'hidden', 14, 'mode',
|
2012-04-16 21:28:48 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'value_string_size', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'value_string_size', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
|
|
|
],
|
|
|
|
'The C extension is significantly faster than Ruby, as expected.'
|
2012-04-25 21:15:31 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#c_vs_ruby', 'key_string_size insert C versus Ruby', 'hidden', 14, 'mode',
|
2012-04-30 21:21:50 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'key_string_size', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'key_string_size', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
|
|
|
],
|
|
|
|
'The C extension is significantly faster than Ruby, as expected.'
|
2012-04-30 21:21:50 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#c_vs_ruby', 'array_size_fixnum insert C versus Ruby', 'hidden', 12, 'mode',
|
2012-04-25 21:15:31 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
|
|
|
],
|
|
|
|
'The C extension is significantly faster than Ruby, as expected.'
|
2012-04-25 21:15:31 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#c_vs_ruby', 'hash_size_fixnum insert C versus Ruby', 'hidden', 12, 'mode',
|
2012-04-25 21:15:31 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
|
|
|
],
|
|
|
|
'The C extension is significantly faster than Ruby, as expected.'
|
2012-04-30 21:21:50 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#c_vs_ruby', 'array_nest_fixnum base 2 insert C versus Ruby', 'hidden', 12, 'mode',
|
2012-04-30 21:21:50 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode:'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode:'ruby', tag: 'base_ruby' }
|
|
|
|
],
|
|
|
|
'The C extension is significantly faster than Ruby, as expected.'
|
2012-04-30 21:21:50 +00:00
|
|
|
],
|
2012-05-04 21:16:57 +00:00
|
|
|
[ '#c_vs_ruby', 'hash_nest_fixnum base 2 insert C versus Ruby', 'hidden', 12, 'mode',
|
2012-04-30 21:21:50 +00:00
|
|
|
[
|
2012-05-04 21:16:57 +00:00
|
|
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
|
|
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
|
|
|
],
|
|
|
|
'The C extension is significantly faster than Ruby, as expected.'
|
2012-04-30 21:21:50 +00:00
|
|
|
],
|
2012-04-09 15:39:57 +00:00
|
|
|
];
|
|
|
|
$.each(graph, function(i, e){
|
2012-05-03 20:43:12 +00:00
|
|
|
var section, title, classes, xMax, labelSpec, plotSpecs;
|
2012-05-04 21:16:57 +00:00
|
|
|
//[section, title, classes, xMax, labelSpec, plotSpecs, notes] = e;
|
|
|
|
section = e[0], title = e[1]; classes = e[2], xMax = e[3]; labelSpec = e[4]; plotSpecs = e[5], notes = e[6];
|
2012-04-17 13:25:11 +00:00
|
|
|
var series = flotSeries(expSeries, xMax, labelSpec, plotSpecs);
|
2012-05-04 21:16:57 +00:00
|
|
|
doPlot(section, title, series, classes, notes);
|
2012-04-09 15:39:57 +00:00
|
|
|
});
|
|
|
|
|
2012-04-25 21:15:31 +00:00
|
|
|
function showTooltip(x, y, contents) {
|
|
|
|
$('<div id="tooltip">' + contents + '</div>').css( {
|
|
|
|
position: 'absolute',
|
|
|
|
display: 'none',
|
|
|
|
top: y + 5,
|
|
|
|
left: x + 5,
|
|
|
|
border: '1px solid #fdd',
|
|
|
|
padding: '2px',
|
|
|
|
'background-color': '#fee',
|
|
|
|
opacity: 0.80
|
|
|
|
}).appendTo("body").fadeIn(200);
|
|
|
|
}
|
|
|
|
|
|
|
|
var previousPoint = null;
|
|
|
|
$('.graph').bind('plothover', function (event, pos, item) {
|
|
|
|
$("#x").text(pos.x.toFixed(2));
|
|
|
|
$("#y").text(pos.y.toFixed(2));
|
|
|
|
if (item) {
|
|
|
|
if (previousPoint != item.dataIndex) {
|
|
|
|
previousPoint = item.dataIndex;
|
|
|
|
|
|
|
|
$("#tooltip").remove();
|
|
|
|
var x = item.datapoint[0].toFixed(2),
|
|
|
|
y = item.datapoint[1].toFixed(2);
|
|
|
|
|
|
|
|
showTooltip(item.pageX, item.pageY,
|
|
|
|
item.series.label + ' [ ' + Math.round(x) + ', ' + Math.round(y) + ' ]');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$("#tooltip").remove();
|
|
|
|
previousPoint = null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2012-05-03 20:43:12 +00:00
|
|
|
$('.show_hide').bind('click', function(event) {
|
|
|
|
var id = $(this).attr('id').replace(/^show_hide_/, '');
|
|
|
|
$('#' + id).toggleClass('hidden');
|
|
|
|
});
|
|
|
|
|
2012-04-09 15:39:57 +00:00
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|