--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -248,16 +248,31 @@ private:
};
struct PrefHashEntry : PLDHashEntryHdr
{
PrefTypeFlags mPrefFlags; // this field first to minimize 64-bit struct size
const char* mKey;
PrefValue mDefaultPref;
PrefValue mUserPref;
+
+ size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)
+ {
+ // Note: mKey is allocated in gPrefNameArena, measured elsewhere.
+ size_t n = 0;
+ if (mPrefFlags.IsTypeString()) {
+ if (mPrefFlags.HasDefault()) {
+ n += aMallocSizeOf(mDefaultPref.mStringVal);
+ }
+ if (mPrefFlags.HasUserValue()) {
+ n += aMallocSizeOf(mUserPref.mStringVal);
+ }
+ }
+ return n;
+ }
};
static void
ClearPrefEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
{
auto pref = static_cast<PrefHashEntry*>(aEntry);
if (pref->mPrefFlags.IsTypeString()) {
free(const_cast<char*>(pref->mDefaultPref.mStringVal));
@@ -1951,16 +1966,26 @@ public:
{
if (!IsWeak())
return false;
nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef));
return !observer;
}
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+ {
+ size_t n = aMallocSizeOf(this);
+ n += mDomain.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+
+ // All the other fields are non-owning pointers, so we don't measure them.
+
+ return n;
+ }
+
enum
{
ALLOW_MEMMOVE = true
};
private:
nsCString mDomain;
nsPrefBranch* mBranch;
@@ -1989,17 +2014,17 @@ public:
nsPrefBranch(const char* aPrefRoot, bool aDefaultBranch);
nsPrefBranch() = delete;
int32_t GetRootLength() const { return mPrefRoot.Length(); }
static void NotifyObserver(const char* aNewpref, void* aData);
- size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
static void ReportToConsole(const nsAString& aMessage);
private:
// Helper class for either returning a raw cstring or nsCString.
typedef mozilla::Variant<const char*, const nsCString> PrefNameBase;
class PrefName : public PrefNameBase
{
@@ -2916,21 +2941,28 @@ nsPrefBranch::NotifyObserver(const char*
nsAutoCString suffix(aNewPref + len);
observer->Observe(static_cast<nsIPrefBranch*>(pCallback->GetPrefBranch()),
NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
NS_ConvertASCIItoUTF16(suffix).get());
}
size_t
-nsPrefBranch::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+nsPrefBranch::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
+
n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+
n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ for (auto iter = mObservers.ConstIter(); !iter.Done(); iter.Next()) {
+ const PrefCallback* data = iter.UserData();
+ n += data->SizeOfIncludingThis(aMallocSizeOf);
+ }
+
return n;
}
void
nsPrefBranch::FreeObserverList()
{
// We need to prevent anyone from modifying mObservers while we're iterating
// over it. In particular, some clients will call RemoveObserver() when
@@ -3342,55 +3374,55 @@ ReportToConsole(const char* aMessage, in
{
nsPrintfCString message("** Preference parsing %s (line %d) = %s **\n",
(aError ? "error" : "warning"),
aLine,
aMessage);
nsPrefBranch::ReportToConsole(NS_ConvertUTF8toUTF16(message.get()));
}
+struct PrefsSizes
+{
+ PrefsSizes()
+ : mHashTable(0)
+ , mStringValues(0)
+ , mCacheData(0)
+ , mRootBranches(0)
+ , mPrefNameArena(0)
+ , mCallbacks(0)
+ , mMisc(0)
+ {
+ }
+
+ size_t mHashTable;
+ size_t mStringValues;
+ size_t mCacheData;
+ size_t mRootBranches;
+ size_t mPrefNameArena;
+ size_t mCallbacks;
+ size_t mMisc;
+};
+
// Although this is a member of Preferences, it measures sPreferences and
// several other global structures.
-/* static */ int64_t
-Preferences::SizeOfIncludingThisAndOtherStuff(
- mozilla::MallocSizeOf aMallocSizeOf)
-{
- NS_ENSURE_TRUE(InitStaticMembers(), 0);
-
- size_t n = aMallocSizeOf(sPreferences);
- if (gHashTable) {
- // Pref keys are allocated in a private arena, which we count elsewhere.
- // Pref stringvals are allocated out of the same private arena.
- n += gHashTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
- }
-
- if (gCacheData) {
- n += gCacheData->ShallowSizeOfIncludingThis(aMallocSizeOf);
- for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
- n += aMallocSizeOf((*gCacheData)[i]);
- }
- }
-
- if (sPreferences->mRootBranch) {
- n += static_cast<nsPrefBranch*>(sPreferences->mRootBranch.get())
- ->SizeOfIncludingThis(aMallocSizeOf);
- }
-
- if (sPreferences->mDefaultRootBranch) {
- n += static_cast<nsPrefBranch*>(sPreferences->mDefaultRootBranch.get())
- ->SizeOfIncludingThis(aMallocSizeOf);
- }
-
- n += gPrefNameArena.SizeOfExcludingThis(aMallocSizeOf);
- for (CallbackNode* node = gFirstCallback; node; node = node->mNext) {
- n += aMallocSizeOf(node);
- n += aMallocSizeOf(node->mDomain);
- }
-
- return n;
+/* static */ void
+Preferences::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+ PrefsSizes& aSizes)
+{
+ if (!sPreferences) {
+ return;
+ }
+
+ aSizes.mMisc += aMallocSizeOf(sPreferences.get());
+
+ aSizes.mRootBranches +=
+ static_cast<nsPrefBranch*>(sPreferences->mRootBranch.get())
+ ->SizeOfIncludingThis(aMallocSizeOf) +
+ static_cast<nsPrefBranch*>(sPreferences->mDefaultRootBranch.get())
+ ->SizeOfIncludingThis(aMallocSizeOf);
}
class PreferenceServiceReporter final : public nsIMemoryReporter
{
~PreferenceServiceReporter() {}
public:
NS_DECL_ISUPPORTS
@@ -3405,22 +3437,87 @@ NS_IMPL_ISUPPORTS(PreferenceServiceRepor
MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
NS_IMETHODIMP
PreferenceServiceReporter::CollectReports(
nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
bool aAnonymize)
{
- MOZ_COLLECT_REPORT("explicit/preferences",
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MallocSizeOf mallocSizeOf = PreferenceServiceMallocSizeOf;
+ PrefsSizes sizes;
+
+ Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes);
+
+ if (gHashTable) {
+ sizes.mHashTable += gHashTable->ShallowSizeOfIncludingThis(mallocSizeOf);
+ for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+ auto entry = static_cast<PrefHashEntry*>(iter.Get());
+ sizes.mStringValues += entry->SizeOfExcludingThis(mallocSizeOf);
+ }
+ }
+
+ if (gCacheData) {
+ sizes.mCacheData += gCacheData->ShallowSizeOfIncludingThis(mallocSizeOf);
+ for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
+ sizes.mCacheData += mallocSizeOf((*gCacheData)[i]);
+ }
+ }
+
+ sizes.mPrefNameArena += gPrefNameArena.SizeOfExcludingThis(mallocSizeOf);
+
+ for (CallbackNode* node = gFirstCallback; node; node = node->mNext) {
+ sizes.mCallbacks += mallocSizeOf(node);
+ sizes.mCallbacks += mallocSizeOf(node->mDomain);
+ }
+
+ MOZ_COLLECT_REPORT("explicit/preferences/hash-table",
KIND_HEAP,
UNITS_BYTES,
- Preferences::SizeOfIncludingThisAndOtherStuff(
- PreferenceServiceMallocSizeOf),
- "Memory used by the preferences system.");
+ sizes.mHashTable,
+ "Memory used by libpref's hash table.");
+
+ MOZ_COLLECT_REPORT("explicit/preferences/string-values",
+ KIND_HEAP,
+ UNITS_BYTES,
+ sizes.mStringValues,
+ "Memory used by libpref's string pref values.");
+
+ MOZ_COLLECT_REPORT("explicit/preferences/cache-data",
+ KIND_HEAP,
+ UNITS_BYTES,
+ sizes.mCacheData,
+ "Memory used by libpref's VarCaches.");
+
+ MOZ_COLLECT_REPORT("explicit/preferences/root-branches",
+ KIND_HEAP,
+ UNITS_BYTES,
+ sizes.mRootBranches,
+ "Memory used by libpref's root branches.");
+
+ MOZ_COLLECT_REPORT("explicit/preferences/pref-name-arena",
+ KIND_HEAP,
+ UNITS_BYTES,
+ sizes.mPrefNameArena,
+ "Memory used by libpref's arena for pref names.");
+
+ MOZ_COLLECT_REPORT("explicit/preferences/callbacks",
+ KIND_HEAP,
+ UNITS_BYTES,
+ sizes.mCallbacks,
+ "Memory used by libpref's callbacks list, including "
+ "pref names and prefixes.");
+
+ MOZ_COLLECT_REPORT("explicit/preferences/misc",
+ KIND_HEAP,
+ UNITS_BYTES,
+ sizes.mMisc,
+ "Miscellaneous memory used by libpref.");
nsPrefBranch* rootBranch =
static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
if (!rootBranch) {
return NS_OK;
}
size_t numStrong = 0;
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -44,16 +44,18 @@ enum pref_initPhase
#endif
namespace mozilla {
namespace dom {
class PrefSetting;
} // namespace dom
+struct PrefsSizes;
+
class Preferences final
: public nsIPrefService
, public nsIObserver
, public nsIPrefBranch
, public nsSupportsWeakReference
{
public:
typedef mozilla::dom::PrefSetting PrefSetting;
@@ -299,18 +301,18 @@ public:
static void GetPreference(PrefSetting* aPref);
static void SetPreference(const PrefSetting& aPref);
#ifdef DEBUG
static void SetInitPhase(pref_initPhase phase);
static pref_initPhase InitPhase();
#endif
- static int64_t SizeOfIncludingThisAndOtherStuff(
- mozilla::MallocSizeOf aMallocSizeOf);
+ static void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+ PrefsSizes& aSizes);
static void HandleDirty();
// Explicitly choosing synchronous or asynchronous (if allowed) preferences
// file write. Only for the default file. The guarantee for the "blocking"
// is that when it returns, the file on disk reflect the current state of
// preferences.
nsresult SavePrefFileBlocking();