Bug 829439 (part 1) - Add MemoryReporterBase class that promotes better encapsulation within nsIMemoryReporter sub-classes. r=jlebar.

--HG--
extra : rebase_source : 53a77ea456f2aedafe05954ceece7e64db743e66
This commit is contained in:
Nicholas Nethercote 2013-01-14 16:26:47 -08:00
parent 66edabde03
commit dc051e917d
14 changed files with 339 additions and 241 deletions

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=78: */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -247,25 +247,29 @@ static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
static PLDHashTable sEventListenerManagersHash;
static nsCOMPtr<nsIMemoryReporter> sEventListenerManagersHashReporter;
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(EventListenerManagersHashMallocSizeOf)
static int64_t GetEventListenerManagersHash()
class DOMEventListenerManagersHashReporter MOZ_FINAL : public MemoryReporterBase
{
// We don't measure the |nsEventListenerManager| objects pointed to by the
// entries because those references are non-owning.
return PL_DHashTableSizeOfExcludingThis(&sEventListenerManagersHash,
nullptr,
EventListenerManagersHashMallocSizeOf);
}
public:
DOMEventListenerManagersHashReporter()
: MemoryReporterBase(
"explicit/dom/event-listener-managers-hash",
KIND_HEAP,
UNITS_BYTES,
"Memory used by the event listener manager's hash table.")
{}
NS_MEMORY_REPORTER_IMPLEMENT(EventListenerManagersHash,
"explicit/dom/event-listener-managers-hash",
KIND_HEAP,
UNITS_BYTES,
GetEventListenerManagersHash,
"Memory used by the event listener manager's hash table.")
private:
int64_t Amount()
{
// We don't measure the |nsEventListenerManager| objects pointed to by the
// entries because those references are non-owning.
return sEventListenerManagersHash.ops
? PL_DHashTableSizeOfExcludingThis(&sEventListenerManagersHash,
nullptr, MallocSizeOf)
: 0;
}
};
class EventListenerManagerMapEntry : public PLDHashEntryHdr
{
@ -403,9 +407,7 @@ nsContentUtils::Init()
return NS_ERROR_OUT_OF_MEMORY;
}
sEventListenerManagersHashReporter =
new NS_MEMORY_REPORTER_NAME(EventListenerManagersHash);
(void)::NS_RegisterMemoryReporter(sEventListenerManagersHashReporter);
NS_RegisterMemoryReporter(new DOMEventListenerManagersHashReporter);
}
sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >;
@ -1487,9 +1489,6 @@ nsContentUtils::Shutdown()
if (sEventListenerManagersHash.entryCount == 0) {
PL_DHashTableFinish(&sEventListenerManagersHash);
sEventListenerManagersHash.ops = nullptr;
(void)::NS_UnregisterMemoryReporter(sEventListenerManagersHashReporter);
sEventListenerManagersHashReporter = nullptr;
}
}

View File

