Skip to content

Commit

Permalink
Improve the description of all benchmarks
Browse files Browse the repository at this point in the history
Closes elastic#3
  • Loading branch information
danielmitterdorfer committed Aug 17, 2016
1 parent 71dfd7a commit f0134fe
Show file tree
Hide file tree
Showing 7 changed files with 413 additions and 57 deletions.
11 changes: 11 additions & 0 deletions external/pages/assets/js/charts.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var chartingLib = {
"drawPoints": true,
"pointSize": 3,
"gridLineColor": "#BBB"
//"strokePattern": [5, 10]
}
},

Expand All @@ -31,5 +32,15 @@ var chartingLib = {
g.setAnnotations(json);
});
});
return g;
},

synchronize: function(graphs) {
var sync = Dygraph.synchronize(graphs, {
selection: false,
zoom: true,
// synchronize x-axis only
range: false
});
}
};
243 changes: 243 additions & 0 deletions external/pages/assets/js/synchronizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
/**
* Synchronize zooming and/or selections between a set of dygraphs.
*
* Usage:
*
* var g1 = new Dygraph(...),
* g2 = new Dygraph(...),
* ...;
* var sync = Dygraph.synchronize(g1, g2, ...);
* // charts are now synchronized
* sync.detach();
* // charts are no longer synchronized
*
* You can set options using the last parameter, for example:
*
* var sync = Dygraph.synchronize(g1, g2, g3, {
* selection: true,
* zoom: true
* });
*
* The default is to synchronize both of these.
*
* Instead of passing one Dygraph objet as each parameter, you may also pass an
* array of dygraphs:
*
* var sync = Dygraph.synchronize([g1, g2, g3], {
* selection: false,
* zoom: true
* });
*/
(function() {
/* global Dygraph:false */
'use strict';

Dygraph.synchronize = function(/* dygraphs..., opts */) {
if (arguments.length === 0) {
throw 'Invalid invocation of Dygraph.synchronize(). Need >= 1 argument.';
}

var OPTIONS = ['selection', 'zoom'];
var opts = {
selection: true,
zoom: true
};
var dygraphs = [];

var prevCallbacks = {
draw: null,
highlight: null,
unhighlight: null
};

var parseOpts = function(obj) {
if (!(obj instanceof Object)) {
throw 'Last argument must be either Dygraph or Object.';
} else {
for (var i = 0; i < OPTIONS.length; i++) {
var optName = OPTIONS[i];
if (obj.hasOwnProperty(optName)) opts[optName] = obj[optName];
}
}
};

if (arguments[0] instanceof Dygraph) {
// Arguments are Dygraph objects.
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] instanceof Dygraph) {
dygraphs.push(arguments[i]);
} else {
break;
}
}
if (i < arguments.length - 1) {
throw 'Invalid invocation of Dygraph.synchronize(). ' +
'All but the last argument must be Dygraph objects.';
} else if (i == arguments.length - 1) {
parseOpts(arguments[arguments.length - 1]);
}
} else if (arguments[0].length) {
// Invoked w/ list of dygraphs, options
for (var i = 0; i < arguments[0].length; i++) {
dygraphs.push(arguments[0][i]);
}
if (arguments.length == 2) {
parseOpts(arguments[1]);
} else if (arguments.length > 2) {
throw 'Invalid invocation of Dygraph.synchronize(). ' +
'Expected two arguments: array and optional options argument.';
} // otherwise arguments.length == 1, which is fine.
} else {
throw 'Invalid invocation of Dygraph.synchronize(). ' +
'First parameter must be either Dygraph or list of Dygraphs.';
}

if (dygraphs.length < 2) {
throw 'Invalid invocation of Dygraph.synchronize(). ' +
'Need two or more dygraphs to synchronize.';
}

var readycount = dygraphs.length;
for (var i = 0; i < dygraphs.length; i++) {
var g = dygraphs[i];
g.ready( function() {
if (--readycount == 0) {
// Listen for draw, highlight, unhighlight callbacks.
if (opts.zoom) {
attachZoomHandlers(dygraphs, opts, prevCallbacks);
}

if (opts.selection) {
attachSelectionHandlers(dygraphs, prevCallbacks);
}
}
});
}

