Bug 1123237 - Part 9. Interface to memory-profiler add-ons. r=jimb
authorKan-Ru Chen <kanru@kanru.info>
Fri, 08 May 2015 11:24:12 +0800
changeset 295336 aeb013bd06feaba540bc17796e6d3a466d909e0e
parent 295335 a7bc50840fa23fd8b391c3b0d9f1bc4c98751871
child 295337 5985b8441eb0c314b145fbb8c51d349f3956888a
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1123237
milestone43.0a1
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
Bug 1123237 - Part 9. Interface to memory-profiler add-ons. r=jimb Based on patch from Ting-Yuan Huang <laszio.bugzilla@gmail.com>
toolkit/devtools/server/actors/memprof.js
toolkit/devtools/server/main.js
toolkit/devtools/server/moz.build
toolkit/devtools/server/tests/mochitest/chrome.ini
toolkit/devtools/server/tests/mochitest/memprof-helpers.js
toolkit/devtools/server/tests/mochitest/test_memprof.html
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/actors/memprof.js
@@ -0,0 +1,66 @@
+/* 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 } = require("chrome");
+let protocol = require("devtools/server/protocol");
+let { method, RetVal, Arg, types } = protocol;
+const { reportException } = require("devtools/toolkit/DevToolsUtils");
+loader.lazyRequireGetter(this, "events", "sdk/event/core");
+
+let MemprofActor = protocol.ActorClass({
+  typeName: "memprof",
+
+  initialize: function(conn) {
+    protocol.Actor.prototype.initialize.call(this, conn);
+    this._profiler = Cc["@mozilla.org/tools/memory-profiler;1"]
+      .getService(Ci.nsIMemoryProfiler);
+  },
+
+  destroy: function() {
+    this._profiler = null;
+    protocol.Actor.prototype.destroy.call(this);
+  },
+
+  startProfiler: method(function() {
+    this._profiler.startProfiler();
+  }, {
+    request: {},
+    response: {}
+  }),
+
+  stopProfiler: method(function() {
+    this._profiler.stopProfiler();
+  }, {
+    request: {},
+    response: {}
+  }),
+
+  resetProfiler: method(function() {
+    this._profiler.resetProfiler();
+  }, {
+    request: {},
+    response: {}
+  }),
+
+  getResults: method(function() {
+    return this._profiler.getResults();
+  }, {
+    request: {},
+    response: {
+      ret: RetVal("json")
+    }
+  })
+});
+
+exports.MemprofActor = MemprofActor;
+
+exports.MemprofFront = protocol.FrontClass(MemprofActor, {
+  initialize: function(client, form) {
+    protocol.Front.prototype.initialize.call(this, client, form);
+    this.actorID = form.memprofActor;
+    this.manage(this);
+  }
+});
--- a/toolkit/devtools/server/main.js
+++ b/toolkit/devtools/server/main.js
@@ -488,16 +488,21 @@ var DebuggerServer = {
       constructor: "GcliActor",
       type: { tab: true }
     });
     this.registerModule("devtools/server/actors/memory", {
       prefix: "memory",
       constructor: "MemoryActor",
       type: { tab: true }
     });
+    this.registerModule("devtools/server/actors/memprof", {
+      prefix: "memprof",
+      constructor: "MemprofActor",
+      type: { global: true, tab: true }
+    });
     this.registerModule("devtools/server/actors/framerate", {
       prefix: "framerate",
       constructor: "FramerateActor",
       type: { tab: true }
     });
     this.registerModule("devtools/server/actors/eventlooplag", {
       prefix: "eventLoopLag",
       constructor: "EventLoopLagActor",
--- a/toolkit/devtools/server/moz.build
+++ b/toolkit/devtools/server/moz.build
@@ -49,16 +49,17 @@ EXTRA_JS_MODULES.devtools.server.actors 
     'actors/director-registry.js',
     'actors/eventlooplag.js',
     'actors/framerate.js',
     'actors/gcli.js',
     'actors/highlighter.js',
     'actors/inspector.js',
     'actors/layout.js',
     'actors/memory.js',
+    'actors/memprof.js',
     'actors/monitor.js',
     'actors/object.js',
     'actors/performance-entries.js',
     'actors/performance-recording.js',
     'actors/performance.js',
     'actors/preference.js',
     'actors/pretty-print-worker.js',
     'actors/profiler.js',
--- a/toolkit/devtools/server/tests/mochitest/chrome.ini
+++ b/toolkit/devtools/server/tests/mochitest/chrome.ini
@@ -10,16 +10,17 @@ support-files =
   inspector_getImageData.html
   inspector-delay-image-response.sjs
   inspector-helpers.js
   inspector-styles-data.css
   inspector-styles-data.html
   inspector-traversal-data.html
   large-image.jpg
   memory-helpers.js
+  memprof-helpers.js
   nonchrome_unsafeDereference.html
   small-image.gif
   setup-in-child.js
   setup-in-parent.js
 
 [test_connection-manager.html]
 skip-if = buildapp == 'mulet'
 [test_connectToChild.html]
@@ -86,16 +87,17 @@ skip-if = buildapp == 'mulet'
 [test_memory_allocations_05.html]
 [test_memory_allocations_06.html]
 [test_memory_allocations_07.html]
 [test_memory_attach_01.html]
 [test_memory_attach_02.html]
 [test_memory_census.html]
 [test_memory_gc_01.html]
 [test_memory_gc_events.html]
+[test_memprof.html]
 [test_preference.html]
 [test_registerActor.html]
 [test_settings.html]
 [test_setupInParentChild.html]
 [test_styles-applied.html]
 [test_styles-computed.html]
 [test_styles-layout.html]
 [test_styles-matched.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/mochitest/memprof-helpers.js
@@ -0,0 +1,54 @@
+let Cu = Components.utils;
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+// Always log packets when running tests.
+Services.prefs.setBoolPref("devtools.debugger.log", true);
+SimpleTest.registerCleanupFunction(function() {
+  Services.prefs.clearUserPref("devtools.debugger.log");
+});
+
+Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
+Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
+
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/devtools/Loader.jsm");
+let { require } = devtools;
+
+let { MemprofFront } = require("devtools/server/actors/memprof");
+
+function startServerAndGetSelectedTabMemprof() {
+  DebuggerServer.init();
+  DebuggerServer.addBrowserActors();
+  var client = new DebuggerClient(DebuggerServer.connectPipe());
+
+  return new Promise((resolve, reject) => {
+    client.connect(response => {
+      if (response.error) {
+        reject(new Error(response.error + ": " + response.message));
+        return;
+      }
+
+      client.listTabs(response => {
+        if (response.error) {
+          reject(new Error(response.error + ": " + response.message));
+          return;
+        }
+
+        var form = response.tabs[response.selected];
+        var memprof = MemprofFront(client, form);
+
+        resolve({ memprof, client });
+      });
+    });
+  });
+}
+
+function destroyServerAndFinish(client) {
+  client.close(() => {
+    DebuggerServer.destroy();
+    SimpleTest.finish();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/mochitest/test_memprof.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Bug 1123237 - Test profiling memory allocations.
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Memory profiler actor test</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="memprof-helpers.js" type="application/javascript;version=1.8"></script>
+<script>
+window.onload = function() {
+  SimpleTest.waitForExplicitFinish();
+
+  Task.spawn(function* () {
+    var { memprof, client } = yield startServerAndGetSelectedTabMemprof();
+    yield memprof.startProfiler();
+    ok(true, "Can start profiling allocations");
+
+    // Allocate some objects.
+
+    var alloc;
+    (function memprof_test_outer() {
+      (function memprof_test_middle() {
+        (function memprof_test_inner() {
+          for (i = 0; i < 65535; ++i) {
+            alloc = {};
+          }
+        }());
+      }());
+    }());
+
+    yield memprof.stopProfiler();
+    ok(true, "Can stop profiling allocations");
+
+    var results = yield memprof.getResults();
+    ok(true, "Can get results");
+
+    function isTestAllocation(name) {
+      return /memprof_test_inner/.test(name)
+        || /memprof_test_middle/.test(name)
+        || /memprof_test_outer/.test(name)
+    }
+
+    var testAllocations = results.names.filter(isTestAllocation);
+    ok(testAllocations.length >= 3, "Should find our 3 test allocations");
+
+    // Ensure the allocation traces has the correct index
+    var inner = results.traces.find(
+      trace => /memprof_test_inner/.test(results.names[trace.nameIdx]));
+    ok(inner, "Find the inner most frame");
+    var middle = results.traces[inner.parentIdx];
+    ok(/memprof_test_middle/.test(results.names[middle.nameIdx]),
+       "Find the middle frame");
+    var outer = results.traces[middle.parentIdx];
+    ok(/memprof_test_outer/.test(results.names[outer.nameIdx]),
+       "Find the outer frame");
+
+    yield memprof.resetProfiler();
+
+    destroyServerAndFinish(client);
+  });
+};
+</script>
+</pre>
+</body>
+</html>