mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 657327 - about:memory: merge the "mapped" and "heap used" trees, and make the resulting tree flatter. r=sdwilsh,Jesse, sr=roc.
This commit is contained in:
parent
1f12055bca
commit
e942f8f50a
@ -172,15 +172,16 @@ static PRInt64 GetCanvasMemoryUsed(void *) {
|
||||
return gCanvasMemoryUsed;
|
||||
}
|
||||
|
||||
// This isn't "heap-used/content/canvas/2d-pixel-bytes" because the pixels of a
|
||||
// canvas may not be stored on the heap. And if they are, they will be tracked
|
||||
// by the underlying surface implementations. See bug 655638 for details.
|
||||
// This is MR_OTHER because it's not always clear where in memory the pixels of
|
||||
// a canvas are stored. Furthermore, this memory will be tracked by the
|
||||
// underlying surface implementations. See bug 655638 for details.
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(CanvasMemory,
|
||||
"canvas-2d-pixel-bytes",
|
||||
"Memory used by 2D canvases. Each canvas "
|
||||
"requires (width * height * 4) bytes.",
|
||||
GetCanvasMemoryUsed,
|
||||
NULL)
|
||||
"canvas-2d-pixel-bytes",
|
||||
MR_OTHER,
|
||||
"Memory used by 2D canvases. Each canvas requires (width * height * 4) "
|
||||
"bytes.",
|
||||
GetCanvasMemoryUsed,
|
||||
NULL)
|
||||
|
||||
static void
|
||||
CopyContext(gfxContext* dest, gfxContext* src)
|
||||
|
@ -313,9 +313,11 @@ ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* chi
|
||||
r->GetNext(getter_AddRefs(report));
|
||||
|
||||
nsCString path;
|
||||
PRInt32 kind;
|
||||
nsCString desc;
|
||||
PRInt64 memoryUsed;
|
||||
report->GetPath(getter_Copies(path));
|
||||
report->GetKind(&kind);
|
||||
report->GetDescription(getter_Copies(desc));
|
||||
report->GetMemoryUsed(&memoryUsed);
|
||||
|
||||
@ -323,6 +325,7 @@ ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* chi
|
||||
MemoryReport memreport(nsPrintfCString(maxLength, "Content (%d)",
|
||||
getpid()),
|
||||
path,
|
||||
kind,
|
||||
desc,
|
||||
memoryUsed);
|
||||
|
||||
|
@ -692,11 +692,13 @@ ContentParent::SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& rep
|
||||
|
||||
nsCString prefix = report[i].prefix();
|
||||
nsCString path = report[i].path();
|
||||
PRInt32 kind = report[i].kind();
|
||||
nsCString desc = report[i].desc();
|
||||
PRInt64 memoryUsed = report[i].memoryUsed();
|
||||
|
||||
nsRefPtr<nsMemoryReporter> r = new nsMemoryReporter(prefix,
|
||||
path,
|
||||
kind,
|
||||
desc,
|
||||
memoryUsed);
|
||||
mMemoryReporters.AppendObject(r);
|
||||
|
@ -44,6 +44,7 @@ namespace dom {
|
||||
struct MemoryReport {
|
||||
nsCString prefix;
|
||||
nsCString path;
|
||||
PRInt32 kind;
|
||||
nsCString desc;
|
||||
PRInt64 memoryUsed;
|
||||
};
|
||||
|
@ -543,30 +543,30 @@ gfxASurface::MovePixels(const nsIntRect& aSourceRect,
|
||||
/** Memory reporting **/
|
||||
|
||||
static const char *sSurfaceNamesForSurfaceType[] = {
|
||||
"heap-used/gfx/surface/image",
|
||||
"heap-used/gfx/surface/pdf",
|
||||
"heap-used/gfx/surface/ps",
|
||||
"heap-used/gfx/surface/xlib",
|
||||
"heap-used/gfx/surface/xcb",
|
||||
"heap-used/gfx/surface/glitz",
|
||||
"heap-used/gfx/surface/quartz",
|
||||
"heap-used/gfx/surface/win32",
|
||||
"heap-used/gfx/surface/beos",
|
||||
"heap-used/gfx/surface/directfb",
|
||||
"heap-used/gfx/surface/svg",
|
||||
"heap-used/gfx/surface/os2",
|
||||
"heap-used/gfx/surface/win32printing",
|
||||
"heap-used/gfx/surface/quartzimage",
|
||||
"heap-used/gfx/surface/script",
|
||||
"heap-used/gfx/surface/qpainter",
|
||||
"heap-used/gfx/surface/recording",
|
||||
"heap-used/gfx/surface/vg",
|
||||
"heap-used/gfx/surface/gl",
|
||||
"heap-used/gfx/surface/drm",
|
||||
"heap-used/gfx/surface/tee",
|
||||
"heap-used/gfx/surface/xml",
|
||||
"heap-used/gfx/surface/skia",
|
||||
"heap-used/gfx/surface/d2d"
|
||||
"explicit/gfx/surface/image",
|
||||
"explicit/gfx/surface/pdf",
|
||||
"explicit/gfx/surface/ps",
|
||||
"explicit/gfx/surface/xlib",
|
||||
"explicit/gfx/surface/xcb",
|
||||
"explicit/gfx/surface/glitz",
|
||||
"explicit/gfx/surface/quartz",
|
||||
"explicit/gfx/surface/win32",
|
||||
"explicit/gfx/surface/beos",
|
||||
"explicit/gfx/surface/directfb",
|
||||
"explicit/gfx/surface/svg",
|
||||
"explicit/gfx/surface/os2",
|
||||
"explicit/gfx/surface/win32printing",
|
||||
"explicit/gfx/surface/quartzimage",
|
||||
"explicit/gfx/surface/script",
|
||||
"explicit/gfx/surface/qpainter",
|
||||
"explicit/gfx/surface/recording",
|
||||
"explicit/gfx/surface/vg",
|
||||
"explicit/gfx/surface/gl",
|
||||
"explicit/gfx/surface/drm",
|
||||
"explicit/gfx/surface/tee",
|
||||
"explicit/gfx/surface/xml",
|
||||
"explicit/gfx/surface/skia",
|
||||
"explicit/gfx/surface/d2d"
|
||||
};
|
||||
|
||||
PR_STATIC_ASSERT(NS_ARRAY_LENGTH(sSurfaceNamesForSurfaceType) == gfxASurface::SurfaceTypeMax);
|
||||
@ -580,7 +580,7 @@ SurfaceMemoryReporterPathForType(gfxASurface::gfxSurfaceType aType)
|
||||
{
|
||||
if (aType < 0 ||
|
||||
aType >= gfxASurface::SurfaceTypeMax)
|
||||
return "heap-used/gfx/surface/unknown";
|
||||
return "explicit/gfx/surface/unknown";
|
||||
|
||||
return sSurfaceNamesForSurfaceType[aType];
|
||||
}
|
||||
@ -604,8 +604,13 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetKind(PRInt32 *kind) {
|
||||
*kind = MR_HEAP;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetDescription(char **desc) {
|
||||
*desc = strdup("Memory used by gfx surface of given type.");
|
||||
*desc = strdup("Memory used by gfx surface of the given type.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,11 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetKind(PRInt32 *kind) {
|
||||
*kind = MR_OTHER;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetDescription(char **desc) {
|
||||
*desc = strdup("Memory used by the Direct2D internal surface cache.");
|
||||
return NS_OK;
|
||||
@ -127,6 +132,11 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetKind(PRInt32 *kind) {
|
||||
*kind = MR_OTHER;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetDescription(char **desc) {
|
||||
*desc = strdup("Video memory used by D2D surfaces");
|
||||
return NS_OK;
|
||||
|
@ -52,17 +52,18 @@ static PRInt64 GetShmemAllocated(void*) { return gShmemAllocated; }
|
||||
static PRInt64 GetShmemMapped(void*) { return gShmemMapped; }
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(ShmemAllocated,
|
||||
"shmem-allocated",
|
||||
"Memory shared with other processes that is "
|
||||
"accessible (but not necessarily mapped).",
|
||||
GetShmemAllocated,
|
||||
nsnull)
|
||||
"shmem-allocated",
|
||||
MR_OTHER,
|
||||
"Memory shared with other processes that is accessible (but not "
|
||||
"necessarily mapped).",
|
||||
GetShmemAllocated,
|
||||
nsnull)
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(ShmemMapped,
|
||||
"shmem-mapped",
|
||||
"Memory shared with other processes that is "
|
||||
"mapped into the address space.",
|
||||
GetShmemMapped,
|
||||
nsnull)
|
||||
"shmem-mapped",
|
||||
MR_OTHER,
|
||||
"Memory shared with other processes that is mapped into the address space.",
|
||||
GetShmemMapped,
|
||||
nsnull)
|
||||
|
||||
SharedMemory::SharedMemory()
|
||||
: mAllocSize(0)
|
||||
|
@ -1278,16 +1278,18 @@ protected:
|
||||
|
||||
static XPConnectGCChunkAllocator gXPCJSChunkAllocator;
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
|
||||
#ifdef MOZ_MEMORY
|
||||
"heap-used/js/gc-heap",
|
||||
#define JS_GC_HEAP_KIND MR_HEAP
|
||||
#else
|
||||
"mapped/js/gc-heap",
|
||||
#define JS_GC_HEAP_KIND MR_MAPPED
|
||||
#endif
|
||||
"Memory used by the garbage-collected JavaScript "
|
||||
"heap.",
|
||||
XPConnectGCChunkAllocator::GetGCChunkBytesInUse,
|
||||
&gXPCJSChunkAllocator)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
|
||||
"explicit/js/gc-heap",
|
||||
JS_GC_HEAP_KIND,
|
||||
"Memory used by the garbage-collected JavaScript heap.",
|
||||
XPConnectGCChunkAllocator::GetGCChunkBytesInUse,
|
||||
&gXPCJSChunkAllocator)
|
||||
|
||||
static PRInt64
|
||||
GetPerCompartmentSize(PRInt64 (*f)(JSCompartment *c))
|
||||
@ -1322,19 +1324,19 @@ GetJSMJitData(void *data)
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSMjitCode,
|
||||
"mapped/js/mjit-code",
|
||||
"Memory mapped by the method JIT to hold "
|
||||
"generated code.",
|
||||
GetJSMjitCode,
|
||||
NULL)
|
||||
"explicit/js/mjit-code",
|
||||
MR_MAPPED,
|
||||
"Memory used by the method JIT to hold generated code.",
|
||||
GetJSMjitCode,
|
||||
NULL)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSMjitData,
|
||||
"heap-used/js/mjit-data",
|
||||
"Memory allocated by the method JIT for the "
|
||||
"following data: JITScripts, native maps, and "
|
||||
"inline cache structs.",
|
||||
GetJSMJitData,
|
||||
NULL)
|
||||
"explicit/js/mjit-data",
|
||||
MR_HEAP,
|
||||
"Memory used by the method JIT for the following data: "
|
||||
"JITScripts, native maps, and inline cache structs.",
|
||||
GetJSMJitData,
|
||||
NULL)
|
||||
#endif // JS_METHODJIT
|
||||
|
||||
#ifdef JS_TRACER
|
||||
@ -1384,25 +1386,26 @@ GetJSTjitDataAllocatorsReserve(void *data)
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSTjitCode,
|
||||
"mapped/js/tjit-code",
|
||||
"Memory mapped by the trace JIT to hold "
|
||||
"generated code.",
|
||||
GetJSTjitCode,
|
||||
NULL)
|
||||
"explicit/js/tjit-code",
|
||||
MR_MAPPED,
|
||||
"Memory used by the trace JIT to hold generated code.",
|
||||
GetJSTjitCode,
|
||||
NULL)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSTjitDataAllocatorsMain,
|
||||
"heap-used/js/tjit-data/allocators/main",
|
||||
"Memory allocated by the trace JIT's "
|
||||
"VMAllocators.",
|
||||
GetJSTjitDataAllocatorsMain,
|
||||
NULL)
|
||||
"explicit/js/tjit-data/allocators-main",
|
||||
MR_HEAP,
|
||||
"Memory used by the trace JIT's VMAllocators.",
|
||||
GetJSTjitDataAllocatorsMain,
|
||||
NULL)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSTjitDataAllocatorsReserve,
|
||||
"heap-used/js/tjit-data/allocators/reserve",
|
||||
"Memory allocated by the trace JIT and held in "
|
||||
"reserve for VMAllocators in case of OOM.",
|
||||
GetJSTjitDataAllocatorsReserve,
|
||||
NULL)
|
||||
"explicit/js/tjit-data/allocators-reserve",
|
||||
MR_HEAP,
|
||||
"Memory used by the trace JIT and held in reserve for VMAllocators "
|
||||
"in case of OOM.",
|
||||
GetJSTjitDataAllocatorsReserve,
|
||||
NULL)
|
||||
#endif // JS_TRACER
|
||||
|
||||
XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
||||
|
@ -1676,17 +1676,18 @@ NS_NewPresShell(nsIPresShell** aInstancePtrResult)
|
||||
nsTHashtable<PresShell::PresShellPtrKey> *nsIPresShell::sLiveShells = 0;
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresShell,
|
||||
"heap-used/layout/all",
|
||||
"Memory used by layout PresShell, PresContext, "
|
||||
"and other related areas.",
|
||||
PresShell::SizeOfLayoutMemoryReporter,
|
||||
nsnull)
|
||||
"explicit/layout/all",
|
||||
MR_HEAP,
|
||||
"Memory used by layout PresShell, PresContext, and other related areas.",
|
||||
PresShell::SizeOfLayoutMemoryReporter,
|
||||
nsnull)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(LayoutBidi,
|
||||
"heap-used/layout/bidi",
|
||||
"Memory used by layout Bidi processor.",
|
||||
PresShell::SizeOfBidiMemoryReporter,
|
||||
nsnull)
|
||||
"explicit/layout/bidi",
|
||||
MR_HEAP,
|
||||
"Memory used by layout Bidi processor.",
|
||||
PresShell::SizeOfBidiMemoryReporter,
|
||||
nsnull)
|
||||
|
||||
PresShell::PresShell()
|
||||
: mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
|
||||
|
@ -160,25 +160,31 @@ public:
|
||||
NS_IMETHOD GetPath(char **memoryPath)
|
||||
{
|
||||
if (mType == ChromeUsedRaw) {
|
||||
*memoryPath = strdup("heap-used/images/chrome/used/raw");
|
||||
*memoryPath = strdup("explicit/images/chrome/used/raw");
|
||||
} else if (mType == ChromeUsedUncompressed) {
|
||||
*memoryPath = strdup("heap-used/images/chrome/used/uncompressed");
|
||||
*memoryPath = strdup("explicit/images/chrome/used/uncompressed");
|
||||
} else if (mType == ChromeUnusedRaw) {
|
||||
*memoryPath = strdup("heap-used/images/chrome/unused/raw");
|
||||
*memoryPath = strdup("explicit/images/chrome/unused/raw");
|
||||
} else if (mType == ChromeUnusedUncompressed) {
|
||||
*memoryPath = strdup("heap-used/images/chrome/unused/uncompressed");
|
||||
*memoryPath = strdup("explicit/images/chrome/unused/uncompressed");
|
||||
} else if (mType == ContentUsedRaw) {
|
||||
*memoryPath = strdup("heap-used/images/content/used/raw");
|
||||
*memoryPath = strdup("explicit/images/content/used/raw");
|
||||
} else if (mType == ContentUsedUncompressed) {
|
||||
*memoryPath = strdup("heap-used/images/content/used/uncompressed");
|
||||
*memoryPath = strdup("explicit/images/content/used/uncompressed");
|
||||
} else if (mType == ContentUnusedRaw) {
|
||||
*memoryPath = strdup("heap-used/images/content/unused/raw");
|
||||
*memoryPath = strdup("explicit/images/content/unused/raw");
|
||||
} else if (mType == ContentUnusedUncompressed) {
|
||||
*memoryPath = strdup("heap-used/images/content/unused/uncompressed");
|
||||
*memoryPath = strdup("explicit/images/content/unused/uncompressed");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetKind(PRInt32 *kind)
|
||||
{
|
||||
*kind = MR_HEAP;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetDescription(char **desc)
|
||||
{
|
||||
if (mType == ChromeUsedRaw) {
|
||||
|
@ -353,7 +353,7 @@ public:
|
||||
{
|
||||
nsCString path;
|
||||
|
||||
path.AppendLiteral("heap-used/storage/sqlite/");
|
||||
path.AppendLiteral("explicit/storage/sqlite/");
|
||||
path.Append(mDBConn.getFilename());
|
||||
|
||||
if (mType == LookAside_Used) {
|
||||
@ -373,6 +373,12 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetKind(PRInt32 *kind)
|
||||
{
|
||||
*kind = MR_HEAP;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetDescription(char **desc)
|
||||
{
|
||||
if (mType == LookAside_Used) {
|
||||
@ -382,7 +388,8 @@ public:
|
||||
*desc = ::strdup("Memory (approximate) used by all pager caches.");
|
||||
}
|
||||
else if (mType == Schema_Used) {
|
||||
*desc = ::strdup("Memory (approximate) used to store the schema for all databases associated with the connection");
|
||||
*desc = ::strdup("Memory (approximate) used to store the schema "
|
||||
"for all databases associated with the connection");
|
||||
}
|
||||
else if (mType == Stmt_Used) {
|
||||
*desc = ::strdup("Memory (approximate) used by all prepared statements");
|
||||
|
@ -139,10 +139,11 @@ GetStorageSQLiteMemoryUsed(void *)
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(StorageSQLiteMemoryUsed,
|
||||
"heap-used/storage/sqlite",
|
||||
"Memory used by SQLite.",
|
||||
GetStorageSQLiteMemoryUsed,
|
||||
nsnull)
|
||||
"explicit/storage/sqlite",
|
||||
MR_HEAP,
|
||||
"Memory used by SQLite.",
|
||||
GetStorageSQLiteMemoryUsed,
|
||||
nsnull)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Helpers
|
||||
|
@ -48,6 +48,11 @@
|
||||
color: #004;
|
||||
}
|
||||
|
||||
.mrStar {
|
||||
font-style: italic;
|
||||
color: #604;
|
||||
}
|
||||
|
||||
.treeLine {
|
||||
color: #888;
|
||||
}
|
||||
|
@ -48,6 +48,12 @@ var gVerbose = (location.href.split(/[\?,]/).indexOf("verbose") !== -1);
|
||||
|
||||
var gAddedObserver = false;
|
||||
|
||||
const MR_MAPPED = Ci.nsIMemoryReporter.MR_MAPPED;
|
||||
const MR_HEAP = Ci.nsIMemoryReporter.MR_HEAP;
|
||||
const MR_OTHER = Ci.nsIMemoryReporter.MR_OTHER;
|
||||
|
||||
const kUnknown = -1; // used for _memoryUsed if a memory reporter failed
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
@ -145,8 +151,9 @@ function update()
|
||||
//
|
||||
// interface Tmr {
|
||||
// _tpath: string;
|
||||
// _kind: number;
|
||||
// _description: string;
|
||||
// _memoryUsed: number;
|
||||
// _memoryUsed: number;
|
||||
// }
|
||||
//
|
||||
// - The .path property is renamed ._tpath ("truncated path") in the copy
|
||||
@ -170,6 +177,7 @@ function update()
|
||||
process = mr.path.slice(0, i);
|
||||
tmr._tpath = mr.path.slice(i + 1);
|
||||
}
|
||||
tmr._kind = mr.kind;
|
||||
tmr._description = mr.description;
|
||||
tmr._memoryUsed = mr.memoryUsed;
|
||||
|
||||
@ -201,10 +209,11 @@ function update()
|
||||
const CCDesc = "Do a global garbage collection followed by a cycle " +
|
||||
"collection. (It currently is not possible to do a cycle " +
|
||||
"collection on its own, see bug 625302.)";
|
||||
const MPDesc = "Send three \"heap-minimize\" notifications in a row. Each " +
|
||||
"notification triggers a global garbage collection followed " +
|
||||
"by a cycle collection, and causes the process to reduce " +
|
||||
"memory usage in other ways, e.g. by flushing various caches.";
|
||||
const MPDesc = "Send three \"heap-minimize\" notifications in a " +
|
||||
"row. Each notification triggers a global garbage " +
|
||||
"collection followed by a cycle collection, and causes the " +
|
||||
"process to reduce memory usage in other ways, e.g. by " +
|
||||
"flushing various caches.";
|
||||
|
||||
text += "<div>" +
|
||||
"<button title='" + GCDesc + "' onclick='doGlobalGC()'>GC</button>" +
|
||||
@ -222,6 +231,11 @@ function update()
|
||||
content.appendChild(div);
|
||||
}
|
||||
|
||||
function cmpTmrs(a, b)
|
||||
{
|
||||
return b._memoryUsed - a._memoryUsed
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates the text for a single process.
|
||||
*
|
||||
@ -233,35 +247,26 @@ function update()
|
||||
*/
|
||||
function genProcessText(aProcess, aTmrs)
|
||||
{
|
||||
// First, duplicate the "mapped/heap/used" reporter as "heap-used"; this
|
||||
// value shows up in both the "mapped" and the "heap-used" trees.
|
||||
var mappedHeapUsedTmr = aTmrs["mapped/heap/used"];
|
||||
aTmrs["heap-used"] = {
|
||||
_tpath: "heap-used",
|
||||
_description: mappedHeapUsedTmr._description,
|
||||
_memoryUsed: mappedHeapUsedTmr._memoryUsed
|
||||
};
|
||||
|
||||
/**
|
||||
* From a list of memory reporters, builds a tree that mirrors the tree
|
||||
* structure that will be shown as output.
|
||||
*
|
||||
* @param aTreeName
|
||||
* The name of the tree; either "mapped" or "heap-used"
|
||||
* @param aOmitThresholdPerc
|
||||
* The threshold percentage; entries that account for less than
|
||||
* this fraction are aggregated
|
||||
* @return The built tree. The tree nodes have this structure:
|
||||
* interface Node {
|
||||
* _name: string;
|
||||
* _kind: number;
|
||||
* _description: string;
|
||||
* _memoryUsed: number;
|
||||
* _kids: [Node];
|
||||
* _hasReporter: boolean; (might not be defined)
|
||||
* _memoryUsed: number; (non-negative or 'kUnknown')
|
||||
* _kids: [Node];
|
||||
* _hasReporter: boolean; (only defined if 'true')
|
||||
* _hasProblem: boolean; (only defined if 'true')
|
||||
* }
|
||||
*/
|
||||
function buildTree(aTreeName, aOmitThresholdPerc)
|
||||
function buildTree()
|
||||
{
|
||||
const treeName = "explicit";
|
||||
const omitThresholdPerc = 0.5; /* percent */
|
||||
|
||||
function findKid(aName, aKids)
|
||||
{
|
||||
for (var i = 0; i < aKids.length; i++) {
|
||||
@ -272,13 +277,17 @@ function genProcessText(aProcess, aTmrs)
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// We want to process all reporters that begin with 'aTreeName'.
|
||||
// First we build the tree but only filling in '_name', '_kids' and
|
||||
// maybe '._hasReporter'. This is done top-down from the reporters.
|
||||
var t = { _name: "falseRoot", _kids: [] };
|
||||
// We want to process all reporters that begin with 'treeName'.
|
||||
// First we build the tree but only filling in '_name', '_kind', '_kids'
|
||||
// and maybe '._hasReporter'. This is done top-down from the reporters.
|
||||
var t = {
|
||||
_name: "falseRoot",
|
||||
_kind: MR_OTHER,
|
||||
_kids: []
|
||||
};
|
||||
for (var tpath in aTmrs) {
|
||||
var tmr = aTmrs[tpath];
|
||||
if (tmr._tpath.slice(0, aTreeName.length) === aTreeName) {
|
||||
if (tmr._tpath.slice(0, treeName.length) === treeName) {
|
||||
var names = tmr._tpath.split('/');
|
||||
var u = t;
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
@ -287,66 +296,126 @@ function genProcessText(aProcess, aTmrs)
|
||||
if (uMatch) {
|
||||
u = uMatch;
|
||||
} else {
|
||||
var v = { _name: name, _kids: [] };
|
||||
var v = {
|
||||
_name: name,
|
||||
_kind: MR_OTHER,
|
||||
_kids: []
|
||||
};
|
||||
u._kids.push(v);
|
||||
u = v;
|
||||
}
|
||||
}
|
||||
u._kind = tmr._kind;
|
||||
u._hasReporter = true;
|
||||
}
|
||||
}
|
||||
// Using falseRoot makes the above code simpler. Now discard it, leaving
|
||||
// aTreeName at the root.
|
||||
// treeName at the root.
|
||||
t = t._kids[0];
|
||||
|
||||
// Next, fill in '_description' and '_memoryUsed' for each node. This is
|
||||
// done bottom-up because for most non-leaf nodes '_memoryUsed' and
|
||||
// '_description' are determined from the child nodes.
|
||||
// Next, fill in '_description' and '_memoryUsed', and maybe '_hasProblem'
|
||||
// for each node. This is done bottom-up because for most non-leaf nodes
|
||||
// '_memoryUsed' and '_description' are determined from the child nodes.
|
||||
function fillInTree(aT, aPretpath)
|
||||
{
|
||||
var tpath = aPretpath ? aPretpath + '/' + aT._name : aT._name;
|
||||
if (aT._kids.length === 0) {
|
||||
// Leaf node. Must have a reporter.
|
||||
aT._memoryUsed = getBytes(aTmrs, tpath);
|
||||
aT._description = getDescription(aTmrs, tpath);
|
||||
var memoryUsed = getBytes(aTmrs, tpath);
|
||||
if (memoryUsed !== kUnknown) {
|
||||
aT._memoryUsed = memoryUsed;
|
||||
} else {
|
||||
aT._memoryUsed = 0;
|
||||
aT._hasProblem = true;
|
||||
}
|
||||
} else {
|
||||
// Non-leaf node. Get the size of the children.
|
||||
var childrenBytes = 0;
|
||||
for (var i = 0; i < aT._kids.length; i++) {
|
||||
// Allow for -1 (ie. "unknown"), treat it like 0.
|
||||
// Allow for kUnknown, treat it like 0.
|
||||
var b = fillInTree(aT._kids[i], tpath);
|
||||
childrenBytes += (b === -1 ? 0 : b);
|
||||
childrenBytes += (b === kUnknown ? 0 : b);
|
||||
}
|
||||
if (aT._hasReporter === true) {
|
||||
// Non-leaf node with its own reporter. Use the reporter and add an
|
||||
// "other" child node (unless the byte count is -1, ie. unknown).
|
||||
aT._memoryUsed = getBytes(aTmrs, tpath);
|
||||
aT._description = getDescription(aTmrs, tpath);
|
||||
if (aT._memoryUsed !== -1) {
|
||||
var memoryUsed = getBytes(aTmrs, tpath);
|
||||
if (memoryUsed !== kUnknown) {
|
||||
// Non-leaf node with its own reporter. Use the reporter and add
|
||||
// an "other" child node.
|
||||
aT._memoryUsed = memoryUsed;
|
||||
var other = {
|
||||
_name: "other",
|
||||
_kind: MR_OTHER,
|
||||
_description: "All unclassified " + aT._name + " memory.",
|
||||
_memoryUsed: aT._memoryUsed - childrenBytes,
|
||||
_kids: []
|
||||
};
|
||||
aT._kids.push(other);
|
||||
} else {
|
||||
// Non-leaf node with a reporter that returns kUnknown.
|
||||
// Use the sum of the children and mark it as problematic.
|
||||
aT._memoryUsed = childrenBytes;
|
||||
aT._hasProblem = true;
|
||||
}
|
||||
} else {
|
||||
// Non-leaf node without its own reporter. Derive its size and
|
||||
// description entirely from its children.
|
||||
aT._memoryUsed = childrenBytes;
|
||||
aT._description = "The sum of all entries below " + aT._name + ".";
|
||||
aT._description = "The sum of all entries below '" + aT._name + "'.";
|
||||
}
|
||||
}
|
||||
return aT._memoryUsed;
|
||||
}
|
||||
fillInTree(t, "");
|
||||
|
||||
// Determine how many bytes are reported by heap reporters. Be careful
|
||||
// with non-leaf reporters; if we count a non-leaf reporter we don't want
|
||||
// to count any of its child reporters.
|
||||
var s = "";
|
||||
function getKnownHeapUsedBytes(aT)
|
||||
{
|
||||
if (aT._kind === MR_HEAP) {
|
||||
return aT._memoryUsed;
|
||||
} else {
|
||||
var n = 0;
|
||||
for (var i = 0; i < aT._kids.length; i++) {
|
||||
n += getKnownHeapUsedBytes(aT._kids[i]);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
// A special case: compute the derived "heap-unclassified" value. Don't
|
||||
// mark "heap-used" when we get its size because we want it to appear in
|
||||
// the "Other Measurements" list.
|
||||
var heapUsedBytes = getBytes(aTmrs, "heap-used", true);
|
||||
var unknownHeapUsedBytes = 0;
|
||||
var hasProblem = true;
|
||||
if (heapUsedBytes !== kUnknown) {
|
||||
unknownHeapUsedBytes = heapUsedBytes - getKnownHeapUsedBytes(t);
|
||||
hasProblem = false;
|
||||
}
|
||||
var heapUnclassified = {
|
||||
_name: "heap-unclassified",
|
||||
_kind: MR_HEAP,
|
||||
_description:
|
||||
"Memory not classified by a more specific reporter. This includes " +
|
||||
"memory allocated by the heap allocator in excess of that requested " +
|
||||
"by the application; this can happen when the heap allocator rounds " +
|
||||
"up request sizes.",
|
||||
_memoryUsed: unknownHeapUsedBytes,
|
||||
_hasProblem: hasProblem,
|
||||
_kids: []
|
||||
}
|
||||
t._kids.push(heapUnclassified);
|
||||
t._memoryUsed += unknownHeapUsedBytes;
|
||||
|
||||
function shouldOmit(aBytes)
|
||||
{
|
||||
return !gVerbose &&
|
||||
t._memoryUsed !== -1 &&
|
||||
(100 * aBytes / t._memoryUsed) < aOmitThresholdPerc;
|
||||
t._memoryUsed !== kUnknown &&
|
||||
(100 * aBytes / t._memoryUsed) < omitThresholdPerc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -358,7 +427,6 @@ function genProcessText(aProcess, aTmrs)
|
||||
*/
|
||||
function filterTree(aT)
|
||||
{
|
||||
var cmpTmrs = function(a, b) { return b._memoryUsed - a._memoryUsed };
|
||||
aT._kids.sort(cmpTmrs);
|
||||
|
||||
for (var i = 0; i < aT._kids.length; i++) {
|
||||
@ -377,6 +445,7 @@ function genProcessText(aProcess, aTmrs)
|
||||
var n = i - i0;
|
||||
var tmrSub = {
|
||||
_name: "(" + n + " omitted)",
|
||||
_kind: MR_OTHER,
|
||||
_description: "Omitted sub-trees: " + aggNames.join(", ") + ".",
|
||||
_memoryUsed: aggBytes,
|
||||
_kids: []
|
||||
@ -392,17 +461,10 @@ function genProcessText(aProcess, aTmrs)
|
||||
return t;
|
||||
}
|
||||
|
||||
// The threshold used for the "mapped" tree is lower than the one for the
|
||||
// "heap-used" tree, because the "mapped" total size is dominated (especially
|
||||
// on Mac) by memory usage that isn't covered by more specific reporters.
|
||||
var mappedTree = buildTree("mapped", 0.01);
|
||||
var heapUsedTree = buildTree("heap-used", 0.1);
|
||||
|
||||
// Nb: the newlines give nice spacing if we cut+paste into a text buffer.
|
||||
var text = "";
|
||||
text += "<h1>" + aProcess + " Process</h1>\n\n";
|
||||
text += genTreeText(mappedTree, "Mapped Memory");
|
||||
text += genTreeText(heapUsedTree, "Used Heap Memory");
|
||||
text += genTreeText(buildTree());
|
||||
text += genOtherText(aTmrs);
|
||||
text += "<hr></hr>";
|
||||
return text;
|
||||
@ -419,10 +481,6 @@ function formatBytes(aBytes)
|
||||
{
|
||||
var unit = gVerbose ? "B" : "MB";
|
||||
|
||||
if (aBytes === -1) {
|
||||
return "??? " + unit;
|
||||
}
|
||||
|
||||
function formatInt(aN)
|
||||
{
|
||||
var neg = false;
|
||||
@ -483,26 +541,30 @@ function pad(aS, aN, aC)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the byte count for a particular memory reporter.
|
||||
* Gets the byte count for a particular memory reporter and sets its _done
|
||||
* property.
|
||||
*
|
||||
* @param aTmrs
|
||||
* Table of Tmrs for this process
|
||||
* @param aTpath
|
||||
* The tpath of the memory reporter
|
||||
* @param aDoNotMark
|
||||
* If set, the _done property is not set.
|
||||
* @return The byte count
|
||||
*/
|
||||
function getBytes(aTmrs, aTpath)
|
||||
function getBytes(aTmrs, aTpath, aDoNotMark)
|
||||
{
|
||||
var tmr = aTmrs[aTpath];
|
||||
if (tmr) {
|
||||
var bytes = tmr._memoryUsed;
|
||||
tmr.done = true;
|
||||
if (!aDoNotMark) {
|
||||
tmr._done = true;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
// Nb: this should never occur; "mapped" and "mapped/heap/used" should
|
||||
// always be registered, and all other tpaths have been extracted from
|
||||
// aTmrs and so the lookup will succeed. Return an obviously wrong
|
||||
// number that will likely be noticed.
|
||||
// Nb: this should never occur; all tpaths have been extracted from aTmrs and
|
||||
// so the lookup will succeed. Return an obviously wrong number that will
|
||||
// likely be noticed.
|
||||
return -2 * 1024 * 1024;
|
||||
}
|
||||
|
||||
@ -526,22 +588,44 @@ function genMrValueText(aValue)
|
||||
return "<span class='mrValue'>" + aValue + "</span>";
|
||||
}
|
||||
|
||||
function genMrNameText(aDesc, aName)
|
||||
function kindToString(aKind)
|
||||
{
|
||||
return "-- <span class='mrName' title=\"" + aDesc + "\">" +
|
||||
aName + "</span>\n";
|
||||
switch (aKind) {
|
||||
case MR_MAPPED: return "(Mapped) ";
|
||||
case MR_HEAP: return "(Heap) ";
|
||||
case MR_OTHER: return "";
|
||||
default: return "(???) ";
|
||||
}
|
||||
}
|
||||
|
||||
function escapeQuotes(aStr)
|
||||
{
|
||||
return aStr.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function genMrNameText(aKind, aDesc, aName, aHasProblem)
|
||||
{
|
||||
const problemDesc =
|
||||
"Warning: this memory reporter was unable to compute a useful value. " +
|
||||
"The reported value is the sum of all entries below '" + aName + "', " +
|
||||
"which is probably less than the true value.";
|
||||
var text = "-- <span class='mrName' title='" +
|
||||
kindToString(aKind) + escapeQuotes(aDesc) +
|
||||
"'>" + aName + "</span>";
|
||||
text += aHasProblem
|
||||
? " <span class='mrStar' title=\"" + problemDesc + "\">[*]</span>\n"
|
||||
: "\n";
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the text for a particular tree, including its heading.
|
||||
* Generates the text for the tree, including its heading.
|
||||
*
|
||||
* @param aT
|
||||
* The tree
|
||||
* @param aTreeName
|
||||
* The tree's name
|
||||
* @return The generated text
|
||||
*/
|
||||
function genTreeText(aT, aTreeName)
|
||||
function genTreeText(aT)
|
||||
{
|
||||
var treeBytes = aT._memoryUsed;
|
||||
var treeBytesLength = formatBytes(treeBytes).length;
|
||||
@ -605,20 +689,17 @@ function genTreeText(aT, aTreeName)
|
||||
|
||||
// Generate the percentage.
|
||||
var perc = "";
|
||||
if (treeBytes !== -1) {
|
||||
if (aT._memoryUsed === -1) {
|
||||
perc = "??.??";
|
||||
} else if (aT._memoryUsed === treeBytes) {
|
||||
perc = "100.0";
|
||||
} else {
|
||||
perc = (100 * aT._memoryUsed / treeBytes).toFixed(2);
|
||||
perc = pad(perc, 5, '0');
|
||||
}
|
||||
perc = "<span class='mrPerc'>(" + perc + "%)</span> ";
|
||||
if (aT._memoryUsed === treeBytes) {
|
||||
perc = "100.0";
|
||||
} else {
|
||||
perc = (100 * aT._memoryUsed / treeBytes).toFixed(2);
|
||||
perc = pad(perc, 5, '0');
|
||||
}
|
||||
perc = "<span class='mrPerc'>(" + perc + "%)</span> ";
|
||||
|
||||
var text = indent + genMrValueText(tMemoryUsedStr) + " " + perc +
|
||||
genMrNameText(aT._description, aT._name);
|
||||
genMrNameText(aT._kind, aT._description, aT._name,
|
||||
aT._hasProblem);
|
||||
|
||||
for (var i = 0; i < aT._kids.length; i++) {
|
||||
// 3 is the standard depth, the callee adjusts it if necessary.
|
||||
@ -631,7 +712,21 @@ function genTreeText(aT, aTreeName)
|
||||
|
||||
var text = genTreeText2(aT, [], treeBytesLength);
|
||||
// Nb: the newlines give nice spacing if we cut+paste into a text buffer.
|
||||
return "<h2>" + aTreeName + "</h2>\n<pre>" + text + "</pre>\n";
|
||||
const desc =
|
||||
"This tree covers explicit memory allocations by the application, " +
|
||||
"both at the operating system level (via calls to functions such as " +
|
||||
"VirtualAlloc, vm_allocate, and mmap), and at the heap allocation level " +
|
||||
"(via functions such as malloc, calloc, realloc, memalign, operator " +
|
||||
"new, and operator new[]). It excludes memory that is mapped implicitly " +
|
||||
"such as code and data segments, and thread stacks. It also excludes " +
|
||||
"heap memory that has been freed by the application but is still being " +
|
||||
"held onto by the heap allocator. It is not guaranteed to cover every " +
|
||||
"explicit allocation, but it does cover most (including the entire " +
|
||||
"heap), and therefore it is the single best number to focus on when " +
|
||||
"trying to reduce memory usage.";
|
||||
|
||||
return "<h2 title='" + escapeQuotes(desc) +
|
||||
"'>Explicit Allocations</h2>\n" + "<pre>" + text + "</pre>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -643,30 +738,48 @@ function genTreeText(aT, aTreeName)
|
||||
*/
|
||||
function genOtherText(aTmrs)
|
||||
{
|
||||
// Get the biggest not-yet-printed value, to determine the field width
|
||||
// for all these entries. These should all be "other" values, assuming
|
||||
// all paths are well-formed.
|
||||
var maxBytes = 0;
|
||||
// Generate an array of tmr-like elements, stripping out all the tmrs that
|
||||
// have already been handled. Also find the width of the widest element, so
|
||||
// we can format things nicely.
|
||||
var maxBytesLength = 0;
|
||||
var tmrArray = [];
|
||||
for (var tpath in aTmrs) {
|
||||
var tmr = aTmrs[tpath];
|
||||
if (!tmr.done && tmr._memoryUsed > maxBytes) {
|
||||
maxBytes = tmr._memoryUsed;
|
||||
if (!tmr._done) {
|
||||
var hasProblem = false;
|
||||
if (tmr._memoryUsed === kUnknown) {
|
||||
hasProblem = true;
|
||||
}
|
||||
var elem = {
|
||||
_tpath: tmr._tpath,
|
||||
_kind: tmr._kind,
|
||||
_description: tmr._description,
|
||||
_memoryUsed: hasProblem ? 0 : tmr._memoryUsed,
|
||||
_hasProblem: hasProblem
|
||||
};
|
||||
tmrArray.push(elem);
|
||||
var thisBytesLength = formatBytes(elem._memoryUsed).length;
|
||||
if (thisBytesLength > maxBytesLength) {
|
||||
maxBytesLength = thisBytesLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
tmrArray.sort(cmpTmrs);
|
||||
|
||||
// Generate text for the not-yet-yet-printed values.
|
||||
var maxBytesLength = formatBytes(maxBytes).length;
|
||||
// Generate text for the not-yet-printed values.
|
||||
var text = "";
|
||||
for (var tpath in aTmrs) {
|
||||
var tmr = aTmrs[tpath];
|
||||
if (!tmr.done) {
|
||||
text += genMrValueText(
|
||||
pad(formatBytes(tmr._memoryUsed), maxBytesLength, ' ')) + " ";
|
||||
text += genMrNameText(tmr._description, tmr._tpath);
|
||||
}
|
||||
for (var i = 0; i < tmrArray.length; i++) {
|
||||
var elem = tmrArray[i];
|
||||
text += genMrValueText(
|
||||
pad(formatBytes(elem._memoryUsed), maxBytesLength, ' ')) + " ";
|
||||
text += genMrNameText(elem._kind, elem._description, elem._tpath,
|
||||
elem._hasProblem);
|
||||
}
|
||||
|
||||
// Nb: the newlines give nice spacing if we cut+paste into a text buffer.
|
||||
return "<h2>Other Measurements</h2>\n<pre>" + text + "</pre>\n";
|
||||
const desc = "This list contains other memory measurements that cross-cut " +
|
||||
"the requested memory measurements above."
|
||||
return "<h2 title='" + desc + "'>Other Measurements</h2>\n" +
|
||||
"<pre>" + text + "</pre>\n";
|
||||
}
|
||||
|
||||
|
@ -30,41 +30,49 @@
|
||||
// Setup various fake-but-deterministic reporters.
|
||||
const KB = 1024;
|
||||
const MB = KB * KB;
|
||||
const kUnknown = -1;
|
||||
const MAPPED = Ci.nsIMemoryReporter.MR_MAPPED;
|
||||
const HEAP = Ci.nsIMemoryReporter.MR_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.MR_OTHER;
|
||||
|
||||
fakeReporters = [
|
||||
{ path: "mapped", memoryUsed: 1000 * MB },
|
||||
{ path: "mapped/heap/used", memoryUsed: 500 * MB },
|
||||
{ path: "mapped/heap/unused", memoryUsed: 100 * MB },
|
||||
{ path: "mapped/a", memoryUsed: 222 * MB },
|
||||
{ path: "heap-used/a", memoryUsed: 99 * MB },
|
||||
{ path: "heap-used/b/a", memoryUsed: 80 * MB },
|
||||
{ path: "heap-used/b/b", memoryUsed: 75 * MB },
|
||||
{ path: "heap-used/b/c/a", memoryUsed: 44 * MB },
|
||||
{ path: "heap-used/b/c/b", memoryUsed: 33 * MB }, // aggregated
|
||||
{ path: "heap-used/c", memoryUsed: 123 * MB },
|
||||
{ path: "heap-used/d", memoryUsed: 499 * KB }, // aggregated
|
||||
{ path: "heap-used/e", memoryUsed: 100 * KB }, // aggregated
|
||||
{ path: "heap-used/f/g/h/i", memoryUsed: 20 * MB },
|
||||
{ path: "heap-used/g", memoryUsed: 15 * MB }, // internal
|
||||
{ path: "heap-used/g/a", memoryUsed: 6 * MB },
|
||||
{ path: "heap-used/g/b", memoryUsed: 5 * MB },
|
||||
{ path: "other1", memoryUsed: 111 * MB },
|
||||
{ path: "other2", memoryUsed: 222 * MB },
|
||||
{ path: "heap-used", kind: OTHER, memoryUsed: 500 * MB },
|
||||
{ path: "heap-unused", kind: OTHER, memoryUsed: 100 * MB },
|
||||
{ path: "explicit/a", kind: HEAP, memoryUsed: 222 * MB },
|
||||
{ path: "explicit/b/a", kind: HEAP, memoryUsed: 85 * MB },
|
||||
{ path: "explicit/b/b", kind: HEAP, memoryUsed: 75 * MB },
|
||||
{ path: "explicit/b/c/a", kind: HEAP, memoryUsed: 70 * MB },
|
||||
{ path: "explicit/b/c/b", kind: HEAP, memoryUsed: 2 * MB }, // omitted
|
||||
{ path: "explicit/c", kind: MAPPED,memoryUsed: 123 * MB },
|
||||
{ path: "explicit/d", kind: MAPPED,memoryUsed: 499 * KB }, // omitted
|
||||
{ path: "explicit/e", kind: MAPPED,memoryUsed: 100 * KB }, // omitted
|
||||
{ path: "explicit/f/g/h/i", kind: HEAP, memoryUsed: 20 * MB },
|
||||
{ path: "explicit/g", kind: HEAP, memoryUsed: 14 * MB }, // internal
|
||||
{ path: "explicit/g", kind: HEAP, memoryUsed: 1 * MB }, // internal, dup: merge
|
||||
{ path: "explicit/g/a", kind: HEAP, memoryUsed: 6 * MB },
|
||||
{ path: "explicit/g/b", kind: HEAP, memoryUsed: 5 * MB },
|
||||
{ path: "other1", kind: OTHER, memoryUsed: 111 * MB },
|
||||
{ path: "other2", kind: OTHER, memoryUsed: 222 * MB },
|
||||
|
||||
{ path: "2nd:mapped", memoryUsed: 1000 * MB },
|
||||
{ path: "2nd:mapped/heap/used", memoryUsed: 500 * MB },
|
||||
{ path: "2nd:mapped/a/b/c", memoryUsed: 499 * MB },
|
||||
{ path: "2nd:heap-used/a", memoryUsed: 400 * MB },
|
||||
{ path: "2nd:other1", memoryUsed: 777 * MB },
|
||||
{ path: "2nd:heap-used", kind: OTHER, memoryUsed: 1000 * MB },
|
||||
{ path: "2nd:heap-unused", kind: OTHER, memoryUsed: 100 * MB },
|
||||
{ path: "2nd:explicit/a/b/c",kind: HEAP, memoryUsed: 498 * MB },
|
||||
{ path: "2nd:explicit/a/b/c",kind: HEAP, memoryUsed: 1 * MB }, // dup: merge
|
||||
{ path: "2nd:explicit/b", kind: HEAP, memoryUsed: 400 * MB },
|
||||
{ path: "2nd:other1", kind: OTHER, memoryUsed: 777 * MB },
|
||||
|
||||
// -1 means "don't know"; this should be handled gracefully for
|
||||
// "mapped" and "mapped/heap/used".
|
||||
{ path: "3rd:mapped", memoryUsed: -1 },
|
||||
{ path: "3rd:mapped/heap/used", memoryUsed: -1 },
|
||||
{ path: "3rd:mapped/a/b", memoryUsed: 333 * MB },
|
||||
{ path: "3rd:heap-used/a/b", memoryUsed: 444 * MB },
|
||||
{ path: "3rd:other1", memoryUsed: 555 * MB }
|
||||
// kUnknown should be handled gracefully for "heap-used", non-leaf
|
||||
// reporters, leaf-reporters, and "other" reporters.
|
||||
{ path: "3rd:heap-used", kind: OTHER, memoryUsed: kUnknown },
|
||||
{ path: "3rd:explicit/a", kind: HEAP, memoryUsed: kUnknown },
|
||||
{ path: "3rd:explicit/a/b", kind: HEAP, memoryUsed: 333 * MB },
|
||||
{ path: "3rd:explicit/a/c", kind: HEAP, memoryUsed: 444 * MB },
|
||||
{ path: "3rd:explicit/a/d", kind: HEAP, memoryUsed: kUnknown },
|
||||
{ path: "3rd:explicit/b", kind: MAPPED,memoryUsed: kUnknown },
|
||||
{ path: "3rd:other1", kind: OTHER, memoryUsed: kUnknown }
|
||||
];
|
||||
for (var i = 0; i < fakeReporters.length; i++) {
|
||||
fakeReporters[i].description = "(description)";
|
||||
mgr.registerReporter(fakeReporters[i]);
|
||||
}
|
||||
]]>
|
||||
@ -79,74 +87,61 @@
|
||||
"\
|
||||
Main Process\n\
|
||||
\n\
|
||||
Mapped Memory\n\
|
||||
1,000.00 MB (100.0%) -- mapped\n\
|
||||
├────600.00 MB (60.00%) -- heap\n\
|
||||
│ ├──500.00 MB (50.00%) -- used\n\
|
||||
│ └──100.00 MB (10.00%) -- unused\n\
|
||||
├────222.00 MB (22.20%) -- a\n\
|
||||
└────178.00 MB (17.80%) -- other\n\
|
||||
\n\
|
||||
Used Heap Memory\n\
|
||||
500.00 MB (100.0%) -- heap-used\n\
|
||||
├──232.00 MB (46.40%) -- b\n\
|
||||
│ ├───80.00 MB (16.00%) -- a\n\
|
||||
│ ├───77.00 MB (15.40%) -- c\n\
|
||||
│ │ ├──44.00 MB (08.80%) -- a\n\
|
||||
│ │ └──33.00 MB (06.60%) -- b\n\
|
||||
│ └───75.00 MB (15.00%) -- b\n\
|
||||
├──123.00 MB (24.60%) -- c\n\
|
||||
├───99.00 MB (19.80%) -- a\n\
|
||||
├───20.00 MB (04.00%) -- f\n\
|
||||
│ └──20.00 MB (04.00%) -- g\n\
|
||||
│ └──20.00 MB (04.00%) -- h\n\
|
||||
│ └──20.00 MB (04.00%) -- i\n\
|
||||
├───15.00 MB (03.00%) -- g\n\
|
||||
│ ├───6.00 MB (01.20%) -- a\n\
|
||||
│ ├───5.00 MB (01.00%) -- b\n\
|
||||
│ └───4.00 MB (00.80%) -- other\n\
|
||||
├───10.42 MB (02.08%) -- other\n\
|
||||
└────0.58 MB (00.12%) -- (2 omitted)\n\
|
||||
Explicit Allocations\n\
|
||||
623.58 MB (100.0%) -- explicit\n\
|
||||
├──232.00 MB (37.20%) -- b\n\
|
||||
│ ├───85.00 MB (13.63%) -- a\n\
|
||||
│ ├───75.00 MB (12.03%) -- b\n\
|
||||
│ └───72.00 MB (11.55%) -- c\n\
|
||||
│ ├──70.00 MB (11.23%) -- a\n\
|
||||
│ └───2.00 MB (00.32%) -- (1 omitted)\n\
|
||||
├──222.00 MB (35.60%) -- a\n\
|
||||
├──123.00 MB (19.72%) -- c\n\
|
||||
├───20.00 MB (03.21%) -- f\n\
|
||||
│ └──20.00 MB (03.21%) -- g\n\
|
||||
│ └──20.00 MB (03.21%) -- h\n\
|
||||
│ └──20.00 MB (03.21%) -- i\n\
|
||||
├───15.00 MB (02.41%) -- g\n\
|
||||
│ ├───6.00 MB (00.96%) -- a\n\
|
||||
│ ├───5.00 MB (00.80%) -- b\n\
|
||||
│ └───4.00 MB (00.64%) -- other\n\
|
||||
├───11.00 MB (01.76%) -- heap-unclassified\n\
|
||||
└────0.58 MB (00.09%) -- (2 omitted)\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
111.00 MB -- other1\n\
|
||||
500.00 MB -- heap-used\n\
|
||||
222.00 MB -- other2\n\
|
||||
111.00 MB -- other1\n\
|
||||
100.00 MB -- heap-unused\n\
|
||||
\n\
|
||||
2nd Process\n\
|
||||
\n\
|
||||
Mapped Memory\n\
|
||||
1,000.00 MB (100.0%) -- mapped\n\
|
||||
├────500.00 MB (50.00%) -- heap\n\
|
||||
│ └──500.00 MB (50.00%) -- used\n\
|
||||
Explicit Allocations\n\
|
||||
1,000.00 MB (100.0%) -- explicit\n\
|
||||
├────499.00 MB (49.90%) -- a\n\
|
||||
│ └──499.00 MB (49.90%) -- b\n\
|
||||
│ └──499.00 MB (49.90%) -- c\n\
|
||||
└──────1.00 MB (00.10%) -- other\n\
|
||||
\n\
|
||||
Used Heap Memory\n\
|
||||
500.00 MB (100.0%) -- heap-used\n\
|
||||
├──400.00 MB (80.00%) -- a\n\
|
||||
└──100.00 MB (20.00%) -- other\n\
|
||||
├────400.00 MB (40.00%) -- b\n\
|
||||
└────101.00 MB (10.10%) -- heap-unclassified\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
777.00 MB -- other1\n\
|
||||
1,000.00 MB -- heap-used\n\
|
||||
777.00 MB -- other1\n\
|
||||
100.00 MB -- heap-unused\n\
|
||||
\n\
|
||||
3rd Process\n\
|
||||
\n\
|
||||
Mapped Memory\n\
|
||||
??? MB -- mapped\n\
|
||||
├──333.00 MB -- a\n\
|
||||
│ └──333.00 MB -- b\n\
|
||||
└──0.00 MB -- heap\n\
|
||||
└───??? MB -- used\n\
|
||||
\n\
|
||||
Used Heap Memory\n\
|
||||
??? MB -- heap-used\n\
|
||||
└──444.00 MB -- a\n\
|
||||
└──444.00 MB -- b\n\
|
||||
Explicit Allocations\n\
|
||||
777.00 MB (100.0%) -- explicit\n\
|
||||
├──777.00 MB (100.0%) -- a [*]\n\
|
||||
│ ├──444.00 MB (57.14%) -- c\n\
|
||||
│ ├──333.00 MB (42.86%) -- b\n\
|
||||
│ └────0.00 MB (00.00%) -- (1 omitted)\n\
|
||||
└────0.00 MB (00.00%) -- (2 omitted)\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
555.00 MB -- other1\n\
|
||||
0.00 MB -- heap-used [*]\n\
|
||||
0.00 MB -- other1 [*]\n\
|
||||
\n\
|
||||
";
|
||||
|
||||
@ -154,75 +149,63 @@ Other Measurements\n\
|
||||
"\
|
||||
Main Process\n\
|
||||
\n\
|
||||
Mapped Memory\n\
|
||||
1,048,576,000 B (100.0%) -- mapped\n\
|
||||
├────629,145,600 B (60.00%) -- heap\n\
|
||||
│ ├──524,288,000 B (50.00%) -- used\n\
|
||||
│ └──104,857,600 B (10.00%) -- unused\n\
|
||||
├────232,783,872 B (22.20%) -- a\n\
|
||||
└────186,646,528 B (17.80%) -- other\n\
|
||||
\n\
|
||||
Used Heap Memory\n\
|
||||
524,288,000 B (100.0%) -- heap-used\n\
|
||||
├──243,269,632 B (46.40%) -- b\n\
|
||||
│ ├───83,886,080 B (16.00%) -- a\n\
|
||||
│ ├───80,740,352 B (15.40%) -- c\n\
|
||||
│ │ ├──46,137,344 B (08.80%) -- a\n\
|
||||
│ │ └──34,603,008 B (06.60%) -- b\n\
|
||||
│ └───78,643,200 B (15.00%) -- b\n\
|
||||
├──128,974,848 B (24.60%) -- c\n\
|
||||
├──103,809,024 B (19.80%) -- a\n\
|
||||
├───20,971,520 B (04.00%) -- f\n\
|
||||
│ └──20,971,520 B (04.00%) -- g\n\
|
||||
│ └──20,971,520 B (04.00%) -- h\n\
|
||||
│ └──20,971,520 B (04.00%) -- i\n\
|
||||
├───15,728,640 B (03.00%) -- g\n\
|
||||
│ ├───6,291,456 B (01.20%) -- a\n\
|
||||
│ ├───5,242,880 B (01.00%) -- b\n\
|
||||
│ └───4,194,304 B (00.80%) -- other\n\
|
||||
├───10,920,960 B (02.08%) -- other\n\
|
||||
├──────510,976 B (00.10%) -- d\n\
|
||||
Explicit Allocations\n\
|
||||
653,876,224 B (100.0%) -- explicit\n\
|
||||
├──243,269,632 B (37.20%) -- b\n\
|
||||
│ ├───89,128,960 B (13.63%) -- a\n\
|
||||
│ ├───78,643,200 B (12.03%) -- b\n\
|
||||
│ └───75,497,472 B (11.55%) -- c\n\
|
||||
│ ├──73,400,320 B (11.23%) -- a\n\
|
||||
│ └───2,097,152 B (00.32%) -- b\n\
|
||||
├──232,783,872 B (35.60%) -- a\n\
|
||||
├──128,974,848 B (19.72%) -- c\n\
|
||||
├───20,971,520 B (03.21%) -- f\n\
|
||||
│ └──20,971,520 B (03.21%) -- g\n\
|
||||
│ └──20,971,520 B (03.21%) -- h\n\
|
||||
│ └──20,971,520 B (03.21%) -- i\n\
|
||||
├───15,728,640 B (02.41%) -- g\n\
|
||||
│ ├───6,291,456 B (00.96%) -- a\n\
|
||||
│ ├───5,242,880 B (00.80%) -- b\n\
|
||||
│ └───4,194,304 B (00.64%) -- other\n\
|
||||
├───11,534,336 B (01.76%) -- heap-unclassified\n\
|
||||
├──────510,976 B (00.08%) -- d\n\
|
||||
└──────102,400 B (00.02%) -- e\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
116,391,936 B -- other1\n\
|
||||
524,288,000 B -- heap-used\n\
|
||||
232,783,872 B -- other2\n\
|
||||
116,391,936 B -- other1\n\
|
||||
104,857,600 B -- heap-unused\n\
|
||||
\n\
|
||||
2nd Process\n\
|
||||
\n\
|
||||
Mapped Memory\n\
|
||||
1,048,576,000 B (100.0%) -- mapped\n\
|
||||
├────524,288,000 B (50.00%) -- heap\n\
|
||||
│ └──524,288,000 B (50.00%) -- used\n\
|
||||
Explicit Allocations\n\
|
||||
1,048,576,000 B (100.0%) -- explicit\n\
|
||||
├────523,239,424 B (49.90%) -- a\n\
|
||||
│ └──523,239,424 B (49.90%) -- b\n\
|
||||
│ └──523,239,424 B (49.90%) -- c\n\
|
||||
└──────1,048,576 B (00.10%) -- other\n\
|
||||
\n\
|
||||
Used Heap Memory\n\
|
||||
524,288,000 B (100.0%) -- heap-used\n\
|
||||
├──419,430,400 B (80.00%) -- a\n\
|
||||
└──104,857,600 B (20.00%) -- other\n\
|
||||
├────419,430,400 B (40.00%) -- b\n\
|
||||
└────105,906,176 B (10.10%) -- heap-unclassified\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
814,743,552 B -- other1\n\
|
||||
1,048,576,000 B -- heap-used\n\
|
||||
814,743,552 B -- other1\n\
|
||||
104,857,600 B -- heap-unused\n\
|
||||
\n\
|
||||
3rd Process\n\
|
||||
\n\
|
||||
Mapped Memory\n\
|
||||
??? B -- mapped\n\
|
||||
├──349,175,808 B -- a\n\
|
||||
│ └──349,175,808 B -- b\n\
|
||||
└────0 B -- heap\n\
|
||||
└──??? B -- used\n\
|
||||
\n\
|
||||
Used Heap Memory\n\
|
||||
??? B -- heap-used\n\
|
||||
└──465,567,744 B -- a\n\
|
||||
└──465,567,744 B -- b\n\
|
||||
Explicit Allocations\n\
|
||||
814,743,552 B (100.0%) -- explicit\n\
|
||||
├──814,743,552 B (100.0%) -- a [*]\n\
|
||||
│ ├──465,567,744 B (57.14%) -- c\n\
|
||||
│ ├──349,175,808 B (42.86%) -- b\n\
|
||||
│ └────────────0 B (00.00%) -- d [*]\n\
|
||||
├────────────0 B (00.00%) -- b [*]\n\
|
||||
└────────────0 B (00.00%) -- heap-unclassified [*]\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
581,959,680 B -- other1\n\
|
||||
0 B -- heap-used [*]\n\
|
||||
0 B -- other1 [*]\n\
|
||||
\n\
|
||||
"
|
||||
|
||||
|
@ -47,39 +47,52 @@ interface nsIMemoryReporter : nsISupports
|
||||
* The path that this memory usage should be reported under. Paths can
|
||||
* begin with a process name plus a colon, eg "Content:", but this is not
|
||||
* necessary for the main process. After the process name, paths are
|
||||
* '/'-delimited, eg. "a/b/c". There are three categories of paths.
|
||||
* '/'-delimited, eg. "a/b/c". There are two categories of paths.
|
||||
*
|
||||
* - Paths starting with "mapped" represent non-overlapping regions of mapped
|
||||
* memory. Each one can be viewed as representing a path in a tree from
|
||||
* the root node ("mapped") to a node lower in the tree; this lower node
|
||||
* may be a non-leaf or a leaf node. So, for example, "mapped",
|
||||
* "mapped/heap/used", "mapped/heap/unused", "mapped/js/mjit-code",
|
||||
* and "mapped/js/tjit-code" define this tree:
|
||||
* - Paths starting with "explicit" represent non-overlapping regions of
|
||||
* memory that have been explicitly allocated with an OS-level allocation
|
||||
* (eg. mmap/VirtualAlloc/vm_allocate) or a heap-level allocation (eg.
|
||||
* malloc/calloc/operator new). Each one can be viewed as representing a
|
||||
* path in a tree from the root node ("explicit") to a node lower in the
|
||||
* tree; this lower node does not have to be a leaf node.
|
||||
*
|
||||
* mapped [*]
|
||||
* |--heap
|
||||
* | |--used [*]
|
||||
* | \--unused [*]
|
||||
* \--js
|
||||
* |--mjit-code [*]
|
||||
* \--tjit-code [*]
|
||||
* So, for example, "explicit/a/b", "explicit/a/c", "explicit/d",
|
||||
* "explicit/d/e", and "explicit/d/f" define this tree:
|
||||
*
|
||||
* explicit
|
||||
* |--a
|
||||
* | |--b [*]
|
||||
* | \--c [*]
|
||||
* \--d [*]
|
||||
* |--e [*]
|
||||
* \--f [*]
|
||||
*
|
||||
* Nodes marked with a [*] have a reporter.
|
||||
*
|
||||
* - Paths starting with "heap-used" represent non-overlapping regions of
|
||||
* used heap memory. The "mapped" rules above apply equally here. These
|
||||
* paths are actually sub-paths of "mapped/heap/used", but that reporter
|
||||
* is duplicated under the name "heap-used" to make the processing for
|
||||
* about:memory simpler.
|
||||
*
|
||||
* - All other paths represent cross-cuttings memory regions, ie. ones that
|
||||
* may overlap arbitrarily with regions in the "mapped" and "heap-used"
|
||||
* trees.
|
||||
* may overlap arbitrarily with regions in the "explicit" tree.
|
||||
*/
|
||||
readonly attribute string path;
|
||||
|
||||
/*
|
||||
* A human-readable description of this memory usage report
|
||||
* Allocation kinds. "MAPPED" means it is allocated directly by the OS, eg.
|
||||
* by calling mmap, VirtualAlloc, vm_allocate, etc. "HEAP" means it is
|
||||
* allocated by the heap allocator, eg. by calling malloc, calloc, realloc,
|
||||
* memalign, operator new, operator new[], etc. "OTHER" means it doesn't fit
|
||||
* into either of these categories; such reporters should have a path that
|
||||
* does *not* start with "explicit".
|
||||
*/
|
||||
const PRInt32 MR_MAPPED = 0;
|
||||
const PRInt32 MR_HEAP = 1;
|
||||
const PRInt32 MR_OTHER = 2;
|
||||
|
||||
/*
|
||||
* The memory kind, see MR_* above.
|
||||
*/
|
||||
readonly attribute PRInt32 kind;
|
||||
|
||||
/*
|
||||
* A human-readable description of this memory usage report.
|
||||
*/
|
||||
readonly attribute string description;
|
||||
|
||||
@ -119,11 +132,12 @@ interface nsIMemoryReporterManager : nsISupports
|
||||
|
||||
%{C++
|
||||
|
||||
#define NS_MEMORY_REPORTER_IMPLEMENT(_classname,_path,_desc,_usageFunction,_dataptr) \
|
||||
#define NS_MEMORY_REPORTER_IMPLEMENT(_classname,_path,_kind,_desc,_usageFunction,_dataptr) \
|
||||
class MemoryReporter_##_classname : public nsIMemoryReporter { \
|
||||
public: \
|
||||
NS_DECL_ISUPPORTS \
|
||||
NS_IMETHOD GetPath(char **memoryPath) { *memoryPath = strdup(_path); return NS_OK; } \
|
||||
NS_IMETHOD GetKind(int *kind) { *kind = _kind; return NS_OK; } \
|
||||
NS_IMETHOD GetDescription(char **desc) { *desc = strdup(_desc); return NS_OK; } \
|
||||
NS_IMETHOD GetMemoryUsed(PRInt64 *memoryUsed) { *memoryUsed = _usageFunction(_dataptr); return NS_OK; } \
|
||||
}; \
|
||||
|
@ -60,7 +60,7 @@ static PRInt64 GetProcSelfStatmField(int n)
|
||||
return (PRInt64) -1;
|
||||
}
|
||||
|
||||
static PRInt64 GetMapped(void *)
|
||||
static PRInt64 GetVsize(void *)
|
||||
{
|
||||
return GetProcSelfStatmField(0);
|
||||
}
|
||||
@ -83,11 +83,10 @@ static bool GetTaskBasicInfo(struct task_basic_info *ti)
|
||||
return kr == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
// Getting a sensible "mapped" number on Mac is difficult. The following is
|
||||
// easy and (I think) corresponds to the VSIZE figure reported by 'top' and
|
||||
// 'ps', but that includes shared memory and so is always absurdly high. This
|
||||
// doesn't really matter as the "mapped" figure is never that useful.
|
||||
static PRInt64 GetMapped(void *)
|
||||
// The VSIZE figure on Mac includes huge amounts of shared memory and is always
|
||||
// absurdly high, eg. 2GB+ even at start-up. But both 'top' and 'ps' report
|
||||
// it, so we might as well too.
|
||||
static PRInt64 GetVsize(void *)
|
||||
{
|
||||
task_basic_info ti;
|
||||
return (PRInt64) (GetTaskBasicInfo(&ti) ? ti.virtual_size : -1);
|
||||
@ -104,22 +103,29 @@ static PRInt64 GetResident(void *)
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
|
||||
static PRInt64 GetMapped(void *)
|
||||
{
|
||||
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
PROCESS_MEMORY_COUNTERS_EX pmcex;
|
||||
pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
|
||||
static PRInt64 GetPrivate(void *)
|
||||
{
|
||||
PROCESS_MEMORY_COUNTERS_EX pmcex;
|
||||
pmcex.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
|
||||
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(),
|
||||
(PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex)))
|
||||
return (PRInt64) -1;
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(),
|
||||
(PPROCESS_MEMORY_COUNTERS) &pmcex, sizeof(pmcex)))
|
||||
return (PRInt64) -1;
|
||||
|
||||
return pmcex.PrivateUsage;
|
||||
#else
|
||||
return (PRInt64) -1;
|
||||
#endif
|
||||
return pmcex.PrivateUsage;
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Private,
|
||||
"private",
|
||||
MR_OTHER,
|
||||
"Memory that cannot be shared with other processes, including memory that "
|
||||
"is committed and marked MEM_PRIVATE, data that is not mapped, and "
|
||||
"executable pages that have been written to.",
|
||||
GetPrivate,
|
||||
NULL)
|
||||
#endif
|
||||
|
||||
static PRInt64 GetResident(void *)
|
||||
{
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
@ -133,11 +139,6 @@ static PRInt64 GetResident(void *)
|
||||
|
||||
#else
|
||||
|
||||
static PRInt64 GetMapped(void *)
|
||||
{
|
||||
return (PRInt64) -1;
|
||||
}
|
||||
|
||||
static PRInt64 GetResident(void *)
|
||||
{
|
||||
return (PRInt64) -1;
|
||||
@ -145,25 +146,25 @@ static PRInt64 GetResident(void *)
|
||||
|
||||
#endif
|
||||
|
||||
// aboutMemory.js requires that this reporter always be registered, even if the
|
||||
// byte count returned is always -1.
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Mapped,
|
||||
"mapped",
|
||||
"Memory mapped by the process, including the heap, code and data segments, "
|
||||
"thread stacks, and memory explicitly mapped by the process via "
|
||||
"mmap, VirtualAlloc and similar operations. "
|
||||
"Note that 'resident' is a better measure of memory resources used by the "
|
||||
"process. "
|
||||
"On Windows (XP SP2 or later only) this is the private usage and does not "
|
||||
"include memory shared with other processes. "
|
||||
"On Mac and Linux this is the vsize figure as reported by 'top' or 'ps' "
|
||||
"and includes memory shared with other processes; on Mac the amount of "
|
||||
"shared memory can be very high and so this figure is of limited use.",
|
||||
GetMapped,
|
||||
#if defined(XP_LINUX) || defined(XP_MACOSX)
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Vsize,
|
||||
"vsize",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the process, including code and data segments, the "
|
||||
"heap, thread stacks, memory explicitly mapped by the process via mmap "
|
||||
"and similar operations, and memory shared with other processes. "
|
||||
"(Note that 'resident' is a better measure of the memory resources used "
|
||||
"by the process.) "
|
||||
"This is the vsize figure as reported by 'top' or 'ps'; on Mac the amount "
|
||||
"of memory shared with other processes is very high and so this figure is "
|
||||
"of limited use.",
|
||||
GetVsize,
|
||||
NULL)
|
||||
#endif
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(Resident,
|
||||
"resident",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the process that is present in physical memory, "
|
||||
"also known as the resident set size (RSS). This is the best single "
|
||||
"figure to use when considering the memory resources used by the process, "
|
||||
@ -199,14 +200,14 @@ extern void jemalloc_stats(jemalloc_stats_t* stats)
|
||||
|
||||
#if HAVE_JEMALLOC_STATS
|
||||
|
||||
static PRInt64 GetMappedHeapUsed(void *)
|
||||
static PRInt64 GetHeapUsed(void *)
|
||||
{
|
||||
jemalloc_stats_t stats;
|
||||
jemalloc_stats(&stats);
|
||||
return (PRInt64) stats.allocated;
|
||||
}
|
||||
|
||||
static PRInt64 GetMappedHeapUnused(void *)
|
||||
static PRInt64 GetHeapUnused(void *)
|
||||
{
|
||||
jemalloc_stats_t stats;
|
||||
jemalloc_stats(&stats);
|
||||
@ -228,30 +229,30 @@ static PRInt64 GetHeapDirty(void *)
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapCommitted,
|
||||
"heap-committed",
|
||||
"Memory mapped by the heap allocator that is "
|
||||
"committed, i.e. in physical memory or paged to "
|
||||
"disk.",
|
||||
GetHeapCommitted,
|
||||
NULL)
|
||||
"heap-committed",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the heap allocator that is committed, i.e. in physical "
|
||||
"memory or paged to disk.",
|
||||
GetHeapCommitted,
|
||||
NULL)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty,
|
||||
"heap-dirty",
|
||||
"Memory mapped by the heap allocator that is "
|
||||
"committed but unused.",
|
||||
GetHeapDirty,
|
||||
NULL)
|
||||
"heap-dirty",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the heap allocator that is committed but unused.",
|
||||
GetHeapDirty,
|
||||
NULL)
|
||||
|
||||
#elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
|
||||
#include <malloc/malloc.h>
|
||||
|
||||
static PRInt64 GetMappedHeapUsed(void *)
|
||||
static PRInt64 GetHeapUsed(void *)
|
||||
{
|
||||
struct mstats stats = mstats();
|
||||
return (PRInt64) stats.bytes_used;
|
||||
}
|
||||
|
||||
static PRInt64 GetMappedHeapUnused(void *)
|
||||
static PRInt64 GetHeapUnused(void *)
|
||||
{
|
||||
struct mstats stats = mstats();
|
||||
return (PRInt64) (stats.bytes_total - stats.bytes_used);
|
||||
@ -272,52 +273,51 @@ static PRInt64 GetHeapZone0Used(void *)
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Committed,
|
||||
"heap-zone0-committed",
|
||||
"Memory mapped by the heap allocator that is "
|
||||
"committed in the default zone.",
|
||||
GetHeapZone0Committed,
|
||||
NULL)
|
||||
"heap-zone0-committed",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the heap allocator that is committed in the default "
|
||||
"zone.",
|
||||
GetHeapZone0Committed,
|
||||
NULL)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapZone0Used,
|
||||
"heap-zone0-used",
|
||||
"Memory mapped by the heap allocator in the "
|
||||
"default zone that is available for use by the "
|
||||
"application.",
|
||||
GetHeapZone0Used,
|
||||
NULL)
|
||||
"heap-zone0-used",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the heap allocator in the default zone that is "
|
||||
"available for use by the application.",
|
||||
GetHeapZone0Used,
|
||||
NULL)
|
||||
#else
|
||||
|
||||
static PRInt64 GetMappedHeapUsed(void *)
|
||||
static PRInt64 GetHeapUsed(void *)
|
||||
{
|
||||
return (PRInt64) -1;
|
||||
}
|
||||
|
||||
static PRInt64 GetMappedHeapUnused(void *)
|
||||
static PRInt64 GetHeapUnused(void *)
|
||||
{
|
||||
return (PRInt64) -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// aboutMemory.js requires that this reporter always be registered, even if the
|
||||
// byte count returned is always -1.
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(MappedHeapUsed,
|
||||
"mapped/heap/used",
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapUsed,
|
||||
"heap-used",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the heap allocator that is available for use by the "
|
||||
"application. This may exceed the amount of memory requested by the "
|
||||
"application due to the allocator rounding up request sizes. "
|
||||
"(The exact amount requested is not measured.) "
|
||||
"This is usually the best figure for developers to focus on when trying "
|
||||
"to reduce memory consumption.",
|
||||
GetMappedHeapUsed,
|
||||
"application due to the allocator rounding up request sizes. "
|
||||
"(The exact amount requested is not measured.) ",
|
||||
GetHeapUsed,
|
||||
NULL)
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(MappedHeapUnused,
|
||||
"mapped/heap/unused",
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(HeapUnused,
|
||||
"heap-unused",
|
||||
MR_OTHER,
|
||||
"Memory mapped by the heap allocator and not available for use by the "
|
||||
"application. This can grow large if the heap allocator is holding onto "
|
||||
"memory that the application has freed.",
|
||||
GetMappedHeapUnused,
|
||||
GetHeapUnused,
|
||||
NULL)
|
||||
|
||||
/**
|
||||
@ -336,11 +336,16 @@ nsMemoryReporterManager::Init()
|
||||
|
||||
#define REGISTER(_x) RegisterReporter(new NS_MEMORY_REPORTER_NAME(_x))
|
||||
|
||||
REGISTER(Mapped);
|
||||
REGISTER(MappedHeapUsed);
|
||||
REGISTER(MappedHeapUnused);
|
||||
REGISTER(HeapUsed);
|
||||
REGISTER(HeapUnused);
|
||||
REGISTER(Resident);
|
||||
|
||||
#if defined(XP_LINUX) || defined(XP_MACOSX)
|
||||
REGISTER(Vsize);
|
||||
#elif defined(XP_WIN) && MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
REGISTER(Private);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_JEMALLOC_STATS)
|
||||
REGISTER(HeapCommitted);
|
||||
REGISTER(HeapDirty);
|
||||
@ -395,9 +400,11 @@ NS_IMPL_ISUPPORTS1(nsMemoryReporter, nsIMemoryReporter)
|
||||
|
||||
nsMemoryReporter::nsMemoryReporter(nsCString& prefix,
|
||||
nsCString& path,
|
||||
PRInt32 kind,
|
||||
nsCString& desc,
|
||||
PRInt64 memoryUsed)
|
||||
: mDesc(desc)
|
||||
: mKind(kind)
|
||||
, mDesc(desc)
|
||||
, mMemoryUsed(memoryUsed)
|
||||
{
|
||||
if (!prefix.IsEmpty()) {
|
||||
@ -417,6 +424,12 @@ NS_IMETHODIMP nsMemoryReporter::GetPath(char **aPath)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMemoryReporter::GetKind(PRInt32 *aKind)
|
||||
{
|
||||
*aKind = mKind;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMemoryReporter::GetDescription(char **aDescription)
|
||||
{
|
||||
*aDescription = strdup(mDesc.get());
|
||||
|
@ -13,6 +13,7 @@ public:
|
||||
|
||||
nsMemoryReporter(nsCString& prefix,
|
||||
nsCString& path,
|
||||
PRInt32 kind,
|
||||
nsCString& desc,
|
||||
PRInt64 memoryUsed);
|
||||
|
||||
@ -20,6 +21,7 @@ public:
|
||||
|
||||
protected:
|
||||
nsCString mPath, mDesc;
|
||||
PRInt32 mKind;
|
||||
PRInt64 mMemoryUsed;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user