@ -130,7 +130,6 @@ static NS_NAMED_LITERAL_STRING(kDefaultFontStyle, "10px sans-serif");
const Float SIGMA_MAX = 100;
/* Memory reporter stuff */
static nsIMemoryReporter *gCanvasAzureMemoryReporter = nullptr;
static int64_t gCanvasAzureMemoryUsed = 0;
static int64_t GetCanvasAzureMemoryUsed() {
@ -792,9 +791,10 @@ CanvasRenderingContext2D::EnsureTarget()
}
if (mTarget) {
if (gCanvasAzureMemoryReporter == nullptr) {
gCanvasAzureMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory);
NS_RegisterMemoryReporter(gCanvasAzureMemoryReporter);
static bool registered = false;
if (!registered) {
registered = true;
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory));
}
gCanvasAzureMemoryUsed += mWidth * mHeight * 4;

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=78: */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -175,24 +175,6 @@ static bool sNeedsFullCC = false;
static nsJSContext *sContextList = nullptr;
static nsScriptNameSpaceManager *gNameSpaceManager;
static nsIMemoryReporter *gReporter;
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ScriptNameSpaceManagerMallocSizeOf)
static int64_t
GetScriptNameSpaceManagerSize()
{
MOZ_ASSERT(gNameSpaceManager);
return gNameSpaceManager->SizeOfIncludingThis(
ScriptNameSpaceManagerMallocSizeOf);
}
NS_MEMORY_REPORTER_IMPLEMENT(ScriptNameSpaceManager,
"explicit/script-namespace-manager",
KIND_HEAP,
nsIMemoryReporter::UNITS_BYTES,
GetScriptNameSpaceManagerSize,
"Memory used for the script namespace manager.")
static nsIJSRuntimeService *sRuntimeService;
JSRuntime *nsJSRuntime::sRuntime;
@ -3729,7 +3711,6 @@ nsJSRuntime::Startup()
sDisableExplicitCompartmentGC = false;
sNeedsFullCC = false;
gNameSpaceManager = nullptr;
gReporter = nullptr;
sRuntimeService = nullptr;
sRuntime = nullptr;
sIsInitialized = false;
@ -4072,9 +4053,6 @@ nsJSRuntime::GetNameSpaceManager()
nsresult rv = gNameSpaceManager->Init();
NS_ENSURE_SUCCESS(rv, nullptr);
gReporter = new NS_MEMORY_REPORTER_NAME(ScriptNameSpaceManager);
NS_RegisterMemoryReporter(gReporter);
}
return gNameSpaceManager;
@ -4091,10 +4069,6 @@ nsJSRuntime::Shutdown()
nsJSContext::KillInterSliceGCTimer();
NS_IF_RELEASE(gNameSpaceManager);
if (gReporter) {
(void)::NS_UnregisterMemoryReporter(gReporter);
gReporter = nullptr;
}
if (!sContextCount) {
// We're being shutdown, and there are no more contexts

View File

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -111,6 +112,24 @@ GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
return true;
}
class ScriptNameSpaceManagerReporter MOZ_FINAL : public MemoryReporterBase
{
public:
ScriptNameSpaceManagerReporter(nsScriptNameSpaceManager* aManager)
: MemoryReporterBase(
"explicit/script-namespace-manager",
KIND_HEAP,
nsIMemoryReporter::UNITS_BYTES,
"Memory used for the script namespace manager.")
, mManager(aManager)
{}
private:
int64_t Amount() { return mManager->SizeOfIncludingThis(MallocSizeOf); }
nsScriptNameSpaceManager* mManager;
};
NS_IMPL_ISUPPORTS2(nsScriptNameSpaceManager,
nsIObserver,
nsISupportsWeakReference)
@ -124,6 +143,7 @@ nsScriptNameSpaceManager::nsScriptNameSpaceManager()
nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
{
if (mIsInitialized) {
NS_UnregisterMemoryReporter(mReporter);
// Destroy the hash
PL_DHashTableFinish(&mGlobalNames);
PL_DHashTableFinish(&mNavigatorNames);
@ -398,6 +418,9 @@ nsScriptNameSpaceManager::Init()
return NS_ERROR_OUT_OF_MEMORY;
}
mReporter = new ScriptNameSpaceManagerReporter(this);
NS_RegisterMemoryReporter(mReporter);
nsresult rv = NS_OK;
rv = FillHashWithDOMInterfaces();

View File

@ -1,6 +1,6 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
@ -78,6 +78,7 @@ private:
class nsIScriptContext;
class nsICategoryManager;
class nsIMemoryReporter;
class GlobalNameMapEntry;
@ -191,6 +192,8 @@ private:
PLDHashTable mNavigatorNames;
bool mIsInitialized;
nsCOMPtr<nsIMemoryReporter> mReporter;
};
#endif /* nsScriptNameSpaceManager_h__ */

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -21,7 +21,6 @@
#include "nsDiskCacheDevice.h"
#include "nsDiskCacheDeviceSQL.h"
#include "nsIMemoryReporter.h"
#include "nsIObserverService.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
@ -1071,26 +1070,6 @@ private:
*****************************************************************************/
nsCacheService * nsCacheService::gService = nullptr;
static nsCOMPtr<nsIMemoryReporter> MemoryCacheReporter = nullptr;
NS_THREADSAFE_MEMORY_REPORTER_IMPLEMENT(NetworkMemoryCache,
"explicit/network/memory-cache",
KIND_HEAP,
UNITS_BYTES,
nsCacheService::MemoryDeviceSize,
"Memory used by the network memory cache.")
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(NetworkDiskCacheMallocSizeOf)
static nsCOMPtr<nsIMemoryReporter> DiskCacheReporter = nullptr;
NS_THREADSAFE_MEMORY_REPORTER_IMPLEMENT(NetworkDiskCache,
"explicit/network/disk-cache",
KIND_HEAP,
UNITS_BYTES,
nsCacheService::DiskDeviceHeapSize,
"Memory used by the network disk cache.")
NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheService, nsICacheService)
nsCacheService::nsCacheService()
@ -1244,14 +1223,6 @@ nsCacheService::Shutdown()
// obtain the disk cache directory in case we need to sanitize it
parentDir = mObserver->DiskCacheParentDirectory();
shouldSanitize = mObserver->SanitizeAtShutdown();
// unregister memory reporters, before deleting the devices, just
// to be safe
NS_UnregisterMemoryReporter(MemoryCacheReporter);
MemoryCacheReporter = nullptr;
NS_UnregisterMemoryReporter(DiskCacheReporter);
DiskCacheReporter = nullptr;
// deallocate memory and disk caches
delete mMemoryDevice;
@ -1566,7 +1537,7 @@ nsCacheService::CreateDiskDevice()
mDiskDevice->SetCacheParentDirectory(mObserver->DiskCacheParentDirectory());
mDiskDevice->SetCapacity(mObserver->DiskCacheCapacity());
mDiskDevice->SetMaxEntrySize(mObserver->DiskCacheMaxEntrySize());
nsresult rv = mDiskDevice->Init();
if (NS_FAILED(rv)) {
#if DEBUG
@ -1575,7 +1546,7 @@ nsCacheService::CreateDiskDevice()
static_cast<uint32_t>(rv));
printf("### - disabling disk cache for this session.\n");
printf("###\n");
#endif
#endif
mEnableDiskDevice = false;
delete mDiskDevice;
mDiskDevice = nullptr;
@ -1605,9 +1576,6 @@ nsCacheService::CreateDiskDevice()
// Ignore state of the timer and return success since the purpose of the
// method (create the disk-device) has been fulfilled
DiskCacheReporter = new NS_MEMORY_REPORTER_NAME(NetworkDiskCache);
NS_RegisterMemoryReporter(DiskCacheReporter);
return NS_OK;
}
@ -1773,10 +1741,6 @@ nsCacheService::CreateMemoryDevice()
mMemoryDevice = nullptr;
}
MemoryCacheReporter =
new NS_MEMORY_REPORTER_NAME(NetworkMemoryCache);
NS_RegisterMemoryReporter(MemoryCacheReporter);
return rv;
}
@ -2274,21 +2238,6 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry)
return device;
}
int64_t
nsCacheService::MemoryDeviceSize()
{
nsMemoryCacheDevice *memoryDevice = GlobalInstance()->mMemoryDevice;
return memoryDevice ? memoryDevice->TotalSize() : 0;
}
int64_t
nsCacheService::DiskDeviceHeapSize()
{
nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_DISKDEVICEHEAPSIZE));
nsDiskCacheDevice *diskDevice = GlobalInstance()->mDiskDevice;
return (int64_t)(diskDevice ? diskDevice->SizeOfIncludingThis(NetworkDiskCacheMallocSizeOf) : 0);
}
nsresult
nsCacheService::DoomEntry(nsCacheEntry * entry)
{

View File

@ -1,10 +1,9 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsCacheService_h_
#define _nsCacheService_h_
@ -66,7 +65,7 @@ class nsCacheService : public nsICacheService
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICACHESERVICE
nsCacheService();
virtual ~nsCacheService();
@ -130,10 +129,6 @@ public:
static
nsCacheService * GlobalInstance() { return gService; }
static int64_t MemoryDeviceSize();
static int64_t DiskDeviceHeapSize();
static nsresult DoomEntry(nsCacheEntry * entry);
static bool IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy policy);
@ -316,9 +311,9 @@ private:
*/
static nsCacheService * gService; // there can be only one...
nsCacheProfilePrefObserver * mObserver;
mozilla::Mutex mLock;
mozilla::CondVar mCondVar;
@ -326,10 +321,10 @@ private:
nsTArray<nsISupports*> mDoomedObjects;
nsCOMPtr<nsITimer> mSmartSizeTimer;
bool mInitialized;
bool mClearingEntries;
bool mEnableMemoryDevice;
bool mEnableDiskDevice;
bool mEnableOfflineDevice;
@ -344,7 +339,7 @@ private:
PRCList mDoomedEntries;
// stats
uint32_t mTotalEntries;
uint32_t mCacheHits;
uint32_t mCacheMisses;

