toolkit/devtools/server/actors/profiler.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 "use strict";
     7 var startedProfilers = 0;
     8 var startTime = 0;
    10 function getCurrentTime() {
    11   return (new Date()).getTime() - startTime;
    12 }
    14 /**
    15  * Creates a ProfilerActor. ProfilerActor provides remote access to the
    16  * built-in profiler module.
    17  *
    18  * ProfilerActor.onGetProfile returns a JavaScript object with data
    19  * generated by our built-in profiler moduele. It has the following
    20  * format:
    21  *
    22  * {
    23  *   libs: string,
    24  *   meta: {
    25  *     interval: number,
    26  *     platform: string,
    27  *     (...)
    28  *   },
    29  *   threads: [
    30  *     {
    31  *       samples: [
    32  *         {
    33  *           frames: [
    34  *             {
    35  *               line: number,
    36  *               location: string
    37  *             }
    38  *           ],
    39  *           name: string
    40  *           responsiveness: number (in ms)
    41  *           time: number (nspr time)
    42  *         }
    43  *       ]
    44  *     }
    45  *   ]
    46  * }
    47  *
    48  */
    49 function ProfilerActor(aConnection)
    50 {
    51   this._profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
    52   this._started = false;
    53   this._observedEvents = [];
    54 }
    56 ProfilerActor.prototype = {
    57   actorPrefix: "profiler",
    59   disconnect: function() {
    60     for (var event of this._observedEvents) {
    61       Services.obs.removeObserver(this, event);
    62     }
    64     this.stopProfiler();
    65     this._profiler = null;
    66   },
    68   stopProfiler: function() {
    69     // We stop the profiler only after the last client has
    70     // stopped profiling. Otherwise there's a problem where
    71     // we stop the profiler as soon as you close the devtools
    72     // panel in one tab even though there might be other
    73     // profiler instances running in other tabs.
    74     if (!this._started) {
    75       return;
    76     }
    77     this._started = false;
    78     startedProfilers -= 1;
    79     if (startedProfilers <= 0) {
    80       this._profiler.StopProfiler();
    81     }
    82   },
    84   onStartProfiler: function(aRequest) {
    85     this._profiler.StartProfiler(aRequest.entries, aRequest.interval,
    86                            aRequest.features, aRequest.features.length);
    87     this._started = true;
    88     startedProfilers += 1;
    89     startTime = (new Date()).getTime();
    90     return { "msg": "profiler started" }
    91   },
    92   onStopProfiler: function(aRequest) {
    93     this.stopProfiler();
    94     return { "msg": "profiler stopped" }
    95   },
    96   onGetProfileStr: function(aRequest) {
    97     var profileStr = this._profiler.GetProfile();
    98     return { "profileStr": profileStr }
    99   },
   100   onGetProfile: function(aRequest) {
   101     var profile = this._profiler.getProfileData();
   102     return { "profile": profile, "currentTime": getCurrentTime() }
   103   },
   104   onIsActive: function(aRequest) {
   105     var isActive = this._profiler.IsActive();
   106     var currentTime = isActive ? getCurrentTime() : null;
   107     return { "isActive": isActive, "currentTime": currentTime }
   108   },
   109   onGetResponsivenessTimes: function(aRequest) {
   110     var times = this._profiler.GetResponsivenessTimes({});
   111     return { "responsivenessTimes": times }
   112   },
   113   onGetFeatures: function(aRequest) {
   114     var features = this._profiler.GetFeatures([]);
   115     return { "features": features }
   116   },
   117   onGetSharedLibraryInformation: function(aRequest) {
   118     var sharedLibraries = this._profiler.getSharedLibraryInformation();
   119     return { "sharedLibraryInformation": sharedLibraries }
   120   },
   121   onRegisterEventNotifications: function(aRequest) {
   122     let registered = [];
   123     for (var event of aRequest.events) {
   124       if (this._observedEvents.indexOf(event) != -1)
   125         continue;
   126       Services.obs.addObserver(this, event, false);
   127       this._observedEvents.push(event);
   128       registered.push(event);
   129     }
   130     return { registered: registered }
   131   },
   132   onUnregisterEventNotifications: function(aRequest) {
   133     let unregistered = [];
   134     for (var event of aRequest.events) {
   135       let idx = this._observedEvents.indexOf(event);
   136       if (idx == -1)
   137         continue;
   138       Services.obs.removeObserver(this, event);
   139       this._observedEvents.splice(idx, 1);
   140       unregistered.push(event);
   141     }
   142     return { unregistered: unregistered }
   143   },
   144   observe: DevToolsUtils.makeInfallible(function(aSubject, aTopic, aData) {
   145     /*
   146      * this.conn.send can only transmit acyclic values. However, it is
   147      * idiomatic for wrapped JS objects like aSubject (and possibly aData?)
   148      * to have a 'wrappedJSObject' property pointing to themselves.
   149      *
   150      * this.conn.send also assumes that it can retain the object it is
   151      * passed to be handled on later event ticks; and that it's okay to
   152      * freeze it. Since we don't really know what aSubject and aData are,
   153      * we need to pass this.conn.send a copy of them, not the originals.
   154      *
   155      * We break the cycle and make the copy by JSON.stringifying those
   156      * values with a replacer that omits properties known to introduce
   157      * cycles, and then JSON.parsing the result. This spends processor
   158      * time, but it's simple.
   159      */
   160     function cycleBreaker(key, value) {
   161       if (key === 'wrappedJSObject') {
   162         return undefined;
   163       }
   164       return value;
   165     }
   167     /*
   168      * If these values are objects with a non-null 'wrappedJSObject' property
   169      * and aren't Xrays, use their .wrappedJSObject. Otherwise, use the value
   170      * unchanged.
   171      */
   172     aSubject = (aSubject && !Cu.isXrayWrapper(aSubject) && aSubject.wrappedJSObject) || aSubject;
   173     aData    = (aData && !Cu.isXrayWrapper(aData) && aData.wrappedJSObject) || aData;
   175     let subj = JSON.parse(JSON.stringify(aSubject, cycleBreaker));
   176     let data = JSON.parse(JSON.stringify(aData,    cycleBreaker));
   178     let send = (extra) => {
   179       data = data || {};
   181       if (extra)
   182         data.extra = extra;
   184       this.conn.send({
   185         from:    this.actorID,
   186         type:    "eventNotification",
   187         event:   aTopic,
   188         subject: subj,
   189         data:    data
   190       });
   191     }
   193     if (aTopic !== "console-api-profiler")
   194       return void send();
   196     // If the event was generated from console.profile or
   197     // console.profileEnd we need to start the profiler
   198     // right away and only then notify our client. Otherwise,
   199     // we'll lose precious samples.
   201     let name = subj.arguments[0];
   203     if (subj.action === "profile") {
   204       let resp = this.onIsActive();
   206       if (resp.isActive) {
   207         return void send({
   208           name: name,
   209           currentTime: resp.currentTime,
   210           action: "profile"
   211         });
   212       }
   214       this.onStartProfiler({
   215         entries: 1000000,
   216         interval: 1,
   217         features: ["js"]
   218       });
   220       return void send({ currentTime: 0, action: "profile", name: name });
   221     }
   223     if (subj.action === "profileEnd") {
   224       let resp = this.onGetProfile();
   225       resp.action = "profileEnd";
   226       resp.name = name;
   227       send(resp);
   228     }
   230     return undefined; // Otherwise xpcshell tests fail.
   231   }, "ProfilerActor.prototype.observe"),
   232 };
   234 /**
   235  * The request types this actor can handle.
   236  */
   237 ProfilerActor.prototype.requestTypes = {
   238   "startProfiler": ProfilerActor.prototype.onStartProfiler,
   239   "stopProfiler": ProfilerActor.prototype.onStopProfiler,
   240   "getProfileStr": ProfilerActor.prototype.onGetProfileStr,
   241   "getProfile": ProfilerActor.prototype.onGetProfile,
   242   "isActive": ProfilerActor.prototype.onIsActive,
   243   "getResponsivenessTimes": ProfilerActor.prototype.onGetResponsivenessTimes,
   244   "getFeatures": ProfilerActor.prototype.onGetFeatures,
   245   "getSharedLibraryInformation": ProfilerActor.prototype.onGetSharedLibraryInformation,
   246   "registerEventNotifications": ProfilerActor.prototype.onRegisterEventNotifications,
   247   "unregisterEventNotifications": ProfilerActor.prototype.onUnregisterEventNotifications
   248 };
   250 DebuggerServer.addGlobalActor(ProfilerActor, "profilerActor");

mercurial