Bug 819772 - Add a memory reporter for DMD's data. r=jlebar.

--HG--
extra : rebase_source : d85f4f08b3c0ec5e81bde9caa63699e60a303b33
This commit is contained in:
Nicholas Nethercote 2012-12-11 13:54:11 -08:00
parent ff4e584f23
commit 7fe17b1ddf
3 changed files with 155 additions and 27 deletions

View File

@ -1448,10 +1448,10 @@ Init(const malloc_table_t* aMallocTable)
DMD_CREATE_TLS_INDEX(gTlsIndex);
gStackTraceTable = InfallibleAllocPolicy::new_<StackTraceTable>();
gStackTraceTable->init(65536);
gStackTraceTable->init(8192);
gLiveBlockTable = InfallibleAllocPolicy::new_<BlockTable>();
gLiveBlockTable->init(65536);
gLiveBlockTable->init(8192);
gDoubleReportBlockGroupTable = InfallibleAllocPolicy::new_<BlockGroupTable>();
gDoubleReportBlockGroupTable->init(0);
@ -1667,35 +1667,28 @@ MallocSizeOf(const void* aPtr)
return gMallocTable->malloc_usable_size(const_cast<void*>(aPtr));
}
static void
ShowExecutionMeasurements(const Writer& aWriter)
// Note that, unlike most SizeOf* functions, this function does not take a
// |nsMallocSizeOfFun| argument. That's because those arguments are primarily
// to aid DMD track heap blocks... but DMD deliberately doesn't track heap
// blocks it allocated for itself!
MOZ_EXPORT void
SizeOf(Sizes* aSizes)
{
// Stats are non-deterministic, so don't show it in test mode.
if (gMode == Test) {
return;
}
WriteTitle("Execution measurements\n");
size_t sizeOfStackTraceTable =
gStackTraceTable->sizeOfIncludingThis(MallocSizeOf);
aSizes->mStackTraces = 0;
for (StackTraceTable::Range r = gStackTraceTable->all();
!r.empty();
r.popFront()) {
StackTrace* const& st = r.front();
sizeOfStackTraceTable += MallocSizeOf(st);
aSizes->mStackTraces += MallocSizeOf(st);
}
W("Stack trace table: %s of %s entries used, taking up %s bytes\n",
Show(gStackTraceTable->count(), gBuf1, kBufLen),
Show(gStackTraceTable->capacity(), gBuf2, kBufLen),
Show(sizeOfStackTraceTable, gBuf3, kBufLen));
W("Live block table: %s of %s entries used, taking up %s bytes\n",
Show(gLiveBlockTable->count(), gBuf1, kBufLen),
Show(gLiveBlockTable->capacity(), gBuf2, kBufLen),
Show(gLiveBlockTable->sizeOfIncludingThis(MallocSizeOf), gBuf3, kBufLen));
aSizes->mStackTraceTable =
gStackTraceTable->sizeOfIncludingThis(MallocSizeOf);
W("\n");
aSizes->mLiveBlockTable = gLiveBlockTable->sizeOfIncludingThis(MallocSizeOf);
aSizes->mDoubleReportTable =
gDoubleReportBlockGroupTable->sizeOfIncludingThis(MallocSizeOf);
}
static void
@ -1731,11 +1724,11 @@ Dump(Writer aWriter)
StatusMsg(" gathering live block groups...\n");
BlockGroupTable unreportedBlockGroupTable;
(void)unreportedBlockGroupTable.init(2048);
(void)unreportedBlockGroupTable.init(1024);
size_t unreportedUsableSize = 0;
BlockGroupTable reportedBlockGroupTable;
(void)reportedBlockGroupTable.init(2048);
(void)reportedBlockGroupTable.init(1024);
size_t reportedUsableSize = 0;
bool anyBlocksSampled = false;
@ -1781,7 +1774,51 @@ Dump(Writer aWriter)
W("\n");
ShowExecutionMeasurements(aWriter);
// Stats are non-deterministic, so don't show them in test mode.
if (gMode != Test) {
Sizes sizes;
SizeOf(&sizes);
WriteTitle("Execution measurements\n");
W("Data structures that persist after Dump() ends:\n");
W(" Stack traces: %10s bytes\n",
Show(sizes.mStackTraces, gBuf1, kBufLen));
W(" Stack trace table: %10s bytes (%s entries, %s used)\n",
Show(sizes.mStackTraceTable, gBuf1, kBufLen),
Show(gStackTraceTable->capacity(), gBuf2, kBufLen),
Show(gStackTraceTable->count(), gBuf3, kBufLen));
W(" Live block table: %10s bytes (%s entries, %s used)\n",
Show(sizes.mLiveBlockTable, gBuf1, kBufLen),
Show(gLiveBlockTable->capacity(), gBuf2, kBufLen),
Show(gLiveBlockTable->count(), gBuf3, kBufLen));
W("\nData structures that are cleared after Dump() ends:\n");
W(" Double-report table: %10s bytes (%s entries, %s used)\n",
Show(sizes.mDoubleReportTable, gBuf1, kBufLen),
Show(gDoubleReportBlockGroupTable->capacity(), gBuf2, kBufLen),
Show(gDoubleReportBlockGroupTable->count(), gBuf3, kBufLen));
size_t unreportedSize =
unreportedBlockGroupTable.sizeOfIncludingThis(MallocSizeOf);
W(" Unreported table: %10s bytes (%s entries, %s used)\n",
Show(unreportedSize, gBuf1, kBufLen),
Show(unreportedBlockGroupTable.capacity(), gBuf2, kBufLen),
Show(unreportedBlockGroupTable.count(), gBuf3, kBufLen));
size_t reportedSize =
reportedBlockGroupTable.sizeOfIncludingThis(MallocSizeOf);
W(" Reported table: %10s bytes (%s entries, %s used)\n",
Show(reportedSize, gBuf1, kBufLen),
Show(reportedBlockGroupTable.capacity(), gBuf2, kBufLen),
Show(reportedBlockGroupTable.count(), gBuf3, kBufLen));
W("\n");
}
ClearState();

