зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 913260)
CLOSED TREE Backed out changeset 9195be8a50cb (bug 913260) Backed out changeset 09c71a3e7b85 (bug 913260) Backed out changeset 8a8691a26012 (bug 913260)
This commit is contained in:
Родитель
e442bb5b9f
Коммит
12216d4f00
|
@ -9,10 +9,8 @@
|
||||||
#include "nsGlobalWindow.h"
|
#include "nsGlobalWindow.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "nsIEffectiveTLDService.h"
|
#include "nsIEffectiveTLDService.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "nsNetCID.h"
|
#include "nsNetCID.h"
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
#include "XPCJSMemoryReporter.h"
|
#include "XPCJSMemoryReporter.h"
|
||||||
|
@ -21,8 +19,6 @@
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
StaticRefPtr<nsWindowMemoryReporter> sWindowReporter;
|
|
||||||
|
|
||||||
nsWindowMemoryReporter::nsWindowMemoryReporter()
|
nsWindowMemoryReporter::nsWindowMemoryReporter()
|
||||||
: mCheckForGhostWindowsCallbackPending(false)
|
: mCheckForGhostWindowsCallbackPending(false)
|
||||||
{
|
{
|
||||||
|
@ -35,23 +31,27 @@ NS_IMPL_ISUPPORTS3(nsWindowMemoryReporter, nsIMemoryReporter, nsIObserver,
|
||||||
void
|
void
|
||||||
nsWindowMemoryReporter::Init()
|
nsWindowMemoryReporter::Init()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!sWindowReporter);
|
// The memory reporter manager will own this object.
|
||||||
sWindowReporter = new nsWindowMemoryReporter();
|
nsRefPtr<nsWindowMemoryReporter> windowReporter = new nsWindowMemoryReporter();
|
||||||
ClearOnShutdown(&sWindowReporter);
|
NS_RegisterMemoryReporter(windowReporter);
|
||||||
NS_RegisterMemoryReporter(sWindowReporter);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||||
if (os) {
|
if (os) {
|
||||||
// DOM_WINDOW_DESTROYED_TOPIC announces what we call window "detachment",
|
// DOM_WINDOW_DESTROYED_TOPIC announces what we call window "detachment",
|
||||||
// when a window's docshell is set to NULL.
|
// when a window's docshell is set to NULL.
|
||||||
os->AddObserver(sWindowReporter, DOM_WINDOW_DESTROYED_TOPIC,
|
os->AddObserver(windowReporter, DOM_WINDOW_DESTROYED_TOPIC,
|
||||||
/* weakRef = */ true);
|
/* weakRef = */ true);
|
||||||
os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
|
os->AddObserver(windowReporter, "after-minimize-memory-usage",
|
||||||
/* weakRef = */ true);
|
/* weakRef = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_RegisterMemoryReporter(new GhostWindowsReporter());
|
nsRefPtr<GhostURLsReporter> ghostURLsReporter =
|
||||||
RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
|
new GhostURLsReporter(windowReporter);
|
||||||
|
NS_RegisterMemoryReporter(ghostURLsReporter);
|
||||||
|
|
||||||
|
nsRefPtr<NumGhostsReporter> numGhostsReporter =
|
||||||
|
new NumGhostsReporter(windowReporter);
|
||||||
|
NS_RegisterMemoryReporter(numGhostsReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static already_AddRefed<nsIURI>
|
static already_AddRefed<nsIURI>
|
||||||
|
@ -311,52 +311,6 @@ GetWindows(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
|
||||||
return PL_DHASH_NEXT;
|
return PL_DHASH_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReportGhostWindowsEnumeratorData
|
|
||||||
{
|
|
||||||
nsIMemoryReporterCallback* callback;
|
|
||||||
nsISupports* closure;
|
|
||||||
nsresult rv;
|
|
||||||
};
|
|
||||||
|
|
||||||
static PLDHashOperator
|
|
||||||
ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aClosure)
|
|
||||||
{
|
|
||||||
ReportGhostWindowsEnumeratorData *data =
|
|
||||||
static_cast<ReportGhostWindowsEnumeratorData*>(aClosure);
|
|
||||||
|
|
||||||
nsGlobalWindow::WindowByIdTable* windowsById =
|
|
||||||
nsGlobalWindow::GetWindowsTable();
|
|
||||||
if (!windowsById) {
|
|
||||||
NS_WARNING("Couldn't get window-by-id hashtable?");
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsGlobalWindow* window = windowsById->Get(aIDHashKey->GetKey());
|
|
||||||
if (!window) {
|
|
||||||
NS_WARNING("Could not look up window?");
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString path;
|
|
||||||
path.AppendLiteral("ghost-windows/");
|
|
||||||
AppendWindowURI(window, path);
|
|
||||||
|
|
||||||
nsresult rv = data->callback->Callback(
|
|
||||||
/* process = */ EmptyCString(),
|
|
||||||
path,
|
|
||||||
nsIMemoryReporter::KIND_OTHER,
|
|
||||||
nsIMemoryReporter::UNITS_COUNT,
|
|
||||||
/* amount = */ 1,
|
|
||||||
/* description = */ NS_LITERAL_CSTRING("A ghost window."),
|
|
||||||
data->closure);
|
|
||||||
|
|
||||||
if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
|
|
||||||
data->rv = rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsWindowMemoryReporter::GetName(nsACString &aName)
|
nsWindowMemoryReporter::GetName(nsACString &aName)
|
||||||
{
|
{
|
||||||
|
@ -377,18 +331,12 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
|
||||||
WindowArray windows;
|
WindowArray windows;
|
||||||
windowsById->Enumerate(GetWindows, &windows);
|
windowsById->Enumerate(GetWindows, &windows);
|
||||||
|
|
||||||
// Get the IDs of all the "ghost" windows, and call aCb->Callback() for each
|
// Get the IDs of all the "ghost" windows.
|
||||||
// one.
|
|
||||||
nsTHashtable<nsUint64HashKey> ghostWindows;
|
nsTHashtable<nsUint64HashKey> ghostWindows;
|
||||||
CheckForGhostWindows(&ghostWindows);
|
CheckForGhostWindows(&ghostWindows);
|
||||||
ReportGhostWindowsEnumeratorData reportGhostWindowsEnumData =
|
|
||||||
{ aCb, aClosure, NS_OK };
|
|
||||||
ghostWindows.EnumerateEntries(ReportGhostWindowsEnumerator,
|
|
||||||
&reportGhostWindowsEnumData);
|
|
||||||
nsresult rv = reportGhostWindowsEnumData.rv;
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
WindowPaths windowPaths;
|
WindowPaths windowPaths;
|
||||||
|
|
||||||
WindowPaths topWindowPaths;
|
WindowPaths topWindowPaths;
|
||||||
|
|
||||||
// Collect window memory usage.
|
// Collect window memory usage.
|
||||||
|
@ -396,17 +344,17 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
|
||||||
nsCOMPtr<amIAddonManager> addonManager =
|
nsCOMPtr<amIAddonManager> addonManager =
|
||||||
do_GetService("@mozilla.org/addons/integration;1");
|
do_GetService("@mozilla.org/addons/integration;1");
|
||||||
for (uint32_t i = 0; i < windows.Length(); i++) {
|
for (uint32_t i = 0; i < windows.Length(); i++) {
|
||||||
rv = CollectWindowReports(windows[i], addonManager,
|
nsresult rv = CollectWindowReports(windows[i], addonManager,
|
||||||
&windowTotalSizes, &ghostWindows,
|
&windowTotalSizes, &ghostWindows,
|
||||||
&windowPaths, &topWindowPaths, aCb,
|
&windowPaths, &topWindowPaths, aCb,
|
||||||
aClosure);
|
aClosure);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report JS memory usage. We do this from here because the JS memory
|
// Report JS memory usage. We do this from here because the JS memory
|
||||||
// reporter needs to be passed |windowPaths|.
|
// reporter needs to be passed |windowPaths|.
|
||||||
rv = xpc::JSReporter::CollectReports(&windowPaths, &topWindowPaths,
|
nsresult rv = xpc::JSReporter::CollectReports(&windowPaths, &topWindowPaths,
|
||||||
aCb, aClosure);
|
aCb, aClosure);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
#define REPORT(_path, _amount, _desc) \
|
#define REPORT(_path, _amount, _desc) \
|
||||||
|
@ -714,11 +662,94 @@ nsWindowMemoryReporter::CheckForGhostWindows(
|
||||||
&ghostEnumData);
|
&ghostEnumData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ int64_t
|
NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter::GhostURLsReporter,
|
||||||
nsWindowMemoryReporter::GhostWindowsReporter::DistinguishedAmount()
|
nsIMemoryReporter)
|
||||||
|
|
||||||
|
nsWindowMemoryReporter::
|
||||||
|
GhostURLsReporter::GhostURLsReporter(
|
||||||
|
nsWindowMemoryReporter* aWindowReporter)
|
||||||
|
: mWindowReporter(aWindowReporter)
|
||||||
{
|
{
|
||||||
nsTHashtable<nsUint64HashKey> ghostWindows;
|
|
||||||
sWindowReporter->CheckForGhostWindows(&ghostWindows);
|
|
||||||
return ghostWindows.Count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsWindowMemoryReporter::
|
||||||
|
GhostURLsReporter::GetName(nsACString& aName)
|
||||||
|
{
|
||||||
|
aName.AssignLiteral("ghost-windows-multi");
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReportGhostWindowsEnumeratorData
|
||||||
|
{
|
||||||
|
nsIMemoryReporterCallback* callback;
|
||||||
|
nsISupports* closure;
|
||||||
|
nsresult rv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PLDHashOperator
|
||||||
|
ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aClosure)
|
||||||
|
{
|
||||||
|
ReportGhostWindowsEnumeratorData *data =
|
||||||
|
static_cast<ReportGhostWindowsEnumeratorData*>(aClosure);
|
||||||
|
|
||||||
|
nsGlobalWindow::WindowByIdTable* windowsById =
|
||||||
|
nsGlobalWindow::GetWindowsTable();
|
||||||
|
if (!windowsById) {
|
||||||
|
NS_WARNING("Couldn't get window-by-id hashtable?");
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsGlobalWindow* window = windowsById->Get(aIDHashKey->GetKey());
|
||||||
|
if (!window) {
|
||||||
|
NS_WARNING("Could not look up window?");
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoCString path;
|
||||||
|
path.AppendLiteral("ghost-windows/");
|
||||||
|
AppendWindowURI(window, path);
|
||||||
|
|
||||||
|
nsresult rv = data->callback->Callback(
|
||||||
|
/* process = */ EmptyCString(),
|
||||||
|
path,
|
||||||
|
nsIMemoryReporter::KIND_OTHER,
|
||||||
|
nsIMemoryReporter::UNITS_COUNT,
|
||||||
|
/* amount = */ 1,
|
||||||
|
/* description = */ NS_LITERAL_CSTRING("A ghost window."),
|
||||||
|
data->closure);
|
||||||
|
|
||||||
|
if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
|
||||||
|
data->rv = rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsWindowMemoryReporter::
|
||||||
|
GhostURLsReporter::CollectReports(
|
||||||
|
nsIMemoryReporterCallback* aCb,
|
||||||
|
nsISupports* aClosure)
|
||||||
|
{
|
||||||
|
// Get the IDs of all the ghost windows in existance.
|
||||||
|
nsTHashtable<nsUint64HashKey> ghostWindows;
|
||||||
|
mWindowReporter->CheckForGhostWindows(&ghostWindows);
|
||||||
|
|
||||||
|
ReportGhostWindowsEnumeratorData reportGhostWindowsEnumData =
|
||||||
|
{ aCb, aClosure, NS_OK };
|
||||||
|
|
||||||
|
// Call aCb->Callback() for each ghost window.
|
||||||
|
ghostWindows.EnumerateEntries(ReportGhostWindowsEnumerator,
|
||||||
|
&reportGhostWindowsEnumData);
|
||||||
|
|
||||||
|
return reportGhostWindowsEnumData.rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
nsWindowMemoryReporter::NumGhostsReporter::Amount()
|
||||||
|
{
|
||||||
|
nsTHashtable<nsUint64HashKey> ghostWindows;
|
||||||
|
mWindowReporter->CheckForGhostWindows(&ghostWindows);
|
||||||
|
return ghostWindows.Count();
|
||||||
|
}
|
||||||
|
|
|
@ -120,14 +120,31 @@ public:
|
||||||
static void Init();
|
static void Init();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* GhostURLsReporter generates the list of all ghost windows' URLs. If
|
||||||
|
* you're only interested in this list, running this report is faster than
|
||||||
|
* running nsWindowMemoryReporter.
|
||||||
|
*/
|
||||||
|
class GhostURLsReporter MOZ_FINAL : public nsIMemoryReporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GhostURLsReporter(nsWindowMemoryReporter* aWindowReporter);
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSIMEMORYREPORTER
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsRefPtr<nsWindowMemoryReporter> mWindowReporter;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nsGhostWindowReporter generates the "ghost-windows" report, which counts
|
* nsGhostWindowReporter generates the "ghost-windows" report, which counts
|
||||||
* the number of ghost windows present.
|
* the number of ghost windows present.
|
||||||
*/
|
*/
|
||||||
class GhostWindowsReporter MOZ_FINAL : public mozilla::MemoryUniReporter
|
class NumGhostsReporter MOZ_FINAL : public mozilla::MemoryUniReporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GhostWindowsReporter()
|
NumGhostsReporter(nsWindowMemoryReporter* aWindowReporter)
|
||||||
: MemoryUniReporter("ghost-windows", KIND_OTHER, UNITS_COUNT,
|
: MemoryUniReporter("ghost-windows", KIND_OTHER, UNITS_COUNT,
|
||||||
"The number of ghost windows present (the number of nodes underneath "
|
"The number of ghost windows present (the number of nodes underneath "
|
||||||
"explicit/window-objects/top(none)/ghost, modulo race conditions). A ghost "
|
"explicit/window-objects/top(none)/ghost, modulo race conditions). A ghost "
|
||||||
|
@ -137,12 +154,13 @@ private:
|
||||||
"about:memory's minimize memory usage button.\n\n"
|
"about:memory's minimize memory usage button.\n\n"
|
||||||
"Ghost windows can happen legitimately, but they are often indicative of "
|
"Ghost windows can happen legitimately, but they are often indicative of "
|
||||||
"leaks in the browser or add-ons.")
|
"leaks in the browser or add-ons.")
|
||||||
|
, mWindowReporter(aWindowReporter)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static int64_t DistinguishedAmount();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE { return DistinguishedAmount(); }
|
int64_t Amount() MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
nsRefPtr<nsWindowMemoryReporter> mWindowReporter;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Protect ctor, use Init() instead.
|
// Protect ctor, use Init() instead.
|
||||||
|
|
|
@ -137,7 +137,7 @@ public:
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t ImagesContentUsedUncompressedDistinguishedAmount()
|
static int64_t GetImagesContentUsedUncompressed()
|
||||||
{
|
{
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) {
|
for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) {
|
||||||
|
@ -223,6 +223,26 @@ private:
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(imgMemoryReporter, nsIMemoryReporter)
|
NS_IMPL_ISUPPORTS1(imgMemoryReporter, nsIMemoryReporter)
|
||||||
|
|
||||||
|
// This is used by telemetry.
|
||||||
|
class ImagesContentUsedUncompressedReporter MOZ_FINAL
|
||||||
|
: public MemoryUniReporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImagesContentUsedUncompressedReporter()
|
||||||
|
: MemoryUniReporter("images-content-used-uncompressed",
|
||||||
|
KIND_OTHER, UNITS_BYTES,
|
||||||
|
"This is the sum of the 'explicit/images/content/used/uncompressed-heap' "
|
||||||
|
"and 'explicit/images/content/used/uncompressed-nonheap' numbers. However, "
|
||||||
|
"it is measured at a different time and so may give slightly different "
|
||||||
|
"results.")
|
||||||
|
{}
|
||||||
|
private:
|
||||||
|
int64_t Amount() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
return imgMemoryReporter::GetImagesContentUsedUncompressed();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS3(nsProgressNotificationProxy,
|
NS_IMPL_ISUPPORTS3(nsProgressNotificationProxy,
|
||||||
nsIProgressEventSink,
|
nsIProgressEventSink,
|
||||||
nsIChannelEventSink,
|
nsIChannelEventSink,
|
||||||
|
@ -819,7 +839,7 @@ void imgLoader::GlobalInit()
|
||||||
|
|
||||||
sMemReporter = new imgMemoryReporter();
|
sMemReporter = new imgMemoryReporter();
|
||||||
NS_RegisterMemoryReporter(sMemReporter);
|
NS_RegisterMemoryReporter(sMemReporter);
|
||||||
RegisterImagesContentUsedUncompressedDistinguishedAmount(imgMemoryReporter::ImagesContentUsedUncompressedDistinguishedAmount);
|
NS_RegisterMemoryReporter(new ImagesContentUsedUncompressedReporter());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult imgLoader::InitCache()
|
nsresult imgLoader::InitCache()
|
||||||
|
|
|
@ -1575,35 +1575,67 @@ GetCompartmentName(JSCompartment *c, nsCString &name, bool replaceSlashes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
// Telemetry relies on this being a uni-reporter (rather than part of the "js"
|
||||||
JSMainRuntimeGCHeapDistinguishedAmount()
|
// reporter).
|
||||||
|
class JSMainRuntimeGCHeapReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
public:
|
||||||
return int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
|
JSMainRuntimeGCHeapReporter()
|
||||||
js::gc::ChunkSize;
|
: MemoryUniReporter("js-main-runtime-gc-heap", KIND_OTHER, UNITS_BYTES,
|
||||||
}
|
"Memory used by the garbage-collected heap in the main JSRuntime.")
|
||||||
|
{}
|
||||||
|
private:
|
||||||
|
int64_t Amount() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
||||||
|
return int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
|
||||||
|
js::gc::ChunkSize;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static int64_t
|
// Nb: js-main-runtime-compartments/system + js-main-runtime-compartments/user
|
||||||
JSMainRuntimeTemporaryPeakDistinguishedAmount()
|
// could be different to the number of compartments reported by JSReporter if a
|
||||||
|
// garbage collection occurred between them being consulted. We could move
|
||||||
|
// these reporters into JSReporter to avoid that problem, but then we couldn't
|
||||||
|
// easily report them via telemetry, so we live with the small risk of
|
||||||
|
// inconsistencies.
|
||||||
|
|
||||||
|
class RedundantJSMainRuntimeCompartmentsSystemReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
public:
|
||||||
return JS::PeakSizeOfTemporary(rt);
|
// An empty description is ok because this is a "redundant/"-prefixed
|
||||||
}
|
// reporter and so is ignored by about:memory.
|
||||||
|
RedundantJSMainRuntimeCompartmentsSystemReporter()
|
||||||
|
: MemoryUniReporter("redundant/js-main-runtime-compartments/system",
|
||||||
|
KIND_OTHER, UNITS_COUNT, "")
|
||||||
|
{}
|
||||||
|
private:
|
||||||
|
int64_t Amount() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
||||||
|
return JS::SystemCompartmentCount(rt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static int64_t
|
class RedundantJSMainRuntimeCompartmentsUserReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
JSMainRuntimeCompartmentsSystemDistinguishedAmount()
|
|
||||||
{
|
{
|
||||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
public:
|
||||||
return JS::SystemCompartmentCount(rt);
|
// An empty description is ok because this is a "redundant/"-prefixed
|
||||||
}
|
// reporter and so is ignored by about:memory.
|
||||||
|
RedundantJSMainRuntimeCompartmentsUserReporter()
|
||||||
static int64_t
|
: MemoryUniReporter("redundant/js-main-runtime-compartments/user",
|
||||||
JSMainRuntimeCompartmentsUserDistinguishedAmount()
|
KIND_OTHER, UNITS_COUNT,
|
||||||
{
|
"The number of JavaScript compartments for user code in the main JSRuntime.")
|
||||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
{}
|
||||||
return JS::UserCompartmentCount(rt);
|
private:
|
||||||
}
|
int64_t Amount() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
||||||
|
return JS::UserCompartmentCount(rt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is also a single reporter so it can be used by telemetry.
|
||||||
class JSMainRuntimeTemporaryPeakReporter MOZ_FINAL : public MemoryUniReporter
|
class JSMainRuntimeTemporaryPeakReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -1616,7 +1648,8 @@ public:
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE
|
int64_t Amount() MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
return JSMainRuntimeTemporaryPeakDistinguishedAmount();
|
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->Runtime();
|
||||||
|
return JS::PeakSizeOfTemporary(rt);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3023,13 +3056,11 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
||||||
if (!xpc_LocalizeRuntime(runtime))
|
if (!xpc_LocalizeRuntime(runtime))
|
||||||
NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
|
NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
|
||||||
|
|
||||||
// Register memory reporters and distinguished amount functions.
|
NS_RegisterMemoryReporter(new JSMainRuntimeGCHeapReporter());
|
||||||
NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
|
NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsSystemReporter());
|
||||||
|
NS_RegisterMemoryReporter(new RedundantJSMainRuntimeCompartmentsUserReporter());
|
||||||
NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
|
NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
|
||||||
RegisterJSMainRuntimeGCHeapDistinguishedAmount(JSMainRuntimeGCHeapDistinguishedAmount);
|
NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
|
||||||
RegisterJSMainRuntimeTemporaryPeakDistinguishedAmount(JSMainRuntimeTemporaryPeakDistinguishedAmount);
|
|
||||||
RegisterJSMainRuntimeCompartmentsSystemDistinguishedAmount(JSMainRuntimeCompartmentsSystemDistinguishedAmount);
|
|
||||||
RegisterJSMainRuntimeCompartmentsUserDistinguishedAmount(JSMainRuntimeCompartmentsUserDistinguishedAmount);
|
|
||||||
|
|
||||||
// Install a JavaScript 'debugger' keyword handler in debug builds only
|
// Install a JavaScript 'debugger' keyword handler in debug builds only
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -53,13 +53,22 @@ namespace storage {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Memory Reporting
|
//// Memory Reporting
|
||||||
|
|
||||||
static int64_t
|
// We don't need an "explicit" reporter for total SQLite memory usage, because
|
||||||
StorageSQLiteDistinguishedAmount()
|
// the multi-reporter provides reports that add up to the total. But it's
|
||||||
|
// useful to have the total in the "Other Measurements" list in about:memory,
|
||||||
|
// and more importantly, we also gather the total via telemetry.
|
||||||
|
class StorageSQLiteUniReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
return ::sqlite3_memory_used();
|
public:
|
||||||
}
|
StorageSQLiteUniReporter()
|
||||||
|
: MemoryUniReporter("storage-sqlite", KIND_OTHER, UNITS_BYTES,
|
||||||
|
"Memory used by SQLite.")
|
||||||
|
{}
|
||||||
|
private:
|
||||||
|
int64_t Amount() MOZ_OVERRIDE { return ::sqlite3_memory_used(); }
|
||||||
|
};
|
||||||
|
|
||||||
class StorageSQLiteReporter MOZ_FINAL : public nsIMemoryReporter
|
class StorageSQLiteMultiReporter MOZ_FINAL : public nsIMemoryReporter
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Service *mService; // a weakref because Service contains a strongref to this
|
Service *mService; // a weakref because Service contains a strongref to this
|
||||||
|
@ -70,7 +79,7 @@ private:
|
||||||
public:
|
public:
|
||||||
NS_DECL_THREADSAFE_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
|
||||||
StorageSQLiteReporter(Service *aService)
|
StorageSQLiteMultiReporter(Service *aService)
|
||||||
: mService(aService)
|
: mService(aService)
|
||||||
{
|
{
|
||||||
mStmtDesc = NS_LITERAL_CSTRING(
|
mStmtDesc = NS_LITERAL_CSTRING(
|
||||||
|
@ -205,7 +214,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS1(
|
NS_IMPL_ISUPPORTS1(
|
||||||
StorageSQLiteReporter,
|
StorageSQLiteMultiReporter,
|
||||||
nsIMemoryReporter
|
nsIMemoryReporter
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -298,8 +307,8 @@ Service::Service()
|
||||||
|
|
||||||
Service::~Service()
|
Service::~Service()
|
||||||
{
|
{
|
||||||
(void)::NS_UnregisterMemoryReporter(mStorageSQLiteReporter);
|
(void)::NS_UnregisterMemoryReporter(mStorageSQLiteUniReporter);
|
||||||
mozilla::UnregisterStorageSQLiteDistinguishedAmount();
|
(void)::NS_UnregisterMemoryReporter(mStorageSQLiteMultiReporter);
|
||||||
|
|
||||||
int rc = sqlite3_vfs_unregister(mSqliteVFS);
|
int rc = sqlite3_vfs_unregister(mSqliteVFS);
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
|
@ -529,12 +538,12 @@ Service::initialize()
|
||||||
sDefaultPageSize =
|
sDefaultPageSize =
|
||||||
Preferences::GetInt(PREF_TS_PAGESIZE, PREF_TS_PAGESIZE_DEFAULT);
|
Preferences::GetInt(PREF_TS_PAGESIZE, PREF_TS_PAGESIZE_DEFAULT);
|
||||||
|
|
||||||
// Create and register our SQLite memory reporter and distinguished amount
|
// Create and register our SQLite memory reporters. Registration can only
|
||||||
// function. Registration can only happen on the main thread (otherwise
|
// happen on the main thread (otherwise you'll get cryptic crashes).
|
||||||
// you'll get cryptic crashes).
|
mStorageSQLiteUniReporter = new StorageSQLiteUniReporter();
|
||||||
mStorageSQLiteReporter = new StorageSQLiteReporter(this);
|
mStorageSQLiteMultiReporter = new StorageSQLiteMultiReporter(this);
|
||||||
(void)::NS_RegisterMemoryReporter(mStorageSQLiteReporter);
|
(void)::NS_RegisterMemoryReporter(mStorageSQLiteUniReporter);
|
||||||
mozilla::RegisterStorageSQLiteDistinguishedAmount(StorageSQLiteDistinguishedAmount);
|
(void)::NS_RegisterMemoryReporter(mStorageSQLiteMultiReporter);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,8 @@ private:
|
||||||
|
|
||||||
nsCOMPtr<nsIFile> mProfileStorageFile;
|
nsCOMPtr<nsIFile> mProfileStorageFile;
|
||||||
|
|
||||||
nsCOMPtr<nsIMemoryReporter> mStorageSQLiteReporter;
|
nsCOMPtr<nsIMemoryReporter> mStorageSQLiteUniReporter;
|
||||||
|
nsCOMPtr<nsIMemoryReporter> mStorageSQLiteMultiReporter;
|
||||||
|
|
||||||
static Service *gService;
|
static Service *gService;
|
||||||
|
|
||||||
|
|
|
@ -131,21 +131,32 @@ function onUnload()
|
||||||
/**
|
/**
|
||||||
* Iterates over each reporter.
|
* Iterates over each reporter.
|
||||||
*
|
*
|
||||||
|
* @param aIgnoreReporter
|
||||||
|
* Function that indicates if we should skip an entire reporter, based
|
||||||
|
* on its name.
|
||||||
|
* @param aIgnoreReport
|
||||||
|
* Function that indicates if we should skip a single report from a
|
||||||
|
* reporter, based on its path.
|
||||||
* @param aHandleReport
|
* @param aHandleReport
|
||||||
* The function that's called for each non-skipped report.
|
* The function that's called for each non-skipped report.
|
||||||
*/
|
*/
|
||||||
function processMemoryReporters(aHandleReport)
|
function processMemoryReporters(aIgnoreReporter, aIgnoreReport, aHandleReport)
|
||||||
{
|
{
|
||||||
let handleReport = function(aProcess, aUnsafePath, aKind, aUnits,
|
let handleReport = function(aProcess, aUnsafePath, aKind, aUnits,
|
||||||
aAmount, aDescription) {
|
aAmount, aDescription) {
|
||||||
aHandleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
|
if (!aIgnoreReport(aUnsafePath)) {
|
||||||
aDescription, /* presence = */ undefined);
|
aHandleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
|
||||||
|
aDescription, /* presence = */ undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let e = gMgr.enumerateReporters();
|
let e = gMgr.enumerateReporters();
|
||||||
while (e.hasMoreElements()) {
|
while (e.hasMoreElements()) {
|
||||||
let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||||
mr.collectReports(handleReport, null);
|
if (!aIgnoreReporter(mr.name)) {
|
||||||
|
// |collectReports| never passes in a |presence| argument.
|
||||||
|
mr.collectReports(handleReport, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,17 +165,22 @@ function processMemoryReporters(aHandleReport)
|
||||||
*
|
*
|
||||||
* @param aReports
|
* @param aReports
|
||||||
* Array of reports, read from a file or the clipboard.
|
* Array of reports, read from a file or the clipboard.
|
||||||
|
* @param aIgnoreReport
|
||||||
|
* Function that indicates if we should skip a single report, based
|
||||||
|
* on its path.
|
||||||
* @param aHandleReport
|
* @param aHandleReport
|
||||||
* The function that's called for each report.
|
* The function that's called for each report.
|
||||||
*/
|
*/
|
||||||
function processMemoryReportsFromFile(aReports, aHandleReport)
|
function processMemoryReportsFromFile(aReports, aIgnoreReport, aHandleReport)
|
||||||
{
|
{
|
||||||
// Process each memory reporter with aHandleReport.
|
// Process each memory reporter with aHandleReport.
|
||||||
|
|
||||||
for (let i = 0; i < aReports.length; i++) {
|
for (let i = 0; i < aReports.length; i++) {
|
||||||
let r = aReports[i];
|
let r = aReports[i];
|
||||||
aHandleReport(r.process, r.path, r.kind, r.units, r.amount,
|
if (!aIgnoreReport(r.path)) {
|
||||||
r.description, r._presence);
|
aHandleReport(r.process, r.path, r.kind, r.units, r.amount,
|
||||||
|
r.description, r._presence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +199,7 @@ let gVerbose;
|
||||||
// Values for the second argument to updateMainAndFooter.
|
// Values for the second argument to updateMainAndFooter.
|
||||||
let HIDE_FOOTER = 0;
|
let HIDE_FOOTER = 0;
|
||||||
let SHOW_FOOTER = 1;
|
let SHOW_FOOTER = 1;
|
||||||
|
let IGNORE_FOOTER = 2;
|
||||||
|
|
||||||
function updateMainAndFooter(aMsg, aFooterAction, aClassName)
|
function updateMainAndFooter(aMsg, aFooterAction, aClassName)
|
||||||
{
|
{
|
||||||
|
@ -209,6 +226,7 @@ function updateMainAndFooter(aMsg, aFooterAction, aClassName)
|
||||||
switch (aFooterAction) {
|
switch (aFooterAction) {
|
||||||
case HIDE_FOOTER: gFooter.classList.add('hidden'); break;
|
case HIDE_FOOTER: gFooter.classList.add('hidden'); break;
|
||||||
case SHOW_FOOTER: gFooter.classList.remove('hidden'); break;
|
case SHOW_FOOTER: gFooter.classList.remove('hidden'); break;
|
||||||
|
case IGNORE_FOOTER: break;
|
||||||
default: assertInput(false, "bad footer action in updateMainAndFooter");
|
default: assertInput(false, "bad footer action in updateMainAndFooter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,8 +504,8 @@ function updateAboutMemoryFromJSONObject(aObj)
|
||||||
"missing 'hasMozMallocUsableSize' property");
|
"missing 'hasMozMallocUsableSize' property");
|
||||||
assertInput(aObj.reports && aObj.reports instanceof Array,
|
assertInput(aObj.reports && aObj.reports instanceof Array,
|
||||||
"missing or non-array 'reports' property");
|
"missing or non-array 'reports' property");
|
||||||
let process = function(aHandleReport) {
|
let process = function(aIgnoreReporter, aIgnoreReport, aHandleReport) {
|
||||||
processMemoryReportsFromFile(aObj.reports, aHandleReport);
|
processMemoryReportsFromFile(aObj.reports, aIgnoreReport, aHandleReport);
|
||||||
}
|
}
|
||||||
appendAboutMemoryMain(process, aObj.hasMozMallocUsableSize);
|
appendAboutMemoryMain(process, aObj.hasMozMallocUsableSize);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
@ -919,6 +937,19 @@ function getPCollsByProcess(aProcessReports)
|
||||||
// be in parentheses, so a ')' might appear after the '.'.)
|
// be in parentheses, so a ')' might appear after the '.'.)
|
||||||
const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
|
const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
|
||||||
|
|
||||||
|
// Ignore any "redundant/"-prefixed reporters and reports, which are only
|
||||||
|
// used by telemetry.
|
||||||
|
|
||||||
|
function ignoreReporter(aName)
|
||||||
|
{
|
||||||
|
return aName.startsWith("redundant/");
|
||||||
|
}
|
||||||
|
|
||||||
|
function ignoreReport(aUnsafePath)
|
||||||
|
{
|
||||||
|
return aUnsafePath.startsWith("redundant/");
|
||||||
|
}
|
||||||
|
|
||||||
function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
|
function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
|
||||||
aDescription, aPresence)
|
aDescription, aPresence)
|
||||||
{
|
{
|
||||||
|
@ -957,8 +988,7 @@ function getPCollsByProcess(aProcessReports)
|
||||||
|
|
||||||
assert(aPresence === undefined ||
|
assert(aPresence === undefined ||
|
||||||
aPresence == DReport.PRESENT_IN_FIRST_ONLY ||
|
aPresence == DReport.PRESENT_IN_FIRST_ONLY ||
|
||||||
aPresence == DReport.PRESENT_IN_SECOND_ONLY,
|
aPresence == DReport.PRESENT_IN_SECOND_ONLY);
|
||||||
"bad presence");
|
|
||||||
|
|
||||||
let process = aProcess === "" ? gUnnamedProcessStr : aProcess;
|
let process = aProcess === "" ? gUnnamedProcessStr : aProcess;
|
||||||
let unsafeNames = aUnsafePath.split('/');
|
let unsafeNames = aUnsafePath.split('/');
|
||||||
|
@ -1016,7 +1046,7 @@ function getPCollsByProcess(aProcessReports)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aProcessReports(handleReport);
|
aProcessReports(ignoreReporter, ignoreReport, handleReport);
|
||||||
|
|
||||||
return pcollsByProcess;
|
return pcollsByProcess;
|
||||||
}
|
}
|
||||||
|
@ -1342,11 +1372,6 @@ function appendProcessAboutMemoryElements(aP, aProcess, aTrees, aDegenerates,
|
||||||
let t = aTrees[treeName];
|
let t = aTrees[treeName];
|
||||||
if (t) {
|
if (t) {
|
||||||
fillInTree(t);
|
fillInTree(t);
|
||||||
// Using the "heap-allocated" reporter here instead of
|
|
||||||
// nsMemoryReporterManager.heapAllocated goes against the usual pattern.
|
|
||||||
// But the "heap-allocated" node will go in the tree like the others, so
|
|
||||||
// we have to deal with it, and once we're dealing with it, it's easier
|
|
||||||
// to keep doing so rather than switching to the distinguished amount.
|
|
||||||
hasKnownHeapAllocated =
|
hasKnownHeapAllocated =
|
||||||
aDegenerates &&
|
aDegenerates &&
|
||||||
addHeapUnclassifiedNode(t, aDegenerates["heap-allocated"], aHeapTotal);
|
addHeapUnclassifiedNode(t, aDegenerates["heap-allocated"], aHeapTotal);
|
||||||
|
|
|
@ -150,6 +150,14 @@
|
||||||
// the largest). Processes without a |resident| memory reporter are saved
|
// the largest). Processes without a |resident| memory reporter are saved
|
||||||
// for the end.
|
// for the end.
|
||||||
let fakeReporters2 = [
|
let fakeReporters2 = [
|
||||||
|
{ name: "redundant/foobar",
|
||||||
|
collectReports: function(aCbObj, aClosure) {
|
||||||
|
// Shouldn't reach here; aboutMemory.js should skip the reporter.
|
||||||
|
// (Nb: this must come after |mgr.explicit| is accessed, otherwise it
|
||||||
|
// *will* be run by nsMemoryReporterManager::GetExplicit()).
|
||||||
|
ok(false, "'redundant/foobar' reporter was run");
|
||||||
|
}
|
||||||
|
},
|
||||||
{ name: "fake3",
|
{ name: "fake3",
|
||||||
collectReports: function(aCbObj, aClosure) {
|
collectReports: function(aCbObj, aClosure) {
|
||||||
function f(aP1, aP2, aK, aU, aA) {
|
function f(aP1, aP2, aK, aU, aA) {
|
||||||
|
@ -166,6 +174,7 @@
|
||||||
HEAP, BYTES,200 * MB);
|
HEAP, BYTES,200 * MB);
|
||||||
f("2nd", "other0", OTHER, BYTES,666 * MB);
|
f("2nd", "other0", OTHER, BYTES,666 * MB);
|
||||||
f("2nd", "other1", OTHER, BYTES,111 * MB);
|
f("2nd", "other1", OTHER, BYTES,111 * MB);
|
||||||
|
f("2nd", "redundant/blah", NONHEAP, BYTES,24*4*KB); // ignored!
|
||||||
|
|
||||||
// Check that we can handle "heap-allocated" not being present.
|
// Check that we can handle "heap-allocated" not being present.
|
||||||
f("3rd", "explicit/a/b", HEAP, BYTES,333 * MB);
|
f("3rd", "explicit/a/b", HEAP, BYTES,333 * MB);
|
||||||
|
|
|
@ -45,7 +45,16 @@
|
||||||
let heapAllocatedAmounts = [];
|
let heapAllocatedAmounts = [];
|
||||||
let storageSqliteAmounts = [];
|
let storageSqliteAmounts = [];
|
||||||
|
|
||||||
let present = {}
|
let areJsNonWindowCompartmentsPresent = false;
|
||||||
|
let areWindowObjectsJsCompartmentsPresent = false;
|
||||||
|
let isSandboxLocationShown = false;
|
||||||
|
let isPlacesPresent = false;
|
||||||
|
let isImagesPresent = false;
|
||||||
|
let isXptiWorkingSetPresent = false;
|
||||||
|
let isAtomTablePresent = false;
|
||||||
|
let isBigStringPresent = false;
|
||||||
|
let isSmallString1Present = false;
|
||||||
|
let isSmallString2Present = false;
|
||||||
|
|
||||||
// Generate a long, random string. We'll check that this string is
|
// Generate a long, random string. We'll check that this string is
|
||||||
// reported in at least one of the memory reporters.
|
// reported in at least one of the memory reporters.
|
||||||
|
@ -83,36 +92,35 @@
|
||||||
|
|
||||||
// Check the presence of some other notable reporters.
|
// Check the presence of some other notable reporters.
|
||||||
} else if (aPath.search(/^explicit\/js-non-window\/.*compartment\(/) >= 0) {
|
} else if (aPath.search(/^explicit\/js-non-window\/.*compartment\(/) >= 0) {
|
||||||
present.jsNonWindowCompartments = true;
|
areJsNonWindowCompartmentsPresent = true;
|
||||||
} else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js-compartment\(/) >= 0) {
|
} else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js-compartment\(/) >= 0) {
|
||||||
present.windowObjectsJsCompartments = true;
|
areWindowObjectsJsCompartmentsPresent = true;
|
||||||
} else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
|
} else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
|
||||||
present.places = true;
|
isPlacesPresent = true;
|
||||||
} else if (aPath.search(/^explicit\/images/) >= 0) {
|
} else if (aPath.search(/^explicit\/images/) >= 0) {
|
||||||
present.images = true;
|
isImagesPresent = true;
|
||||||
} else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) {
|
} else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) {
|
||||||
present.xptiWorkingSet = true;
|
isXptiWorkingSetPresent = true;
|
||||||
} else if (aPath.search(/^explicit\/atom-tables$/) >= 0) {
|
} else if (aPath.search(/^explicit\/atom-tables$/) >= 0) {
|
||||||
present.atomTable = true;
|
isAtomTablePresent = true;
|
||||||
} else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) {
|
} else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) {
|
||||||
// A system compartment with a location (such as a sandbox) should
|
// A system compartment with a location (such as a sandbox) should
|
||||||
// show that location.
|
// show that location.
|
||||||
present.sandboxLocation = true;
|
isSandboxLocationShown = true;
|
||||||
} else if (aPath.contains(bigStringPrefix)) {
|
} else if (aPath.contains(bigStringPrefix)) {
|
||||||
present.bigString = true;
|
isBigStringPresent = true;
|
||||||
} else if (aPath.contains("!)(*&")) {
|
} else if (aPath.contains("!)(*&")) {
|
||||||
present.smallString1 = true;
|
isSmallString1Present = true;
|
||||||
} else if (aPath.contains("@)(*&")) {
|
} else if (aPath.contains("@)(*&")) {
|
||||||
present.smallString2 = true;
|
isSmallString2Present = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||||
getService(Ci.nsIMemoryReporterManager);
|
getService(Ci.nsIMemoryReporterManager);
|
||||||
|
|
||||||
// Access the distinguished amounts (mgr.explicit et al.) just to make sure
|
// Access mgr.explicit and mgr.resident just to make sure they don't crash.
|
||||||
// they don't crash. We can't check their actual values because they're
|
// We can't check their actual values because they're non-deterministic.
|
||||||
// non-deterministic.
|
|
||||||
//
|
//
|
||||||
// Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a
|
// Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a
|
||||||
// --enable-trace-malloc build. Allow for that exception, but *only* that
|
// --enable-trace-malloc build. Allow for that exception, but *only* that
|
||||||
|
@ -125,35 +133,7 @@
|
||||||
is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
|
is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
|
||||||
haveExplicit = false;
|
haveExplicit = false;
|
||||||
}
|
}
|
||||||
let amounts = [
|
dummy = mgr.resident;
|
||||||
"vsize",
|
|
||||||
"resident",
|
|
||||||
"residentFast",
|
|
||||||
"heapAllocated",
|
|
||||||
"heapOverheadRatio",
|
|
||||||
"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.
|
|
||||||
dummy = mgr[amounts[i]];
|
|
||||||
ok(dummy !== undefined,
|
|
||||||
"accessed an unknown distinguished amount: " + amounts[i]);
|
|
||||||
} catch (ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let e = mgr.enumerateReporters();
|
let e = mgr.enumerateReporters();
|
||||||
while (e.hasMoreElements()) {
|
while (e.hasMoreElements()) {
|
||||||
|
@ -180,17 +160,18 @@
|
||||||
checkSpecialReport("vsize", vsizeAmounts);
|
checkSpecialReport("vsize", vsizeAmounts);
|
||||||
checkSpecialReport("resident", residentAmounts);
|
checkSpecialReport("resident", residentAmounts);
|
||||||
checkSpecialReport("js-main-runtime-gc-heap-committed/used/gc-things", jsGcHeapAmounts);
|
checkSpecialReport("js-main-runtime-gc-heap-committed/used/gc-things", jsGcHeapAmounts);
|
||||||
|
checkSpecialReport("storage-sqlite", storageSqliteAmounts);
|
||||||
|
|
||||||
ok(present.jsNonWindowCompartments, "js-non-window compartments are present");
|
ok(areJsNonWindowCompartmentsPresent, "js-non-window compartments are present");
|
||||||
ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present");
|
ok(areWindowObjectsJsCompartmentsPresent, "window-objects/.../js compartments are present");
|
||||||
ok(present.places, "places is present");
|
ok(isSandboxLocationShown, "sandbox locations are present");
|
||||||
ok(present.images, "images is present");
|
ok(isPlacesPresent, "places is present");
|
||||||
ok(present.xptiWorkingSet, "xpti-working-set is present");
|
ok(isImagesPresent, "images is present");
|
||||||
ok(present.atomTable, "atom-table is present");
|
ok(isXptiWorkingSetPresent, "xpti-working-set is present");
|
||||||
ok(present.sandboxLocation, "sandbox locations are present");
|
ok(isAtomTablePresent, "atom-table is present");
|
||||||
ok(present.bigString, "large string is present");
|
ok(isBigStringPresent, "large string is present");
|
||||||
ok(present.smallString1, "small string 1 is present");
|
ok(isSmallString1Present, "small string 1 is present");
|
||||||
ok(present.smallString2, "small string 2 is present");
|
ok(isSmallString2Present, "small string 2 is present");
|
||||||
|
|
||||||
]]>
|
]]>
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -39,6 +39,39 @@ const TELEMETRY_INTERVAL = 60000;
|
||||||
// Delay before intializing telemetry (ms)
|
// Delay before intializing telemetry (ms)
|
||||||
const TELEMETRY_DELAY = 60000;
|
const TELEMETRY_DELAY = 60000;
|
||||||
|
|
||||||
|
// MEM_HISTOGRAMS lists the memory reporters we turn into histograms.
|
||||||
|
//
|
||||||
|
// Note that we currently handle only vanilla memory reporters, not memory
|
||||||
|
// multi-reporters.
|
||||||
|
//
|
||||||
|
// test_TelemetryPing.js relies on some of these memory reporters
|
||||||
|
// being here. If you remove any of the following histograms from
|
||||||
|
// MEM_HISTOGRAMS, you'll have to modify test_TelemetryPing.js:
|
||||||
|
//
|
||||||
|
// * MEMORY_JS_GC_HEAP, and
|
||||||
|
// * MEMORY_JS_COMPARTMENTS_SYSTEM.
|
||||||
|
//
|
||||||
|
// We used to measure "explicit" too, but it could cause hangs, and the data
|
||||||
|
// was always really noisy anyway. See bug 859657.
|
||||||
|
const MEM_HISTOGRAMS = {
|
||||||
|
"js-main-runtime-gc-heap": "MEMORY_JS_GC_HEAP",
|
||||||
|
"redundant/js-main-runtime-compartments/system": "MEMORY_JS_COMPARTMENTS_SYSTEM",
|
||||||
|
"redundant/js-main-runtime-compartments/user": "MEMORY_JS_COMPARTMENTS_USER",
|
||||||
|
"js-main-runtime-temporary-peak": "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK",
|
||||||
|
"redundant/resident-fast": "MEMORY_RESIDENT",
|
||||||
|
"vsize": "MEMORY_VSIZE",
|
||||||
|
"storage-sqlite": "MEMORY_STORAGE_SQLITE",
|
||||||
|
"images-content-used-uncompressed":
|
||||||
|
"MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED",
|
||||||
|
"heap-allocated": "MEMORY_HEAP_ALLOCATED",
|
||||||
|
"heap-overhead": "MEMORY_HEAP_COMMITTED_UNUSED",
|
||||||
|
"heap-overhead-ratio": "MEMORY_HEAP_COMMITTED_UNUSED_RATIO",
|
||||||
|
"page-faults-hard": "PAGE_FAULTS_HARD",
|
||||||
|
"low-memory-events/virtual": "LOW_MEMORY_EVENTS_VIRTUAL",
|
||||||
|
"low-memory-events/physical": "LOW_MEMORY_EVENTS_PHYSICAL",
|
||||||
|
"ghost-windows": "GHOST_WINDOWS"
|
||||||
|
};
|
||||||
|
|
||||||
// Seconds of idle time before pinging.
|
// Seconds of idle time before pinging.
|
||||||
// On idle-daily a gather-telemetry notification is fired, during it probes can
|
// On idle-daily a gather-telemetry notification is fired, during it probes can
|
||||||
// start asynchronous tasks to gather data. On the next idle the data is sent.
|
// start asynchronous tasks to gather data. On the next idle the data is sent.
|
||||||
|
@ -414,57 +447,39 @@ TelemetryPing.prototype = {
|
||||||
|
|
||||||
let histogram = Telemetry.getHistogramById("TELEMETRY_MEMORY_REPORTER_MS");
|
let histogram = Telemetry.getHistogramById("TELEMETRY_MEMORY_REPORTER_MS");
|
||||||
let startTime = new Date();
|
let startTime = new Date();
|
||||||
|
let e = mgr.enumerateReporters();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||||
|
let id = MEM_HISTOGRAMS[mr.name];
|
||||||
|
if (!id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Get memory measurements from distinguished amount attributes. We used
|
// collectReports might throw an exception. If so, just ignore that
|
||||||
// to measure "explicit" too, but it could cause hangs, and the data was
|
// memory reporter; we're not getting useful data out of it.
|
||||||
// always really noisy anyway. See bug 859657.
|
|
||||||
//
|
|
||||||
// test_TelemetryPing.js relies on some of these histograms being
|
|
||||||
// here. If you remove any of the following histograms from here, you'll
|
|
||||||
// have to modify test_TelemetryPing.js:
|
|
||||||
//
|
|
||||||
// * MEMORY_JS_GC_HEAP, and
|
|
||||||
// * MEMORY_JS_COMPARTMENTS_SYSTEM.
|
|
||||||
//
|
|
||||||
// The distinguished amount attribute names don't match the telemetry id
|
|
||||||
// names in some cases due to a combination of (a) historical reasons, and
|
|
||||||
// (b) the fact that we can't change telemetry id names without breaking
|
|
||||||
// data continuity.
|
|
||||||
//
|
|
||||||
let boundHandleMemoryReport = this.handleMemoryReport.bind(this);
|
|
||||||
function h(id, units, amountName) {
|
|
||||||
try {
|
try {
|
||||||
// If mgr[amountName] throws an exception, just move on -- some amounts
|
// Bind handleMemoryReport() so it can be called inside the closure
|
||||||
// aren't available on all platforms. But if the attribute simply
|
// used as the callback.
|
||||||
// isn't present, that indicates the distinguished amounts have changed
|
let boundHandleMemoryReport = this.handleMemoryReport.bind(this);
|
||||||
// and this file hasn't been updated appropriately.
|
|
||||||
let amount = mgr[amountName];
|
// Reporters used for telemetry should be uni-reporters! we assert if
|
||||||
NS_ASSERT(amount !== undefined,
|
// they make more than one report.
|
||||||
"telemetry accessed an unknown distinguished amount");
|
let hasReported = false;
|
||||||
boundHandleMemoryReport(id, units, amount);
|
|
||||||
} catch (e) {
|
function h(process, path, kind, units, amount, desc) {
|
||||||
};
|
if (!hasReported) {
|
||||||
|
boundHandleMemoryReport(id, units, amount);
|
||||||
|
hasReported = true;
|
||||||
|
} else {
|
||||||
|
NS_ASSERT(false,
|
||||||
|
"reporter " + mr.name + " has made more than one report");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mr.collectReports(h, null);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let b = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_BYTES, n);
|
|
||||||
let c = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_COUNT, n);
|
|
||||||
let cc= (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE, n);
|
|
||||||
let p = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_PERCENTAGE, n);
|
|
||||||
|
|
||||||
b("MEMORY_VSIZE", "vsize");
|
|
||||||
b("MEMORY_RESIDENT", "residentFast");
|
|
||||||
b("MEMORY_HEAP_ALLOCATED", "heapAllocated");
|
|
||||||
p("MEMORY_HEAP_COMMITTED_UNUSED_RATIO", "heapOverheadRatio");
|
|
||||||
b("MEMORY_JS_GC_HEAP", "JSMainRuntimeGCHeap");
|
|
||||||
b("MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK", "JSMainRuntimeTemporaryPeak");
|
|
||||||
c("MEMORY_JS_COMPARTMENTS_SYSTEM", "JSMainRuntimeCompartmentsSystem");
|
|
||||||
c("MEMORY_JS_COMPARTMENTS_USER", "JSMainRuntimeCompartmentsUser");
|
|
||||||
b("MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED", "imagesContentUsedUncompressed");
|
|
||||||
b("MEMORY_STORAGE_SQLITE", "storageSQLite");
|
|
||||||
cc("MEMORY_EVENTS_VIRTUAL", "lowMemoryEventsVirtual");
|
|
||||||
cc("MEMORY_EVENTS_PHYSICAL", "lowMemoryEventsPhysical");
|
|
||||||
c("GHOST_WINDOWS", "ghostWindows");
|
|
||||||
cc("PAGE_FAULTS_HARD", "pageFaultsHard");
|
|
||||||
|
|
||||||
histogram.add(new Date() - startTime);
|
histogram.add(new Date() - startTime);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -325,12 +325,6 @@ CreateDIBSectionHook(HDC aDC,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
|
||||||
LowMemoryEventsVirtualDistinguishedAmount()
|
|
||||||
{
|
|
||||||
return sNumLowVirtualMemEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LowMemoryEventsVirtualReporter MOZ_FINAL : public MemoryUniReporter
|
class LowMemoryEventsVirtualReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -351,7 +345,7 @@ private:
|
||||||
// force-disable virtual-memory tracking there.
|
// force-disable virtual-memory tracking there.
|
||||||
MOZ_ASSERT(sizeof(void*) == 4);
|
MOZ_ASSERT(sizeof(void*) == 4);
|
||||||
|
|
||||||
return LowMemoryEventsVirtualDistinguishedAmount();
|
return sNumLowVirtualMemEvents;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -372,12 +366,6 @@ private:
|
||||||
int64_t Amount() MOZ_OVERRIDE { return sNumLowCommitSpaceEvents; }
|
int64_t Amount() MOZ_OVERRIDE { return sNumLowCommitSpaceEvents; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int64_t
|
|
||||||
LowMemoryEventsPhysicalDistinguishedAmount()
|
|
||||||
{
|
|
||||||
return sNumLowPhysicalMemEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LowMemoryEventsPhysicalReporter MOZ_FINAL : public MemoryUniReporter
|
class LowMemoryEventsPhysicalReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -392,7 +380,7 @@ public:
|
||||||
{}
|
{}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE { return LowMemoryEventsPhysicalDistinguishedAmount(); }
|
int64_t Amount() MOZ_OVERRIDE { return sNumLowPhysicalMemEvents; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // defined(XP_WIN)
|
#endif // defined(XP_WIN)
|
||||||
|
@ -515,8 +503,6 @@ void Activate()
|
||||||
if (sizeof(void*) == 4) {
|
if (sizeof(void*) == 4) {
|
||||||
NS_RegisterMemoryReporter(new LowMemoryEventsVirtualReporter());
|
NS_RegisterMemoryReporter(new LowMemoryEventsVirtualReporter());
|
||||||
}
|
}
|
||||||
RegisterLowMemoryEventsVirtualDistinguishedAmount(LowMemoryEventsVirtualDistinguishedAmount);
|
|
||||||
RegisterLowMemoryEventsPhysicalDistinguishedAmount(LowMemoryEventsPhysicalDistinguishedAmount);
|
|
||||||
sHooksActive = true;
|
sHooksActive = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,11 @@ interface nsIMemoryReporterCallback : nsISupports
|
||||||
* description that is a sentence (i.e. starts with a capital letter and
|
* description that is a sentence (i.e. starts with a capital letter and
|
||||||
* ends with a period, or similar).
|
* ends with a period, or similar).
|
||||||
*
|
*
|
||||||
|
* - The "redundant" tree is optional, and can be used for reports that are
|
||||||
|
* redundant w.r.t. other reports. These are useful for telemetry, and are
|
||||||
|
* not shown in about:memory. Reports in this tree are entirely
|
||||||
|
* unconstrained.
|
||||||
|
*
|
||||||
* - All other reports are unconstrained except that they must have a
|
* - All other reports are unconstrained except that they must have a
|
||||||
* description that is a sentence.
|
* description that is a sentence.
|
||||||
*/
|
*/
|
||||||
|
@ -184,21 +189,21 @@ interface nsIMemoryReporterManager : nsISupports
|
||||||
/*
|
/*
|
||||||
* Return an enumerator of nsIMemoryReporters that are currently registered.
|
* Return an enumerator of nsIMemoryReporters that are currently registered.
|
||||||
*/
|
*/
|
||||||
nsISimpleEnumerator enumerateReporters();
|
nsISimpleEnumerator enumerateReporters ();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register the given nsIMemoryReporter. After a reporter is registered,
|
* Register the given nsIMemoryReporter. After a reporter is registered,
|
||||||
* it will be available via enumerateReporters(). The Manager service
|
* it will be available via enumerateReporters(). The Manager service
|
||||||
* will hold a strong reference to the given reporter.
|
* will hold a strong reference to the given reporter.
|
||||||
*/
|
*/
|
||||||
void registerReporter(in nsIMemoryReporter reporter);
|
void registerReporter (in nsIMemoryReporter reporter);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unregister the given memory reporter.
|
* Unregister the given memory reporter.
|
||||||
*/
|
*/
|
||||||
void unregisterReporter(in nsIMemoryReporter reporter);
|
void unregisterReporter (in nsIMemoryReporter reporter);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* These functions should only be used for testing purposes.
|
* These functions should only be used for testing purposes.
|
||||||
*/
|
*/
|
||||||
void blockRegistration();
|
void blockRegistration();
|
||||||
|
@ -208,94 +213,24 @@ interface nsIMemoryReporterManager : nsISupports
|
||||||
/*
|
/*
|
||||||
* Initialize.
|
* Initialize.
|
||||||
*/
|
*/
|
||||||
void init();
|
void init ();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The memory reporter manager, for the most part, treats reporters
|
* Get the resident size (aka. RSS, physical memory used). This reporter
|
||||||
* registered with it as a black box. However, there are some
|
* is special-cased because it's interesting and is available on most
|
||||||
* "distinguished" amounts (as could be reported by a memory reporter) that
|
* platforms. Accesses can fail.
|
||||||
* the manager provides as attributes, because they are sufficiently
|
*/
|
||||||
* interesting that we want external code (e.g. telemetry) to be able to rely
|
readonly attribute int64_t resident;
|
||||||
* on them.
|
|
||||||
*
|
/*
|
||||||
* Note that these are not reporters and so enumerateReporters() does not
|
* Get the total size of explicit memory allocations, both at the OS-level
|
||||||
* look at them. However, they can be embedded in a reporter.
|
* (eg. via mmap, VirtualAlloc) and at the heap level (eg. via malloc,
|
||||||
*
|
* calloc, operator new). (Nb: it covers all heap allocations, but will
|
||||||
* Access to these attributes can fail. In particular, some of them are not
|
* miss any OS-level ones not covered by memory reporters.) This reporter
|
||||||
* available on all platforms.
|
* is special-cased because it's interesting, and is difficult to compute
|
||||||
*
|
* from JavaScript code. Accesses can fail.
|
||||||
* If you add a new distinguished amount, please update
|
|
||||||
* toolkit/components/aboutmemory/tests/test_memoryReporters.xul.
|
|
||||||
*
|
|
||||||
* |explicit| (UNITS_BYTES) The total size of explicit memory allocations,
|
|
||||||
* both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level
|
|
||||||
* (eg. via malloc, calloc, operator new). It covers all heap allocations,
|
|
||||||
* but will miss any OS-level ones not covered by memory reporters.
|
|
||||||
*
|
|
||||||
* |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space
|
|
||||||
* taken up.
|
|
||||||
*
|
|
||||||
* |resident| (UNITS_BYTES) The resident size (a.k.a. RSS or physical memory
|
|
||||||
* used).
|
|
||||||
*
|
|
||||||
* |residentFast| (UNITS_BYTES) This is like |resident|, but on Mac OS
|
|
||||||
* |resident| can purge pages, which is slow. It also affects the result of
|
|
||||||
* |residentFast|, and so |resident| and |residentFast| should not be used
|
|
||||||
* together.
|
|
||||||
*
|
|
||||||
* |heapAllocated| (UNITS_BYTES) Memory mapped by the heap allocator.
|
|
||||||
*
|
|
||||||
* |heapOverheadRatio| (UNITS_PERCENTAGE) In the heap allocator, this is the
|
|
||||||
* ratio of committed, unused bytes to allocated bytes. Like all
|
|
||||||
* UNITS_PERCENTAGE measurements, its amount is multiplied by 100x so it can
|
|
||||||
* be represented by an int64_t.
|
|
||||||
*
|
|
||||||
* |JSMainRuntimeGCHeap| (UNITS_BYTES) Size of the main JS runtime's GC
|
|
||||||
* heap.
|
|
||||||
*
|
|
||||||
* |JSMainRuntimeTemporaryPeak| (UNITS_BYTES) Peak size of the transient
|
|
||||||
* storage in the main JSRuntime.
|
|
||||||
*
|
|
||||||
* |JSMainRuntimeCompartments{System,User}| (UNITS_COUNT) The number of
|
|
||||||
* {system,user} compartments in the main JS runtime.
|
|
||||||
*
|
|
||||||
* |imagesContentUsedUncompressed| (UNITS_BYTES) Memory used for decoded
|
|
||||||
* images in content.
|
|
||||||
*
|
|
||||||
* |storageSQLite| (UNITS_BYTES) Memory used by SQLite.
|
|
||||||
*
|
|
||||||
* |lowMemoryEvents{Virtual,Physical}| (UNITS_COUNT_CUMULATIVE) The number
|
|
||||||
* of low-{virtual,physical}-memory events that have occurred since the
|
|
||||||
* process started.
|
|
||||||
*
|
|
||||||
* |ghostWindows| (UNITS_COUNT) The number of ghost windows.
|
|
||||||
*
|
|
||||||
* |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a.
|
|
||||||
* major) page faults that have occurred since the process started.
|
|
||||||
*/
|
*/
|
||||||
readonly attribute int64_t explicit;
|
readonly attribute int64_t explicit;
|
||||||
readonly attribute int64_t vsize;
|
|
||||||
readonly attribute int64_t resident;
|
|
||||||
readonly attribute int64_t residentFast;
|
|
||||||
|
|
||||||
readonly attribute int64_t heapAllocated;
|
|
||||||
readonly attribute int64_t heapOverheadRatio;
|
|
||||||
|
|
||||||
readonly attribute int64_t JSMainRuntimeGCHeap;
|
|
||||||
readonly attribute int64_t JSMainRuntimeTemporaryPeak;
|
|
||||||
readonly attribute int64_t JSMainRuntimeCompartmentsSystem;
|
|
||||||
readonly attribute int64_t JSMainRuntimeCompartmentsUser;
|
|
||||||
|
|
||||||
readonly attribute int64_t imagesContentUsedUncompressed;
|
|
||||||
|
|
||||||
readonly attribute int64_t storageSQLite;
|
|
||||||
|
|
||||||
readonly attribute int64_t lowMemoryEventsVirtual;
|
|
||||||
readonly attribute int64_t lowMemoryEventsPhysical;
|
|
||||||
|
|
||||||
readonly attribute int64_t ghostWindows;
|
|
||||||
|
|
||||||
readonly attribute int64_t pageFaultsHard;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This attribute indicates if moz_malloc_usable_size() works.
|
* This attribute indicates if moz_malloc_usable_size() works.
|
||||||
|
@ -321,42 +256,6 @@ interface nsIMemoryReporterManager : nsISupports
|
||||||
XPCOM_API(nsresult) NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter);
|
XPCOM_API(nsresult) NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter);
|
||||||
XPCOM_API(nsresult) NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter);
|
XPCOM_API(nsresult) NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter);
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
// The memory reporter manager provides access to several distinguished
|
|
||||||
// amounts via attributes. Some of these amounts are provided by Gecko
|
|
||||||
// components that cannot be accessed directly from XPCOM code. So we provide
|
|
||||||
// the following functions for those components to be registered with the
|
|
||||||
// manager.
|
|
||||||
|
|
||||||
typedef int64_t (*InfallibleAmountFn)();
|
|
||||||
typedef nsresult (*FallibleAmountFn)(int64_t* aAmount);
|
|
||||||
|
|
||||||
#define DECL_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
|
|
||||||
nsresult Register##name##DistinguishedAmount(kind##AmountFn aAmountFn);
|
|
||||||
#define DECL_UNREGISTER_DISTINGUISHED_AMOUNT(name) \
|
|
||||||
nsresult Unregister##name##DistinguishedAmount();
|
|
||||||
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeGCHeap)
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeTemporaryPeak)
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
|
|
||||||
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, ImagesContentUsedUncompressed)
|
|
||||||
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, StorageSQLite)
|
|
||||||
DECL_UNREGISTER_DISTINGUISHED_AMOUNT(StorageSQLite)
|
|
||||||
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsVirtual)
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsPhysical)
|
|
||||||
|
|
||||||
DECL_REGISTER_DISTINGUISHED_AMOUNT(Infallible, GhostWindows)
|
|
||||||
|
|
||||||
#undef DECL_REGISTER_DISTINGUISHED_AMOUNT
|
|
||||||
#undef DECL_UNREGISTER_DISTINGUISHED_AMOUNT
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(MOZ_DMD)
|
#if defined(MOZ_DMD)
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dmd {
|
namespace dmd {
|
||||||
|
@ -494,4 +393,5 @@ protected:
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
|
@ -16,10 +16,9 @@
|
||||||
#if defined(XP_LINUX)
|
#if defined(XP_LINUX)
|
||||||
#include "nsMemoryInfoDumper.h"
|
#include "nsMemoryInfoDumper.h"
|
||||||
#endif
|
#endif
|
||||||
#include "mozilla/Attributes.h"
|
|
||||||
#include "mozilla/PodOperations.h"
|
|
||||||
#include "mozilla/Services.h"
|
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
|
#include "mozilla/Services.h"
|
||||||
|
|
||||||
#ifndef XP_WIN
|
#ifndef XP_WIN
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -427,6 +426,26 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD GetAmount(int64_t* aAmount) { return GetResident(aAmount); }
|
NS_IMETHOD GetAmount(int64_t* aAmount) { return GetResident(aAmount); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is a "redundant/"-prefixed reporter, which means it's ignored by
|
||||||
|
// about:memory. This is good because the "resident" reporter can purge pages
|
||||||
|
// on MacOS, which affects the "resident-fast" results, and we don't want the
|
||||||
|
// measurements shown in about:memory to be affected by the (arbitrary) order
|
||||||
|
// of memory reporter execution. This reporter is used by telemetry.
|
||||||
|
class ResidentFastReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ResidentFastReporter()
|
||||||
|
: MemoryUniReporter("redundant/resident-fast", KIND_OTHER, UNITS_BYTES,
|
||||||
|
"This is the same measurement as 'resident', but it tries to be as fast as "
|
||||||
|
"possible at the expense of accuracy. On most platforms this is identical to "
|
||||||
|
"the 'resident' measurement, but on Mac it may over-count. You should use "
|
||||||
|
"'resident-fast' where you care about latency of collection (e.g. in "
|
||||||
|
"telemetry). Otherwise you should use 'resident'.")
|
||||||
|
{}
|
||||||
|
|
||||||
|
NS_IMETHOD GetAmount(int64_t* aAmount) { return GetResidentFast(aAmount); }
|
||||||
|
};
|
||||||
#endif // HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
#endif // HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
||||||
|
|
||||||
#ifdef XP_UNIX
|
#ifdef XP_UNIX
|
||||||
|
@ -464,18 +483,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static nsresult
|
|
||||||
PageFaultsHardDistinguishedAmount(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
struct rusage usage;
|
|
||||||
int err = getrusage(RUSAGE_SELF, &usage);
|
|
||||||
if (err != 0) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
*aAmount = usage.ru_majflt;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PageFaultsHardReporter MOZ_FINAL : public MemoryUniReporter
|
class PageFaultsHardReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -495,7 +502,13 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD GetAmount(int64_t* aAmount)
|
NS_IMETHOD GetAmount(int64_t* aAmount)
|
||||||
{
|
{
|
||||||
return PageFaultsHardDistinguishedAmount(aAmount);
|
struct rusage usage;
|
||||||
|
int err = getrusage(RUSAGE_SELF, &usage);
|
||||||
|
if (err != 0) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
*aAmount = usage.ru_majflt;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif // HAVE_PAGE_FAULT_REPORTERS
|
#endif // HAVE_PAGE_FAULT_REPORTERS
|
||||||
|
@ -508,25 +521,6 @@ public:
|
||||||
|
|
||||||
#ifdef HAVE_JEMALLOC_STATS
|
#ifdef HAVE_JEMALLOC_STATS
|
||||||
|
|
||||||
static int64_t
|
|
||||||
HeapAllocated()
|
|
||||||
{
|
|
||||||
jemalloc_stats_t stats;
|
|
||||||
jemalloc_stats(&stats);
|
|
||||||
return (int64_t) stats.allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This has UNITS_PERCENTAGE, so it is multiplied by 100x.
|
|
||||||
static int64_t
|
|
||||||
HeapOverheadRatio()
|
|
||||||
{
|
|
||||||
jemalloc_stats_t stats;
|
|
||||||
jemalloc_stats(&stats);
|
|
||||||
return (int64_t) 10000 *
|
|
||||||
(stats.waste + stats.bookkeeping + stats.page_cache) /
|
|
||||||
((double)stats.allocated);
|
|
||||||
}
|
|
||||||
|
|
||||||
class HeapAllocatedReporter MOZ_FINAL : public MemoryUniReporter
|
class HeapAllocatedReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -538,7 +532,12 @@ public:
|
||||||
"exact amount requested is not recorded.)")
|
"exact amount requested is not recorded.)")
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE { return HeapAllocated(); }
|
int64_t Amount() MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
jemalloc_stats_t stats;
|
||||||
|
jemalloc_stats(&stats);
|
||||||
|
return (int64_t) stats.allocated;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class HeapOverheadWasteReporter MOZ_FINAL : public MemoryUniReporter
|
class HeapOverheadWasteReporter MOZ_FINAL : public MemoryUniReporter
|
||||||
|
@ -557,7 +556,7 @@ public:
|
||||||
"fragmented, or that allocator is performing poorly for some other reason.")
|
"fragmented, or that allocator is performing poorly for some other reason.")
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE
|
int64_t Amount()
|
||||||
{
|
{
|
||||||
jemalloc_stats_t stats;
|
jemalloc_stats_t stats;
|
||||||
jemalloc_stats(&stats);
|
jemalloc_stats(&stats);
|
||||||
|
@ -574,7 +573,7 @@ public:
|
||||||
"Committed bytes which the heap allocator uses for internal data structures.")
|
"Committed bytes which the heap allocator uses for internal data structures.")
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE
|
int64_t Amount()
|
||||||
{
|
{
|
||||||
jemalloc_stats_t stats;
|
jemalloc_stats_t stats;
|
||||||
jemalloc_stats(&stats);
|
jemalloc_stats(&stats);
|
||||||
|
@ -594,7 +593,7 @@ public:
|
||||||
"is typically not larger than a few megabytes.")
|
"is typically not larger than a few megabytes.")
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE
|
int64_t Amount()
|
||||||
{
|
{
|
||||||
jemalloc_stats_t stats;
|
jemalloc_stats_t stats;
|
||||||
jemalloc_stats(&stats);
|
jemalloc_stats(&stats);
|
||||||
|
@ -614,7 +613,7 @@ public:
|
||||||
"exactly.")
|
"exactly.")
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE
|
int64_t Amount()
|
||||||
{
|
{
|
||||||
jemalloc_stats_t stats;
|
jemalloc_stats_t stats;
|
||||||
jemalloc_stats(&stats);
|
jemalloc_stats(&stats);
|
||||||
|
@ -634,7 +633,14 @@ public:
|
||||||
"the heap allocator relative to amount of memory allocated.")
|
"the heap allocator relative to amount of memory allocated.")
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE { return HeapOverheadRatio(); }
|
int64_t Amount()
|
||||||
|
{
|
||||||
|
jemalloc_stats_t stats;
|
||||||
|
jemalloc_stats(&stats);
|
||||||
|
return (int64_t) 10000 *
|
||||||
|
(stats.waste + stats.bookkeeping + stats.page_cache) /
|
||||||
|
((double)stats.allocated);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#endif // HAVE_JEMALLOC_STATS
|
#endif // HAVE_JEMALLOC_STATS
|
||||||
|
|
||||||
|
@ -651,10 +657,7 @@ public:
|
||||||
"Memory used by the dynamic and static atoms tables.")
|
"Memory used by the dynamic and static atoms tables.")
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
int64_t Amount() MOZ_OVERRIDE
|
int64_t Amount() { return NS_SizeOfAtomTablesIncludingThis(MallocSizeOf); }
|
||||||
{
|
|
||||||
return NS_SizeOfAtomTablesIncludingThis(MallocSizeOf);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef MOZ_DMD
|
#ifdef MOZ_DMD
|
||||||
|
@ -749,6 +752,7 @@ nsMemoryReporterManager::Init()
|
||||||
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
||||||
RegisterReporter(new VsizeReporter);
|
RegisterReporter(new VsizeReporter);
|
||||||
RegisterReporter(new ResidentReporter);
|
RegisterReporter(new ResidentReporter);
|
||||||
|
RegisterReporter(new ResidentFastReporter);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_RESIDENT_UNIQUE_REPORTER
|
#ifdef HAVE_RESIDENT_UNIQUE_REPORTER
|
||||||
|
@ -844,7 +848,6 @@ nsMemoryReporterManager::nsMemoryReporterManager()
|
||||||
: mMutex("nsMemoryReporterManager::mMutex"),
|
: mMutex("nsMemoryReporterManager::mMutex"),
|
||||||
mIsRegistrationBlocked(false)
|
mIsRegistrationBlocked(false)
|
||||||
{
|
{
|
||||||
PodZero(&mAmountFns);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsMemoryReporterManager::~nsMemoryReporterManager()
|
nsMemoryReporterManager::~nsMemoryReporterManager()
|
||||||
|
@ -961,6 +964,17 @@ nsMemoryReporterManager::UnblockRegistration()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsMemoryReporterManager::GetResident(int64_t* aResident)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
||||||
|
return ::GetResident(aResident);
|
||||||
|
#else
|
||||||
|
*aResident = 0;
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// This is just a wrapper for int64_t that implements nsISupports, so it can be
|
// This is just a wrapper for int64_t that implements nsISupports, so it can be
|
||||||
// passed to nsIMemoryReporter::CollectReports.
|
// passed to nsIMemoryReporter::CollectReports.
|
||||||
class Int64Wrapper MOZ_FINAL : public nsISupports {
|
class Int64Wrapper MOZ_FINAL : public nsISupports {
|
||||||
|
@ -981,12 +995,6 @@ public:
|
||||||
const nsACString& aDescription,
|
const nsACString& aDescription,
|
||||||
nsISupports* aWrappedExplicit)
|
nsISupports* aWrappedExplicit)
|
||||||
{
|
{
|
||||||
// Using the "heap-allocated" reporter here instead of
|
|
||||||
// nsMemoryReporterManager.heapAllocated goes against the usual
|
|
||||||
// pattern. But it's for a good reason: in tests, we can easily
|
|
||||||
// create artificial (i.e. deterministic) reporters -- which allows us
|
|
||||||
// to precisely test nsMemoryReporterManager.explicit -- but we can't
|
|
||||||
// do that for distinguished amounts.
|
|
||||||
if (aPath.Equals("heap-allocated") ||
|
if (aPath.Equals("heap-allocated") ||
|
||||||
(aKind == nsIMemoryReporter::KIND_NONHEAP &&
|
(aKind == nsIMemoryReporter::KIND_NONHEAP &&
|
||||||
PromiseFlatCString(aPath).Find("explicit") == 0))
|
PromiseFlatCString(aPath).Find("explicit") == 0))
|
||||||
|
@ -1001,10 +1009,10 @@ public:
|
||||||
NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIMemoryReporterCallback)
|
NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIMemoryReporterCallback)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
|
nsMemoryReporterManager::GetExplicit(int64_t* aExplicit)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG_POINTER(aAmount);
|
NS_ENSURE_ARG_POINTER(aExplicit);
|
||||||
*aAmount = 0;
|
*aExplicit = 0;
|
||||||
#ifndef HAVE_JEMALLOC_STATS
|
#ifndef HAVE_JEMALLOC_STATS
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
#else
|
#else
|
||||||
|
@ -1027,149 +1035,12 @@ nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
|
||||||
r->CollectReports(cb, wrappedExplicitSize);
|
r->CollectReports(cb, wrappedExplicitSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
*aAmount = wrappedExplicitSize->mValue;
|
*aExplicit = wrappedExplicitSize->mValue;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
#endif // HAVE_JEMALLOC_STATS
|
#endif // HAVE_JEMALLOC_STATS
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetVsize(int64_t* aVsize)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
|
||||||
return ::GetVsize(aVsize);
|
|
||||||
#else
|
|
||||||
*aResident = 0;
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetResident(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
|
||||||
return ::GetResident(aAmount);
|
|
||||||
#else
|
|
||||||
*aAmount = 0;
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetResidentFast(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
|
|
||||||
return ::GetResidentFast(aAmount);
|
|
||||||
#else
|
|
||||||
*aAmount = 0;
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetHeapAllocated(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_JEMALLOC_STATS
|
|
||||||
*aAmount = HeapAllocated();
|
|
||||||
return NS_OK;
|
|
||||||
#else
|
|
||||||
*aAmount = 0;
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// This has UNITS_PERCENTAGE, so it is multiplied by 100x.
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetHeapOverheadRatio(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_JEMALLOC_STATS
|
|
||||||
*aAmount = HeapOverheadRatio();
|
|
||||||
return NS_OK;
|
|
||||||
#else
|
|
||||||
*aAmount = 0;
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static nsresult
|
|
||||||
GetInfallibleAmount(InfallibleAmountFn aAmountFn, int64_t* aAmount)
|
|
||||||
{
|
|
||||||
if (aAmountFn) {
|
|
||||||
*aAmount = aAmountFn();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
*aAmount = 0;
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetJSMainRuntimeGCHeap(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeGCHeap, aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetJSMainRuntimeTemporaryPeak(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeTemporaryPeak, aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetJSMainRuntimeCompartmentsSystem(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeCompartmentsSystem,
|
|
||||||
aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetJSMainRuntimeCompartmentsUser(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mJSMainRuntimeCompartmentsUser,
|
|
||||||
aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetImagesContentUsedUncompressed(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mImagesContentUsedUncompressed,
|
|
||||||
aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetStorageSQLite(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mStorageSQLite, aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetLowMemoryEventsVirtual(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mLowMemoryEventsVirtual, aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetLowMemoryEventsPhysical(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mLowMemoryEventsPhysical, aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetGhostWindows(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
return GetInfallibleAmount(mAmountFns.mGhostWindows, aAmount);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsMemoryReporterManager::GetPageFaultsHard(int64_t* aAmount)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_PAGE_FAULT_REPORTERS
|
|
||||||
return PageFaultsHardDistinguishedAmount(aAmount);
|
|
||||||
#else
|
|
||||||
*aAmount = 0;
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::GetHasMozMallocUsableSize(bool* aHas)
|
nsMemoryReporterManager::GetHasMozMallocUsableSize(bool* aHas)
|
||||||
{
|
{
|
||||||
|
@ -1292,60 +1163,6 @@ NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter)
|
||||||
return mgr->UnregisterReporter(aReporter);
|
return mgr->UnregisterReporter(aReporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
// Macro for generating functions that register distinguished amount functions
|
|
||||||
// with the memory reporter manager.
|
|
||||||
#define DEFINE_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \
|
|
||||||
nsresult \
|
|
||||||
Register##name##DistinguishedAmount(kind##AmountFn aAmountFn) \
|
|
||||||
{ \
|
|
||||||
nsCOMPtr<nsIMemoryReporterManager> imgr = \
|
|
||||||
do_GetService("@mozilla.org/memory-reporter-manager;1"); \
|
|
||||||
nsRefPtr<nsMemoryReporterManager> mgr = \
|
|
||||||
static_cast<nsMemoryReporterManager*>(imgr.get()); \
|
|
||||||
if (!mgr) { \
|
|
||||||
return NS_ERROR_FAILURE; \
|
|
||||||
} \
|
|
||||||
mgr->mAmountFns.m##name = aAmountFn; \
|
|
||||||
return NS_OK; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT(name) \
|
|
||||||
nsresult \
|
|
||||||
Unregister##name##DistinguishedAmount() \
|
|
||||||
{ \
|
|
||||||
nsCOMPtr<nsIMemoryReporterManager> imgr = \
|
|
||||||
do_GetService("@mozilla.org/memory-reporter-manager;1"); \
|
|
||||||
nsRefPtr<nsMemoryReporterManager> mgr = \
|
|
||||||
static_cast<nsMemoryReporterManager*>(imgr.get()); \
|
|
||||||
if (!mgr) { \
|
|
||||||
return NS_ERROR_FAILURE; \
|
|
||||||
} \
|
|
||||||
mgr->mAmountFns.m##name = nullptr; \
|
|
||||||
return NS_OK; \
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeGCHeap)
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeTemporaryPeak)
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsSystem)
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, JSMainRuntimeCompartmentsUser)
|
|
||||||
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, ImagesContentUsedUncompressed)
|
|
||||||
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, StorageSQLite)
|
|
||||||
DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT(StorageSQLite)
|
|
||||||
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsVirtual)
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, LowMemoryEventsPhysical)
|
|
||||||
|
|
||||||
DEFINE_REGISTER_DISTINGUISHED_AMOUNT(Infallible, GhostWindows)
|
|
||||||
|
|
||||||
#undef DEFINE_REGISTER_DISTINGUISHED_AMOUNT
|
|
||||||
#undef DEFINE_UNREGISTER_DISTINGUISHED_AMOUNT
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(MOZ_DMD)
|
#if defined(MOZ_DMD)
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
|
@ -20,27 +20,8 @@ public:
|
||||||
nsMemoryReporterManager();
|
nsMemoryReporterManager();
|
||||||
virtual ~nsMemoryReporterManager();
|
virtual ~nsMemoryReporterManager();
|
||||||
|
|
||||||
// Functions that (a) implement distinguished amounts, and (b) are outside of
|
|
||||||
// this module.
|
|
||||||
struct AmountFns {
|
|
||||||
mozilla::InfallibleAmountFn mJSMainRuntimeGCHeap;
|
|
||||||
mozilla::InfallibleAmountFn mJSMainRuntimeTemporaryPeak;
|
|
||||||
mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsSystem;
|
|
||||||
mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsUser;
|
|
||||||
|
|
||||||
mozilla::InfallibleAmountFn mImagesContentUsedUncompressed;
|
|
||||||
|
|
||||||
mozilla::InfallibleAmountFn mStorageSQLite;
|
|
||||||
|
|
||||||
mozilla::InfallibleAmountFn mLowMemoryEventsVirtual;
|
|
||||||
mozilla::InfallibleAmountFn mLowMemoryEventsPhysical;
|
|
||||||
|
|
||||||
mozilla::InfallibleAmountFn mGhostWindows;
|
|
||||||
};
|
|
||||||
AmountFns mAmountFns;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsresult RegisterReporterHelper(nsIMemoryReporter *aReporter, bool aForce);
|
nsresult RegisterReporterHelper(nsIMemoryReporter *reporter, bool aForce);
|
||||||
|
|
||||||
nsTHashtable<nsISupportsHashKey> mReporters;
|
nsTHashtable<nsISupportsHashKey> mReporters;
|
||||||
Mutex mMutex;
|
Mutex mMutex;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче