author | Mike Hommey <mh+mozilla@glandium.org> |
Tue, 18 Nov 2014 19:21:06 +0900 | |
changeset 242643 | 3c6bd176246d277649e7a73dd00f201cfa194fc6 |
parent 242642 | bd1cbced0ccb7963fcda09ede2cd17af4bd41de0 |
child 242644 | 3b2c7cb5dabed177b3e4950e10fe621313db8c5f |
push id | 660 |
push user | raliiev@mozilla.com |
push date | Wed, 18 Feb 2015 20:30:48 +0000 |
treeherder | mozilla-release@49e493494178 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | njn |
bugs | 1097507 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/memory/build/replace_malloc_bridge.h +++ b/memory/build/replace_malloc_bridge.h @@ -53,19 +53,28 @@ struct ReplaceMallocBridge; #include "mozilla/NullPtr.h" #include "mozilla/Types.h" #ifndef REPLACE_MALLOC_IMPL /* Returns the replace-malloc bridge if there is one to be returned. */ extern "C" MFBT_API ReplaceMallocBridge* get_bridge(); #endif +namespace mozilla { +namespace dmd { +struct DMDFuncs; +} +} + struct ReplaceMallocBridge { - ReplaceMallocBridge() : mVersion(0) {} + ReplaceMallocBridge() : mVersion(1) {} + + /* This method was added in version 1 of the bridge. */ + virtual mozilla::dmd::DMDFuncs* GetDMDFuncs() { return nullptr; } #ifndef REPLACE_MALLOC_IMPL /* Returns the replace-malloc bridge if its version is at least the * requested one. */ static ReplaceMallocBridge* Get(int aMinimumVersion) { static ReplaceMallocBridge* sSingleton = get_bridge(); return (sSingleton && sSingleton->mVersion >= aMinimumVersion) ? sSingleton : nullptr; @@ -80,14 +89,21 @@ protected: /* Class containing wrappers for calls to ReplaceMallocBridge methods. * Those wrappers need to be static methods in a class because compilers * complain about unused static global functions, and linkers complain * about multiple definitions of non-static global functions. * Using a separate class from ReplaceMallocBridge allows the function * names to be identical. */ struct ReplaceMalloc { + /* Don't call this method from performance critical code. Use + * mozilla::dmd::DMDFuncs::Get() instead, it has less overhead. */ + static mozilla::dmd::DMDFuncs* GetDMDFuncs() + { + auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 1); + return singleton ? singleton->GetDMDFuncs() : nullptr; + } }; #endif #endif /* __cplusplus */ #endif /* replace_malloc_bridge_h */
--- a/memory/replace/dmd/DMD.cpp +++ b/memory/replace/dmd/DMD.cpp @@ -1,16 +1,14 @@ /* -*- 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/. */ -#include "DMD.h" - #include <ctype.h> #include <errno.h> #include <limits.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -40,16 +38,18 @@ #include "mozilla/JSONWriter.h" #include "mozilla/Likely.h" #include "mozilla/MemoryReporting.h" // CodeAddressService is defined entirely in the header, so this does not make // DMD depend on XPCOM's object file. #include "CodeAddressService.h" +// replace_malloc.h needs to be included before replace_malloc_bridge.h, +// which DMD.h includes, so DMD.h needs to be included after replace_malloc.h. // MOZ_REPLACE_ONLY_MEMALIGN saves us from having to define // replace_{posix_memalign,aligned_alloc,valloc}. It requires defining // PAGE_SIZE. Nb: sysconf() is expensive, but it's only used for (the obsolete // and rarely used) valloc. #define MOZ_REPLACE_ONLY_MEMALIGN 1 #ifdef XP_WIN #define PAGE_SIZE GetPageSize() @@ -61,33 +61,58 @@ static long GetPageSize() } #else #define PAGE_SIZE sysconf(_SC_PAGESIZE) #endif #include "replace_malloc.h" #undef MOZ_REPLACE_ONLY_MEMALIGN #undef PAGE_SIZE +#include "DMD.h" + namespace mozilla { namespace dmd { +class DMDBridge : public ReplaceMallocBridge +{ + virtual DMDFuncs* GetDMDFuncs() MOZ_OVERRIDE; +}; + +static DMDBridge sDMDBridge; +static DMDFuncs sDMDFuncs; + +DMDFuncs* +DMDBridge::GetDMDFuncs() +{ + return &sDMDFuncs; +} + +inline void +StatusMsg(const char* aFmt, ...) +{ + va_list ap; + va_start(ap, aFmt); + sDMDFuncs.StatusMsg(aFmt, ap); + va_end(ap); +} + //--------------------------------------------------------------------------- // Utilities //--------------------------------------------------------------------------- #ifndef DISALLOW_COPY_AND_ASSIGN #define DISALLOW_COPY_AND_ASSIGN(T) \ T(const T&); \ void operator=(const T&) #endif static const malloc_table_t* gMallocTable = nullptr; -// This enables/disables DMD. -static bool gIsDMDRunning = false; +// Whether DMD finished initializing. +static bool gIsDMDInitialized = false; // This provides infallible allocations (they abort on OOM). We use it for all // of DMD's own allocations, which fall into the following three cases. // - Direct allocations (the easy case). // - Indirect allocations in js::{Vector,HashSet,HashMap} -- this class serves // as their AllocPolicy. // - Other indirect allocations (e.g. NS_StackWalk) -- see the comments on // Thread::mBlockIntercepts and in replace_malloc for how these work. @@ -192,36 +217,33 @@ public: // This is only needed because of the |const void*| vs |void*| arg mismatch. static size_t MallocSizeOf(const void* aPtr) { return gMallocTable->malloc_usable_size(const_cast<void*>(aPtr)); } -MOZ_EXPORT void -StatusMsg(const char* aFmt, ...) +void +DMDFuncs::StatusMsg(const char* aFmt, va_list aAp) { - va_list ap; - va_start(ap, aFmt); #ifdef ANDROID #ifdef MOZ_B2G_LOADER // Don't call __android_log_vprint() during initialization, or the magic file // descriptors will be occupied by android logcat. - if (gIsDMDRunning) + if (gIsDMDInitialized) #endif - __android_log_vprint(ANDROID_LOG_INFO, "DMD", aFmt, ap); + __android_log_vprint(ANDROID_LOG_INFO, "DMD", aFmt, aAp); #else // The +64 is easily enough for the "DMD[<pid>] " prefix and the NUL. char* fmt = (char*) InfallibleAllocPolicy::malloc_(strlen(aFmt) + 64); sprintf(fmt, "DMD[%d] %s", getpid(), aFmt); - vfprintf(stderr, fmt, ap); + vfprintf(stderr, fmt, aAp); InfallibleAllocPolicy::free_(fmt); #endif - va_end(ap); } /* static */ void InfallibleAllocPolicy::ExitOnFailure(const void* aP) { if (!aP) { MOZ_CRASH("DMD out of memory; aborting"); } @@ -949,18 +971,16 @@ GCStackTraces() // malloc/free callbacks //--------------------------------------------------------------------------- static size_t gSmallBlockActualSizeCounter = 0; static void AllocCallback(void* aPtr, size_t aReqSize, Thread* aT) { - MOZ_ASSERT(gIsDMDRunning); - if (!aPtr) { return; } AutoLockState lock; AutoBlockIntercepts block(aT); size_t actualSize = gMallocTable->malloc_usable_size(aPtr); @@ -983,18 +1003,16 @@ AllocCallback(void* aPtr, size_t aReqSiz Block b(aPtr, aReqSize, StackTrace::Get(aT), /* sampled */ false); (void)gBlockTable->putNew(aPtr, b); } } static void FreeCallback(void* aPtr, Thread* aT) { - MOZ_ASSERT(gIsDMDRunning); - if (!aPtr) { return; } AutoLockState lock; AutoBlockIntercepts block(aT); gBlockTable->remove(aPtr); @@ -1014,22 +1032,28 @@ static void Init(const malloc_table_t* a } // namespace mozilla void replace_init(const malloc_table_t* aMallocTable) { mozilla::dmd::Init(aMallocTable); } +ReplaceMallocBridge* +replace_get_bridge() +{ + return &mozilla::dmd::sDMDBridge; +} + void* replace_malloc(size_t aSize) { using namespace mozilla::dmd; - if (!gIsDMDRunning) { + if (!gIsDMDInitialized) { // DMD hasn't started up, either because it wasn't enabled by the user, or // we're still in Init() and something has indirectly called malloc. Do a // vanilla malloc. (In the latter case, if it fails we'll crash. But // OOM is highly unlikely so early on.) return gMallocTable->malloc(aSize); } Thread* t = Thread::Fetch(); @@ -1045,17 +1069,17 @@ replace_malloc(size_t aSize) return ptr; } void* replace_calloc(size_t aCount, size_t aSize) { using namespace mozilla::dmd; - if (!gIsDMDRunning) { + if (!gIsDMDInitialized) { return gMallocTable->calloc(aCount, aSize); } Thread* t = Thread::Fetch(); if (t->InterceptsAreBlocked()) { return InfallibleAllocPolicy::calloc_(aCount * aSize); } @@ -1064,17 +1088,17 @@ replace_calloc(size_t aCount, size_t aSi return ptr; } void* replace_realloc(void* aOldPtr, size_t aSize) { using namespace mozilla::dmd; - if (!gIsDMDRunning) { + if (!gIsDMDInitialized) { return gMallocTable->realloc(aOldPtr, aSize); } Thread* t = Thread::Fetch(); if (t->InterceptsAreBlocked()) { return InfallibleAllocPolicy::realloc_(aOldPtr, aSize); } @@ -1101,17 +1125,17 @@ replace_realloc(void* aOldPtr, size_t aS return ptr; } void* replace_memalign(size_t aAlignment, size_t aSize) { using namespace mozilla::dmd; - if (!gIsDMDRunning) { + if (!gIsDMDInitialized) { return gMallocTable->memalign(aAlignment, aSize); } Thread* t = Thread::Fetch(); if (t->InterceptsAreBlocked()) { return InfallibleAllocPolicy::memalign_(aAlignment, aSize); } @@ -1120,17 +1144,17 @@ replace_memalign(size_t aAlignment, size return ptr; } void replace_free(void* aPtr) { using namespace mozilla::dmd; - if (!gIsDMDRunning) { + if (!gIsDMDInitialized) { gMallocTable->free(aPtr); return; } Thread* t = Thread::Fetch(); if (t->InterceptsAreBlocked()) { return InfallibleAllocPolicy::free_(aPtr); } @@ -1261,21 +1285,18 @@ Options::Options(const char* aDMDEnvVar) } void Options::BadArg(const char* aArg) { StatusMsg("\n"); StatusMsg("Bad entry in the $DMD environment variable: '%s'.\n", aArg); StatusMsg("\n"); - StatusMsg("Valid values of $DMD are:\n"); - StatusMsg("- undefined or \"\" or \"0\", which disables DMD, or\n"); - StatusMsg("- \"1\", which enables it with the default options, or\n"); - StatusMsg("- a whitespace-separated list of |--option=val| entries, which\n"); - StatusMsg(" enables it with non-default options.\n"); + StatusMsg("$DMD must be a whitespace-separated list of |--option=val|\n"); + StatusMsg("entries.\n"); StatusMsg("\n"); StatusMsg("The following options are allowed; defaults are shown in [].\n"); StatusMsg(" --sample-below=<1..%d> Sample blocks smaller than this [%d]\n", int(mSampleBelowSize.mMax), int(mSampleBelowSize.mDefault)); StatusMsg(" (prime numbers are recommended)\n"); StatusMsg(" --max-frames=<1..%d> Max. depth of stack traces [%d]\n", int(mMaxFrames.mMax), @@ -1299,28 +1320,23 @@ NopStackWalkCallback(uint32_t aFrameNumb // WARNING: this function runs *very* early -- before all static initializers // have run. For this reason, non-scalar globals such as gStateLock and // gStackTraceTable are allocated dynamically (so we can guarantee their // construction in this function) rather than statically. static void Init(const malloc_table_t* aMallocTable) { - MOZ_ASSERT(!gIsDMDRunning); - gMallocTable = aMallocTable; // DMD is controlled by the |DMD| environment variable. - // - If it's unset or empty or "0", DMD doesn't run. - // - Otherwise, the contents dictate DMD's behaviour. + const char* e = getenv("DMD"); - char* e = getenv("DMD"); - - if (!e || strcmp(e, "") == 0 || strcmp(e, "0") == 0) { - return; + if (!e) { + e = "1"; } StatusMsg("$DMD = '%s'\n", e); // Parse $DMD env var. gOptions = InfallibleAllocPolicy::new_<Options>(e); #ifdef XP_MACOSX @@ -1345,27 +1361,27 @@ Init(const malloc_table_t* aMallocTable) gStackTraceTable = InfallibleAllocPolicy::new_<StackTraceTable>(); gStackTraceTable->init(8192); gBlockTable = InfallibleAllocPolicy::new_<BlockTable>(); gBlockTable->init(8192); } - gIsDMDRunning = true; + gIsDMDInitialized = true; } //--------------------------------------------------------------------------- // DMD reporting and unreporting //--------------------------------------------------------------------------- static void ReportHelper(const void* aPtr, bool aReportedOnAlloc) { - if (!gIsDMDRunning || !aPtr) { + if (!aPtr) { return; } Thread* t = Thread::Fetch(); AutoBlockIntercepts block(t); AutoLockState lock; @@ -1374,24 +1390,24 @@ ReportHelper(const void* aPtr, bool aRep } else { // We have no record of the block. Do nothing. Either: // - We're sampling and we skipped this block. This is likely. // - It's a bogus pointer. This is unlikely because Report() is almost // always called in conjunction with a malloc_size_of-style function. } } -MOZ_EXPORT void -Report(const void* aPtr) +void +DMDFuncs::Report(const void* aPtr) { ReportHelper(aPtr, /* onAlloc */ false); } -MOZ_EXPORT void -ReportOnAlloc(const void* aPtr) +void +DMDFuncs::ReportOnAlloc(const void* aPtr) { ReportHelper(aPtr, /* onAlloc */ true); } //--------------------------------------------------------------------------- // DMD output //--------------------------------------------------------------------------- @@ -1415,20 +1431,16 @@ static const int kOutputVersionNumber = static void SizeOfInternal(Sizes* aSizes) { MOZ_ASSERT(gStateLock->IsLocked()); MOZ_ASSERT(Thread::Fetch()->InterceptsAreBlocked()); aSizes->Clear(); - if (!gIsDMDRunning) { - return; - } - StackTraceSet usedStackTraces; GatherUsedStackTraces(usedStackTraces); for (StackTraceTable::Range r = gStackTraceTable->all(); !r.empty(); r.popFront()) { StackTrace* const& st = r.front(); @@ -1440,53 +1452,39 @@ SizeOfInternal(Sizes* aSizes) } aSizes->mStackTraceTable = gStackTraceTable->sizeOfIncludingThis(MallocSizeOf); aSizes->mBlockTable = gBlockTable->sizeOfIncludingThis(MallocSizeOf); } -MOZ_EXPORT void -SizeOf(Sizes* aSizes) +void +DMDFuncs::SizeOf(Sizes* aSizes) { aSizes->Clear(); - if (!gIsDMDRunning) { - return; - } - AutoBlockIntercepts block(Thread::Fetch()); AutoLockState lock; SizeOfInternal(aSizes); } -MOZ_EXPORT void -ClearReports() +void +DMDFuncs::ClearReports() { - if (!gIsDMDRunning) { - return; - } - AutoLockState lock; // Unreport all blocks that were marked reported by a memory reporter. This // excludes those that were reported on allocation, because they need to keep // their reported marking. for (BlockTable::Range r = gBlockTable->all(); !r.empty(); r.popFront()) { r.front().UnreportIfNotReportedOnAlloc(); } } -MOZ_EXPORT bool -IsRunning() -{ - return gIsDMDRunning; -} - class ToIdStringConverter MOZ_FINAL { public: ToIdStringConverter() : mNextId(0) { mIdMap.init(512); } // Converts a pointer to a unique ID. Reuses the existing ID for the pointer if // it's been seen before. const char* ToIdString(const void* aPtr) @@ -1546,20 +1544,16 @@ private: uint32_t mNextId; static const size_t kIdBufLen = 16; char mIdBuf[kIdBufLen]; }; static void AnalyzeReportsImpl(UniquePtr<JSONWriteFunc> aWriter) { - if (!gIsDMDRunning) { - return; - } - AutoBlockIntercepts block(Thread::Fetch()); AutoLockState lock; // Allocate this on the heap instead of the stack because it's fairly large. auto locService = InfallibleAllocPolicy::new_<CodeAddressService>(); StackTraceSet usedStackTraces; usedStackTraces.init(512); @@ -1722,34 +1716,34 @@ AnalyzeReportsImpl(UniquePtr<JSONWriteFu StatusMsg(" }\n"); } InfallibleAllocPolicy::delete_(locService); StatusMsg("}\n"); } -MOZ_EXPORT void -AnalyzeReports(UniquePtr<JSONWriteFunc> aWriter) +void +DMDFuncs::AnalyzeReports(UniquePtr<JSONWriteFunc> aWriter) { AnalyzeReportsImpl(Move(aWriter)); ClearReports(); } //--------------------------------------------------------------------------- // Testing //--------------------------------------------------------------------------- -MOZ_EXPORT void -SetSampleBelowSize(size_t aSize) +void +DMDFuncs::SetSampleBelowSize(size_t aSize) { gOptions->SetSampleBelowSize(aSize); } -MOZ_EXPORT void -ClearBlocks() +void +DMDFuncs::ClearBlocks() { gBlockTable->clear(); gSmallBlockActualSizeCounter = 0; } } // namespace dmd } // namespace mozilla
--- a/memory/replace/dmd/DMD.h +++ b/memory/replace/dmd/DMD.h @@ -3,42 +3,142 @@ /* 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 DMD_h___ #define DMD_h___ #include <string.h> +#include <stdarg.h> +#include "mozilla/DebugOnly.h" +#include "mozilla/Move.h" #include "mozilla/Types.h" #include "mozilla/UniquePtr.h" +#include "replace_malloc_bridge.h" + namespace mozilla { class JSONWriteFunc; namespace dmd { +struct Sizes +{ + size_t mStackTracesUsed; + size_t mStackTracesUnused; + size_t mStackTraceTable; + size_t mBlockTable; + + Sizes() { Clear(); } + void Clear() { memset(this, 0, sizeof(Sizes)); } +}; + +// See further below for a description of each method. The DMDFuncs class +// should contain a virtual method for each of them (except IsRunning, +// which can be inferred from the DMDFuncs singleton existing). +struct DMDFuncs +{ + virtual void Report(const void*); + + virtual void ReportOnAlloc(const void*); + + virtual void ClearReports(); + + virtual void AnalyzeReports(UniquePtr<JSONWriteFunc>); + + virtual void SizeOf(Sizes*); + + virtual void StatusMsg(const char*, va_list); + + virtual void SetSampleBelowSize(size_t); + + virtual void ClearBlocks(); + +#ifndef REPLACE_MALLOC_IMPL + // We deliberately don't use ReplaceMalloc::GetDMDFuncs here, because if we + // did, the following would happen. + // - The code footprint of each call to Get() larger as GetDMDFuncs ends + // up inlined. + // - When no replace-malloc library is loaded, the number of instructions + // executed is equivalent, but don't necessarily fit in the same cache + // line. + // - When a non-DMD replace-malloc library is loaded, the overhead is + // higher because there is first a check for the replace malloc bridge + // and then for the DMDFuncs singleton. + // Initializing the DMDFuncs singleton on the first access makes the + // overhead even worse. Either Get() is inlined and massive, or it isn't + // and a simple value check becomes a function call. + static DMDFuncs* Get() { return sSingleton.Get(); } + +private: + // Wrapper class keeping a pointer to the DMD functions. It is statically + // initialized because it needs to be set early enough. + // Debug builds also check that it's never accessed before the static + // initialization actually occured, which could be the case if some other + // static initializer ended up calling into DMD. + class Singleton + { + public: + Singleton() : mValue(ReplaceMalloc::GetDMDFuncs()), mInitialized(true) {} + + DMDFuncs* Get() + { + MOZ_ASSERT(mInitialized); + return mValue; + } + + private: + DMDFuncs* mValue; + DebugOnly<bool> mInitialized; + }; + + // This singleton pointer must be defined on the program side. In Gecko, + // this is done in xpcom/base/nsMemoryInfoDumper.cpp. + static /* DMDFuncs:: */Singleton sSingleton; +#endif +}; + +#ifndef REPLACE_MALLOC_IMPL // Mark a heap block as reported by a memory reporter. -MOZ_EXPORT void -Report(const void* aPtr); +inline void +Report(const void* aPtr) +{ + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + funcs->Report(aPtr); + } +} // Mark a heap block as reported immediately on allocation. -MOZ_EXPORT void -ReportOnAlloc(const void* aPtr); +inline void +ReportOnAlloc(const void* aPtr) +{ + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + funcs->ReportOnAlloc(aPtr); + } +} // Clears existing reportedness data from any prior runs of the memory // reporters. The following sequence should be used. // - ClearReports() // - run the memory reporters // - AnalyzeReports() // This sequence avoids spurious twice-reported warnings. -MOZ_EXPORT void -ClearReports(); +inline void +ClearReports() +{ + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + funcs->ClearReports(); + } +} // Determines which heap blocks have been reported, and dumps JSON output // (via |aWriter|) describing the heap. // // The following sample output contains comments that explain the format and // design choices. The output files can be quite large, so a number of // decisions were made to minimize size, such as using short property names and // omitting properties whenever possible. @@ -116,47 +216,79 @@ ClearReports(); // // that output stack traces in a conventional non-shared format. // "D": "#00: foo (Foo.cpp:123)", // "E": "#00: bar (Bar.cpp:234)", // "F": "#00: baz (Baz.cpp:345)", // "G": "#00: quux (Quux.cpp:456)", // "H": "#00: quuux (Quux.cpp:567)" // } // } -MOZ_EXPORT void -AnalyzeReports(mozilla::UniquePtr<mozilla::JSONWriteFunc>); - -struct Sizes +// Implementation note: normally, this wouldn't be templated, but in that case, +// the function is compiled, which makes the destructor for the UniquePtr fire up, +// and that needs JSONWriteFunc to be fully defined. That, in turn, requires to +// include JSONWriter.h, which includes double-conversion.h, which ends up breaking +// various things built with -Werror for various reasons. +template <typename JSONWriteFunc> +inline void +AnalyzeReports(UniquePtr<JSONWriteFunc> aWriteFunc) { - size_t mStackTracesUsed; - size_t mStackTracesUnused; - size_t mStackTraceTable; - size_t mBlockTable; - - Sizes() { Clear(); } - void Clear() { memset(this, 0, sizeof(Sizes)); } -}; + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + funcs->AnalyzeReports(Move(aWriteFunc)); + } +} // Gets the size of various data structures. Used to implement a memory // reporter for DMD. -MOZ_EXPORT void -SizeOf(Sizes* aSizes); +inline void +SizeOf(Sizes* aSizes) +{ + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + funcs->SizeOf(aSizes); + } +} // Prints a status message prefixed with "DMD[<pid>]". Use sparingly. -MOZ_EXPORT void -StatusMsg(const char* aFmt, ...); +inline void +StatusMsg(const char* aFmt, ...) +{ + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + va_list ap; + va_start(ap, aFmt); + funcs->StatusMsg(aFmt, ap); + va_end(ap); + } +} // Indicates whether or not DMD is running. -MOZ_EXPORT bool -IsRunning(); +inline bool +IsRunning() +{ + return !!DMDFuncs::Get(); +} // Sets the sample-below size. Only used for testing purposes. -MOZ_EXPORT void -SetSampleBelowSize(size_t aSize); +inline void +SetSampleBelowSize(size_t aSize) +{ + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + funcs->SetSampleBelowSize(aSize); + } +} // Clears all records of live allocations. Only used for testing purposes. -MOZ_EXPORT void -ClearBlocks(); +inline void +ClearBlocks() +{ + DMDFuncs* funcs = DMDFuncs::Get(); + if (funcs) { + funcs->ClearBlocks(); + } +} +#endif +} // namespace dmd } // namespace mozilla -} // namespace dmd #endif /* DMD_h___ */
--- a/memory/replace/dmd/test/SmokeDMD.cpp +++ b/memory/replace/dmd/test/SmokeDMD.cpp @@ -21,16 +21,18 @@ #include "mozilla/JSONWriter.h" #include "mozilla/UniquePtr.h" #include "DMD.h" using mozilla::JSONWriter; using mozilla::MakeUnique; using namespace mozilla::dmd; +DMDFuncs::Singleton DMDFuncs::sSingleton; + class FpWriteFunc : public mozilla::JSONWriteFunc { public: explicit FpWriteFunc(const char* aFilename) { mFp = fopen(aFilename, "w"); if (!mFp) { fprintf(stderr, "SmokeDMD: can't create %s file: %s\n",
--- a/memory/replace/dmd/test/moz.build +++ b/memory/replace/dmd/test/moz.build @@ -13,14 +13,12 @@ if CONFIG['OS_ARCH'] == 'WINNT': CXXFLAGS += ['-Og-'] else: CXXFLAGS += ['-O0'] DEFINES['MOZ_NO_MOZALLOC'] = True DISABLE_STL_WRAPPING = True -USE_LIBS += ['dmd'] - XPCSHELL_TESTS_MANIFESTS += [ 'xpcshell.ini', ]
index 709e27ed21d26ee7b2d934e2933185b5ea138c75..f8b602a7359a80984fffd76099696733288788a8 GIT binary patch literal 267 zc$@(X0rdVKiwFQ;h-Fj)|IJcOPlPZKz4up4W-pi!Q*^Tmx3=--P2<II=(05-TPPNS ziDdt~Q+7q*2dH!E`<T~E@&*Rj8{d|$#tf2}U|ILB(A}9C7yurs!$aM_Xio$t7zeJ^ zRb!1b)_pvcpC&9bIEDSab;a?qY&+s!$vU7n@ATgCbQc3^OL_<r80^0z-^W0+l4trY z=bYAC>zZ)MDoifJ{)su+jYlnJWuCcj_%{8CCUiHCR?Fx=G&9IUi8`+f^Q`yQe3wv! zI-wAlkNuM)l=1@A2$jP8(!w{dt5rZqzzyda2#CaW(KK0_UY+YK<s?do<Wf{>5*0*h R66q^;VqeUm2{A(h007$kfOP->
--- a/toolkit/library/moz.build +++ b/toolkit/library/moz.build @@ -106,21 +106,16 @@ USE_LIBS += [ 'js', ] if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT': USE_LIBS += [ 'sandboxbroker', ] -if CONFIG['MOZ_DMD']: - USE_LIBS += [ - 'dmd', - ] - USE_LIBS += [ 'gkmedias', 'mozalloc', 'nspr', 'nss', 'sqlite', 'zlib', ]
--- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -755,16 +755,18 @@ nsMemoryInfoDumper::DumpMemoryInfoToTemp nsRefPtr<TempDirFinishCallback> finishDumping = new TempDirFinishCallback(reportsTmpFile, reportsFinalFilename); return DumpMemoryInfoToFile(reportsTmpFile, finishDumping, nullptr, aAnonymize, aMinimizeMemoryUsage, identifier); } #ifdef MOZ_DMD +dmd::DMDFuncs::Singleton dmd::DMDFuncs::sSingleton; + nsresult nsMemoryInfoDumper::OpenDMDFile(const nsAString& aIdentifier, int aPid, FILE** aOutFile) { if (!dmd::IsRunning()) { *aOutFile = nullptr; return NS_OK; }
--- a/xpcom/tests/TestDeadlockDetectorScalability.cpp +++ b/xpcom/tests/TestDeadlockDetectorScalability.cpp @@ -1,14 +1,17 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: sw=4 ts=4 et : * 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/. */ +// Avoid DMD-specific parts of MOZ_DEFINE_MALLOC_SIZE_OF +#undef MOZ_DMD + #include "TestHarness.h" #include "nsIMemoryReporter.h" //#define OLD_API #define PASS() \ do { \ passed(__FUNCTION__); \