| // 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 |
| |
| if (typeof importScripts !== "undefined") { |
| // Running on a worker |
| importScripts('util.js', 'util_worker.js'); |
| } |
| |
| // Namespace for holding globals. |
| var benchmark = {startTimeInMs: 0}; |
| |
| var sockets = []; |
| var numEstablishedSockets = 0; |
| |
| var timerID = null; |
| |
| function destroySocket(socket) { |
| socket.onopen = null; |
| socket.onmessage = null; |
| socket.onerror = null; |
| socket.onclose = null; |
| socket.close(); |
| } |
| |
| function destroyAllSockets() { |
| for (var i = 0; i < sockets.length; ++i) { |
| destroySocket(sockets[i]); |
| } |
| sockets = []; |
| } |
| |
| function sendBenchmarkStep(size, config) { |
| timerID = null; |
| |
| var totalSize = 0; |
| var totalReplied = 0; |
| |
| var onMessageHandler = function(event) { |
| if (!verifyAcknowledgement(config, event.data, size)) { |
| destroyAllSockets(); |
| return; |
| } |
| |
| totalReplied += size; |
| |
| if (totalReplied < totalSize) { |
| return; |
| } |
| |
| calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize); |
| |
| runNextTask(config); |
| }; |
| |
| for (var i = 0; i < sockets.length; ++i) { |
| var socket = sockets[i]; |
| socket.onmessage = onMessageHandler; |
| } |
| |
| var dataArray = []; |
| |
| while (totalSize < config.minTotal) { |
| var buffer = new ArrayBuffer(size); |
| |
| fillArrayBuffer(buffer, 0x61); |
| |
| dataArray.push(buffer); |
| totalSize += size; |
| } |
| |
| benchmark.startTimeInMs = getTimeStamp(); |
| |
| totalSize = 0; |
| |
| var socketIndex = 0; |
| var dataIndex = 0; |
| while (totalSize < config.minTotal) { |
| var command = ['send']; |
| command.push(config.verifyData ? '1' : '0'); |
| sockets[socketIndex].send(command.join(' ')); |
| sockets[socketIndex].send(dataArray[dataIndex]); |
| socketIndex = (socketIndex + 1) % sockets.length; |
| |
| totalSize += size; |
| ++dataIndex; |
| } |
| } |
| |
| function receiveBenchmarkStep(size, config) { |
| timerID = null; |
| |
| var totalSize = 0; |
| var totalReplied = 0; |
| |
| var onMessageHandler = function(event) { |
| var bytesReceived = event.data.byteLength; |
| if (bytesReceived != size) { |
| config.addToLog('Expected ' + size + 'B but received ' + |
| bytesReceived + 'B'); |
| destroyAllSockets(); |
| return; |
| } |
| |
| if (config.verifyData && !verifyArrayBuffer(event.data, 0x61)) { |
| config.addToLog('Response verification failed'); |
| destroyAllSockets(); |
| return; |
| } |
| |
| totalReplied += bytesReceived; |
| |
| if (totalReplied < totalSize) { |
| return; |
| } |
| |
| calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize); |
| |
| runNextTask(config); |
| }; |
| |
| for (var i = 0; i < sockets.length; ++i) { |
| var socket = sockets[i]; |
| socket.binaryType = 'arraybuffer'; |
| socket.onmessage = onMessageHandler; |
| } |
| |
| benchmark.startTimeInMs = getTimeStamp(); |
| |
| var socketIndex = 0; |
| while (totalSize < config.minTotal) { |
| sockets[socketIndex].send('receive ' + size); |
| socketIndex = (socketIndex + 1) % sockets.length; |
| |
| totalSize += size; |
| } |
| } |
| |
| function createSocket(config) { |
| // TODO(tyoshino): Add TCP warm up. |
| var url = config.prefixUrl; |
| |
| config.addToLog('Connect ' + url); |
| |
| var socket = new WebSocket(url); |
| socket.onmessage = function(event) { |
| config.addToLog('Unexpected message received. Aborting.'); |
| }; |
| socket.onerror = function() { |
| config.addToLog('Error'); |
| }; |
| socket.onclose = function(event) { |
| config.addToLog('Closed'); |
| }; |
| return socket; |
| } |
| |
| var tasks = []; |
| |
| function startBenchmark(config) { |
| clearTimeout(timerID); |
| destroyAllSockets(); |
| |
| numEstablishedSockets = 0; |
| |
| for (var i = 0; i < config.numSockets; ++i) { |
| var socket = createSocket(config); |
| socket.onopen = function() { |
| config.addToLog('Opened'); |
| |
| ++numEstablishedSockets; |
| |
| if (numEstablishedSockets == sockets.length) { |
| runNextTask(config); |
| } |
| }; |
| sockets.push(socket); |
| } |
| } |
| |
| function runNextTask(config) { |
| var task = tasks.shift(); |
| if (task == undefined) { |
| config.addToLog('Finished'); |
| destroyAllSockets(); |
| 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 getConfigString(config) { |
| return '(WebSocket' + |
| ', ' + (typeof importScripts !== "undefined" ? 'Worker' : 'Main') + |
| ', numSockets=' + config.numSockets + |
| ', numIterations=' + config.numIterations + |
| ', verifyData=' + config.verifyData + |
| ', minTotal=' + config.minTotal + |
| ', numWarmUpIterations=' + config.numWarmUpIterations + |
| ')'; |
| } |
| |
| 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(config) { |
| config.addToLog('Batch benchmark'); |
| config.addToLog(buildLegendString(config)); |
| |
| tasks = []; |
| clearAverageData(); |
| addTasks(config, sendBenchmarkStep); |
| addResultReportingTask(config, 'Send Benchmark ' + getConfigString(config)); |
| addTasks(config, receiveBenchmarkStep); |
| addResultReportingTask(config, 'Receive Benchmark ' + |
| getConfigString(config)); |
| startBenchmark(config); |
| } |
| |
| function stop(config) { |
| clearTimeout(timerID); |
| timerID = null; |
| config.addToLog('Stopped'); |
| destroyAllSockets(); |
| } |
| |
| 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); |
| }; |