View File

@ -9,6 +9,7 @@
#include "mozilla/DebugOnly.h"
#include "nsCache.h"
#include "nsIMemoryReporter.h"
// include files for ftruncate (or equivalent)
#if defined(XP_UNIX)
@ -368,16 +369,43 @@ nsDiskCache::Truncate(PRFileDesc * fd, uint32_t newEOF)
* nsDiskCacheDevice
*****************************************************************************/
class NetworkDiskCacheReporter MOZ_FINAL : public MemoryReporterBase
{
public:
NetworkDiskCacheReporter(nsDiskCacheDevice* aDevice)
: MemoryReporterBase(
"explicit/network/disk-cache",
KIND_HEAP,
UNITS_BYTES,
"Memory used by the network disk cache.")
, mDevice(aDevice)
{}
private:
int64_t Amount()
{
nsCacheServiceAutoLock
lock(LOCK_TELEM(NSCACHESERVICE_DISKDEVICEHEAPSIZE));
return mDevice->SizeOfIncludingThis(MallocSizeOf);
}
nsDiskCacheDevice* mDevice;
};
nsDiskCacheDevice::nsDiskCacheDevice()
: mCacheCapacity(0)
, mMaxEntrySize(-1) // -1 means "no limit"
, mInitialized(false)
, mClearingDiskCache(false)
, mReporter(nullptr)
{
mReporter = new NetworkDiskCacheReporter(this);
NS_RegisterMemoryReporter(mReporter);
}
nsDiskCacheDevice::~nsDiskCacheDevice()
{
NS_UnregisterMemoryReporter(mReporter);
Shutdown();
}

