diff options
Diffstat (limited to 'browser/devtools/performance/modules/io.js')
-rw-r--r-- | browser/devtools/performance/modules/io.js | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/browser/devtools/performance/modules/io.js b/browser/devtools/performance/modules/io.js new file mode 100644 index 000000000..6239d5a00 --- /dev/null +++ b/browser/devtools/performance/modules/io.js @@ -0,0 +1,147 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const { Cc, Ci, Cu, Cr } = require("chrome"); + +loader.lazyRequireGetter(this, "Services"); +loader.lazyRequireGetter(this, "promise"); + +loader.lazyImporter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); +loader.lazyImporter(this, "NetUtil", + "resource://gre/modules/NetUtil.jsm"); + +// This identifier string is used to tentatively ascertain whether or not +// a JSON loaded from disk is actually something generated by this tool. +// It isn't, of course, a definitive verification, but a Good Enoughâ„¢ +// approximation before continuing the import. Don't localize this. +const PERF_TOOL_SERIALIZER_IDENTIFIER = "Recorded Performance Data"; +const PERF_TOOL_SERIALIZER_LEGACY_VERSION = 1; +const PERF_TOOL_SERIALIZER_CURRENT_VERSION = 2; + +/** + * Helpers for importing/exporting JSON. + */ +let PerformanceIO = { + /** + * Gets a nsIScriptableUnicodeConverter instance with a default UTF-8 charset. + * @return object + */ + getUnicodeConverter: function() { + let className = "@mozilla.org/intl/scriptableunicodeconverter"; + let converter = Cc[className].createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + return converter; + }, + + /** + * Saves a recording as JSON to a file. The provided data is assumed to be + * acyclical, so that it can be properly serialized. + * + * @param object recordingData + * The recording data to stream as JSON. + * @param nsILocalFile file + * The file to stream the data into. + * @return object + * A promise that is resolved once streaming finishes, or rejected + * if there was an error. + */ + saveRecordingToFile: function(recordingData, file) { + let deferred = promise.defer(); + + recordingData.fileType = PERF_TOOL_SERIALIZER_IDENTIFIER; + recordingData.version = PERF_TOOL_SERIALIZER_CURRENT_VERSION; + + let string = JSON.stringify(recordingData); + let inputStream = this.getUnicodeConverter().convertToInputStream(string); + let outputStream = FileUtils.openSafeFileOutputStream(file); + + NetUtil.asyncCopy(inputStream, outputStream, deferred.resolve); + return deferred.promise; + }, + + /** + * Loads a recording stored as JSON from a file. + * + * @param nsILocalFile file + * The file to import the data from. + * @return object + * A promise that is resolved once importing finishes, or rejected + * if there was an error. + */ + loadRecordingFromFile: function(file) { + let deferred = promise.defer(); + + let channel = NetUtil.newChannel(file); + channel.contentType = "text/plain"; + + NetUtil.asyncFetch(channel, (inputStream, status) => { + try { + let string = NetUtil.readInputStreamToString(inputStream, inputStream.available()); + var recordingData = JSON.parse(string); + } catch (e) { + deferred.reject(new Error("Could not read recording data file.")); + return; + } + if (recordingData.fileType != PERF_TOOL_SERIALIZER_IDENTIFIER) { + deferred.reject(new Error("Unrecognized recording data file.")); + return; + } + if (!isValidSerializerVersion(recordingData.version)) { + deferred.reject(new Error("Unsupported recording data file version.")); + return; + } + if (recordingData.version === PERF_TOOL_SERIALIZER_LEGACY_VERSION) { + recordingData = convertLegacyData(recordingData); + } + deferred.resolve(recordingData); + }); + + return deferred.promise; + } +}; + +exports.PerformanceIO = PerformanceIO; + +/** + * Returns a boolean indicating whether or not the passed in `version` + * is supported by this serializer. + * + * @param number version + * @return boolean + */ +function isValidSerializerVersion (version) { + return !!~[ + PERF_TOOL_SERIALIZER_LEGACY_VERSION, + PERF_TOOL_SERIALIZER_CURRENT_VERSION + ].indexOf(version); +} + +/** + * Takes recording data (with version `1`, from the original profiler tool), and + * massages the data to be line with the current performance tool's property names + * and values. + * + * @param object legacyData + * @return object + */ +function convertLegacyData (legacyData) { + let { profilerData, ticksData, recordingDuration } = legacyData; + + // The `profilerData` and `ticksData` stay, but the previously unrecorded + // fields just are empty arrays or objects. + let data = { + label: profilerData.profilerLabel, + duration: recordingDuration, + markers: [], + frames: [], + memory: [], + ticks: ticksData, + allocations: { sites: [], timestamps: [], frames: [], counts: [] }, + profile: profilerData.profile + }; + + return data; +} |