1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/profiler/cleopatra/js/parser.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,271 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +Array.prototype.clone = function() { return this.slice(0); } 1.11 + 1.12 +function makeSample(frames, extraInfo, lines) { 1.13 + return { 1.14 + frames: frames, 1.15 + extraInfo: extraInfo, 1.16 + lines: lines 1.17 + }; 1.18 +} 1.19 + 1.20 +function cloneSample(sample) { 1.21 + return makeSample(sample.frames.clone(), sample.extraInfo, sample.lines.clone()); 1.22 +} 1.23 + 1.24 +function bucketsBySplittingArray(array, maxItemsPerBucket) { 1.25 + var buckets = []; 1.26 + while (buckets.length * maxItemsPerBucket < array.length) { 1.27 + buckets.push(array.slice(buckets.length * maxItemsPerBucket, 1.28 + (buckets.length + 1) * maxItemsPerBucket)); 1.29 + } 1.30 + return buckets; 1.31 +} 1.32 + 1.33 +var gParserWorker = new Worker("profiler/cleopatra/js/parserWorker.js"); 1.34 +gParserWorker.nextRequestID = 0; 1.35 + 1.36 +function WorkerRequest(worker) { 1.37 + var self = this; 1.38 + this._eventListeners = {}; 1.39 + var requestID = worker.nextRequestID++; 1.40 + this._requestID = requestID; 1.41 + this._worker = worker; 1.42 + this._totalReporter = new ProgressReporter(); 1.43 + this._totalReporter.addListener(function (reporter) { 1.44 + self._fireEvent("progress", reporter.getProgress(), reporter.getAction()); 1.45 + }) 1.46 + this._sendChunkReporter = this._totalReporter.addSubreporter(500); 1.47 + this._executeReporter = this._totalReporter.addSubreporter(3000); 1.48 + this._receiveChunkReporter = this._totalReporter.addSubreporter(100); 1.49 + this._totalReporter.begin("Processing task in worker..."); 1.50 + var partialResult = null; 1.51 + function onMessageFromWorker(msg) { 1.52 + pendingMessages.push(msg); 1.53 + scheduleMessageProcessing(); 1.54 + } 1.55 + function processMessage(msg) { 1.56 + var startTime = Date.now(); 1.57 + var data = msg.data; 1.58 + var readTime = Date.now() - startTime; 1.59 + 1.60 + if (data.requestID == requestID || !data.requestID) { 1.61 + switch(data.type) { 1.62 + case "error": 1.63 + self._sendChunkReporter.setAction("Error in worker: " + data.error); 1.64 + self._executeReporter.setAction("Error in worker: " + data.error); 1.65 + self._receiveChunkReporter.setAction("Error in worker: " + data.error); 1.66 + self._totalReporter.setAction("Error in worker: " + data.error); 1.67 + PROFILERERROR("Error in worker: " + data.error); 1.68 + self._fireEvent("error", data.error); 1.69 + break; 1.70 + case "progress": 1.71 + self._executeReporter.setProgress(data.progress); 1.72 + break; 1.73 + case "finished": 1.74 + self._executeReporter.finish(); 1.75 + self._receiveChunkReporter.begin("Receiving data from worker..."); 1.76 + self._receiveChunkReporter.finish(); 1.77 + self._fireEvent("finished", data.result); 1.78 + worker.removeEventListener("message", onMessageFromWorker); 1.79 + break; 1.80 + case "finishedStart": 1.81 + partialResult = null; 1.82 + self._totalReceiveChunks = data.numChunks; 1.83 + self._gotReceiveChunks = 0; 1.84 + self._executeReporter.finish(); 1.85 + self._receiveChunkReporter.begin("Receiving data from worker..."); 1.86 + break; 1.87 + case "finishedChunk": 1.88 + partialResult = partialResult ? partialResult.concat(data.chunk) : data.chunk; 1.89 + var chunkIndex = self._gotReceiveChunks++; 1.90 + self._receiveChunkReporter.setProgress((chunkIndex + 1) / self._totalReceiveChunks); 1.91 + break; 1.92 + case "finishedEnd": 1.93 + self._receiveChunkReporter.finish(); 1.94 + self._fireEvent("finished", partialResult); 1.95 + worker.removeEventListener("message", onMessageFromWorker); 1.96 + break; 1.97 + } 1.98 + // dump log if present 1.99 + if (data.log) { 1.100 + for (var line in data.log) { 1.101 + PROFILERLOG(line); 1.102 + } 1.103 + } 1.104 + } 1.105 + } 1.106 + var pendingMessages = []; 1.107 + var messageProcessingTimer = 0; 1.108 + function processMessages() { 1.109 + messageProcessingTimer = 0; 1.110 + processMessage(pendingMessages.shift()); 1.111 + if (pendingMessages.length) 1.112 + scheduleMessageProcessing(); 1.113 + } 1.114 + function scheduleMessageProcessing() { 1.115 + if (messageProcessingTimer) 1.116 + return; 1.117 + messageProcessingTimer = setTimeout(processMessages, 10); 1.118 + } 1.119 + worker.addEventListener("message", onMessageFromWorker); 1.120 +} 1.121 + 1.122 +WorkerRequest.prototype = { 1.123 + send: function WorkerRequest_send(task, taskData) { 1.124 + this._sendChunkReporter.begin("Sending data to worker..."); 1.125 + var startTime = Date.now(); 1.126 + this._worker.postMessage({ 1.127 + requestID: this._requestID, 1.128 + task: task, 1.129 + taskData: taskData 1.130 + }); 1.131 + var postTime = Date.now() - startTime; 1.132 + this._sendChunkReporter.finish(); 1.133 + this._executeReporter.begin("Processing worker request..."); 1.134 + }, 1.135 + sendInChunks: function WorkerRequest_sendInChunks(task, taskData, params, maxChunkSize) { 1.136 + this._sendChunkReporter.begin("Sending data to worker..."); 1.137 + var self = this; 1.138 + var chunks = bucketsBySplittingArray(taskData, maxChunkSize); 1.139 + var pendingMessages = [ 1.140 + { 1.141 + requestID: this._requestID, 1.142 + task: "chunkedStart", 1.143 + numChunks: chunks.length 1.144 + } 1.145 + ].concat(chunks.map(function (chunk) { 1.146 + return { 1.147 + requestID: self._requestID, 1.148 + task: "chunkedChunk", 1.149 + chunk: chunk 1.150 + }; 1.151 + })).concat([ 1.152 + { 1.153 + requestID: this._requestID, 1.154 + task: "chunkedEnd" 1.155 + }, 1.156 + { 1.157 + requestID: this._requestID, 1.158 + params: params, 1.159 + task: task 1.160 + }, 1.161 + ]); 1.162 + var totalMessages = pendingMessages.length; 1.163 + var numSentMessages = 0; 1.164 + function postMessage(msg) { 1.165 + var msgIndex = numSentMessages++; 1.166 + var startTime = Date.now(); 1.167 + self._worker.postMessage(msg); 1.168 + var postTime = Date.now() - startTime; 1.169 + self._sendChunkReporter.setProgress((msgIndex + 1) / totalMessages); 1.170 + } 1.171 + var messagePostingTimer = 0; 1.172 + function postMessages() { 1.173 + messagePostingTimer = 0; 1.174 + postMessage(pendingMessages.shift()); 1.175 + if (pendingMessages.length) { 1.176 + scheduleMessagePosting(); 1.177 + } else { 1.178 + self._sendChunkReporter.finish(); 1.179 + self._executeReporter.begin("Processing worker request..."); 1.180 + } 1.181 + } 1.182 + function scheduleMessagePosting() { 1.183 + if (messagePostingTimer) 1.184 + return; 1.185 + messagePostingTimer = setTimeout(postMessages, 10); 1.186 + } 1.187 + scheduleMessagePosting(); 1.188 + }, 1.189 + 1.190 + // TODO: share code with TreeView 1.191 + addEventListener: function WorkerRequest_addEventListener(eventName, callbackFunction) { 1.192 + if (!(eventName in this._eventListeners)) 1.193 + this._eventListeners[eventName] = []; 1.194 + if (this._eventListeners[eventName].indexOf(callbackFunction) != -1) 1.195 + return; 1.196 + this._eventListeners[eventName].push(callbackFunction); 1.197 + }, 1.198 + removeEventListener: function WorkerRequest_removeEventListener(eventName, callbackFunction) { 1.199 + if (!(eventName in this._eventListeners)) 1.200 + return; 1.201 + var index = this._eventListeners[eventName].indexOf(callbackFunction); 1.202 + if (index == -1) 1.203 + return; 1.204 + this._eventListeners[eventName].splice(index, 1); 1.205 + }, 1.206 + _fireEvent: function WorkerRequest__fireEvent(eventName, eventObject, p1) { 1.207 + if (!(eventName in this._eventListeners)) 1.208 + return; 1.209 + this._eventListeners[eventName].forEach(function (callbackFunction) { 1.210 + callbackFunction(eventObject, p1); 1.211 + }); 1.212 + }, 1.213 +} 1.214 + 1.215 +var Parser = { 1.216 + parse: function Parser_parse(data, params) { 1.217 + var request = new WorkerRequest(gParserWorker); 1.218 + request.sendInChunks("parseRawProfile", data, params, 3000000); 1.219 + return request; 1.220 + }, 1.221 + 1.222 + updateFilters: function Parser_updateFilters(filters) { 1.223 + var request = new WorkerRequest(gParserWorker); 1.224 + request.send("updateFilters", { 1.225 + filters: filters, 1.226 + profileID: 0 1.227 + }); 1.228 + return request; 1.229 + }, 1.230 + 1.231 + updateViewOptions: function Parser_updateViewOptions(options) { 1.232 + var request = new WorkerRequest(gParserWorker); 1.233 + request.send("updateViewOptions", { 1.234 + options: options, 1.235 + profileID: 0 1.236 + }); 1.237 + return request; 1.238 + }, 1.239 + 1.240 + getSerializedProfile: function Parser_getSerializedProfile(complete, callback) { 1.241 + var request = new WorkerRequest(gParserWorker); 1.242 + request.send("getSerializedProfile", { 1.243 + profileID: 0, 1.244 + complete: complete 1.245 + }); 1.246 + request.addEventListener("finished", callback); 1.247 + }, 1.248 + 1.249 + calculateHistogramData: function Parser_calculateHistogramData() { 1.250 + var request = new WorkerRequest(gParserWorker); 1.251 + request.send("calculateHistogramData", { 1.252 + profileID: 0 1.253 + }); 1.254 + return request; 1.255 + }, 1.256 + 1.257 + calculateDiagnosticItems: function Parser_calculateDiagnosticItems(meta) { 1.258 + var request = new WorkerRequest(gParserWorker); 1.259 + request.send("calculateDiagnosticItems", { 1.260 + profileID: 0, 1.261 + meta: meta 1.262 + }); 1.263 + return request; 1.264 + }, 1.265 + 1.266 + updateLogSetting: function Parser_updateLogSetting() { 1.267 + var request = new WorkerRequest(gParserWorker); 1.268 + request.send("initWorker", { 1.269 + debugLog: gDebugLog, 1.270 + debugTrace: gDebugTrace, 1.271 + }); 1.272 + return request; 1.273 + }, 1.274 +};