Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
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="about:memory" |
michael@0 | 5 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> |
michael@0 | 6 | <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> |
michael@0 | 7 | <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> |
michael@0 | 8 | |
michael@0 | 9 | <!-- This file tests the saving and loading of memory reports to/from file in |
michael@0 | 10 | about:memory. --> |
michael@0 | 11 | |
michael@0 | 12 | <!-- test results are displayed in the html:body --> |
michael@0 | 13 | <body xmlns="http://www.w3.org/1999/xhtml"></body> |
michael@0 | 14 | |
michael@0 | 15 | <!-- test code goes here --> |
michael@0 | 16 | <script type="application/javascript"> |
michael@0 | 17 | <![CDATA[ |
michael@0 | 18 | "use strict"; |
michael@0 | 19 | |
michael@0 | 20 | const Cc = Components.classes; |
michael@0 | 21 | const Ci = Components.interfaces; |
michael@0 | 22 | let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. |
michael@0 | 23 | getService(Ci.nsIMemoryReporterManager); |
michael@0 | 24 | |
michael@0 | 25 | // Hide all the real reporters; we'll restore them at the end. |
michael@0 | 26 | mgr.blockRegistrationAndHideExistingReporters(); |
michael@0 | 27 | |
michael@0 | 28 | // Setup a minimal number of fake reporters. |
michael@0 | 29 | const KB = 1024; |
michael@0 | 30 | const MB = KB * KB; |
michael@0 | 31 | const HEAP = Ci.nsIMemoryReporter.KIND_HEAP; |
michael@0 | 32 | const OTHER = Ci.nsIMemoryReporter.KIND_OTHER; |
michael@0 | 33 | const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES; |
michael@0 | 34 | |
michael@0 | 35 | let fakeReporters = [ |
michael@0 | 36 | { collectReports: function(aCbObj, aClosure) { |
michael@0 | 37 | function f(aP, aK, aA, aD) { |
michael@0 | 38 | aCbObj.callback("", aP, aK, BYTES, aA, aD, aClosure); |
michael@0 | 39 | } |
michael@0 | 40 | f("heap-allocated", OTHER, 250 * MB, "Heap allocated."); |
michael@0 | 41 | f("explicit/a/b", HEAP, 50 * MB, "A b."); |
michael@0 | 42 | f("other/a", OTHER, 0.2 * MB, "Other a."); |
michael@0 | 43 | f("other/b", OTHER, 0.1 * MB, "Other b."); |
michael@0 | 44 | } |
michael@0 | 45 | } |
michael@0 | 46 | ]; |
michael@0 | 47 | |
michael@0 | 48 | for (let i = 0; i < fakeReporters.length; i++) { |
michael@0 | 49 | mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]); |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | ]]> |
michael@0 | 53 | </script> |
michael@0 | 54 | |
michael@0 | 55 | <iframe id="amFrame" height="400" src="about:memory"></iframe> |
michael@0 | 56 | |
michael@0 | 57 | <script type="application/javascript"> |
michael@0 | 58 | <![CDATA[ |
michael@0 | 59 | function finish() |
michael@0 | 60 | { |
michael@0 | 61 | mgr.unblockRegistrationAndRestoreOriginalReporters(); |
michael@0 | 62 | SimpleTest.finish(); |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | // Load the given file into the frame, then copy+paste the entire frame and |
michael@0 | 66 | // check that the cut text matches what we expect. |
michael@0 | 67 | function test(aFilename, aFilename2, aExpected, aDumpFirst, aNext) { |
michael@0 | 68 | let frame = document.getElementById("amFrame"); |
michael@0 | 69 | frame.focus(); |
michael@0 | 70 | |
michael@0 | 71 | let doc = frame.contentWindow.document; |
michael@0 | 72 | let verbosity = doc.getElementById("verbose"); |
michael@0 | 73 | verbosity.checked = true; |
michael@0 | 74 | |
michael@0 | 75 | function getFilePath(aFilename) { |
michael@0 | 76 | let file = Cc["@mozilla.org/file/directory_service;1"] |
michael@0 | 77 | .getService(Components.interfaces.nsIProperties) |
michael@0 | 78 | .get("CurWorkD", Components.interfaces.nsIFile); |
michael@0 | 79 | file.append("chrome"); |
michael@0 | 80 | file.append("toolkit"); |
michael@0 | 81 | file.append("components"); |
michael@0 | 82 | file.append("aboutmemory"); |
michael@0 | 83 | file.append("tests"); |
michael@0 | 84 | file.append(aFilename); |
michael@0 | 85 | return file.path; |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | let filePath = getFilePath(aFilename); |
michael@0 | 89 | |
michael@0 | 90 | let e = document.createEvent('Event'); |
michael@0 | 91 | e.initEvent('change', true, true); |
michael@0 | 92 | |
michael@0 | 93 | function check() { |
michael@0 | 94 | // Initialize the clipboard contents. |
michael@0 | 95 | SpecialPowers.clipboardCopyString("initial clipboard value"); |
michael@0 | 96 | |
michael@0 | 97 | let numFailures = 0, maxFailures = 30; |
michael@0 | 98 | |
michael@0 | 99 | // Because the file load is async, we don't know when it will finish and |
michael@0 | 100 | // the output will show up. So we poll. |
michael@0 | 101 | function copyPasteAndCheck() { |
michael@0 | 102 | // Copy and paste frame contents, and filter out non-deterministic |
michael@0 | 103 | // differences. |
michael@0 | 104 | synthesizeKey("A", {accelKey: true}); |
michael@0 | 105 | synthesizeKey("C", {accelKey: true}); |
michael@0 | 106 | let actual = SpecialPowers.getClipboardData("text/unicode"); |
michael@0 | 107 | actual = actual.replace(/\(pid \d+\)/g, "(pid NNN)"); |
michael@0 | 108 | |
michael@0 | 109 | if (actual === aExpected) { |
michael@0 | 110 | SimpleTest.ok(true, "Clipboard has the expected contents"); |
michael@0 | 111 | aNext(); |
michael@0 | 112 | } else { |
michael@0 | 113 | numFailures++; |
michael@0 | 114 | if (numFailures === maxFailures) { |
michael@0 | 115 | ok(false, "pasted text doesn't match"); |
michael@0 | 116 | dump("******EXPECTED******\n"); |
michael@0 | 117 | dump(aExpected); |
michael@0 | 118 | dump("*******ACTUAL*******\n"); |
michael@0 | 119 | dump(actual); |
michael@0 | 120 | dump("********************\n"); |
michael@0 | 121 | finish(); |
michael@0 | 122 | } else { |
michael@0 | 123 | setTimeout(copyPasteAndCheck, 100); |
michael@0 | 124 | } |
michael@0 | 125 | } |
michael@0 | 126 | } |
michael@0 | 127 | copyPasteAndCheck(); |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | if (!aFilename2) { |
michael@0 | 131 | function loadAndCheck() { |
michael@0 | 132 | let fileInput1 = |
michael@0 | 133 | frame.contentWindow.document.getElementById("fileInput1"); |
michael@0 | 134 | fileInput1.value = filePath; // this works because it's a chrome test |
michael@0 | 135 | |
michael@0 | 136 | fileInput1.dispatchEvent(e); |
michael@0 | 137 | check(); |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | if (aDumpFirst) { |
michael@0 | 141 | let dumper = Cc["@mozilla.org/memory-info-dumper;1"]. |
michael@0 | 142 | getService(Ci.nsIMemoryInfoDumper); |
michael@0 | 143 | dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null); |
michael@0 | 144 | } else { |
michael@0 | 145 | loadAndCheck(); |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | } else { |
michael@0 | 149 | let fileInput2 = |
michael@0 | 150 | frame.contentWindow.document.getElementById("fileInput2"); |
michael@0 | 151 | fileInput2.value = filePath; // this works because it's a chrome test |
michael@0 | 152 | |
michael@0 | 153 | // Hack alert: fileInput2's onchange handler calls fileInput2.click(). |
michael@0 | 154 | // But we don't want that to happen, because we want to bypass the file |
michael@0 | 155 | // picker for the test. So we set |e.skipClick|, which causes |
michael@0 | 156 | // fileInput2.click() to be skipped, and dispatch the second change event |
michael@0 | 157 | // directly ourselves. |
michael@0 | 158 | |
michael@0 | 159 | e.skipClick = true; |
michael@0 | 160 | fileInput2.dispatchEvent(e); |
michael@0 | 161 | |
michael@0 | 162 | let filePath2 = getFilePath(aFilename2); |
michael@0 | 163 | fileInput2.value = filePath2; // this works because it's a chrome test |
michael@0 | 164 | |
michael@0 | 165 | let e2 = document.createEvent('Event'); |
michael@0 | 166 | e2.initEvent('change', true, true); |
michael@0 | 167 | fileInput2.dispatchEvent(e); |
michael@0 | 168 | |
michael@0 | 169 | check(); |
michael@0 | 170 | } |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | // Returns a function that chains together multiple test() calls. |
michael@0 | 174 | function chain(aPieces) { |
michael@0 | 175 | let x = aPieces.shift(); |
michael@0 | 176 | if (x) { |
michael@0 | 177 | return function() { test(x.filename, x.filename2, x.expected, x.dumpFirst, chain(aPieces)); } |
michael@0 | 178 | } else { |
michael@0 | 179 | return function() { finish(); }; |
michael@0 | 180 | } |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | let expectedGood = |
michael@0 | 184 | "\ |
michael@0 | 185 | Explicit-only process\n\ |
michael@0 | 186 | \n\ |
michael@0 | 187 | WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\ |
michael@0 | 188 | Explicit Allocations\n\ |
michael@0 | 189 | \n\ |
michael@0 | 190 | 100,000 B (100.0%) -- explicit\n\ |
michael@0 | 191 | └──100,000 B (100.0%) ── a/b\n\ |
michael@0 | 192 | \n\ |
michael@0 | 193 | Other Measurements\n\ |
michael@0 | 194 | \n\ |
michael@0 | 195 | End of Explicit-only process\n\ |
michael@0 | 196 | Main Process (pid NNN)\n\ |
michael@0 | 197 | Explicit Allocations\n\ |
michael@0 | 198 | \n\ |
michael@0 | 199 | 262,144,000 B (100.0%) -- explicit\n\ |
michael@0 | 200 | ├──209,715,200 B (80.00%) ── heap-unclassified\n\ |
michael@0 | 201 | └───52,428,800 B (20.00%) ── a/b\n\ |
michael@0 | 202 | \n\ |
michael@0 | 203 | Other Measurements\n\ |
michael@0 | 204 | \n\ |
michael@0 | 205 | 1,024 B (100.0%) -- compartments\n\ |
michael@0 | 206 | └──1,024 B (100.0%) ── system/a\n\ |
michael@0 | 207 | \n\ |
michael@0 | 208 | 1,024 B (100.0%) -- ghost-windows\n\ |
michael@0 | 209 | └──1,024 B (100.0%) ── a\n\ |
michael@0 | 210 | \n\ |
michael@0 | 211 | 314,572 B (100.0%) -- other\n\ |
michael@0 | 212 | ├──209,715 B (66.67%) ── a\n\ |
michael@0 | 213 | └──104,857 B (33.33%) ── b\n\ |
michael@0 | 214 | \n\ |
michael@0 | 215 | 1,024 B (100.0%) -- pss\n\ |
michael@0 | 216 | └──1,024 B (100.0%) ── a\n\ |
michael@0 | 217 | \n\ |
michael@0 | 218 | 1,024 B (100.0%) -- rss\n\ |
michael@0 | 219 | └──1,024 B (100.0%) ── a\n\ |
michael@0 | 220 | \n\ |
michael@0 | 221 | 1,024 B (100.0%) -- size\n\ |
michael@0 | 222 | └──1,024 B (100.0%) ── a\n\ |
michael@0 | 223 | \n\ |
michael@0 | 224 | 1,024 B (100.0%) -- swap\n\ |
michael@0 | 225 | └──1,024 B (100.0%) ── a\n\ |
michael@0 | 226 | \n\ |
michael@0 | 227 | 262,144,000 B ── heap-allocated\n\ |
michael@0 | 228 | \n\ |
michael@0 | 229 | End of Main Process (pid NNN)\n\ |
michael@0 | 230 | Other-only process\n\ |
michael@0 | 231 | Other Measurements\n\ |
michael@0 | 232 | \n\ |
michael@0 | 233 | 200,000 B (100.0%) -- a\n\ |
michael@0 | 234 | ├──100,000 B (50.00%) ── b\n\ |
michael@0 | 235 | └──100,000 B (50.00%) ── c\n\ |
michael@0 | 236 | \n\ |
michael@0 | 237 | 500,000 B ── heap-allocated\n\ |
michael@0 | 238 | \n\ |
michael@0 | 239 | End of Other-only process\n\ |
michael@0 | 240 | "; |
michael@0 | 241 | |
michael@0 | 242 | let expectedGood2 = |
michael@0 | 243 | "\ |
michael@0 | 244 | Main Process (pid NNN)\n\ |
michael@0 | 245 | Explicit Allocations\n\ |
michael@0 | 246 | \n\ |
michael@0 | 247 | 262,144,000 B (100.0%) -- explicit\n\ |
michael@0 | 248 | ├──209,715,200 B (80.00%) ── heap-unclassified\n\ |
michael@0 | 249 | └───52,428,800 B (20.00%) ── a/b\n\ |
michael@0 | 250 | \n\ |
michael@0 | 251 | Other Measurements\n\ |
michael@0 | 252 | \n\ |
michael@0 | 253 | 314,572 B (100.0%) -- other\n\ |
michael@0 | 254 | ├──209,715 B (66.67%) ── a\n\ |
michael@0 | 255 | └──104,857 B (33.33%) ── b\n\ |
michael@0 | 256 | \n\ |
michael@0 | 257 | 262,144,000 B ── heap-allocated\n\ |
michael@0 | 258 | \n\ |
michael@0 | 259 | End of Main Process (pid NNN)\n\ |
michael@0 | 260 | "; |
michael@0 | 261 | |
michael@0 | 262 | // This is the output for a malformed data file. |
michael@0 | 263 | let expectedBad = |
michael@0 | 264 | "\ |
michael@0 | 265 | Invalid memory report(s): missing 'hasMozMallocUsableSize' property\ |
michael@0 | 266 | "; |
michael@0 | 267 | |
michael@0 | 268 | // This is the output for a diff. |
michael@0 | 269 | let expectedDiff = |
michael@0 | 270 | "\ |
michael@0 | 271 | P\n\ |
michael@0 | 272 | \n\ |
michael@0 | 273 | WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\ |
michael@0 | 274 | Explicit Allocations\n\ |
michael@0 | 275 | \n\ |
michael@0 | 276 | -10,005 B (100.0%) -- explicit\n\ |
michael@0 | 277 | ├──-10,000 B (99.95%) ── storage/prefixset/goog-phish-shavar\n\ |
michael@0 | 278 | ├───────-6 B (00.06%) ── spell-check [2]\n\ |
michael@0 | 279 | └────────1 B (-0.01%) ── xpcom/category-manager\n\ |
michael@0 | 280 | \n\ |
michael@0 | 281 | Other Measurements\n\ |
michael@0 | 282 | \n\ |
michael@0 | 283 | 3,000 B ── canvas-2d-pixel-bytes [2] [+]\n\ |
michael@0 | 284 | -100 B ── foobar [-]\n\ |
michael@0 | 285 | \n\ |
michael@0 | 286 | End of P\n\ |
michael@0 | 287 | P2 (pid NNN)\n\ |
michael@0 | 288 | Other Measurements\n\ |
michael@0 | 289 | \n\ |
michael@0 | 290 | 11 B ── z 0xNNN\n\ |
michael@0 | 291 | \n\ |
michael@0 | 292 | End of P2 (pid NNN)\n\ |
michael@0 | 293 | P3\n\ |
michael@0 | 294 | Other Measurements\n\ |
michael@0 | 295 | \n\ |
michael@0 | 296 | -55 B ── p3 [-]\n\ |
michael@0 | 297 | \n\ |
michael@0 | 298 | End of P3\n\ |
michael@0 | 299 | P4\n\ |
michael@0 | 300 | Other Measurements\n\ |
michael@0 | 301 | \n\ |
michael@0 | 302 | 66 B ── p4 [+]\n\ |
michael@0 | 303 | \n\ |
michael@0 | 304 | End of P4\n\ |
michael@0 | 305 | P7\n\ |
michael@0 | 306 | Other Measurements\n\ |
michael@0 | 307 | \n\ |
michael@0 | 308 | 7 B (100.0%) -- p7\n\ |
michael@0 | 309 | ├──4 B (57.14%) ── c [+]\n\ |
michael@0 | 310 | └──3 B (42.86%) ── b [+]\n\ |
michael@0 | 311 | \n\ |
michael@0 | 312 | -5 B ── p7 [-]\n\ |
michael@0 | 313 | \n\ |
michael@0 | 314 | End of P7\n\ |
michael@0 | 315 | P8\n\ |
michael@0 | 316 | Other Measurements\n\ |
michael@0 | 317 | \n\ |
michael@0 | 318 | -22 B (100.0%) -- p8\n\ |
michael@0 | 319 | └──-22 B (100.0%) -- a\n\ |
michael@0 | 320 | ├──-11 B (50.00%) -- b\n\ |
michael@0 | 321 | │ ├───-7 B (31.82%) -- c\n\ |
michael@0 | 322 | │ │ ├──-4 B (18.18%) ── e [-]\n\ |
michael@0 | 323 | │ │ └──-3 B (13.64%) ── d [-]\n\ |
michael@0 | 324 | │ ├───-5 B (22.73%) ── f [-]\n\ |
michael@0 | 325 | │ └────1 B (-4.55%) ── (fake child) [!]\n\ |
michael@0 | 326 | └──-11 B (50.00%) -- g\n\ |
michael@0 | 327 | ├───-7 B (31.82%) ── i [-]\n\ |
michael@0 | 328 | ├───-6 B (27.27%) ── h [-]\n\ |
michael@0 | 329 | └────2 B (-9.09%) ── (fake child) [!]\n\ |
michael@0 | 330 | \n\ |
michael@0 | 331 | End of P8\n\ |
michael@0 | 332 | "; |
michael@0 | 333 | |
michael@0 | 334 | let frames = [ |
michael@0 | 335 | // This loads a pre-existing file that is valid. |
michael@0 | 336 | { filename: "memory-reports-good.json", expected: expectedGood, dumpFirst: false }, |
michael@0 | 337 | |
michael@0 | 338 | // This dumps to a file and then reads it back in. |
michael@0 | 339 | { filename: "memory-reports-dumped.json.gz", expected: expectedGood2, dumpFirst: true }, |
michael@0 | 340 | |
michael@0 | 341 | // This loads a pre-existing file that is invalid. |
michael@0 | 342 | { filename: "memory-reports-bad.json", expected: expectedBad, dumpFirst: false }, |
michael@0 | 343 | |
michael@0 | 344 | // This loads a pre-existing diff file. |
michael@0 | 345 | { filename: "memory-reports-diff1.json", filename2: "memory-reports-diff2.json", expected: expectedDiff, dumpFirst: false } |
michael@0 | 346 | ]; |
michael@0 | 347 | |
michael@0 | 348 | SimpleTest.waitForFocus(chain(frames)); |
michael@0 | 349 | |
michael@0 | 350 | SimpleTest.waitForExplicitFinish(); |
michael@0 | 351 | ]]> |
michael@0 | 352 | </script> |
michael@0 | 353 | </window> |