From dc051e917dbee3626249eb995d16c600a7bc2ef1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Jan 2013 16:26:47 -0800 Subject: [PATCH] Bug 829439 (part 1) - Add MemoryReporterBase class that promotes better encapsulation within nsIMemoryReporter sub-classes. r=jlebar. --HG-- extra : rebase_source : 53a77ea456f2aedafe05954ceece7e64db743e66 --- content/base/src/nsContentUtils.cpp | 47 +++-- .../canvas/src/CanvasRenderingContext2D.cpp | 8 +- dom/base/nsJSEnvironment.cpp | 30 +-- dom/base/nsScriptNameSpaceManager.cpp | 25 ++- dom/base/nsScriptNameSpaceManager.h | 9 +- netwerk/cache/nsCacheService.cpp | 59 +----- netwerk/cache/nsCacheService.h | 23 +-- netwerk/cache/nsDiskCacheDevice.cpp | 28 +++ netwerk/cache/nsDiskCacheDevice.h | 3 + netwerk/cache/nsMemoryCacheDevice.cpp | 38 +++- netwerk/cache/nsMemoryCacheDevice.h | 9 +- xpcom/base/nsCycleCollector.cpp | 185 +++++++++--------- xpcom/base/nsIMemoryReporter.idl | 103 ++++++++-- xpcom/base/nsMemoryReporterManager.cpp | 13 +- 14 files changed, 339 insertions(+), 241 deletions(-) diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index e0967d2cdff..9dfe722df2b 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -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 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 >; @@ -1487,9 +1489,6 @@ nsContentUtils::Shutdown() if (sEventListenerManagersHash.entryCount == 0) { PL_DHashTableFinish(&sEventListenerManagersHash); sEventListenerManagersHash.ops = nullptr; - - (void)::NS_UnregisterMemoryReporter(sEventListenerManagersHashReporter); - sEventListenerManagersHashReporter = nullptr; } } diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index 123f01fc783..10ada20ce0a 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -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; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 849ae739d88..5458097916f 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -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 diff --git a/dom/base/nsScriptNameSpaceManager.cpp b/dom/base/nsScriptNameSpaceManager.cpp index 09cf954e4da..f73bb9e6bf6 100644 --- a/dom/base/nsScriptNameSpaceManager.cpp +++ b/dom/base/nsScriptNameSpaceManager.cpp @@ -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(); diff --git a/dom/base/nsScriptNameSpaceManager.h b/dom/base/nsScriptNameSpaceManager.h index a613df9ef4e..913488d30a3 100644 --- a/dom/base/nsScriptNameSpaceManager.h +++ b/dom/base/nsScriptNameSpaceManager.h @@ -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 mReporter; }; #endif /* nsScriptNameSpaceManager_h__ */ diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index ce9f73023f8..110fded019b 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -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 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 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(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) { diff --git a/netwerk/cache/nsCacheService.h b/netwerk/cache/nsCacheService.h index d05b62fe26d..e008b7fa668 100644 --- a/netwerk/cache/nsCacheService.h +++ b/netwerk/cache/nsCacheService.h @@ -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 mDoomedObjects; nsCOMPtr 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; diff --git a/netwerk/cache/nsDiskCacheDevice.cpp b/netwerk/cache/nsDiskCacheDevice.cpp index 5b92d0bc342..6ebdbd5d6cf 100644 --- a/netwerk/cache/nsDiskCacheDevice.cpp +++ b/netwerk/cache/nsDiskCacheDevice.cpp @@ -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(); } diff --git a/netwerk/cache/nsDiskCacheDevice.h b/netwerk/cache/nsDiskCacheDevice.h index c402b1c6293..88f822314ee 100644 --- a/netwerk/cache/nsDiskCacheDevice.h +++ b/netwerk/cache/nsDiskCacheDevice.h @@ -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 mReporter; }; #endif // _nsDiskCacheDevice_h_ diff --git a/netwerk/cache/nsMemoryCacheDevice.cpp b/netwerk/cache/nsMemoryCacheDevice.cpp index 050ab47a8e5..23c8a8925d9 100644 --- a/netwerk/cache/nsMemoryCacheDevice.cpp +++ b/netwerk/cache/nsMemoryCacheDevice.cpp @@ -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 mReporter; }; diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 80e1290c55f..f43dbd1c1db 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -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 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* diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 35b59f76536..5e8ad151552 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -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 + + %} diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index db708221b79..fee97b68617 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -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) {