toolkit/components/aboutmemory/tests/test_memoryReporters.xul

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 <?xml version="1.0"?>
michael@0 2 <?xml-stylesheet type="text/css" href="chrome://global/skin"?>
michael@0 3 <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
michael@0 4 <window title="Memory reporters"
michael@0 5 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
michael@0 6 <script type="application/javascript"
michael@0 7 src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
michael@0 8
michael@0 9 <!-- This file tests (in a rough fashion) whether the memory reporters are
michael@0 10 producing sensible results. test_aboutmemory.xul tests the
michael@0 11 presentation of memory reports in about:memory. -->
michael@0 12
michael@0 13 <!-- test results are displayed in the html:body -->
michael@0 14 <body xmlns="http://www.w3.org/1999/xhtml">
michael@0 15 <!-- In bug 773533, <marquee> elements crashed the JS memory reporter -->
michael@0 16 <marquee>Marquee</marquee>
michael@0 17 </body>
michael@0 18
michael@0 19 <!-- test code goes here -->
michael@0 20 <script type="application/javascript">
michael@0 21 <![CDATA[
michael@0 22
michael@0 23 // Nb: this test is all JS and so should be done with an xpcshell test,
michael@0 24 // but bug 671753 is preventing the memory-reporter-manager from being
michael@0 25 // accessed from xpcshell.
michael@0 26
michael@0 27 "use strict";
michael@0 28
michael@0 29 const Cc = Components.classes;
michael@0 30 const Ci = Components.interfaces;
michael@0 31 const Cr = Components.results;
michael@0 32
michael@0 33 const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP;
michael@0 34 const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
michael@0 35 const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
michael@0 36
michael@0 37 const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
michael@0 38 const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT;
michael@0 39 const COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE;
michael@0 40 const PERCENTAGE = Ci.nsIMemoryReporter.UNITS_PERCENTAGE;
michael@0 41
michael@0 42 let vsizeAmounts = [];
michael@0 43 let residentAmounts = [];
michael@0 44 let jsGcHeapAmounts = [];
michael@0 45 let heapAllocatedAmounts = [];
michael@0 46 let storageSqliteAmounts = [];
michael@0 47
michael@0 48 let present = {}
michael@0 49
michael@0 50 // Generate a long, random string. We'll check that this string is
michael@0 51 // reported in at least one of the memory reporters.
michael@0 52 let bigString = "";
michael@0 53 while (bigString.length < 10000) {
michael@0 54 bigString += Math.random();
michael@0 55 }
michael@0 56 let bigStringPrefix = bigString.substring(0, 100);
michael@0 57
michael@0 58 // Generate many copies of two distinctive short strings, "!)(*&" and
michael@0 59 // "@)(*&". We'll check that these strings are reported in at least
michael@0 60 // one of the memory reporters.
michael@0 61 let shortStrings = [];
michael@0 62 for (let i = 0; i < 10000; i++) {
michael@0 63 let str = (Math.random() > 0.5 ? "!" : "@") + ")(*&";
michael@0 64 shortStrings.push(str);
michael@0 65 }
michael@0 66
michael@0 67 let mySandbox = Components.utils.Sandbox(document.nodePrincipal,
michael@0 68 { sandboxName: "this-is-a-sandbox-name" });
michael@0 69
michael@0 70 function handleReport(aProcess, aPath, aKind, aUnits, aAmount, aDescription)
michael@0 71 {
michael@0 72 // Record the values of some notable reporters.
michael@0 73 if (aPath === "vsize") {
michael@0 74 vsizeAmounts.push(aAmount);
michael@0 75 } else if (aPath === "resident") {
michael@0 76 residentAmounts.push(aAmount);
michael@0 77 } else if (aPath === "js-main-runtime-gc-heap-committed/used/gc-things") {
michael@0 78 jsGcHeapAmounts.push(aAmount);
michael@0 79 } else if (aPath === "heap-allocated") {
michael@0 80 heapAllocatedAmounts.push(aAmount);
michael@0 81 } else if (aPath === "storage-sqlite") {
michael@0 82 storageSqliteAmounts.push(aAmount);
michael@0 83
michael@0 84 // Check the presence of some other notable reporters.
michael@0 85 } else if (aPath.search(/^explicit\/js-non-window\/.*compartment\(/) >= 0) {
michael@0 86 present.jsNonWindowCompartments = true;
michael@0 87 } else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js-compartment\(/) >= 0) {
michael@0 88 present.windowObjectsJsCompartments = true;
michael@0 89 } else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
michael@0 90 present.places = true;
michael@0 91 } else if (aPath.search(/^explicit\/images/) >= 0) {
michael@0 92 present.images = true;
michael@0 93 } else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) {
michael@0 94 present.xptiWorkingSet = true;
michael@0 95 } else if (aPath.search(/^explicit\/atom-tables$/) >= 0) {
michael@0 96 present.atomTable = true;
michael@0 97 } else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) {
michael@0 98 // A system compartment with a location (such as a sandbox) should
michael@0 99 // show that location.
michael@0 100 present.sandboxLocation = true;
michael@0 101 } else if (aPath.contains(bigStringPrefix)) {
michael@0 102 present.bigString = true;
michael@0 103 } else if (aPath.contains("!)(*&")) {
michael@0 104 present.smallString1 = true;
michael@0 105 } else if (aPath.contains("@)(*&")) {
michael@0 106 present.smallString2 = true;
michael@0 107 }
michael@0 108 }
michael@0 109
michael@0 110 let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
michael@0 111 getService(Ci.nsIMemoryReporterManager);
michael@0 112
michael@0 113 // Access the distinguished amounts (mgr.explicit et al.) just to make sure
michael@0 114 // they don't crash. We can't check their actual values because they're
michael@0 115 // non-deterministic.
michael@0 116 //
michael@0 117 // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a
michael@0 118 // --enable-trace-malloc build. Allow for that exception, but *only* that
michael@0 119 // exception.
michael@0 120 let dummy;
michael@0 121 let haveExplicit = true;
michael@0 122 try {
michael@0 123 dummy = mgr.explicit;
michael@0 124 } catch (ex) {
michael@0 125 is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
michael@0 126 haveExplicit = false;
michael@0 127 }
michael@0 128 let amounts = [
michael@0 129 "vsize",
michael@0 130 "vsizeMaxContiguous",
michael@0 131 "resident",
michael@0 132 "residentFast",
michael@0 133 "heapAllocated",
michael@0 134 "heapOverheadRatio",
michael@0 135 "JSMainRuntimeGCHeap",
michael@0 136 "JSMainRuntimeTemporaryPeak",
michael@0 137 "JSMainRuntimeCompartmentsSystem",
michael@0 138 "JSMainRuntimeCompartmentsUser",
michael@0 139 "imagesContentUsedUncompressed",
michael@0 140 "storageSQLite",
michael@0 141 "lowMemoryEventsVirtual",
michael@0 142 "lowMemoryEventsPhysical",
michael@0 143 "ghostWindows",
michael@0 144 "pageFaultsHard",
michael@0 145 ];
michael@0 146 for (let i = 0; i < amounts.length; i++) {
michael@0 147 try {
michael@0 148 // If mgr[amounts[i]] throws an exception, just move on -- some amounts
michael@0 149 // aren't available on all platforms. But if the attribute simply
michael@0 150 // isn't present, that indicates the distinguished amounts have changed
michael@0 151 // and this file hasn't been updated appropriately.
michael@0 152 dummy = mgr[amounts[i]];
michael@0 153 ok(dummy !== undefined,
michael@0 154 "accessed an unknown distinguished amount: " + amounts[i]);
michael@0 155 } catch (ex) {
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 // Run sizeOfTab() to make sure it doesn't crash. We can't check the result
michael@0 160 // values because they're non-deterministic.
michael@0 161 let jsObjectsSize = {};
michael@0 162 let jsStringsSize = {};
michael@0 163 let jsOtherSize = {};
michael@0 164 let domSize = {};
michael@0 165 let styleSize = {};
michael@0 166 let otherSize = {};
michael@0 167 let totalSize = {};
michael@0 168 let jsMilliseconds = {};
michael@0 169 let nonJSMilliseconds = {};
michael@0 170 mgr.sizeOfTab(window, jsObjectsSize, jsStringsSize, jsOtherSize,
michael@0 171 domSize, styleSize, otherSize, totalSize,
michael@0 172 jsMilliseconds, nonJSMilliseconds);
michael@0 173
michael@0 174 mgr.getReportsForThisProcess(handleReport, null);
michael@0 175
michael@0 176 function checkSpecialReport(aName, aAmounts, aCanBeUnreasonable)
michael@0 177 {
michael@0 178 ok(aAmounts.length == 1, aName + " has " + aAmounts.length + " report");
michael@0 179 let n = aAmounts[0];
michael@0 180 // Check the size is reasonable -- i.e. not ridiculously large or small.
michael@0 181 ok((100 * 1000 <= n && n <= 10 * 1000 * 1000 * 1000) || aCanBeUnreasonable,
michael@0 182 aName + "'s size is reasonable");
michael@0 183 }
michael@0 184
michael@0 185 // If mgr.explicit failed, we won't have "heap-allocated" either.
michael@0 186 if (haveExplicit) {
michael@0 187 checkSpecialReport("heap-allocated", heapAllocatedAmounts);
michael@0 188 }
michael@0 189 // vsize may be unreasonable if ASAN is enabled
michael@0 190 checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true);
michael@0 191 checkSpecialReport("resident", residentAmounts);
michael@0 192 checkSpecialReport("js-main-runtime-gc-heap-committed/used/gc-things", jsGcHeapAmounts);
michael@0 193
michael@0 194 ok(present.jsNonWindowCompartments, "js-non-window compartments are present");
michael@0 195 ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present");
michael@0 196 ok(present.places, "places is present");
michael@0 197 ok(present.images, "images is present");
michael@0 198 ok(present.xptiWorkingSet, "xpti-working-set is present");
michael@0 199 ok(present.atomTable, "atom-table is present");
michael@0 200 ok(present.sandboxLocation, "sandbox locations are present");
michael@0 201 ok(present.bigString, "large string is present");
michael@0 202 ok(present.smallString1, "small string 1 is present");
michael@0 203 ok(present.smallString2, "small string 2 is present");
michael@0 204
michael@0 205
michael@0 206 // Reporter registration tests
michael@0 207
michael@0 208 // collectReports() calls to the test reporter.
michael@0 209 let called = 0;
michael@0 210
michael@0 211 // The test memory reporter, testing the various report units.
michael@0 212 // Also acts as a report collector, verifying the reported values match the
michael@0 213 // expected ones after passing through XPConnect / nsMemoryReporterManager
michael@0 214 // and back.
michael@0 215 function MemoryReporterAndCallback() {
michael@0 216 this.seen = 0;
michael@0 217 }
michael@0 218 MemoryReporterAndCallback.prototype = {
michael@0 219 // The test reports.
michael@0 220 // Each test key corresponds to the path of the report. |amount| is a
michael@0 221 // function called when generating the report. |expected| is a function
michael@0 222 // to be tested when receiving a report during collection. If |expected| is
michael@0 223 // omitted the |amount| will be checked instead.
michael@0 224 tests: {
michael@0 225 "test-memory-reporter-bytes1": {
michael@0 226 units: BYTES,
michael@0 227 amount: () => 0
michael@0 228 },
michael@0 229 "test-memory-reporter-bytes2": {
michael@0 230 units: BYTES,
michael@0 231 amount: () => (1<<30) * 8 // awkward way to say 8G in JS
michael@0 232 },
michael@0 233 "test-memory-reporter-counter": {
michael@0 234 units: COUNT,
michael@0 235 amount: () => 2
michael@0 236 },
michael@0 237 "test-memory-reporter-ccounter": {
michael@0 238 units: COUNT_CUMULATIVE,
michael@0 239 amount: () => ++called,
michael@0 240 expected: () => called
michael@0 241 },
michael@0 242 "test-memory-reporter-percentage": {
michael@0 243 units: PERCENTAGE,
michael@0 244 amount: () => 9999
michael@0 245 }
michael@0 246 },
michael@0 247 // nsIMemoryReporter
michael@0 248 collectReports: function(callback, data) {
michael@0 249 for (let path of Object.keys(this.tests)) {
michael@0 250 try {
michael@0 251 let test = this.tests[path];
michael@0 252 callback.callback(
michael@0 253 "", // Process. Should be "" initially.
michael@0 254 path,
michael@0 255 OTHER,
michael@0 256 test.units,
michael@0 257 test.amount(),
michael@0 258 "Test " + path + ".",
michael@0 259 data);
michael@0 260 }
michael@0 261 catch (ex) {
michael@0 262 ok(false, ex);
michael@0 263 }
michael@0 264 }
michael@0 265 },
michael@0 266 // nsIMemoryReporterCallback
michael@0 267 callback: function(process, path, kind, units, amount, data) {
michael@0 268 if (path in this.tests) {
michael@0 269 this.seen++;
michael@0 270 let test = this.tests[path];
michael@0 271 ok(units === test.units, "Test reporter units match");
michael@0 272 ok(amount === (test.expected || test.amount)(),
michael@0 273 "Test reporter values match: " + amount);
michael@0 274 }
michael@0 275 },
michael@0 276 // Checks that the callback has seen the expected number of reports, and
michael@0 277 // resets the callback counter.
michael@0 278 // @param expected Optional. Expected number of reports the callback
michael@0 279 // should have processed.
michael@0 280 finish: function(expected) {
michael@0 281 if (expected === undefined) {
michael@0 282 expected = Object.keys(this.tests).length;
michael@0 283 }
michael@0 284 is(expected, this.seen,
michael@0 285 "Test reporter called the correct number of times: " + expected);
michael@0 286 this.seen = 0;
michael@0 287 }
michael@0 288 };
michael@0 289
michael@0 290 // General memory reporter + registerStrongReporter tests.
michael@0 291 function test_register_strong() {
michael@0 292 let reporterAndCallback = new MemoryReporterAndCallback();
michael@0 293 // Registration works.
michael@0 294 mgr.registerStrongReporter(reporterAndCallback);
michael@0 295
michael@0 296 // Check the generated reports.
michael@0 297 mgr.getReportsForThisProcess(reporterAndCallback, null);
michael@0 298 reporterAndCallback.finish();
michael@0 299
michael@0 300 // Unregistration works.
michael@0 301 mgr.unregisterStrongReporter(reporterAndCallback);
michael@0 302
michael@0 303 // The reporter was unregistered, hence there shouldn't be any reports from
michael@0 304 // the test reporter.
michael@0 305 mgr.getReportsForThisProcess(reporterAndCallback, null);
michael@0 306 reporterAndCallback.finish(0);
michael@0 307 }
michael@0 308
michael@0 309 test_register_strong();
michael@0 310
michael@0 311 // Check strong reporters a second time, to make sure a reporter can be
michael@0 312 // re-registered.
michael@0 313 test_register_strong();
michael@0 314
michael@0 315
michael@0 316 // Check that you cannot register JS components as weak reporters.
michael@0 317 function test_register_weak() {
michael@0 318 let reporterAndCallback = new MemoryReporterAndCallback();
michael@0 319 try {
michael@0 320 // Should fail! nsMemoryReporterManager will only hold a raw pointer to
michael@0 321 // "weak" reporters. When registering a weak reporter, XPConnect will
michael@0 322 // create a WrappedJS for JS components. This WrappedJS would be
michael@0 323 // successfully registered with the manager, only to be destroyed
michael@0 324 // immediately after, which would eventually lead to a crash when
michael@0 325 // collecting the reports. Therefore nsMemoryReporterManager should
michael@0 326 // reject WrappedJS reporters, which is what is tested here.
michael@0 327 // See bug 950391 comment #0.
michael@0 328 mgr.registerWeakReporter(reporterAndCallback);
michael@0 329 ok(false, "Shouldn't be allowed to register a JS component (WrappedJS)");
michael@0 330 }
michael@0 331 catch (ex) {
michael@0 332 ok(ex.message.indexOf("NS_ERROR_") >= 0,
michael@0 333 "WrappedJS reporter got rejected: " + ex);
michael@0 334 }
michael@0 335 }
michael@0 336
michael@0 337 test_register_weak();
michael@0 338
michael@0 339 ]]>
michael@0 340 </script>
michael@0 341 </window>
michael@0 342

mercurial