return {
detach: function() {
for (var i = 0; i < dygraphs.length; i++) {
var g = dygraphs[i];
if (opts.zoom) {
g.updateOptions({drawCallback: prevCallbacks.draw});
}
if (opts.selection) {
g.updateOptions({
highlightCallback: prevCallbacks.highlight,
unhighlightCallback: prevCallbacks.unhighlight
});
}
}
// release references & make subsequent calls throw.
dygraphs = null;
opts = null;
prevCallbacks = null;
}
};
};

function arraysAreEqual(a, b) {
if (!Array.isArray(a) || !Array.isArray(b)) return false;
var i = a.length;
if (i !== b.length) return false;
while (i--) {
if (a[i] !== b[i]) return false;
}
return true;
}

function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
var block = false;
for (var i = 0; i < gs.length; i++) {
var g = gs[i];
g.updateOptions({
drawCallback: function(me, initial) {
if (block || initial) return;
block = true;
var opts = {
dateWindow: me.xAxisRange()
};
if (syncOpts.range) opts.valueRange = me.yAxisRange();

for (var j = 0; j < gs.length; j++) {
if (gs[j] == me) {
if (prevCallbacks[j] && prevCallbacks[j].drawCallback) {
prevCallbacks[j].drawCallback.apply(this, arguments);
}
continue;
}

// Only redraw if there are new options
if (arraysAreEqual(opts.dateWindow, gs[j].getOption('dateWindow')) &&
arraysAreEqual(opts.valueRange, gs[j].getOption('valueRange'))) {
continue;
}

gs[j].updateOptions(opts);
}
block = false;
}
}, true /* no need to redraw */);
}
}

function attachSelectionHandlers(gs, prevCallbacks) {
var block = false;
for (var i = 0; i < gs.length; i++) {
var g = gs[i];
prevCallbacks.highlight = g.getFunctionOption('highlightCallback');
prevCallbacks.unhighlight = g.getFunctionOption('unhighlightCallback');
g.updateOptions({
highlightCallback: function(event, x, points, row, seriesName) {
if (prevCallbacks.highlight) {
prevCallbacks.highlight(event, x, points, row, seriesName);
}
if (block) return;
block = true;
var me = this;
for (var i = 0; i < gs.length; i++) {
if (me == gs[i]) continue;
var idx = dygraphsBinarySearch(gs[i], x);
if (idx !== null) {
gs[i].setSelection(idx, seriesName);
}
}
block = false;
},
unhighlightCallback: function(event) {
if (prevCallbacks.unhighlight) prevCallbacks.unhighlight(event);
if (block) return;
block = true;
var me = this;
for (var i = 0; i < gs.length; i++) {
if (me == gs[i]) continue;
gs[i].clearSelection();
}
block = false;
}
});
}
}

