summaryrefslogtreecommitdiff
path: root/browser/devtools/performance/modules/io.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/devtools/performance/modules/io.js')
-rw-r--r--browser/devtools/performance/modules/io.js147
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;
+}