diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /toolkit/components/aboutmemory/tests/test_memoryReporters.xul | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/components/aboutmemory/tests/test_memoryReporters.xul')
-rw-r--r-- | toolkit/components/aboutmemory/tests/test_memoryReporters.xul | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul new file mode 100644 index 000000000..9d56890b3 --- /dev/null +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -0,0 +1,424 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<window title="Memory reporters" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + + <!-- This file tests (in a rough fashion) whether the memory reporters are + producing sensible results. test_aboutmemory.xul tests the + presentation of memory reports in about:memory. --> + + <!-- test results are displayed in the html:body --> + <body xmlns="http://www.w3.org/1999/xhtml"> + <!-- In bug 773533, <marquee> elements crashed the JS memory reporter --> + <marquee>Marquee</marquee> + </body> + + <!-- some URIs that should be anonymized in anonymous mode --> + <iframe id="amFrame" height="200" src="http://example.org:80"></iframe> + <iframe id="amFrame" height="200" src="https://example.com:443"></iframe> + + <!-- test code goes here --> + <script type="application/javascript"> + <![CDATA[ + + "use strict"; + + const Cc = Components.classes; + const Ci = Components.interfaces; + const Cr = Components.results; + + const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP; + const HEAP = Ci.nsIMemoryReporter.KIND_HEAP; + const OTHER = Ci.nsIMemoryReporter.KIND_OTHER; + + const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES; + const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT; + const COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE; + const PERCENTAGE = Ci.nsIMemoryReporter.UNITS_PERCENTAGE; + + // Use backslashes instead of forward slashes due to memory reporting's hacky + // handling of URLs. + const XUL_NS = + "http:\\\\www.mozilla.org\\keymaster\\gatekeeper\\there.is.only.xul"; + + SimpleTest.waitForExplicitFinish(); + + let vsizeAmounts = []; + let residentAmounts = []; + let heapAllocatedAmounts = []; + let storageSqliteAmounts = []; + + let jsGcHeapUsedGcThingsTotal = 0; + let jsGcHeapUsedGcThings = {}; + + let present = {} + + // Generate a long, random string. We'll check that this string is + // reported in at least one of the memory reporters. + let bigString = ""; + while (bigString.length < 10000) { + bigString += Math.random(); + } + let bigStringPrefix = bigString.substring(0, 100); + + // Generate many copies of two distinctive short strings, "!)(*&" and + // "@)(*&". We'll check that these strings are reported in at least + // one of the memory reporters. + let shortStrings = []; + for (let i = 0; i < 10000; i++) { + let str = (Math.random() > 0.5 ? "!" : "@") + ")(*&"; + shortStrings.push(str); + } + + let mySandbox = Components.utils.Sandbox(document.nodePrincipal, + { sandboxName: "this-is-a-sandbox-name" }); + + function handleReportNormal(aProcess, aPath, aKind, aUnits, aAmount, + aDescription) + { + // Record the values of some notable reporters. + if (aPath === "vsize") { + vsizeAmounts.push(aAmount); + } else if (aPath === "resident") { + residentAmounts.push(aAmount); + } else if (aPath.search(/^js-main-runtime-gc-heap-committed\/used\/gc-things\//) >= 0) { + jsGcHeapUsedGcThingsTotal += aAmount; + jsGcHeapUsedGcThings[aPath] = (jsGcHeapUsedGcThings[aPath] | 0) + 1; + } else if (aPath === "heap-allocated") { + heapAllocatedAmounts.push(aAmount); + } else if (aPath === "storage-sqlite") { + storageSqliteAmounts.push(aAmount); + + // Check the presence of some other notable reporters. + } else if (aPath.search(/^explicit\/js-non-window\/.*compartment\(/) >= 0) { + present.jsNonWindowCompartments = true; + } else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js-compartment\(/) >= 0) { + present.windowObjectsJsCompartments = true; + } else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) { + present.places = true; + } else if (aPath.search(/^explicit\/images/) >= 0) { + present.images = true; + } else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) { + present.xptiWorkingSet = true; + } else if (aPath.search(/^explicit\/atom-tables\/main$/) >= 0) { + present.atomTablesMain = true; + } else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) { + // A system compartment with a location (such as a sandbox) should + // show that location. + present.sandboxLocation = true; + } else if (aPath.includes(bigStringPrefix)) { + present.bigString = true; + } else if (aPath.includes("!)(*&")) { + present.smallString1 = true; + } else if (aPath.includes("@)(*&")) { + present.smallString2 = true; + } + + // Shouldn't get any anonymized paths. + if (aPath.includes('<anonymized')) { + present.anonymizedWhenUnnecessary = aPath; + } + } + + function handleReportAnonymized(aProcess, aPath, aKind, aUnits, aAmount, + aDescription) + { + // Path might include an xmlns using http, which is safe to ignore. + let reducedPath = aPath.replace(XUL_NS, ""); + + // Shouldn't get http: or https: in any paths. + if (reducedPath.includes('http:')) { + present.httpWhenAnonymized = aPath; + } + + // file: URLs should have their path anonymized. + if (reducedPath.search('file:..[^<]') !== -1) { + present.unanonymizedFilePathWhenAnonymized = aPath; + } + } + + let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. + getService(Ci.nsIMemoryReporterManager); + + let amounts = [ + "vsize", + "vsizeMaxContiguous", + "resident", + "residentFast", + "residentPeak", + "residentUnique", + "heapAllocated", + "heapOverheadFraction", + "JSMainRuntimeGCHeap", + "JSMainRuntimeTemporaryPeak", + "JSMainRuntimeCompartmentsSystem", + "JSMainRuntimeCompartmentsUser", + "imagesContentUsedUncompressed", + "storageSQLite", + "lowMemoryEventsVirtual", + "lowMemoryEventsPhysical", + "ghostWindows", + "pageFaultsHard", + ]; + for (let i = 0; i < amounts.length; i++) { + try { + // If mgr[amounts[i]] throws an exception, just move on -- some amounts + // aren't available on all platforms. But if the attribute simply + // isn't present, that indicates the distinguished amounts have changed + // and this file hasn't been updated appropriately. + let dummy = mgr[amounts[i]]; + ok(dummy !== undefined, + "accessed an unknown distinguished amount: " + amounts[i]); + } catch (ex) { + } + } + + // Run sizeOfTab() to make sure it doesn't crash. We can't check the result + // values because they're non-deterministic. + let jsObjectsSize = {}; + let jsStringsSize = {}; + let jsOtherSize = {}; + let domSize = {}; + let styleSize = {}; + let otherSize = {}; + let totalSize = {}; + let jsMilliseconds = {}; + let nonJSMilliseconds = {}; + mgr.sizeOfTab(window, jsObjectsSize, jsStringsSize, jsOtherSize, + domSize, styleSize, otherSize, totalSize, + jsMilliseconds, nonJSMilliseconds); + + let asyncSteps = [ + getReportsNormal, + getReportsAnonymized, + checkResults, + test_register_strong, + test_register_strong, // Make sure re-registering works + test_register_weak, + SimpleTest.finish + ]; + + function runNext() { + setTimeout(asyncSteps.shift(), 0); + } + + function getReportsNormal() + { + mgr.getReports(handleReportNormal, null, + runNext, null, + /* anonymize = */ false); + } + + function getReportsAnonymized() + { + mgr.getReports(handleReportAnonymized, null, + runNext, null, + /* anonymize = */ true); + } + + function checkSizeReasonable(aName, aAmount) + { + // Check the size is reasonable -- i.e. not ridiculously large or small. + ok(100 * 1000 <= aAmount && aAmount <= 10 * 1000 * 1000 * 1000, + aName + "'s size is reasonable"); + } + + function checkSpecialReport(aName, aAmounts, aCanBeUnreasonable) + { + ok(aAmounts.length == 1, aName + " has " + aAmounts.length + " report"); + let n = aAmounts[0]; + if (!aCanBeUnreasonable) { + checkSizeReasonable(aName, n); + } + } + + function checkResults() + { + try { + // Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for skipping this test on that + // exception, but *only* that exception. + let dummy = mgr.heapAllocated; + checkSpecialReport("heap-allocated", heapAllocatedAmounts); + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception"); + } + // vsize may be unreasonable if ASAN is enabled + checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); + checkSpecialReport("resident", residentAmounts); + + for (var reporter in jsGcHeapUsedGcThings) { + ok(jsGcHeapUsedGcThings[reporter] == 1); + } + checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", + jsGcHeapUsedGcThingsTotal); + + ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); + ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); + ok(present.places, "places is present"); + ok(present.images, "images is present"); + ok(present.xptiWorkingSet, "xpti-working-set is present"); + ok(present.atomTablesMain, "atom-tables/main is present"); + ok(present.sandboxLocation, "sandbox locations are present"); + ok(present.bigString, "large string is present"); + ok(present.smallString1, "small string 1 is present"); + ok(present.smallString2, "small string 2 is present"); + + ok(!present.anonymizedWhenUnnecessary, + "anonymized paths are not present when unnecessary. Failed case: " + + present.anonymizedWhenUnnecessary); + ok(!present.httpWhenAnonymized, + "http URLs are anonymized when necessary. Failed case: " + + present.httpWhenAnonymized); + ok(!present.unanonymizedFilePathWhenAnonymized, + "file URLs are anonymized when necessary. Failed case: " + + present.unanonymizedFilePathWhenAnonymized); + + runNext(); + } + + // Reporter registration tests + + // collectReports() calls to the test reporter. + let called = 0; + + // The test memory reporter, testing the various report units. + // Also acts as a report collector, verifying the reported values match the + // expected ones after passing through XPConnect / nsMemoryReporterManager + // and back. + function MemoryReporterAndCallback() { + this.seen = 0; + } + MemoryReporterAndCallback.prototype = { + // The test reports. + // Each test key corresponds to the path of the report. |amount| is a + // function called when generating the report. |expected| is a function + // to be tested when receiving a report during collection. If |expected| is + // omitted the |amount| will be checked instead. + tests: { + "test-memory-reporter-bytes1": { + units: BYTES, + amount: () => 0 + }, + "test-memory-reporter-bytes2": { + units: BYTES, + amount: () => (1<<30) * 8 // awkward way to say 8G in JS + }, + "test-memory-reporter-counter": { + units: COUNT, + amount: () => 2 + }, + "test-memory-reporter-ccounter": { + units: COUNT_CUMULATIVE, + amount: () => ++called, + expected: () => called + }, + "test-memory-reporter-percentage": { + units: PERCENTAGE, + amount: () => 9999 + } + }, + // nsIMemoryReporter + collectReports: function(callback, data, anonymize) { + for (let path of Object.keys(this.tests)) { + try { + let test = this.tests[path]; + callback.callback( + "", // Process. Should be "" initially. + path, + OTHER, + test.units, + test.amount(), + "Test " + path + ".", + data); + } + catch (ex) { + ok(false, ex); + } + } + }, + // nsIMemoryReporterCallback + callback: function(process, path, kind, units, amount, data) { + if (path in this.tests) { + this.seen++; + let test = this.tests[path]; + ok(units === test.units, "Test reporter units match"); + ok(amount === (test.expected || test.amount)(), + "Test reporter values match: " + amount); + } + }, + // Checks that the callback has seen the expected number of reports, and + // resets the callback counter. + // @param expected Optional. Expected number of reports the callback + // should have processed. + finish: function(expected) { + if (expected === undefined) { + expected = Object.keys(this.tests).length; + } + is(expected, this.seen, + "Test reporter called the correct number of times: " + expected); + this.seen = 0; + } + }; + + // General memory reporter + registerStrongReporter tests. + function test_register_strong() { + let reporterAndCallback = new MemoryReporterAndCallback(); + // Registration works. + mgr.registerStrongReporter(reporterAndCallback); + + // Check the generated reports. + mgr.getReports(reporterAndCallback, null, + () => { + reporterAndCallback.finish(); + window.setTimeout(test_unregister_strong, 0, reporterAndCallback); + }, null, + /* anonymize = */ false); + } + + function test_unregister_strong(aReporterAndCallback) + { + mgr.unregisterStrongReporter(aReporterAndCallback); + + // The reporter was unregistered, hence there shouldn't be any reports from + // the test reporter. + mgr.getReports(aReporterAndCallback, null, + () => { + aReporterAndCallback.finish(0); + runNext(); + }, null, + /* anonymize = */ false); + } + + // Check that you cannot register JS components as weak reporters. + function test_register_weak() { + let reporterAndCallback = new MemoryReporterAndCallback(); + try { + // Should fail! nsMemoryReporterManager will only hold a raw pointer to + // "weak" reporters. When registering a weak reporter, XPConnect will + // create a WrappedJS for JS components. This WrappedJS would be + // successfully registered with the manager, only to be destroyed + // immediately after, which would eventually lead to a crash when + // collecting the reports. Therefore nsMemoryReporterManager should + // reject WrappedJS reporters, which is what is tested here. + // See bug 950391 comment #0. + mgr.registerWeakReporter(reporterAndCallback); + ok(false, "Shouldn't be allowed to register a JS component (WrappedJS)"); + } + catch (ex) { + ok(ex.message.indexOf("NS_ERROR_") >= 0, + "WrappedJS reporter got rejected: " + ex); + } + + runNext(); + } + + // Kick-off the async tests. + runNext(); + + ]]> + </script> +</window> |