// Returns the index corresponding to xVal, or null if there is none.
function dygraphsBinarySearch(g, xVal) {
var low = 0,
high = g.numRows() - 1;

while (low <= high) {
var idx = (high + low) >> 1;
var x = g.getValue(idx, 0);
if (x < xVal) {
low = idx + 1;
} else if (x > xVal) {
high = idx - 1;
} else {
return idx;
}
}

// TODO: give an option to find the closest point, i.e. not demand an exact match.
return null;
}

})();
52 changes: 39 additions & 13 deletions external/pages/geonames/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,31 @@
var charts = {
init: function() {
var annotationSource = false;
chartingLib.renderChart('indexing_throughput', 'Indexing throughput', 'Mean Throughput [docs/s]', 'indexing_throughput_annotations.json');
chartingLib.renderChart('indexing_total_times', 'Total times', 'Time [min]', annotationSource);
chartingLib.renderChart('merge_parts', 'Merge Times, By Part', 'Time [min]', annotationSource);
chartingLib.renderChart('segment_total_memory', 'Segment total heap used', 'Heap used [MB]', annotationSource);
chartingLib.renderChart('indexing_cpu_usage', 'Indexing CPU usage', 'CPU usage [%]', annotationSource);
chartingLib.renderChart('disk_usage', 'Index disk usage', '[GB]', annotationSource);
chartingLib.renderChart('segment_counts', 'Index segment counts', 'Segment count', annotationSource);
chartingLib.renderChart('search_latency_queries', 'Search Latency', '99th Percentile Latency [ms]', annotationSource);
chartingLib.renderChart('search_latency_stats', 'Stats Latency', '99th Percentile Latency [ms]', annotationSource);
chartingLib.renderChart('gc_times', 'GC times', 'Total GC runtime [s]', annotationSource);

charts.indexingThroughput = chartingLib.renderChart('indexing_throughput', 'Indexing throughput', 'Mean Throughput [docs/s]', 'indexing_throughput_annotations.json');
charts.totalTimes = chartingLib.renderChart('indexing_total_times', 'Total times', 'Time [min]', annotationSource);
charts.mergeParts = chartingLib.renderChart('merge_parts', 'Merge Times, By Part', 'Time [min]', annotationSource);
charts.segmentMemory = chartingLib.renderChart('segment_total_memory', 'Segment total heap used', 'Heap used [MB]', annotationSource);
charts.cpuUsage = chartingLib.renderChart('indexing_cpu_usage', 'Indexing CPU usage', 'CPU usage [%]', annotationSource)
charts.diskUsage = chartingLib.renderChart('disk_usage', 'Index disk usage', '[GB]', annotationSource),
charts.segmentCounts = chartingLib.renderChart('segment_counts', 'Index segment counts', 'Segment count', annotationSource),
charts.queryLatency = chartingLib.renderChart('search_latency_queries', 'Search Latency', '99th Percentile Latency [ms]', annotationSource),
charts.statsLatency = chartingLib.renderChart('search_latency_stats', 'Stats Latency', '99th Percentile Latency [ms]', annotationSource),
charts.gcTimes = chartingLib.renderChart('gc_times', 'GC times', 'Total GC runtime [s]', annotationSource)


chartingLib.synchronize([
charts.indexingThroughput,
charts.totalTimes,
charts.mergeParts,
charts.segmentMemory,
charts.cpuUsage,
charts.diskUsage,
charts.segmentCounts,
charts.queryLatency,
charts.statsLatency,
charts.gcTimes
]);
}
}
</script>
Expand Down Expand Up @@ -93,14 +108,24 @@
<div class="row">
<div class="col-md-12">
<h3>Overview</h3>
<p>This benchmark executes the <a href="https://github.com/elastic/rally-tracks/blob/master/geonames/track.json">geonames track</a> with Rally (see a <a href="../index.html">more detailed explanation of our benchmarking methodology</a>). The benchmark results are also provided as a
<a href="https://elasticsearch-benchmarks.elastic.co/app/kibana#/dashboard/Nightly-Benchmark-Overview">Kibana dashboard</a>.</p>
<p>The geonames data set contains a lot of structured data. String fields are always indexed as <code>text</code> with a raw <code>keyword</code> subfield. We run the following variations (which we call "challenges" in Rally):</p>
<ul>
<li><strong>Append</strong>: Indexes the whole document corpus using Elasticsearch default settings. We only adjust the number of replicas as we benchmark a single node cluster and Rally will only start the benchmark if the cluster turns green. Document ids are unique so all index operations are append only. After that a couple of queries are run in parallel by multiple clients.</li>
<li><strong>Append Fast</strong>: Indexes the whole document corpus using a setup that will lead to a larger indexing throughput than the default settings. Document ids are unique so all index operations are append only.</li>
<li><strong>Id Conflicts</strong>: Indexes the whole document corpus using a setup that will lead to a larger indexing throughput than the default settings. Rally will produce duplicate ids in 25% of all documents (not configurable) so we can simulate a scenario with appends most of the time and some updates in between.</li>
</ul>
<p>The benchmarks are run either for an out of the box configuration of Elasticsearch ("default settings") or with a larger heap of 4GB ("4g heap"). For more details please refer to the <a href="https://github.com/elastic/rally-tracks/blob/master/geonames/track.json">geonames track specification</a> and have a look at our <a href="../index.html">benchmarking methodology</a>). The benchmark results are also provided as a
<a href="https://elasticsearch-benchmarks.elastic.co/app/kibana#/dashboard/Nightly-Benchmark-Overview">Kibana dashboard</a>.</p>
</div>
</div>

<div class="row">
<div class="col-md-12">
<div class="col-md-6">
<h3>Results</h3>
<div class="alert alert-success alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<strong>Hint</strong> Click and drag to zoom. Double-click to zoom out.
</div>
</div>
</div>

Expand Down Expand Up @@ -214,6 +239,7 @@ <h3>Results</h3>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="../assets/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../assets/js/dygraph-combined.js"></script>
<script type="text/javascript" src="../assets/js/synchronizer.js"></script>
<script type="text/javascript" src="../assets/js/charts.js"></script>
<script>
$(document).ready(charts.init);
Expand Down
Loading

0 comments on commit f0134fe

Please sign in to comment.