author | Ryan VanderMeulen <ryanvm@gmail.com> |
Tue, 01 Sep 2015 12:58:44 -0400 | |
changeset 260401 | 0fe4f8d8a63b264434d3755c05c9f234c5233097 |
parent 260400 | 375ec989b33a7858dd5f271a28ee98baa54e528e |
child 260402 | f546981ba4dc1a7369e2e602fbdd93d4f695cf54 |
push id | 64495 |
push user | ryanvm@gmail.com |
push date | Wed, 02 Sep 2015 01:16:33 +0000 |
treeherder | mozilla-inbound@e747377d86eb [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1171488 |
milestone | 43.0a1 |
backs out | 8613a4ad3e3ba283fa7cbf3a31ee91178dd37b6e |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/addon-sdk/source/lib/node/os.js +++ b/addon-sdk/source/lib/node/os.js @@ -6,37 +6,23 @@ module.metadata = { "stability": "unstable" }; const { Cc, Ci } = require('chrome'); const system = require('../sdk/system'); const runtime = require('../sdk/system/runtime'); -const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); +const oscpu = Cc["@mozilla.org/network/protocol;1?name=http"] + .getService(Ci.nsIHttpProtocolHandler).oscpu; +const hostname = Cc["@mozilla.org/network/dns-service;1"] + .getService(Ci.nsIDNSService).myHostName; const isWindows = system.platform === 'win32'; const endianness = ((new Uint32Array((new Uint8Array([1,2,3,4])).buffer))[0] === 0x04030201) ? 'LE' : 'BE'; -XPCOMUtils.defineLazyGetter(this, "oscpu", () => { - try { - return Cc["@mozilla.org/network/protocol;1?name=http"].getService(Ci.nsIHttpProtocolHandler).oscpu; - } catch (e) { - return ""; - } -}); - -XPCOMUtils.defineLazyGetter(this, "hostname", () => { - try { - // On some platforms (Linux according to try), this service does not exist and fails. - return Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService).myHostName; - } catch (e) { - return ""; - } -}); - /** * Returns a path to a temp directory */ exports.tmpdir = () => system.pathFor('TmpD'); /** * Returns the endianness of the architecture: either 'LE' or 'BE' */
--- a/toolkit/devtools/performance/io.js +++ b/toolkit/devtools/performance/io.js @@ -148,19 +148,17 @@ function convertLegacyData (legacyData) profile: profilerData.profile, // Fake a configuration object here if there's tick data, // so that it can be rendered configuration: { withTicks: !!ticksData.length, withMarkers: false, withMemory: false, withAllocations: false - }, - systemHost: {}, - systemClient: {}, + } }; return data; } exports.getUnicodeConverter = getUnicodeConverter; exports.saveRecordingToFile = saveRecordingToFile; exports.loadRecordingFromFile = loadRecordingFromFile;
--- a/toolkit/devtools/performance/legacy/front.js +++ b/toolkit/devtools/performance/legacy/front.js @@ -16,20 +16,16 @@ loader.lazyRequireGetter(this, "Actors", loader.lazyRequireGetter(this, "LegacyPerformanceRecording", "devtools/toolkit/performance/legacy/recording", true); loader.lazyRequireGetter(this, "importRecording", "devtools/toolkit/performance/legacy/recording", true); loader.lazyRequireGetter(this, "normalizePerformanceFeatures", "devtools/toolkit/performance/utils", true); loader.lazyRequireGetter(this, "DevToolsUtils", "devtools/toolkit/DevToolsUtils"); -loader.lazyRequireGetter(this, "getDeviceFront", - "devtools/toolkit/server/actors/device", true); -loader.lazyRequireGetter(this, "getSystemInfo", - "devtools/toolkit/shared/system", true); loader.lazyRequireGetter(this, "events", "sdk/event/core"); loader.lazyRequireGetter(this, "EventTarget", "sdk/event/target", true); loader.lazyRequireGetter(this, "Class", "sdk/core/heritage", true); /** @@ -332,48 +328,39 @@ const LegacyPerformanceFront = Class({ // from the LegacyPerformanceFront or via `console-profile-stop` event) and then // remove it from the internal store. // // In the case where a console.profile is generated via the console (so the tools are // open), we initialize the Performance tool so it can listen to those events. this._recordings.splice(this._recordings.indexOf(model), 1); let config = model.getConfiguration(); - let startTime = model._getProfilerStartTime(); + let startTime = model.getProfilerStartTime(); let profilerData = yield this._profiler.getProfile({ startTime }); let timelineEndTime = Date.now(); // Only if there are no more sessions recording do we stop // the underlying timeline actors. If we're still recording, // juse use Date.now() for the timeline end times, as those // are only used in tests. if (!this.isRecording()) { // This doesn't stop the profiler, just turns off polling for // events, and also turns off events on timeline actors. yield this._profiler.stop(); timelineEndTime = yield this._timeline.stop(config); } - let systemDeferred = promise.defer(); - this._client.listTabs(form => { - systemDeferred.resolve(getDeviceFront(this._client, form).getDescription()); - }); - let systemHost = yield systemDeferred.promise; - let systemClient = yield getSystemInfo(); - // Set the results on the LegacyPerformanceRecording itself. model._onStopRecording({ // Data available only at the end of a recording. profile: profilerData.profile, // End times for all the actors. profilerEndTime: profilerData.currentTime, - timelineEndTime: timelineEndTime, - systemHost, - systemClient, + timelineEndTime: timelineEndTime }); events.emit(this, "recording-stopped", model); return model; }), /** * Creates a recording object when given a nsILocalFile.
--- a/toolkit/devtools/performance/legacy/recording.js +++ b/toolkit/devtools/performance/legacy/recording.js @@ -5,19 +5,16 @@ const { Cc, Ci, Cu, Cr } = require("chrome"); const { Task } = require("resource://gre/modules/Task.jsm"); loader.lazyRequireGetter(this, "PerformanceIO", "devtools/toolkit/performance/io"); loader.lazyRequireGetter(this, "RecordingUtils", "devtools/toolkit/performance/utils"); -loader.lazyRequireGetter(this, "PerformanceRecordingCommon", - "devtools/toolkit/performance/recording-common", true); -loader.lazyRequireGetter(this, "merge", "sdk/util/object", true); /** * Model for a wholistic profile, containing the duration, profiling data, * frames data, timeline (marker, tick, memory) data, and methods to mark * a recording as 'in progress' or 'finished'. */ const LegacyPerformanceRecording = function (options={}) { this._label = options.label || ""; @@ -31,20 +28,59 @@ const LegacyPerformanceRecording = funct withJITOptimizations: options.withJITOptimizations || false, allocationsSampleProbability: options.allocationsSampleProbability || 0, allocationsMaxLogLength: options.allocationsMaxLogLength || 0, bufferSize: options.bufferSize || 0, sampleFrequency: options.sampleFrequency || 1 }; }; -LegacyPerformanceRecording.prototype = merge({ +LegacyPerformanceRecording.prototype = { + // Private fields, only needed when a recording is started or stopped. + _console: false, + _imported: false, + _recording: false, + _completed: false, _profilerStartTime: 0, _timelineStartTime: 0, _memoryStartTime: 0, + _configuration: {}, + _startingBufferStatus: null, + _bufferPercent: null, + + // Serializable fields, necessary and sufficient for import and export. + _label: "", + _duration: 0, + _markers: null, + _frames: null, + _memory: null, + _ticks: null, + _allocations: null, + _profile: null, + + /** + * Loads a recording from a file. + * + * @param nsILocalFile file + * The file to import the data form. + */ + importRecording: Task.async(function *(file) { + let recordingData = yield PerformanceIO.loadRecordingFromFile(file); + + this._imported = true; + this._label = recordingData.label || ""; + this._duration = recordingData.duration; + this._markers = recordingData.markers; + this._frames = recordingData.frames; + this._memory = recordingData.memory; + this._ticks = recordingData.ticks; + this._allocations = recordingData.allocations; + this._profile = recordingData.profile; + this._configuration = recordingData.configuration || {}; + }), /** * Saves the current recording to a file. * * @param nsILocalFile file * The file to stream the data into. */ exportRecording: Task.async(function *(file) { @@ -66,21 +102,21 @@ LegacyPerformanceRecording.prototype = m this._profilerStartTime = info.profilerStartTime; this._timelineStartTime = info.timelineStartTime; this._memoryStartTime = info.memoryStartTime; this._startingBufferStatus = { position: info.position, totalSize: info.totalSize, generation: info.generation }; + // initialize the _bufferPercent if the server supports it. + this._bufferPercent = info.position !== void 0 ? 0 : null; this._recording = true; - this._systemHost = {}; - this._systemClient = {}; this._markers = []; this._frames = []; this._memory = []; this._ticks = []; this._allocations = { sites: [], timestamps: [], frames: [], sizes: [] }; }, /** @@ -93,46 +129,191 @@ LegacyPerformanceRecording.prototype = m this._duration = endTime - this._localStartTime; this._recording = false; }, /** * Sets results available from stopping a recording from PerformanceFront. * Should only be called by PerformanceFront. */ - _onStopRecording: Task.async(function *({ profilerEndTime, profile, systemClient, systemHost }) { + _onStopRecording: Task.async(function *({ profilerEndTime, profile }) { // Update the duration with the accurate profilerEndTime, so we don't have // samples outside of the approximate duration set in `_onStoppingRecording`. this._duration = profilerEndTime - this._profilerStartTime; this._profile = profile; this._completed = true; // We filter out all samples that fall out of current profile's range // since the profiler is continuously running. Because of this, sample // times are not guaranteed to have a zero epoch, so offset the // timestamps. RecordingUtils.offsetSampleTimes(this._profile, this._profilerStartTime); // Markers need to be sorted ascending by time, to be properly displayed // in a waterfall view. this._markers = this._markers.sort((a, b) => (a.start > b.start)); - - this._systemHost = systemHost; - this._systemClient = systemClient; }), /** * Gets the profile's start time. * @return number */ - _getProfilerStartTime: function () { + getProfilerStartTime: function () { return this._profilerStartTime; }, /** + * Gets the profile's label, from `console.profile(LABEL)`. + * @return string + */ + getLabel: function () { + return this._label; + }, + + /** + * Gets duration of this recording, in milliseconds. + * @return number + */ + getDuration: function () { + // Compute an approximate ending time for the current recording if it is + // still in progress. This is needed to ensure that the view updates even + // when new data is not being generated. + if (this._recording) { + return Date.now() - this._localStartTime; + } else { + return this._duration; + } + }, + + /** + * Returns configuration object of specifying whether the recording + * was started withTicks, withMemory and withAllocations, and other configurations. + * @return object + */ + getConfiguration: function () { + return this._configuration; + }, + + /** + * Gets the accumulated markers in the current recording. + * @return array + */ + getMarkers: function() { + return this._markers; + }, + + /** + * Gets the accumulated stack frames in the current recording. + * @return array + */ + getFrames: function() { + return this._frames; + }, + + /** + * Gets the accumulated memory measurements in this recording. + * @return array + */ + getMemory: function() { + return this._memory; + }, + + /** + * Gets the accumulated refresh driver ticks in this recording. + * @return array + */ + getTicks: function() { + return this._ticks; + }, + + /** + * Gets the memory allocations data in this recording. + * @return array + */ + getAllocations: function() { + return this._allocations; + }, + + /** + * Gets the profiler data in this recording. + * @return array + */ + getProfile: function() { + return this._profile; + }, + + /** + * Gets all the data in this recording. + */ + getAllData: function() { + let label = this.getLabel(); + let duration = this.getDuration(); + let markers = this.getMarkers(); + let frames = this.getFrames(); + let memory = this.getMemory(); + let ticks = this.getTicks(); + let allocations = this.getAllocations(); + let profile = this.getProfile(); + let configuration = this.getConfiguration(); + return { label, duration, markers, frames, memory, ticks, allocations, profile, configuration }; + }, + + /** + * Returns a boolean indicating whether or not this recording model + * was imported via file. + */ + isImported: function () { + return this._imported; + }, + + /** + * Returns a boolean indicating whether or not this recording model + * was started via a `console.profile` call. + */ + isConsole: function () { + return this._console; + }, + + /** + * Returns a boolean indicating whether or not this recording model + * has finished recording. + * There is some delay in fetching data between when the recording stops, and + * when the recording is considered completed once it has all the profiler and timeline data. + */ + isCompleted: function () { + return this._completed || this.isImported(); + }, + + /** + * Returns a boolean indicating whether or not this recording model + * is recording. + * A model may no longer be recording, yet still not have the profiler data. In that + * case, use `isCompleted()`. + */ + isRecording: function () { + return this._recording; + }, + + /** + * Returns a boolean indicating if this recording is no longer recording, but + * not yet completed. + */ + isFinalizing: function () { + return !this.isRecording() && !this.isCompleted(); + }, + + /** + * Returns the position, generation and totalSize of the profiler + * when this recording was started. + */ + getStartingBufferStatus: function () { + return this._startingBufferStatus; + }, + + /** * Fired whenever the PerformanceFront emits markers, memory or ticks. */ _addTimelineData: function (eventName, ...data) { // If this model isn't currently recording, // ignore the timeline data. if (!this.isRecording()) { return; } @@ -162,11 +343,11 @@ LegacyPerformanceRecording.prototype = m let [, timestamps] = data; this._ticks = timestamps; break; } } }, toString: () => "[object LegacyPerformanceRecording]" -}, PerformanceRecordingCommon); +}; exports.LegacyPerformanceRecording = LegacyPerformanceRecording;
--- a/toolkit/devtools/performance/moz.build +++ b/toolkit/devtools/performance/moz.build @@ -5,17 +5,16 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini'] EXTRA_JS_MODULES.devtools.performance += [ 'io.js', 'process-communication.js', 'recorder.js', - 'recording-common.js', 'utils.js', ] EXTRA_JS_MODULES.devtools.performance.legacy += [ 'legacy/actors.js', 'legacy/compatibility.js', 'legacy/front.js', 'legacy/recording.js',
--- a/toolkit/devtools/performance/recorder.js +++ b/toolkit/devtools/performance/recorder.js @@ -20,24 +20,23 @@ loader.lazyRequireGetter(this, "events", loader.lazyRequireGetter(this, "Memory", "devtools/toolkit/shared/memory", true); loader.lazyRequireGetter(this, "Timeline", "devtools/toolkit/shared/timeline", true); loader.lazyRequireGetter(this, "Profiler", "devtools/toolkit/shared/profiler", true); loader.lazyRequireGetter(this, "PerformanceRecordingActor", "devtools/server/actors/performance-recording", true); + loader.lazyRequireGetter(this, "PerformanceRecordingFront", "devtools/server/actors/performance-recording", true); loader.lazyRequireGetter(this, "mapRecordingOptions", "devtools/toolkit/performance/utils", true); loader.lazyRequireGetter(this, "DevToolsUtils", "devtools/toolkit/DevToolsUtils"); -loader.lazyRequireGetter(this, "getSystemInfo", - "devtools/toolkit/shared/system", true); const PROFILER_EVENTS = [ "console-api-profiler", "profiler-started", "profiler-stopped", "profiler-status" ]; @@ -65,36 +64,31 @@ const PerformanceRecorder = exports.Perf this._onTimelineData = this._onTimelineData.bind(this); this._onProfilerEvent = this._onProfilerEvent.bind(this); }, /** * Initializes a connection to the profiler and other miscellaneous actors. * If in the process of opening, or already open, nothing happens. * - * @param {Object} options.systemClient - * Metadata about the client's system to attach to the recording models. - * * @return object * A promise that is resolved once the connection is established. */ - connect: function (options) { + connect: function () { if (this._connected) { return; } // Sets `this._profiler`, `this._timeline` and `this._memory`. // Only initialize the timeline and memory fronts if the respective actors // are available. Older Gecko versions don't have existing implementations, // in which case all the methods we need can be easily mocked. this._connectComponents(); this._registerListeners(); - this._systemClient = options.systemClient; - this._connected = true; }, /** * Destroys this connection. */ destroy: function () { this._unregisterListeners(); @@ -342,19 +336,16 @@ const PerformanceRecorder = exports.Perf // Filter out start times that are not actually used (0 or undefined), and // find the earliest time since all sources use same epoch. let startTimes = [profilerStartData.currentTime, memoryStartData, timelineStartData].filter(Boolean); data.startTime = Math.min(...startTimes); data.position = profilerStartData.position; data.generation = profilerStartData.generation; data.totalSize = profilerStartData.totalSize; - data.systemClient = this._systemClient; - data.systemHost = yield getSystemInfo(); - let model = new PerformanceRecordingActor(this.conn, options, data); this._recordings.push(model); events.emit(this, "recording-started", model); return model; }), /**
deleted file mode 100644 --- a/toolkit/devtools/performance/recording-common.js +++ /dev/null @@ -1,97 +0,0 @@ -/* 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"; - -/** - * A mixin to be used for PerformanceRecordingActor, PerformanceRecordingFront, - * and LegacyPerformanceRecording for helper methods to access data. - */ - -const PerformanceRecordingCommon = exports.PerformanceRecordingCommon = { - // Private fields, only needed when a recording is started or stopped. - _console: false, - _imported: false, - _recording: false, - _completed: false, - _configuration: {}, - _startingBufferStatus: null, - _localStartTime: 0, - - // Serializable fields, necessary and sufficient for import and export. - _label: "", - _duration: 0, - _markers: null, - _frames: null, - _memory: null, - _ticks: null, - _allocations: null, - _profile: null, - _systemHost: null, - _systemClient: null, - - /** - * Helper methods for returning the status of the recording. - * These methods should be consistent on both the front and actor. - */ - isRecording: function () { return this._recording; }, - isCompleted: function () { return this._completed || this.isImported(); }, - isFinalizing: function () { return !this.isRecording() && !this.isCompleted(); }, - isConsole: function () { return this._console; }, - isImported: function () { return this._imported; }, - - /** - * Helper methods for returning configuration for the recording. - * These methods should be consistent on both the front and actor. - */ - getConfiguration: function () { return this._configuration; }, - getLabel: function () { return this._label; }, - - /** - * Gets duration of this recording, in milliseconds. - * @return number - */ - getDuration: function () { - // Compute an approximate ending time for the current recording if it is - // still in progress. This is needed to ensure that the view updates even - // when new data is not being generated. If recording is completed, use - // the duration from the profiler; if between recording and being finalized, - // use the last estimated duration. - if (this.isRecording()) { - return this._estimatedDuration = Date.now() - this._localStartTime; - } else { - return this._duration || this._estimatedDuration || 0; - } - }, - - /** - * Helper methods for returning recording data. - * These methods should be consistent on both the front and actor. - */ - getMarkers: function() { return this._markers; }, - getFrames: function() { return this._frames; }, - getMemory: function() { return this._memory; }, - getTicks: function() { return this._ticks; }, - getAllocations: function() { return this._allocations; }, - getProfile: function() { return this._profile; }, - getHostSystemInfo: function() { return this._systemHost; }, - getClientSystemInfo: function() { return this._systemClient; }, - getStartingBufferStatus: function() { return this._startingBufferStatus; }, - - getAllData: function () { - let label = this.getLabel(); - let duration = this.getDuration(); - let markers = this.getMarkers(); - let frames = this.getFrames(); - let memory = this.getMemory(); - let ticks = this.getTicks(); - let allocations = this.getAllocations(); - let profile = this.getProfile(); - let configuration = this.getConfiguration(); - let systemHost = this.getHostSystemInfo(); - let systemClient = this.getClientSystemInfo(); - - return { label, duration, markers, frames, memory, ticks, allocations, profile, configuration, systemHost, systemClient }; - }, -};
--- a/toolkit/devtools/server/actors/performance-recording.js +++ b/toolkit/devtools/server/actors/performance-recording.js @@ -10,18 +10,82 @@ const { custom, method, RetVal, Arg, Opt const { actorBridge } = require("devtools/server/actors/common"); loader.lazyRequireGetter(this, "events", "sdk/event/core"); loader.lazyRequireGetter(this, "merge", "sdk/util/object", true); loader.lazyRequireGetter(this, "PerformanceIO", "devtools/toolkit/performance/io"); loader.lazyRequireGetter(this, "RecordingUtils", "devtools/toolkit/performance/utils"); -loader.lazyRequireGetter(this, "PerformanceRecordingCommon", - "devtools/toolkit/performance/recording-common", true); + +/** + * A set of functions used by both the front and actor to access + * internal properties. + */ +const PerformanceRecordingCommon = { + // Private fields, only needed when a recording is started or stopped. + _console: false, + _imported: false, + _recording: false, + _completed: false, + _configuration: {}, + _startingBufferStatus: null, + _localStartTime: null, + + // Serializable fields, necessary and sufficient for import and export. + _label: "", + _duration: 0, + _markers: null, + _frames: null, + _memory: null, + _ticks: null, + _allocations: null, + _profile: null, + + /** + * Helper methods for returning the status of the recording. + * These methods should be consistent on both the front and actor. + */ + isRecording: function () { return this._recording; }, + isCompleted: function () { return this._completed || this.isImported(); }, + isFinalizing: function () { return !this.isRecording() && !this.isCompleted(); }, + isConsole: function () { return this._console; }, + isImported: function () { return this._imported; }, + + /** + * Helper methods for returning configuration for the recording. + * These methods should be consistent on both the front and actor. + */ + getConfiguration: function () { return this._configuration; }, + getLabel: function () { return this._label; }, + + /** + * Helper methods for returning recording data. + * These methods should be consistent on both the front and actor. + */ + getMarkers: function() { return this._markers; }, + getFrames: function() { return this._frames; }, + getMemory: function() { return this._memory; }, + getTicks: function() { return this._ticks; }, + getAllocations: function() { return this._allocations; }, + getProfile: function() { return this._profile; }, + + getAllData: function () { + let label = this.getLabel(); + let duration = this.getDuration(); + let markers = this.getMarkers(); + let frames = this.getFrames(); + let memory = this.getMemory(); + let ticks = this.getTicks(); + let allocations = this.getAllocations(); + let profile = this.getProfile(); + let configuration = this.getConfiguration(); + return { label, duration, markers, frames, memory, ticks, allocations, profile, configuration }; + }, +}; /** * This actor wraps the Performance module at toolkit/devtools/shared/performance.js * and provides RDP definitions. * * @see toolkit/devtools/shared/performance.js for documentation. */ let PerformanceRecordingActor = exports.PerformanceRecordingActor = protocol.ActorClass(merge({ @@ -42,22 +106,19 @@ let PerformanceRecordingActor = exports. localStartTime: this._localStartTime, recording: this._recording, completed: this._completed, duration: this._duration, }; // Only send profiler data once it exists and it has // not yet been sent - if (this._profile && !this._sentFinalizedData) { - form.finalizedData = true; - form.profile = this.getProfile(); - form.systemHost = this.getHostSystemInfo(); - form.systemClient = this.getClientSystemInfo(); - this._sentFinalizedData = true; + if (this._profile && !this._sentProfilerData) { + form.profile = this._profile; + this._sentProfilerData = true; } return form; }, /** * @param {object} conn * @param {object} options @@ -98,19 +159,16 @@ let PerformanceRecordingActor = exports. }; this._recording = true; this._markers = []; this._frames = []; this._memory = []; this._ticks = []; this._allocations = { sites: [], timestamps: [], frames: [], sizes: [] }; - - this._systemHost = meta.systemHost || {}; - this._systemClient = meta.systemClient || {}; } }, destroy: function() { protocol.Actor.prototype.destroy.call(this); }, /** @@ -170,20 +228,18 @@ let PerformanceRecordingFront = exports. this._console = form.console; this._label = form.label; this._startTime = form.startTime; this._localStartTime = form.localStartTime; this._recording = form.recording; this._completed = form.completed; this._duration = form.duration; - if (form.finalizedData) { + if (form.profile) { this._profile = form.profile; - this._systemHost = form.systemHost; - this._systemClient = form.systemClient; } // Sort again on the client side if we're using realtime markers and the recording // just finished. This is because GC/Compositing markers can come into the array out of order with // the other markers, leading to strange collapsing in waterfall view. if (this._completed && !this._markersSorted) { this._markers = this._markers.sort((a, b) => (a.start > b.start)); this._markersSorted = true; @@ -210,16 +266,43 @@ let PerformanceRecordingFront = exports. * The file to stream the data into. */ exportRecording: function (file) { let recordingData = this.getAllData(); return PerformanceIO.saveRecordingToFile(recordingData, file); }, /** + * Returns the position, generation, and totalSize of the profiler + * when this recording was started. + * + * @return {object} + */ + getStartingBufferStatus: function () { + return this._form.startingBufferStatus; + }, + + /** + * Gets duration of this recording, in milliseconds. + * @return number + */ + getDuration: function () { + // Compute an approximate ending time for the current recording if it is + // still in progress. This is needed to ensure that the view updates even + // when new data is not being generated. If recording is completed, use + // the duration from the profiler; if between recording and being finalized, + // use the last estimated duration. + if (this.isRecording()) { + return this._estimatedDuration = Date.now() - this._localStartTime; + } else { + return this._duration || this._estimatedDuration || 0; + } + }, + + /** * Fired whenever the PerformanceFront emits markers, memory or ticks. */ _addTimelineData: function (eventName, data) { let config = this.getConfiguration(); switch (eventName) { // Accumulate timeline markers into an array. Furthermore, the timestamps // do not have a zero epoch, so offset all of them by the start time.
--- a/toolkit/devtools/server/actors/performance.js +++ b/toolkit/devtools/server/actors/performance.js @@ -17,18 +17,16 @@ loader.lazyRequireGetter(this, "extend", loader.lazyRequireGetter(this, "PerformanceRecorder", "devtools/toolkit/performance/recorder", true); loader.lazyRequireGetter(this, "PerformanceIO", "devtools/toolkit/performance/io"); loader.lazyRequireGetter(this, "normalizePerformanceFeatures", "devtools/toolkit/performance/utils", true); loader.lazyRequireGetter(this, "LegacyPerformanceFront", "devtools/toolkit/performance/legacy/front", true); -loader.lazyRequireGetter(this, "getSystemInfo", - "devtools/toolkit/shared/system", true); const PIPE_TO_FRONT_EVENTS = new Set([ "recording-started", "recording-stopping", "recording-stopped", "profiler-status", "timeline-data", "console-profile-start" ]); const RECORDING_STATE_CHANGE_EVENTS = new Set([ "recording-started", "recording-stopping", "recording-stopped" @@ -94,23 +92,20 @@ let PerformanceActor = exports.Performan }, destroy: function () { events.off(this.bridge, "*", this._onRecorderEvent); this.bridge.destroy(); protocol.Actor.prototype.destroy.call(this); }, - connect: method(function (config) { - this.bridge.connect({ systemClient: config.systemClient }); - return { traits: this.traits }; - }, { - request: { options: Arg(0, "nullable:json") }, - response: RetVal("json") - }), + connect: method(function () { + this.bridge.connect(); + return this.traits; + }, { response: RetVal("json") }), startRecording: method(Task.async(function *(options={}) { let normalizedOptions = normalizePerformanceFeatures(options, this.traits.features); let recording = yield this.bridge.startRecording(normalizedOptions); this.manage(recording); return recording; @@ -182,27 +177,19 @@ const PerformanceFront = exports.Perform this.actorID = form.performanceActor; this.manage(this); }, destroy: function () { protocol.Front.prototype.destroy.call(this); }, - /** - * Conenct to the server, and handle once-off tasks like storing traits - * or system info. - */ - connect: custom(Task.async(function *() { - let systemClient = yield getSystemInfo(); - let { traits } = yield this._connect({ systemClient }); - this._traits = traits; - - return this._traits; - }), { + connect: custom(function () { + return this._connect().then(traits => this._traits = traits); + }, { impl: "_connect" }), get traits() { if (!this._traits) { Cu.reportError("Cannot access traits of PerformanceFront before calling `connect()`."); } return this._traits; @@ -247,18 +234,16 @@ const PerformanceFront = exports.Perform model._duration = recordingData.duration; model._markers = recordingData.markers; model._frames = recordingData.frames; model._memory = recordingData.memory; model._ticks = recordingData.ticks; model._allocations = recordingData.allocations; model._profile = recordingData.profile; model._configuration = recordingData.configuration || {}; - model._systemHost = recordingData.systemHost; - model._systemClient = recordingData.systemClient; return model; }); }, /** * Store profiler status when the position has been update so we can * calculate recording's buffer percentage usage after emitting the event. */
--- a/toolkit/devtools/server/tests/browser/browser_perf-legacy-front-01.js +++ b/toolkit/devtools/server/tests/browser/browser_perf-legacy-front-01.js @@ -48,18 +48,16 @@ add_task(function*() { ok(recording.getDuration() >= 0, "duration is a positive number"); isEmptyArray(recording.getMarkers(), "markers"); isEmptyArray(recording.getTicks(), "ticks"); isEmptyArray(recording.getMemory(), "memory"); isEmptyArray(recording.getAllocations().sites, "allocations.sites"); isEmptyArray(recording.getAllocations().timestamps, "allocations.timestamps"); isEmptyArray(recording.getAllocations().frames, "allocations.frames"); ok(recording.getProfile().threads[0].samples.data.length, "profile data has some samples"); - checkSystemInfo(recording, "Host"); - checkSystemInfo(recording, "Client"); yield front.destroy(); yield closeDebuggerClient(target.client); gBrowser.removeCurrentTab(); }); function isEmptyArray (array, name) { ok(Array.isArray(array), `${name} is an array`); @@ -73,15 +71,8 @@ function getTab (url) { content.location = url; return loaded.then(() => { return new Promise(resolve => { let isBlank = url == "about:blank"; waitForFocus(() => resolve(tab), content, isBlank); }); }); } - -function checkSystemInfo (recording, type) { - let data = recording[`get${type}SystemInfo`](); - for (let field of ["appid", "apptype", "vendor", "name", "version"]) { - ok(data[field], `get${type}SystemInfo() has ${field} property`); - } -}
--- a/toolkit/devtools/server/tests/browser/browser_perf-recording-actor-01.js +++ b/toolkit/devtools/server/tests/browser/browser_perf-recording-actor-01.js @@ -44,36 +44,23 @@ add_task(function*() { ok(!rec.isCompleted(), "recording is not yet completed on 'recording-stopping'"); ok(rec.isFinalizing(), "recording is considered finalizing between 'recording-stopping' and 'recording-stopped'"); } yield stopped; ok(!rec.isRecording(), "on 'recording-stopped', model is still no longer recording"); ok(rec.isCompleted(), "on 'recording-stopped', model is considered 'complete'"); - checkSystemInfo(rec, "Host"); - checkSystemInfo(rec, "Client"); - // Export and import a rec, and ensure it has the correct state. let file = FileUtils.getFile("TmpD", ["tmpprofile.json"]); file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8)); yield rec.exportRecording(file); let importedModel = yield front.importRecording(file); ok(importedModel.isCompleted(), "All imported recordings should be completed"); ok(!importedModel.isRecording(), "All imported recordings should not be recording"); ok(importedModel.isImported(), "All imported recordings should be considerd imported"); - checkSystemInfo(importedModel, "Host"); - checkSystemInfo(importedModel, "Client"); - yield front.destroy(); yield closeDebuggerClient(client); gBrowser.removeCurrentTab(); }); - -function checkSystemInfo (recording, type) { - let data = recording[`get${type}SystemInfo`](); - for (let field of ["appid", "apptype", "vendor", "name", "version"]) { - ok(data[field], `get${type}SystemInfo() has ${field} property`); - } -}
--- a/toolkit/devtools/shared/system.js +++ b/toolkit/devtools/shared/system.js @@ -3,17 +3,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const { Cc, Ci, Cu } = require("chrome"); const { Task } = require("resource://gre/modules/Task.jsm"); loader.lazyRequireGetter(this, "Services"); loader.lazyRequireGetter(this, "promise"); -loader.lazyRequireGetter(this, "OS", "resource://gre/modules/commonjs/node/os.js"); +loader.lazyRequireGetter(this, "OS", "resource://gre/modules/commonjs/node/os"); loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true); loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true); loader.lazyGetter(this, "screenManager", () => { return Cc["@mozilla.org/gfx/screenmanager;1"].getService(Ci.nsIScreenManager); }); loader.lazyGetter(this, "oscpu", () => { return Cc["@mozilla.org/network/protocol;1?name=http"]