View File

@ -17,6 +17,7 @@
#include "nsCOMArray.h"
class nsDiskCacheMap;
class nsIMemoryReporter;
class nsDiskCacheDevice : public nsCacheDevice {
@ -110,6 +111,8 @@ private:
nsDiskCacheMap mCacheMap;
bool mInitialized;
bool mClearingDiskCache;
nsCOMPtr<nsIMemoryReporter> mReporter;
};
#endif // _nsDiskCacheDevice_h_

View File

@ -1,6 +1,6 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -8,8 +8,9 @@
#include "nsMemoryCacheDevice.h"
#include "nsCacheService.h"
#include "nsICacheService.h"
#include "nsIStorageStream.h"
#include "nsICacheVisitor.h"
#include "nsIStorageStream.h"
#include "nsIMemoryReporter.h"
#include "nsCRT.h"
#include "nsReadableUtils.h"
#include "mozilla/Telemetry.h"
@ -26,6 +27,26 @@
const char *gMemoryDeviceID = "memory";
class NetworkMemoryCacheReporter MOZ_FINAL :
public mozilla::MemoryReporterBase
{
public:
NetworkMemoryCacheReporter(nsMemoryCacheDevice* aDevice)
: MemoryReporterBase(
"explicit/network/memory-cache",
KIND_HEAP,
UNITS_BYTES,
"Memory used by the network memory cache.")
, mDevice(aDevice)
{}
private:
int64_t Amount() { return mDevice->TotalSize(); }
nsMemoryCacheDevice* mDevice;
};
nsMemoryCacheDevice::nsMemoryCacheDevice()
: mInitialized(false),
mHardLimit(4 * 1024 * 1024), // default, if no pref
@ -34,15 +55,20 @@ nsMemoryCacheDevice::nsMemoryCacheDevice()
mInactiveSize(0),
mEntryCount(0),
mMaxEntryCount(0),
mMaxEntrySize(-1) // -1 means "no limit"
mMaxEntrySize(-1), // -1 means "no limit"
mReporter(nullptr)
{
for (int i=0; i<kQueueCount; ++i)
PR_INIT_CLIST(&mEvictionList[i]);
mReporter = new NetworkMemoryCacheReporter(this);
NS_RegisterMemoryReporter(mReporter);
}
nsMemoryCacheDevice::~nsMemoryCacheDevice()
{
{
NS_UnregisterMemoryReporter(mReporter);
Shutdown();
}

View File

@ -1,6 +1,6 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -12,6 +12,7 @@
#include "nsCacheEntry.h"
class nsIMemoryReporter;
class nsMemoryCacheDeviceInfo;
/******************************************************************************
@ -99,6 +100,8 @@ private:
int32_t mMaxEntrySize; // internal unit is bytes
// XXX what other stats do we want to keep?
nsCOMPtr<nsIMemoryReporter> mReporter;
};

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set cindent tabstop=4 expandtab shiftwidth=4: */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -1041,6 +1041,8 @@ struct nsCycleCollector
CC_BeforeUnlinkCallback mBeforeUnlinkCB;
CC_ForgetSkippableCallback mForgetSkippableCB;
nsCOMPtr<nsIMemoryMultiReporter> mReporter;
nsPurpleBuffer mPurpleBuf;
void RegisterJSRuntime(nsCycleCollectionJSRuntime *aJSRuntime);
@ -1139,7 +1141,6 @@ public:
static nsCycleCollector *sCollector = nullptr;
static nsIMemoryMultiReporter *sCollectorReporter = nullptr;
////////////////////////////////////////////////////////////////////////
@ -2440,6 +2441,87 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
}
////////////////////////
// Memory reporter
////////////////////////
class CycleCollectorMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter
{
public:
CycleCollectorMultiReporter(nsCycleCollector* aCollector)
: mCollector(aCollector)
{}
NS_DECL_ISUPPORTS
NS_IMETHOD GetName(nsACString& name)
{
name.AssignLiteral("cycle-collector");
return NS_OK;
}
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback* aCb,
nsISupports* aClosure)
{
size_t objectSize, graphNodesSize, graphEdgesSize, whiteNodesSize,
purpleBufferSize;
mCollector->SizeOfIncludingThis(MallocSizeOf,
&objectSize, &graphNodesSize,
&graphEdgesSize, &whiteNodesSize,
&purpleBufferSize);
#define REPORT(_path, _amount, _desc) \
do { \
size_t amount = _amount; /* evaluate |_amount| only once */ \
if (amount > 0) { \
nsresult rv; \
rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
nsIMemoryReporter::KIND_HEAP, \
nsIMemoryReporter::UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), aClosure); \
NS_ENSURE_SUCCESS(rv, rv); \
} \
} while (0)
REPORT("explicit/cycle-collector/collector-object", objectSize,
"Memory used for the cycle collector object itself.");
REPORT("explicit/cycle-collector/graph-nodes", graphNodesSize,
"Memory used for the nodes of the cycle collector's graph. "
"This should be zero when the collector is idle.");
REPORT("explicit/cycle-collector/graph-edges", graphEdgesSize,
"Memory used for the edges of the cycle collector's graph. "
"This should be zero when the collector is idle.");
REPORT("explicit/cycle-collector/white-nodes", whiteNodesSize,
"Memory used for the cycle collector's white nodes array. "
"This should be zero when the collector is idle.");
REPORT("explicit/cycle-collector/purple-buffer", purpleBufferSize,
"Memory used for the cycle collector's purple buffer.");
#undef REPORT
return NS_OK;
}
NS_IMETHOD GetExplicitNonHeap(int64_t* n)
{
// This reporter does neither "explicit" nor NONHEAP measurements.
*n = 0;
return NS_OK;
}
private:
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
nsCycleCollector* mCollector;
};
NS_IMPL_ISUPPORTS1(CycleCollectorMultiReporter, nsIMemoryMultiReporter)
////////////////////////////////////////////////////////////////////////
// Collector implementation
////////////////////////////////////////////////////////////////////////
@ -2455,6 +2537,7 @@ nsCycleCollector::nsCycleCollector() :
mVisitedGCed(0),
mBeforeUnlinkCB(nullptr),
mForgetSkippableCB(nullptr),
mReporter(nullptr),
#ifdef DEBUG_CC
mPurpleBuf(mParams, mStats),
mPtrLog(nullptr)
@ -2470,10 +2553,11 @@ nsCycleCollector::nsCycleCollector() :
nsCycleCollector::~nsCycleCollector()
{
NS_UnregisterMemoryMultiReporter(mReporter);
}
void
void
nsCycleCollector::RegisterJSRuntime(nsCycleCollectionJSRuntime *aJSRuntime)
{
if (mParams.mDoNothing)
@ -2483,9 +2567,18 @@ nsCycleCollector::RegisterJSRuntime(nsCycleCollectionJSRuntime *aJSRuntime)
Fault("multiple registrations of cycle collector JS runtime", aJSRuntime);
mJSRuntime = aJSRuntime;
// We can't register the reporter in nsCycleCollector() because that runs
// before the memory reporter manager is initialized. So we do it here
// instead.
static bool registered = false;
if (!registered) {
NS_RegisterMemoryMultiReporter(new CycleCollectorMultiReporter(this));
registered = true;
}
}
void
void
nsCycleCollector::ForgetJSRuntime()
{
if (mParams.mDoNothing)
@ -3023,13 +3116,6 @@ nsCycleCollector::WasFreed(nsISupports *n)
}
#endif
////////////////////////
// Memory reporter
////////////////////////
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(CycleCollectorMallocSizeOf)
void
nsCycleCollector::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
size_t *aObjectSize,
@ -3057,73 +3143,6 @@ nsCycleCollector::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
// - mStats, mPtrLog, mExpectedGarbage: because they're DEBUG_CC-only.
}
class CycleCollectorMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter
{
public:
NS_DECL_ISUPPORTS
NS_IMETHOD GetName(nsACString &name)
{
name.AssignLiteral("cycle-collector");
return NS_OK;
}
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *aCb,
nsISupports *aClosure)
{
if (!sCollector)
return NS_OK;
size_t objectSize, graphNodesSize, graphEdgesSize, whiteNodesSize,
purpleBufferSize;
sCollector->SizeOfIncludingThis(CycleCollectorMallocSizeOf,
&objectSize, &graphNodesSize,
&graphEdgesSize, &whiteNodesSize,
&purpleBufferSize);
#define REPORT(_path, _amount, _desc) \
do { \
size_t amount = _amount; /* evaluate |_amount| just once */ \
if (amount > 0) { \
nsresult rv; \
rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
nsIMemoryReporter::KIND_HEAP, \
nsIMemoryReporter::UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), aClosure); \
NS_ENSURE_SUCCESS(rv, rv); \
} \
} while (0)
REPORT("explicit/cycle-collector/collector-object", objectSize,
"Memory used for the cycle collector object itself.");
REPORT("explicit/cycle-collector/graph-nodes", graphNodesSize,
"Memory used for the nodes of the cycle collector's graph. "
"This should be zero when the collector is idle.");
REPORT("explicit/cycle-collector/graph-edges", graphEdgesSize,
"Memory used for the edges of the cycle collector's graph. "
"This should be zero when the collector is idle.");
REPORT("explicit/cycle-collector/white-nodes", whiteNodesSize,
"Memory used for the cycle collector's white nodes array. "
"This should be zero when the collector is idle.");
REPORT("explicit/cycle-collector/purple-buffer", purpleBufferSize,
"Memory used for the cycle collector's purple buffer.");
return NS_OK;
}
NS_IMETHOD GetExplicitNonHeap(int64_t *n)
{
// This reporter does neither "explicit" nor NONHEAP measurements.
*n = 0;
return NS_OK;
}
};
NS_IMPL_ISUPPORTS1(CycleCollectorMultiReporter, nsIMemoryMultiReporter)
////////////////////////////////////////////////////////////////////////
// Module public API (exported in nsCycleCollector.h)
@ -3133,14 +3152,8 @@ NS_IMPL_ISUPPORTS1(CycleCollectorMultiReporter, nsIMemoryMultiReporter)
void
nsCycleCollector_registerJSRuntime(nsCycleCollectionJSRuntime *rt)
{
static bool regMemReport = true;
if (sCollector)
sCollector->RegisterJSRuntime(rt);
if (regMemReport) {
regMemReport = false;
sCollectorReporter = new CycleCollectorMultiReporter;
NS_RegisterMemoryMultiReporter(sCollectorReporter);
}
}
void
@ -3148,10 +3161,6 @@ nsCycleCollector_forgetJSRuntime()
{
if (sCollector)
sCollector->ForgetJSRuntime();
if (sCollectorReporter) {
NS_UnregisterMemoryMultiReporter(sCollectorReporter);
sCollectorReporter = nullptr;
}
}
nsPurpleBufferEntry*