View File

@ -8,6 +8,7 @@
#define DMD_h___
#include <stdarg.h>
#include <string.h>
#include "mozilla/Types.h"
@ -49,6 +50,21 @@ Dump(Writer aWriter);
MOZ_EXPORT void
FpWrite(void* aFp, const char* aFmt, va_list aAp);
struct Sizes
{
size_t mStackTraces;
size_t mStackTraceTable;
size_t mLiveBlockTable;
size_t mDoubleReportTable;
Sizes() { memset(this, 0, sizeof(Sizes)); }
};
// Gets the size of various data structures. Used to implement a memory
// reporter for DMD.
MOZ_EXPORT void
SizeOf(Sizes* aSizes);
} // namespace mozilla
} // namespace dmd

View File

@ -561,6 +561,78 @@ NS_MEMORY_REPORTER_IMPLEMENT(AtomTable,
GetAtomTableSize,
"Memory used by the dynamic and static atoms tables.")
#ifdef MOZ_DMD
namespace mozilla {
namespace dmd {
class MemoryReporter MOZ_FINAL : public nsIMemoryMultiReporter
{
public:
MemoryReporter()
{}
NS_DECL_ISUPPORTS
NS_IMETHOD GetName(nsACString &name)
{
name.Assign("dmd");
return NS_OK;
}
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
dmd::Sizes sizes;
dmd::SizeOf(&sizes);
#define REPORT(_path, _amount, _desc) \
do { \
nsresult rv; \
rv = callback->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
nsIMemoryReporter::KIND_HEAP, \
nsIMemoryReporter::UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), closure); \
NS_ENSURE_SUCCESS(rv, rv); \
} while (0)
REPORT("explicit/dmd/stack-traces",
sizes.mStackTraces,
"Memory used by DMD's stack traces.");
REPORT("explicit/dmd/stack-trace-table",
sizes.mStackTraceTable,
"Memory used by DMD's stack trace table.");
REPORT("explicit/dmd/live-block-table",
sizes.mLiveBlockTable,
"Memory used by DMD's live block table.");
REPORT("explicit/dmd/double-report-table",
sizes.mDoubleReportTable,
"Memory used by DMD's double-report table.");
#undef REPORT
return NS_OK;
}
NS_IMETHOD GetExplicitNonHeap(int64_t *n)
{
// No non-heap allocations.
*n = 0;
return NS_OK;
}
};
NS_IMPL_ISUPPORTS1(MemoryReporter, nsIMemoryMultiReporter)
} // namespace dmd
} // namespace mozilla
#endif // MOZ_DMD
/**
** nsMemoryReporterManager implementation
**/
@ -601,9 +673,12 @@ nsMemoryReporterManager::Init()
REGISTER(Private);
#endif
REGISTER(AtomTable);
#ifdef MOZ_DMD
RegisterMultiReporter(new mozilla::dmd::MemoryReporter);
#endif
#if defined(XP_LINUX)
nsMemoryInfoDumper::Initialize();
#endif