summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/pywebsocket/src/example/xhr_benchmark.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/tools/pywebsocket/src/example/xhr_benchmark.js')
-rw-r--r--testing/web-platform/tests/tools/pywebsocket/src/example/xhr_benchmark.js389
1 files changed, 389 insertions, 0 deletions
diff --git a/testing/web-platform/tests/tools/pywebsocket/src/example/xhr_benchmark.js b/testing/web-platform/tests/tools/pywebsocket/src/example/xhr_benchmark.js
new file mode 100644
index 000000000..233c7cb38
--- /dev/null
+++ b/testing/web-platform/tests/tools/pywebsocket/src/example/xhr_benchmark.js
@@ -0,0 +1,389 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the COPYING file or at
+// https://developers.google.com/open-source/licenses/bsd
+
+var isWorker = typeof importScripts !== "undefined";
+
+if (isWorker) {
+ // Running on a worker
+ importScripts('util.js', 'util_worker.js');
+}
+
+// Namespace for holding globals.
+var benchmark = {};
+benchmark.startTimeInMs = 0;
+
+var xhrs = [];
+
+var timerID = null;
+
+function destroyAllXHRs() {
+ for (var i = 0; i < xhrs.length; ++i) {
+ xhrs[i].onreadystatechange = null;
+ // Abort XHRs if they are not yet DONE state.
+ // Calling abort() here (i.e. in onreadystatechange handler)
+ // causes "NetworkError" messages in DevTools in sync mode,
+ // even if it is after transition to DONE state.
+ if (xhrs[i].readyState != XMLHttpRequest.DONE)
+ xhrs[i].abort();
+ }
+ xhrs = [];
+ // gc() might be needed for Chrome/Blob
+}
+
+function repeatString(str, count) {
+ var data = '';
+ var expChunk = str;
+ var remain = count;
+ while (true) {
+ if (remain % 2) {
+ data += expChunk;
+ remain = (remain - 1) / 2;
+ } else {
+ remain /= 2;
+ }
+
+ if (remain == 0)
+ break;
+
+ expChunk = expChunk + expChunk;
+ }
+ return data;
+}
+
+function sendBenchmarkStep(size, config) {
+ timerID = null;
+
+ benchmark.startTimeInMs = null;
+ var totalSize = 0;
+ var totalReplied = 0;
+
+ var onReadyStateChangeHandler = function () {
+ if (this.readyState != this.DONE) {
+ return;
+ }
+
+ if (this.status != 200) {
+ config.addToLog('Failed (status=' + this.status + ')');
+ destroyAllXHRs();
+ return;
+ }
+
+ if (config.verifyData &&
+ !verifyAcknowledgement(config, this.response, size)) {
+ destroyAllXHRs();
+ return;
+ }
+
+ totalReplied += size;
+
+ if (totalReplied < totalSize) {
+ return;
+ }
+
+ if (benchmark.startTimeInMs == null) {
+ config.addToLog('startTimeInMs not set');
+ destroyAllXHRs();
+ return;
+ }
+
+ calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize);
+
+ destroyAllXHRs();
+
+ runNextTask(config);
+ };
+
+ for (var i = 0; i < config.numXHRs; ++i) {
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = onReadyStateChangeHandler;
+ xhrs.push(xhr);
+ }
+
+ var dataArray = [];
+
+ for (var i = 0; i < xhrs.length; ++i) {
+ var data = null;
+ if (config.dataType == 'arraybuffer' ||
+ config.dataType == 'blob') {
+ data = new ArrayBuffer(size);
+
+ fillArrayBuffer(data, 0x61);
+
+ if (config.dataType == 'blob') {
+ data = new Blob([data]);
+ }
+ } else {
+ data = repeatString('a', size);
+ }
+
+ dataArray.push(data);
+ }
+
+
+ benchmark.startTimeInMs = getTimeStamp();
+ totalSize = size * xhrs.length;
+
+ for (var i = 0; i < xhrs.length; ++i) {
+ var data = dataArray[i];
+ var xhr = xhrs[i];
+ xhr.open('POST', config.prefixUrl + '_send', config.async);
+ xhr.send(data);
+ }
+}
+
+function receiveBenchmarkStep(size, config) {
+ timerID = null;
+
+ benchmark.startTimeInMs = null;
+ var totalSize = 0;
+ var totalReplied = 0;
+
+ var checkResultAndContinue = function (bytesReceived, verificationResult) {
+ if (!verificationResult) {
+ config.addToLog('Response verification failed');
+ destroyAllXHRs();
+ return;
+ }
+
+ totalReplied += bytesReceived;
+
+ if (totalReplied < totalSize) {
+ return;
+ }
+
+ if (benchmark.startTimeInMs == null) {
+ config.addToLog('startTimeInMs not set');
+ destroyAllXHRs();
+ return;
+ }
+
+ calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize);
+
+ destroyAllXHRs();
+
+ runNextTask(config);
+ }
+
+ var onReadyStateChangeHandler = function () {
+ if (this.readyState != this.DONE) {
+ return;
+ }
+
+ if (this.status != 200) {
+ config.addToLog('Failed (status=' + this.status + ')');
+ destroyAllXHRs();
+ return;
+ }
+
+ var bytesReceived = -1;
+ if (this.responseType == 'arraybuffer') {
+ bytesReceived = this.response.byteLength;
+ } else if (this.responseType == 'blob') {
+ bytesReceived = this.response.size;
+ } else {
+ bytesReceived = this.response.length;
+ }
+ if (bytesReceived != size) {
+ config.addToLog('Expected ' + size +
+ 'B but received ' + bytesReceived + 'B');
+ destroyAllXHRs();
+ return;
+ }
+
+ if (this.responseType == 'arraybuffer') {
+ checkResultAndContinue(bytesReceived,
+ !config.verifyData || verifyArrayBuffer(this.response, 0x61));
+ } else if (this.responseType == 'blob') {
+ if (config.verifyData)
+ verifyBlob(config, this.response, 0x61, checkResultAndContinue);
+ else
+ checkResultAndContinue(bytesReceived, true);
+ } else {
+ checkResultAndContinue(
+ bytesReceived,
+ !config.verifyData ||
+ this.response == repeatString('a', this.response.length));
+ }
+ };
+
+ for (var i = 0; i < config.numXHRs; ++i) {
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = onReadyStateChangeHandler;
+ xhrs.push(xhr);
+ }
+
+ benchmark.startTimeInMs = getTimeStamp();
+ totalSize = size * xhrs.length;
+
+ for (var i = 0; i < xhrs.length; ++i) {
+ var xhr = xhrs[i];
+ xhr.open('POST', config.prefixUrl + '_receive', config.async);
+ xhr.responseType = config.dataType;
+ xhr.send(size + ' none');
+ }
+}
+
+
+function getConfigString(config) {
+ return '(' + config.dataType +
+ ', verifyData=' + config.verifyData +
+ ', ' + (isWorker ? 'Worker' : 'Main') +
+ ', ' + (config.async ? 'Async' : 'Sync') +
+ ', numXHRs=' + config.numXHRs +
+ ', numIterations=' + config.numIterations +
+ ', numWarmUpIterations=' + config.numWarmUpIterations +
+ ')';
+}
+
+function startBenchmark(config) {
+ clearTimeout(timerID);
+ destroyAllXHRs();
+
+ runNextTask(config);
+}
+
+// TODO(hiroshige): the following code is the same as benchmark.html
+// and some of them should be merged into e.g. util.js
+
+var tasks = [];
+
+function runNextTask(config) {
+ var task = tasks.shift();
+ if (task == undefined) {
+ config.addToLog('Finished');
+ destroyAllXHRs();
+ return;
+ }
+ timerID = setTimeout(task, 0);
+}
+
+function buildLegendString(config) {
+ var legend = ''
+ if (config.printSize)
+ legend = 'Message size in KiB, Time/message in ms, ';
+ legend += 'Speed in kB/s';
+ return legend;
+}
+
+function addTasks(config, stepFunc) {
+ for (var i = 0;
+ i < config.numWarmUpIterations + config.numIterations; ++i) {
+ // Ignore the first |config.numWarmUpIterations| iterations.
+ if (i == config.numWarmUpIterations)
+ addResultClearingTask(config);
+
+ var multiplierIndex = 0;
+ for (var size = config.startSize;
+ size <= config.stopThreshold;
+ ++multiplierIndex) {
+ var task = stepFunc.bind(
+ null,
+ size,
+ config);
+ tasks.push(task);
+ size *= config.multipliers[
+ multiplierIndex % config.multipliers.length];
+ }
+ }
+}
+
+function addResultReportingTask(config, title) {
+ tasks.push(function(){
+ timerID = null;
+ config.addToSummary(title);
+ reportAverageData(config);
+ clearAverageData();
+ runNextTask(config);
+ });
+}
+
+function addResultClearingTask(config) {
+ tasks.push(function(){
+ timerID = null;
+ clearAverageData();
+ runNextTask(config);
+ });
+}
+
+// --------------------------------
+
+function sendBenchmark(config) {
+ config.addToLog('Send benchmark');
+ config.addToLog(buildLegendString(config));
+
+ tasks = [];
+ clearAverageData();
+ addTasks(config, sendBenchmarkStep);
+ addResultReportingTask(config, 'Send Benchmark ' + getConfigString(config));
+ startBenchmark(config);
+}
+
+function receiveBenchmark(config) {
+ config.addToLog('Receive benchmark');
+ config.addToLog(buildLegendString(config));
+
+ tasks = [];
+ clearAverageData();
+ addTasks(config, receiveBenchmarkStep);
+ addResultReportingTask(config,
+ 'Receive Benchmark ' + getConfigString(config));
+ startBenchmark(config);
+}
+
+function batchBenchmark(originalConfig) {
+ originalConfig.addToLog('Batch benchmark');
+
+ tasks = [];
+ clearAverageData();
+
+ var dataTypes = ['text', 'blob', 'arraybuffer'];
+ var stepFuncs = [sendBenchmarkStep, receiveBenchmarkStep];
+ var names = ['Send', 'Receive'];
+ var async = [true, false];
+ for (var i = 0; i < stepFuncs.length; ++i) {
+ for (var j = 0; j < dataTypes.length; ++j) {
+ for (var k = 0; k < async.length; ++k) {
+ var config = cloneConfig(originalConfig);
+ config.dataType = dataTypes[j];
+ config.async = async[k];
+
+ // Receive && Non-Worker && Sync is not supported by the spec
+ if (stepFuncs[i] === receiveBenchmarkStep && !isWorker &&
+ !config.async)
+ continue;
+
+ addTasks(config, stepFuncs[i]);
+ addResultReportingTask(config,
+ names[i] + ' benchmark ' + getConfigString(config));
+ }
+ }
+ }
+
+ startBenchmark(config);
+}
+
+
+function stop(config) {
+ destroyAllXHRs();
+ clearTimeout(timerID);
+ timerID = null;
+ config.addToLog('Stopped');
+}
+
+onmessage = function (message) {
+ var config = message.data.config;
+ config.addToLog = workerAddToLog;
+ config.addToSummary = workerAddToSummary;
+ config.measureValue = workerMeasureValue;
+ if (message.data.type === 'sendBenchmark')
+ sendBenchmark(config);
+ else if (message.data.type === 'receiveBenchmark')
+ receiveBenchmark(config);
+ else if (message.data.type === 'batchBenchmark')
+ batchBenchmark(config);
+ else if (message.data.type === 'stop')
+ stop(config);
+};