View File

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -304,9 +305,13 @@ interface nsIMemoryReporterManager : nsISupports
%{C++
/*
* Note that this defaults 'process' to "", which is usually what's desired.
*/
#include "nsStringGlue.h"
// The NS_*MEMORY_REPORTER_IMPLEMENT* macros are the deprecated short-cut way
// of defining memory reporters. You should instead subclass the
// MemoryReporterBase class below.
// Note that this defaults 'process' to "", which is usually what's desired.
#define NS_MEMORY_REPORTER_IMPLEMENT_HELPER(_classname, _path, _kind, _units, _amountFunction, _desc, _ts) \
class MemoryReporter_##_classname MOZ_FINAL : public nsIMemoryReporter { \
public: \
@ -320,20 +325,18 @@ interface nsIMemoryReporterManager : nsISupports
}; \
NS_IMPL##_ts##ISUPPORTS1(MemoryReporter_##_classname, nsIMemoryReporter)
/*
* The only difference between this and NS_MEMORY_REPORTER_IMPLEMENT_HELPER
* is that the function used to implement GetAmount is fallible.
*/
// The only difference between this and NS_MEMORY_REPORTER_IMPLEMENT_HELPER
// is that the function used to implement GetAmount is fallible.
#define NS_FALLIBLE_MEMORY_REPORTER_IMPLEMENT_HELPER(_classname, _path, _kind, _units, _amountFunction, _desc, _ts) \
class MemoryReporter_##_classname MOZ_FINAL : public nsIMemoryReporter { \
public: \
NS_DECL_ISUPPORTS \
NS_IMETHOD GetProcess(nsACString &process) { process.Truncate(); return NS_OK; } \
NS_IMETHOD GetPath(nsACString &memoryPath) { memoryPath.AssignLiteral(_path); return NS_OK; } \
NS_IMETHOD GetKind(int *kind) { *kind = _kind; return NS_OK; } \
NS_IMETHOD GetUnits(int *units) { *units = _units; return NS_OK; } \
NS_IMETHOD GetKind(int32_t *kind) { *kind = _kind; return NS_OK; } \
NS_IMETHOD GetUnits(int32_t *units) { *units = _units; return NS_OK; } \
NS_IMETHOD GetAmount(int64_t *amount) { return _amountFunction(amount); } \
NS_IMETHOD GetDescription(nsACString &desc) { desc.AssignLiteral(_desc); return NS_OK; } \
NS_IMETHOD GetDescription(nsACString &desc) { desc.AssignLiteral(_desc); return NS_OK; }\
}; \
NS_IMPL##_ts##ISUPPORTS1(MemoryReporter_##_classname, nsIMemoryReporter)
@ -421,4 +424,82 @@ void RunReporters();
return moz_malloc_size_of(ptr); \
}
namespace mozilla {
// The following base class reduces the amount of boilerplate code required for
// memory reporters. You just need to provide the following.
// - The constant values: path, kind, units, and description. They are passed
// to the MemoryReporterBase constructor.
// - An Amount() method. It can use the MallocSizeOf method if necessary.
//
// The class name of subclasses should match the path, minus the "explicit"
// (if present), and with "Reporter" at the end. For example:
// - "explicit/dom/xyzzy" --> DOMXyzzyReporter
// - "js-compartments/system" --> JSCompartmentsSystemReporter
//
class MemoryReporterBase : public nsIMemoryReporter
{
public:
MemoryReporterBase(const char* aPath, int32_t aKind, int32_t aUnits,
const char* aDescription)
: mPath(aPath)
, mKind(aKind)
, mUnits(aUnits)
, mDescription(aDescription)
{}
virtual ~MemoryReporterBase() {}
NS_DECL_ISUPPORTS
NS_IMETHOD GetProcess(nsACString& aProcess)
{
aProcess.Truncate();
return NS_OK;
}
NS_IMETHOD GetPath(nsACString& aPath)
{
aPath.Assign(mPath);
return NS_OK;
}
NS_IMETHOD GetKind(int32_t* aKind)
{
*aKind = mKind;
return NS_OK;
}
NS_IMETHOD GetUnits(int32_t* aUnits)
{
*aUnits = mUnits;
return NS_OK;
}
NS_IMETHOD GetAmount(int64_t* aAmount)
{
*aAmount = Amount();
return NS_OK;
}
NS_IMETHOD GetDescription(nsACString& aDescription)
{
aDescription.Assign(mDescription);
return NS_OK;
}
protected:
virtual int64_t Amount() = 0;
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
const nsCString mPath;
const int32_t mKind;
const int32_t mUnits;
const nsCString mDescription;
};
} // namespace mozilla
%}

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=4 et sw=4 tw=80: */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -1067,8 +1067,8 @@ NS_IMETHODIMP nsMemoryReporter::GetKind(int32_t *aKind)
NS_IMETHODIMP nsMemoryReporter::GetUnits(int32_t *aUnits)
{
*aUnits = mUnits;
return NS_OK;
*aUnits = mUnits;
return NS_OK;
}
NS_IMETHODIMP nsMemoryReporter::GetAmount(int64_t *aAmount)
@ -1083,6 +1083,11 @@ NS_IMETHODIMP nsMemoryReporter::GetDescription(nsACString &aDescription)
return NS_OK;
}
// Most memory reporters don't need thread safety, but some do. Make them all
// thread-safe just to be safe. Memory reporters are created and destroyed
// infrequently enough that the performance cost should be negligible.
NS_IMPL_THREADSAFE_ISUPPORTS1(MemoryReporterBase, nsIMemoryReporter)
nsresult
NS_RegisterMemoryReporter (nsIMemoryReporter *reporter)
{