michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: michael@0: this.EXPORTED_SYMBOLS = ["TelemetryStopwatch"]; michael@0: michael@0: let Telemetry = Cc["@mozilla.org/base/telemetry;1"] michael@0: .getService(Ci.nsITelemetry); michael@0: michael@0: // simpleTimers are directly associated with a histogram michael@0: // name. objectTimers are associated with an object _and_ michael@0: // a histogram name. michael@0: let simpleTimers = {}; michael@0: let objectTimers = new WeakMap(); michael@0: michael@0: this.TelemetryStopwatch = { michael@0: /** michael@0: * Starts a timer associated with a telemetry histogram. The timer can be michael@0: * directly associated with a histogram, or with a pair of a histogram and michael@0: * an object. michael@0: * michael@0: * @param aHistogram a string which must be a valid histogram name michael@0: * from TelemetryHistograms.h michael@0: * michael@0: * @param aObj Optional parameter. If specified, the timer is associated michael@0: * with this object, meaning that multiple timers for a same michael@0: * histogram may be run concurrently, as long as they are michael@0: * associated with different objects. michael@0: * michael@0: * @return true if the timer was successfully started, false otherwise. If a michael@0: * timer already exists, it can't be started again, and the existing michael@0: * one will be cleared in order to avoid measurements errors. michael@0: */ michael@0: start: function(aHistogram, aObj) { michael@0: if (!validTypes(aHistogram, aObj)) michael@0: return false; michael@0: michael@0: let timers; michael@0: if (aObj) { michael@0: timers = objectTimers.get(aObj, {}); michael@0: objectTimers.set(aObj, timers); michael@0: } else { michael@0: timers = simpleTimers; michael@0: } michael@0: michael@0: if (timers.hasOwnProperty(aHistogram)) { michael@0: delete timers[aHistogram]; michael@0: Cu.reportError("TelemetryStopwatch: key \"" + michael@0: aHistogram + "\" was already initialized"); michael@0: return false; michael@0: } michael@0: michael@0: timers[aHistogram] = Date.now(); michael@0: return true; michael@0: }, michael@0: michael@0: /** michael@0: * Deletes the timer associated with a telemetry histogram. The timer can be michael@0: * directly associated with a histogram, or with a pair of a histogram and michael@0: * an object. Important: Only use this method when a legitimate cancellation michael@0: * should be done. michael@0: * michael@0: * @param aHistogram a string which must be a valid histogram name michael@0: * from TelemetryHistograms.json michael@0: * michael@0: * @param aObj Optional parameter. If specified, the timer is associated michael@0: * with this object, meaning that multiple timers for a same michael@0: * histogram may be run concurrently, as long as they are michael@0: * associated with different objects. michael@0: * michael@0: * @return true if the timer exist and it was cleared, false otherwise. michael@0: */ michael@0: cancel: function ts_cancel(aHistogram, aObj) { michael@0: if (!validTypes(aHistogram, aObj)) michael@0: return false; michael@0: michael@0: let timers = aObj michael@0: ? objectTimers.get(aObj, {}) michael@0: : simpleTimers; michael@0: michael@0: if (timers.hasOwnProperty(aHistogram)) { michael@0: delete timers[aHistogram]; michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: }, michael@0: michael@0: /** michael@0: * Stops the timer associated with the given histogram (and object), michael@0: * calculates the time delta between start and finish, and adds the value michael@0: * to the histogram. michael@0: * michael@0: * @param aHistogram a string which must be a valid histogram name michael@0: * from TelemetryHistograms.h. If an invalid name michael@0: * is given, the function will throw. michael@0: * michael@0: * @param aObj Optional parameter which associates the histogram timer with michael@0: * the given object. michael@0: * michael@0: * @return true if the timer was succesfully stopped and the data was michael@0: * added to the histogram, false otherwise. michael@0: */ michael@0: finish: function(aHistogram, aObj) { michael@0: if (!validTypes(aHistogram, aObj)) michael@0: return false; michael@0: michael@0: let timers = aObj michael@0: ? objectTimers.get(aObj, {}) michael@0: : simpleTimers; michael@0: michael@0: let start = timers[aHistogram]; michael@0: delete timers[aHistogram]; michael@0: michael@0: if (start) { michael@0: let delta = Date.now() - start; michael@0: let histogram = Telemetry.getHistogramById(aHistogram); michael@0: histogram.add(delta); michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: function validTypes(aKey, aObj) { michael@0: return (typeof aKey == "string") && michael@0: (aObj === undefined || typeof aObj == "object"); michael@0: }