Bug 717853 - Add a native version of DMD. r=jlebar,glandium.

--HG--
extra : rebase_source : 9b824556591abd63b42aa7ff823e9cd25976c162
This commit is contained in:
Nicholas Nethercote 2012-12-10 16:05:07 -08:00
parent 188f6e9c8b
commit 0d84313efb
21 changed files with 2910 additions and 128 deletions

View File

@ -54,6 +54,9 @@
@BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
@BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
#ifdef MOZ_DMD
@BINPATH@/@DLL_PREFIX@dmd@DLL_SUFFIX@
#endif
#ifdef XP_MACOSX
@BINPATH@/XUL
#else

View File

@ -199,17 +199,17 @@ endif
endif
#
# Handle trace-malloc in optimized builds.
# Handle trace-malloc and DMD in optimized builds.
# No opt to give sane callstacks.
#
ifdef NS_TRACE_MALLOC
ifneq (,$(NS_TRACE_MALLOC)$(MOZ_DMD))
MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG
ifdef HAVE_64BIT_OS
OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF,ICF
else
OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF
endif
endif # NS_TRACE_MALLOC
endif # NS_TRACE_MALLOC || MOZ_DMD
endif # MOZ_DEBUG
@ -468,20 +468,20 @@ ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
#//------------------------------------------------------------------------
ifdef USE_STATIC_LIBS
RTL_FLAGS=-MT # Statically linked multithreaded RTL
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC))
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)$(MOZ_DMD))
ifndef MOZ_NO_DEBUG_RTL
RTL_FLAGS=-MTd # Statically linked multithreaded MSVC4.0 debug RTL
endif
endif # MOZ_DEBUG || NS_TRACE_MALLOC
endif # MOZ_DEBUG || NS_TRACE_MALLOC || MOZ_DMD
else # !USE_STATIC_LIBS
RTL_FLAGS=-MD # Dynamically linked, multithreaded RTL
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC))
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)$(MOZ_DMD))
ifndef MOZ_NO_DEBUG_RTL
RTL_FLAGS=-MDd # Dynamically linked, multithreaded MSVC4.0 debug RTL
endif
endif # MOZ_DEBUG || NS_TRACE_MALLOC
endif # MOZ_DEBUG || NS_TRACE_MALLOC || MOZ_DMD
endif # USE_STATIC_LIBS
endif # WINNT && !GNU_CC

View File

@ -6994,7 +6994,7 @@ dnl = Enable trace malloc
dnl ========================================================
NS_TRACE_MALLOC=${MOZ_TRACE_MALLOC}
MOZ_ARG_ENABLE_BOOL(trace-malloc,
[ --enable-trace-malloc Enable malloc tracing; also disables jemalloc],
[ --enable-trace-malloc Enable malloc tracing; also disables DMD and jemalloc],
NS_TRACE_MALLOC=1,
NS_TRACE_MALLOC= )
if test "$NS_TRACE_MALLOC"; then
@ -7005,6 +7005,33 @@ if test "$NS_TRACE_MALLOC"; then
fi
AC_SUBST(NS_TRACE_MALLOC)
dnl ========================================================
dnl = Enable DMD
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(dmd,
[ --enable-dmd Enable DMD; also enables jemalloc and replace-malloc and disables DMDV],
MOZ_DMD=1,
MOZ_DMD= )
if test "$NS_TRACE_MALLOC"; then # trace-malloc disables DMD
MOZ_DMD=
fi
if test "$MOZ_DMD"; then
USE_ELF_DYNSTR_GC=
AC_DEFINE(MOZ_DMD)
if test "${CPU_ARCH}" = "arm"; then
CFLAGS="$CFLAGS -funwind-tables"
CXXFLAGS="$CXXFLAGS -funwind-tables"
fi
MOZ_MEMORY=1 # DMD enables jemalloc
MOZ_REPLACE_MALLOC=1 # DMD enables replace-malloc
MOZ_DMDV= # DMD disables DMDV
fi
AC_SUBST(MOZ_DMD)
dnl ========================================================
dnl = Enable jemalloc
dnl ========================================================
@ -7600,9 +7627,9 @@ if test -z "$SKIP_LIBRARY_CHECKS"; then
AC_LANG_RESTORE
fi
# Demangle only for debug or trace-malloc builds
# Demangle only for debug or trace-malloc or DMD builds
MOZ_DEMANGLE_SYMBOLS=
if test "$HAVE_DEMANGLE" && test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC"; then
if test "$HAVE_DEMANGLE" && test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC" -o "$MOZ_DMD"; then
MOZ_DEMANGLE_SYMBOLS=1
AC_DEFINE(MOZ_DEMANGLE_SYMBOLS)
fi
@ -8407,7 +8434,7 @@ if test -n "$MOZ_SERVICES_SYNC"; then
fi
dnl ========================================================
if test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC"; then
if test "$MOZ_DEBUG" -o "$NS_TRACE_MALLOC" -o "$MOZ_DMD"; then
MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS=
fi

View File

@ -2630,6 +2630,70 @@ static JSFunctionSpec TraceMallocFunctions[] = {
#endif /* NS_TRACE_MALLOC */
#ifdef MOZ_DMD
#include <errno.h>
namespace mozilla {
namespace dmd {
// See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
// how to use DMD.
static JSBool
MaybeReportAndDump(JSContext *cx, unsigned argc, jsval *vp, bool report)
{
JSString *str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
if (!str)
return JS_FALSE;
JSAutoByteString pathname(cx, str);
if (!pathname)
return JS_FALSE;
FILE* fp = fopen(pathname.ptr(), "w");
if (!fp) {
JS_ReportError(cx, "DMD can't open %s: %s",
pathname.ptr(), strerror(errno));
return JS_FALSE;
}
if (report) {
fprintf(stderr, "DMD: running reporters...\n");
dmd::RunReporters();
}
dmd::Writer writer(FpWrite, fp);
dmd::Dump(writer);
fclose(fp);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
static JSBool
ReportAndDump(JSContext *cx, unsigned argc, jsval *vp)
{
return MaybeReportAndDump(cx, argc, vp, /* report = */ true);
}
static JSBool
Dump(JSContext *cx, unsigned argc, jsval *vp)
{
return MaybeReportAndDump(cx, argc, vp, /* report = */ false);
}
} // namespace dmd
} // namespace mozilla
static JSFunctionSpec DMDFunctions[] = {
JS_FS("DMDReportAndDump", dmd::ReportAndDump, 1, 0),
JS_FS("DMDDump", dmd::Dump, 1, 0),
JS_FS_END
};
#endif // defined(MOZ_DMD)
#ifdef MOZ_JPROF
#include <signal.h>
@ -2739,15 +2803,22 @@ static JSFunctionSpec JProfFunctions[] = {
// See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
// how to use DMDV.
namespace mozilla {
namespace dmdv {
static JSBool
DMDVCheckAndDumpJS(JSContext *cx, unsigned argc, jsval *vp)
ReportAndDump(JSContext *cx, unsigned argc, jsval *vp)
{
mozilla::DMDVCheckAndDump();
mozilla::dmd::RunReporters();
mozilla::dmdv::Dump();
return JS_TRUE;
}
} // namespace dmdv
} // namespace mozilla
static JSFunctionSpec DMDVFunctions[] = {
JS_FS("DMDV", DMDVCheckAndDumpJS, 0, 0),
JS_FS("DMDVReportAndDump", dmdv::ReportAndDump, 0, 0),
JS_FS_END
};
@ -2771,6 +2842,11 @@ nsJSContext::InitClasses(JSObject* aGlobalObj)
::JS_DefineFunctions(mContext, aGlobalObj, TraceMallocFunctions);
#endif
#ifdef MOZ_DMD
// Attempt to initialize DMD functions
::JS_DefineFunctions(mContext, aGlobalObj, DMDFunctions);
#endif
#ifdef MOZ_JPROF
// Attempt to initialize JProf functions
::JS_DefineFunctions(mContext, aGlobalObj, JProfFunctions);

View File

@ -82,7 +82,12 @@ inline void* hunspell_realloc(void* ptr, size_t size)
{
HunspellReportMemoryDeallocation(ptr);
void* result = moz_realloc(ptr, size);
HunspellReportMemoryAllocation(result);
if (result) {
HunspellReportMemoryAllocation(result);
} else {
// realloc failed; undo the HunspellReportMemoryDeallocation from above
HunspellReportMemoryAllocation(ptr);
}
return result;
}
#define realloc(ptr, size) hunspell_realloc(ptr, size)

View File

@ -98,14 +98,14 @@ NS_IMPL_CYCLE_COLLECTION_3(mozHunspell,
// Memory reporting stuff.
static int64_t gHunspellAllocatedSize = 0;
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(HunspellMallocSizeOfForCounterInc, "hunspell")
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN_UN(HunspellMallocSizeOfForCounterDec)
NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(HunspellMallocSizeOfOnAlloc, "hunspell")
NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(HunspellMallocSizeOfOnFree)
void HunspellReportMemoryAllocation(void* ptr) {
gHunspellAllocatedSize += HunspellMallocSizeOfForCounterInc(ptr);
gHunspellAllocatedSize += HunspellMallocSizeOfOnAlloc(ptr);
}
void HunspellReportMemoryDeallocation(void* ptr) {
gHunspellAllocatedSize -= HunspellMallocSizeOfForCounterDec(ptr);
gHunspellAllocatedSize -= HunspellMallocSizeOfOnFree(ptr);
}
static int64_t HunspellGetCurrentAllocatedSize() {
return gHunspellAllocatedSize;

View File

@ -46,34 +46,34 @@ NS_MEMORY_REPORTER_IMPLEMENT(Freetype,
"Memory used by Freetype."
)
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(FreetypeMallocSizeOfForCounterInc, "freetype")
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN_UN(FreetypeMallocSizeOfForCounterDec)
NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(FreetypeMallocSizeOfOnAlloc, "freetype")
NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(FreetypeMallocSizeOfOnFree)
static void*
CountingAlloc(FT_Memory memory, long size)
{
void *p = malloc(size);
sFreetypeMemoryUsed += FreetypeMallocSizeOfForCounterInc(p);
sFreetypeMemoryUsed += FreetypeMallocSizeOfOnAlloc(p);
return p;
}
static void
CountingFree(FT_Memory memory, void* p)
{
sFreetypeMemoryUsed -= FreetypeMallocSizeOfForCounterDec(p);
sFreetypeMemoryUsed -= FreetypeMallocSizeOfOnFree(p);
free(p);
}
static void*
CountingRealloc(FT_Memory memory, long cur_size, long new_size, void* p)
{
sFreetypeMemoryUsed -= FreetypeMallocSizeOfForCounterDec(p);
sFreetypeMemoryUsed -= FreetypeMallocSizeOfOnFree(p);
void *pnew = realloc(p, new_size);
if (pnew) {
sFreetypeMemoryUsed += FreetypeMallocSizeOfForCounterInc(pnew);
sFreetypeMemoryUsed += FreetypeMallocSizeOfOnAlloc(pnew);
} else {
// realloc failed; undo the decrement from above
sFreetypeMemoryUsed += FreetypeMallocSizeOfForCounterInc(p);
sFreetypeMemoryUsed += FreetypeMallocSizeOfOnAlloc(p);
}
return pnew;
}

View File

@ -199,17 +199,17 @@ endif
endif
#
# Handle trace-malloc in optimized builds.
# Handle trace-malloc and DMD in optimized builds.
# No opt to give sane callstacks.
#
ifdef NS_TRACE_MALLOC
ifneq (,$(NS_TRACE_MALLOC)$(MOZ_DMD))
MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG
ifdef HAVE_64BIT_OS
OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF,ICF
else
OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF
endif
endif # NS_TRACE_MALLOC
endif # NS_TRACE_MALLOC || MOZ_DMD
endif # MOZ_DEBUG
@ -468,20 +468,20 @@ ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
#//------------------------------------------------------------------------
ifdef USE_STATIC_LIBS
RTL_FLAGS=-MT # Statically linked multithreaded RTL
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC))
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)$(MOZ_DMD))
ifndef MOZ_NO_DEBUG_RTL
RTL_FLAGS=-MTd # Statically linked multithreaded MSVC4.0 debug RTL
endif
endif # MOZ_DEBUG || NS_TRACE_MALLOC
endif # MOZ_DEBUG || NS_TRACE_MALLOC || MOZ_DMD
else # !USE_STATIC_LIBS
RTL_FLAGS=-MD # Dynamically linked, multithreaded RTL
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC))
ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)$(MOZ_DMD))
ifndef MOZ_NO_DEBUG_RTL
RTL_FLAGS=-MDd # Dynamically linked, multithreaded MSVC4.0 debug RTL
endif
endif # MOZ_DEBUG || NS_TRACE_MALLOC
endif # MOZ_DEBUG || NS_TRACE_MALLOC || MOZ_DMD
endif # USE_STATIC_LIBS
endif # WINNT && !GNU_CC

2051
memory/replace/dmd/DMD.cpp Normal file

File diff suppressed because it is too large Load Diff

55
memory/replace/dmd/DMD.h Normal file
View File

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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/. */
#ifndef DMD_h___
#define DMD_h___
#include <stdarg.h>
#include "mozilla/Types.h"
namespace mozilla {
namespace dmd {
// Mark a heap block as reported by a memory reporter.
MOZ_EXPORT void
Report(const void* aPtr, const char* aReporterName);
// Mark a heap block as reported immediately on allocation.
MOZ_EXPORT void
ReportOnAlloc(const void* aPtr, const char* aReporterName);
class Writer
{
public:
typedef void (*WriterFun)(void* aWriteState, const char* aFmt, va_list aAp);
Writer(WriterFun aWriterFun, void* aWriteState)
: mWriterFun(aWriterFun), mWriteState(aWriteState)
{}
void Write(const char* aFmt, ...) const;
private:
WriterFun mWriterFun;
void* mWriteState;
};
// Checks which heap blocks have been reported, and dumps a human-readable
// summary (via |aWrite|). If |aWrite| is nullptr it will dump to stderr.
// Beware: this output may have very long lines.
MOZ_EXPORT void
Dump(Writer aWriter);
// A useful |WriterFun|. If |fp| is a FILE* you want |Dump|'s output to be
// written to, call |Dump(FpWrite, fp)|.
MOZ_EXPORT void
FpWrite(void* aFp, const char* aFmt, va_list aAp);
} // namespace mozilla
} // namespace dmd
#endif /* DMD_h___ */

View File

@ -0,0 +1,39 @@
#
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dmd
LIBRARY_NAME = dmd
FORCE_SHARED_LIB= 1
DEFINES += -DMOZ_NO_MOZALLOC
CPPSRCS = DMD.cpp
VPATH += $(topsrcdir)/xpcom/base
CPPSRCS += nsStackWalk.cpp
VPATH += $(topsrcdir)/nsprpub/lib/libc/src
CSRCS += strcpy.c
VPATH += $(topsrcdir)/mfbt
CPPSRCS += HashFunctions.cpp
EXPORTS = DMD.h
# Disable mozglue.
WRAP_LDFLAGS =
MOZ_GLUE_LDFLAGS=
STL_FLAGS =
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,2 @@
This is DMD. See https://wiki.mozilla.org/Performance/MemShrink/DMD for
details on how to use it.

View File

@ -0,0 +1,355 @@
------------------------------------------------------------------
Invocation
------------------------------------------------------------------
$DMD = '--mode=test'
------------------------------------------------------------------
Double-reported blocks
------------------------------------------------------------------
(none)
------------------------------------------------------------------
Unreported blocks
------------------------------------------------------------------
(none)
------------------------------------------------------------------
Reported blocks
------------------------------------------------------------------
(none)
------------------------------------------------------------------
Summary
------------------------------------------------------------------
Total: 0 bytes
Reported: 0 bytes ( 0.00%)
Unreported: 0 bytes ( 0.00%)
------------------------------------------------------------------
Invocation
------------------------------------------------------------------
$DMD = '--mode=test'
------------------------------------------------------------------
Double-reported blocks
------------------------------------------------------------------
Double-reported: 3 blocks in block group 1 of 1
96 bytes (90 requested / 6 slop)
Allocated at
(stack omitted due to test mode)
Previously reported by 'c' at
(stack omitted due to test mode)
Now reported by 'c' at
(stack omitted due to test mode)
------------------------------------------------------------------
Unreported blocks
------------------------------------------------------------------
Unreported: 1 block in block group 1 of 4
4,096 bytes (1 requested / 4,095 slop)
27.44% of the heap (27.44% cumulative); 76.88% of unreported (76.88% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 9 blocks in block group 2 of 4
1,008 bytes (900 requested / 108 slop)
6.75% of the heap (34.19% cumulative); 18.92% of unreported (95.80% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 2 blocks in block group 3 of 4
112 bytes (112 requested / 0 slop)
0.75% of the heap (34.94% cumulative); 2.10% of unreported (97.90% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 2 blocks in block group 4 of 4
112 bytes (112 requested / 0 slop)
0.75% of the heap (35.69% cumulative); 2.10% of unreported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
------------------------------------------------------------------
Reported blocks
------------------------------------------------------------------
Reported: 1 block in block group 1 of 12
8,192 bytes (4,097 requested / 4,095 slop)
54.88% of the heap (54.88% cumulative); 85.33% of reported (85.33% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'e' at
(stack omitted due to test mode)
Reported: 1 block in block group 2 of 12
512 bytes (512 requested / 0 slop)
3.43% of the heap (58.31% cumulative); 5.33% of reported (90.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'e2' at
(stack omitted due to test mode)
Reported: 2 blocks in block group 3 of 12
240 bytes (240 requested / 0 slop)
1.61% of the heap (59.91% cumulative); 2.50% of reported (93.17% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a01' at
(stack omitted due to test mode)
Reported: 2 blocks in block group 4 of 12
240 bytes (240 requested / 0 slop)
1.61% of the heap (61.52% cumulative); 2.50% of reported (95.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a01' at
(stack omitted due to test mode)
Reported: 1 block in block group 5 of 12
96 bytes (96 requested / 0 slop)
0.64% of the heap (62.17% cumulative); 1.00% of reported (96.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a23' at
(stack omitted due to test mode)
Reported: 1 block in block group 6 of 12
96 bytes (96 requested / 0 slop)
0.64% of the heap (62.81% cumulative); 1.00% of reported (97.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a23' at
(stack omitted due to test mode)
Reported: 1 block in block group 7 of 12
80 bytes (80 requested / 0 slop)
0.54% of the heap (63.34% cumulative); 0.83% of reported (98.50% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a23' at
(stack omitted due to test mode)
Reported: 1 block in block group 8 of 12
80 bytes (80 requested / 0 slop)
0.54% of the heap (63.88% cumulative); 0.83% of reported (99.33% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a23' at
(stack omitted due to test mode)
Reported: 1 block in block group 9 of 12
32 bytes (30 requested / 2 slop)
0.21% of the heap (64.09% cumulative); 0.33% of reported (99.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'c' at
(stack omitted due to test mode)
Reported: 1 block in block group 10 of 12
16 bytes (10 requested / 6 slop)
0.11% of the heap (64.20% cumulative); 0.17% of reported (99.83% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'b' at
(stack omitted due to test mode)
Reported: 1 block in block group 11 of 12
8 bytes (0 requested / 8 slop)
0.05% of the heap (64.26% cumulative); 0.08% of reported (99.92% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a2' at
(stack omitted due to test mode)
Reported: 1 block in block group 12 of 12
8 bytes (0 requested / 8 slop)
0.05% of the heap (64.31% cumulative); 0.08% of reported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a2' at
(stack omitted due to test mode)
------------------------------------------------------------------
Summary
------------------------------------------------------------------
Total: 14,928 bytes
Reported: 9,600 bytes (64.31%)
Unreported: 5,328 bytes (35.69%)
------------------------------------------------------------------
Invocation
------------------------------------------------------------------
$DMD = '--mode=test'
------------------------------------------------------------------
Double-reported blocks
------------------------------------------------------------------
Double-reported: 1 block in block group 1 of 1
8 bytes (0 requested / 8 slop)
Allocated at
(stack omitted due to test mode)
Previously reported by 'a2b' at
(stack omitted due to test mode)
Now reported by 'a2b' at
(stack omitted due to test mode)
------------------------------------------------------------------
Unreported blocks
------------------------------------------------------------------
Unreported: 9 blocks in block group 1 of 3
1,008 bytes (900 requested / 108 slop)
38.77% of the heap (38.77% cumulative); 48.84% of unreported (48.84% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 6 blocks in block group 2 of 3
528 bytes (528 requested / 0 slop)
20.31% of the heap (59.08% cumulative); 25.58% of unreported (74.42% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 6 blocks in block group 3 of 3
528 bytes (528 requested / 0 slop)
20.31% of the heap (79.38% cumulative); 25.58% of unreported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
------------------------------------------------------------------
Reported blocks
------------------------------------------------------------------
Reported: 1 block in block group 1 of 3
512 bytes (512 requested / 0 slop)
19.69% of the heap (19.69% cumulative); 95.52% of reported (95.52% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'e2b' at
(stack omitted due to test mode)
Reported: 1 block in block group 2 of 3
16 bytes (10 requested / 6 slop)
0.62% of the heap (20.31% cumulative); 2.99% of reported (98.51% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'b' at
(stack omitted due to test mode)
Reported: 1 block in block group 3 of 3
8 bytes (0 requested / 8 slop)
0.31% of the heap (20.62% cumulative); 1.49% of reported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
Reported by 'a2b' at
(stack omitted due to test mode)
------------------------------------------------------------------
Summary
------------------------------------------------------------------
Total: 2,600 bytes
Reported: 536 bytes (20.62%)
Unreported: 2,064 bytes (79.38%)
------------------------------------------------------------------
Invocation
------------------------------------------------------------------
$DMD = '--mode=test'
------------------------------------------------------------------
Double-reported blocks
------------------------------------------------------------------
(none)
------------------------------------------------------------------
Unreported blocks
------------------------------------------------------------------
Unreported: ~4 blocks in block group 1 of 7
~512 bytes (~512 requested / ~0 slop)
35.96% of the heap (35.96% cumulative); 35.96% of unreported (35.96% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 1 block in block group 2 of 7
256 bytes (256 requested / 0 slop)
17.98% of the heap (53.93% cumulative); 17.98% of unreported (53.93% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 1 block in block group 3 of 7
144 bytes (144 requested / 0 slop)
10.11% of the heap (64.04% cumulative); 10.11% of unreported (64.04% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 1 block in block group 4 of 7
128 bytes (128 requested / 0 slop)
8.99% of the heap (73.03% cumulative); 8.99% of unreported (73.03% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: ~1 block in block group 5 of 7
~128 bytes (~128 requested / ~0 slop)
8.99% of the heap (82.02% cumulative); 8.99% of unreported (82.02% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: ~1 block in block group 6 of 7
~128 bytes (~128 requested / ~0 slop)
8.99% of the heap (91.01% cumulative); 8.99% of unreported (91.01% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: ~1 block in block group 7 of 7
~128 bytes (~128 requested / ~0 slop)
8.99% of the heap (100.00% cumulative); 8.99% of unreported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
------------------------------------------------------------------
Reported blocks
------------------------------------------------------------------
(none)
------------------------------------------------------------------
Summary
------------------------------------------------------------------
Total: ~1,424 bytes
Reported: ~0 bytes ( 0.00%)
Unreported: ~1,424 bytes (100.00%)

View File

@ -518,14 +518,57 @@ namespace {
// from the standard ones -- they use int instead of size_t. But we don't need
// a wrapper for moz_free.
#ifdef MOZ_DMD
#include "DMD.h"
// sqlite does its own memory accounting, and we use its numbers in our memory
// reporters. But we don't want sqlite's heap blocks to show up in DMD's
// output as unreported, so we mark them as reported when they're allocated and
// mark them as unreported when they are freed.
//
// In other words, we are marking all sqlite heap blocks as reported even
// though we're not reporting them ourselves. Instead we're trusting that
// sqlite is fully and correctly accounting for all of its heap blocks via its
// own memory accounting.
NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(sqliteMallocSizeOfOnAlloc, "sqlite")
NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(sqliteMallocSizeOfOnFree)
#endif
static void *sqliteMemMalloc(int n)
{
return ::moz_malloc(n);
void* p = ::moz_malloc(n);
#ifdef MOZ_DMD
sqliteMallocSizeOfOnAlloc(p);
#endif
return p;
}
static void sqliteMemFree(void *p)
{
#ifdef MOZ_DMD
sqliteMallocSizeOfOnFree(p);
#endif
::moz_free(p);
}
static void *sqliteMemRealloc(void *p, int n)
{
#ifdef MOZ_DMD
sqliteMallocSizeOfOnFree(p);
void *pnew = ::moz_realloc(p, n);
if (pnew) {
sqliteMallocSizeOfOnAlloc(pnew);
} else {
// realloc failed; undo the sqliteMallocSizeOfOnFree from above
sqliteMallocSizeOfOnAlloc(p);
}
return pnew;
#else
return ::moz_realloc(p, n);
#endif
}
static int sqliteMemSize(void *p)
@ -554,14 +597,14 @@ static void sqliteMemShutdown(void *p)
const sqlite3_mem_methods memMethods = {
&sqliteMemMalloc,
&moz_free,
&sqliteMemFree,
&sqliteMemRealloc,
&sqliteMemSize,
&sqliteMemRoundup,
&sqliteMemInit,
&sqliteMemShutdown,
NULL
};
};
} // anonymous namespace

View File

@ -394,6 +394,10 @@ ifndef MOZ_TREE_PIXMAN
EXTRA_DSO_LDOPTS += $(MOZ_PIXMAN_LIBS)
endif
ifdef MOZ_DMD
EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME_PATH,dmd,$(DIST)/lib)
endif
EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME_PATH,gkmedias,$(DIST)/lib)
ifdef MOZ_WEBRTC

View File

@ -1597,6 +1597,12 @@ if [ "$NS_TRACE_MALLOC" ]; then
"
fi
if [ "$MOZ_DMD" ]; then
add_makefiles "
memory/replace/dmd/Makefile
"
fi
if [ "$MOZ_MAPINFO" ]; then
add_makefiles "
tools/codesighs/Makefile

View File

@ -15,6 +15,10 @@ ifdef NS_TRACE_MALLOC
tier_platform_dirs = tools/trace-malloc/lib
endif
ifdef MOZ_DMD
tier_platform_dirs += memory/replace/dmd
endif
ifdef MOZ_TREE_FREETYPE
tier_platform_staticdirs += modules/freetype2
endif

View File

@ -357,66 +357,91 @@ nsresult NS_RegisterMemoryMultiReporter(nsIMemoryMultiReporter *reporter);
nsresult NS_UnregisterMemoryReporter(nsIMemoryReporter *reporter);
nsresult NS_UnregisterMemoryMultiReporter(nsIMemoryMultiReporter *reporter);
#if defined(MOZ_DMDV) || defined(MOZ_DMD)
namespace mozilla {
namespace dmd {
// This runs all the memory reporters but does nothing with the results; i.e.
// it does the minimal amount of work possible for DMD/DMDV to do its thing.
void RunReporters();
}
}
#endif // defined(MOZ_DMDV) || defined(MOZ_DMD)
#ifdef MOZ_DMDV
#if defined(MOZ_MEMORY)
#error "MOZ_DMDV precludes MOZ_MEMORY"
#endif
// Because DMDV is not a tool that comes with the standard Valgrind
// distribution, we have to #include our own local copy of dmdv.h. Ugly but
// unavoidable.
#ifdef MOZ_DMDV
#if MOZ_MEMORY
#error "--disable-jemalloc should have been forced when --enable-dmdv was specified"
#endif
#include "dmdv.h"
#endif
#define MOZ_REPORT(ptr, usable, name) VALGRIND_DMDV_REPORT(ptr, usable, name)
#define MOZ_REPORT_ON_ALLOC(ptr, usable, name) VALGRIND_DMDV_REPORT(ptr, usable, name)
namespace mozilla {
namespace dmdv {
// This dumps the DMDV output to stderr (or somewhere else, if one of
// DMDV/Valgrind's logging options was used).
void Dump();
}
}
/*
* Functions generated via this macro should be used by all traversal-based
* memory reporters. Such functions return |moz_malloc_size_of(ptr)|; this
* will always be zero on some obscure platforms.
*
* You might be wondering why we have a macro that creates multiple functions
* distinguished only by |name|, instead of a single MemoryReporterMallocSizeOf
* function. It's mostly to help with DMDV integration, though it sometimes
* also helps with debugging and temporary ad hoc profiling. The |name| chosen
* doesn't matter greatly, but it's best to make it similar to the path used by
* the relevant memory reporter(s).
*/
#elif defined(MOZ_DMD)
#if !defined(MOZ_MEMORY)
#error "MOZ_DMD requires MOZ_MEMORY"
#endif
#include "DMD.h"
#define MOZ_REPORT(ptr, usable, name) mozilla::dmd::Report(ptr, name)
#define MOZ_REPORT_ON_ALLOC(ptr, usable, name) mozilla::dmd::ReportOnAlloc(ptr, name)
#else
#define MOZ_REPORT(ptr, usable, name)
#define MOZ_REPORT_ON_ALLOC(ptr, usable, name)
#endif /* defined(MOZ_DMDV) || defined(MOZ_DMD) */
// Functions generated via this macro should be used by all traversal-based
// memory reporters. Such functions return |moz_malloc_size_of(ptr)|; this
// will always be zero on some obscure platforms.
//
// You might be wondering why we have a macro that creates multiple
// functions distinguished only by |name|, instead of a single
// MemoryReporterMallocSizeOf function. It's mostly to help with DMDV/DMD
// integration, though it sometimes also helps with debugging and temporary
// ad hoc profiling. The |name| chosen doesn't matter greatly, but it's
// best to make it similar to the path used by the relevant memory
// reporter(s).
#define NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(fn, name) \
static size_t fn(const void *ptr) \
{ \
size_t usable = moz_malloc_size_of(ptr); \
VALGRIND_DMDV_REPORT(ptr, usable, name); \
MOZ_REPORT(ptr, usable, name); \
return usable; \
}
/*
* Like NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN, but the created function sends an
* "unreport" message to DMDV.
*/
#define NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN_UN(fn) \
// Functions generated by the next two macros should be used by wrapping
// allocators that report heap blocks as soon as they are allocated and
// unreport them as soon as they are freed. Such allocators are used in cases
// where we have third-party code that we cannot modify. The two functions
// must always be used in tandem.
#define NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(fn, name) \
static size_t fn(const void *ptr) \
{ \
size_t usable = moz_malloc_size_of(ptr); \
VALGRIND_DMDV_UNREPORT(ptr); \
MOZ_REPORT_ON_ALLOC(ptr, usable, name); \
return usable; \
}
#ifdef MOZ_DMDV
/*
* This runs all the memory reporters but does nothing with the results; i.e.
* it does the minimal amount of work possible for DMDV to do its thing. Then
* it dumps the DMDV output to stderr (or somewhere else, if one of
* DMDV/Valgrind's logging options was used).
*/
void DMDVCheckAndDump();
#else
#define VALGRIND_DMDV_REPORT(ptr, usable, name)
#define VALGRIND_DMDV_UNREPORT(ptr)
#endif /* defined(MOZ_DMDV) */
}
#define NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(fn) \
static size_t fn(const void *ptr) \
{ \
return moz_malloc_size_of(ptr); \
}
%}

View File

@ -469,13 +469,73 @@ NS_IMPL_ISUPPORTS1(
} // namespace mozilla
static void
MakeFilename(const char *aPrefix, const nsAString &aIdentifier,
const char *aSuffix, nsACString &aResult)
{
aResult = nsPrintfCString("%s-%s-%d.%s",
aPrefix,
NS_ConvertUTF16toUTF8(aIdentifier).get(),
getpid(), aSuffix);
}
static nsresult
OpenTempFile(const nsACString &aFilename, nsIFile* *aFile)
{
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, aFile);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> file(*aFile);
rv = file->AppendNative(aFilename);
NS_ENSURE_SUCCESS(rv, rv);
rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0644);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef ANDROID
{
// On android the default system umask is 0077 which makes these files
// unreadable to the shell user. In order to pull the dumps off a non-rooted
// device we need to chmod them to something world-readable.
nsAutoCString path;
rv = file->GetNativePath(path);
if (NS_SUCCEEDED(rv)) {
chmod(PromiseFlatCString(path).get(), 0644);
}
}
#endif
return NS_OK;
}
#ifdef MOZ_DMD
struct DMDWriteState
{
static const size_t kBufSize = 4096;
char mBuf[kBufSize];
nsRefPtr<nsGZFileWriter> mGZWriter;
DMDWriteState(nsGZFileWriter *aGZWriter)
: mGZWriter(aGZWriter)
{}
};
static void DMDWrite(void* aState, const char* aFmt, va_list ap)
{
DMDWriteState *state = (DMDWriteState*)aState;
vsnprintf(state->mBuf, state->kBufSize, aFmt, ap);
unused << state->mGZWriter->Write(state->mBuf);
}
#endif
/* static */ nsresult
nsMemoryInfoDumper::DumpMemoryReportsToFileImpl(
const nsAString& aIdentifier)
{
MOZ_ASSERT(!aIdentifier.IsEmpty());
// Open a new file named something like
//
// incomplete-memory-report-<-identifier>-<pid>-42.json.gz
// incomplete-memory-report-<identifier>-<pid>.json.gz
//
// in NS_OS_TEMP_DIR for writing. When we're finished writing the report,
// we'll rename this file and get rid of the "incomplete-" prefix.
@ -484,43 +544,19 @@ nsMemoryInfoDumper::DumpMemoryReportsToFileImpl(
// looking for memory report dumps to grab a file before we're finished
// writing to it.
nsCOMPtr<nsIFile> tmpFile;
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
getter_AddRefs(tmpFile));
NS_ENSURE_SUCCESS(rv, rv);
// Note that |filename| is missing the "incomplete-" prefix; we'll tack
// Note that |mrFilename| is missing the "incomplete-" prefix; we'll tack
// that on in a moment.
nsAutoCString filename;
filename.AppendLiteral("memory-report");
if (!aIdentifier.IsEmpty()) {
filename.AppendLiteral("-");
filename.Append(NS_ConvertUTF16toUTF8(aIdentifier));
}
filename.AppendLiteral("-");
filename.AppendInt(getpid());
filename.AppendLiteral(".json.gz");
nsCString mrFilename;
MakeFilename("memory-report", aIdentifier, ".json.gz", mrFilename);
rv = tmpFile->AppendNative(NS_LITERAL_CSTRING("incomplete-") + filename);
nsCOMPtr<nsIFile> mrTmpFile;
nsresult rv;
rv = OpenTempFile(NS_LITERAL_CSTRING("incomplete-") + mrFilename,
getter_AddRefs(mrTmpFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0644);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef ANDROID
{
// On android the default system umask is 0077 which makes these files
// unreadable to the shell user. In order to pull the dumps off a non-rooted
// device we need to chmod them to something world-readable.
nsAutoCString path;
rv = tmpFile->GetNativePath(path);
if (NS_SUCCEEDED(rv)) {
chmod(PromiseFlatCString(path).get(), 0644);
}
}
#endif
nsRefPtr<nsGZFileWriter> writer = new nsGZFileWriter();
rv = writer->Init(tmpFile);
rv = writer->Init(mrTmpFile);
NS_ENSURE_SUCCESS(rv, rv);
// Dump the memory reports to the file.
@ -593,24 +629,55 @@ nsMemoryInfoDumper::DumpMemoryReportsToFileImpl(
rv = writer->Finish();
NS_ENSURE_SUCCESS(rv, rv);
#ifdef MOZ_DMD
// Open a new file named something like
//
// dmd-<identifier>-<pid>.txt.gz
//
// in NS_OS_TEMP_DIR for writing, and dump DMD output to it. This must occur
// after the memory reporters have been run (above), but before the
// memory-reports file has been renamed (so scripts can detect the DMD file,
// if present).
nsCString dmdFilename;
MakeFilename("dmd", aIdentifier, ".txt.gz", dmdFilename);
nsCOMPtr<nsIFile> dmdFile;
rv = OpenTempFile(dmdFilename, getter_AddRefs(dmdFile));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsGZFileWriter> dmdWriter = new nsGZFileWriter();
rv = dmdWriter->Init(dmdFile);
NS_ENSURE_SUCCESS(rv, rv);
// Dump DMD output to the file.
DMDWriteState state(dmdWriter);
dmd::Writer w(DMDWrite, &state);
mozilla::dmd::Dump(w);
rv = dmdWriter->Finish();
NS_ENSURE_SUCCESS(rv, rv);
#endif // MOZ_DMD
// Rename the file, now that we're done dumping the report. The file's
// ultimate destination is "memory-report<-identifier>-<pid>.json.gz".
nsCOMPtr<nsIFile> dstFile;
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dstFile));
nsCOMPtr<nsIFile> mrFinalFile;
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mrFinalFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = dstFile->AppendNative(filename);
rv = mrFinalFile->AppendNative(mrFilename);
NS_ENSURE_SUCCESS(rv, rv);
rv = dstFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
rv = mrFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString dstFileName;
rv = dstFile->GetLeafName(dstFileName);
nsAutoString mrActualFinalFilename;
rv = mrFinalFile->GetLeafName(mrActualFinalFilename);
NS_ENSURE_SUCCESS(rv, rv);
rv = tmpFile->MoveTo(/* directory */ nullptr, dstFileName);
rv = mrTmpFile->MoveTo(/* directory */ nullptr, mrActualFinalFilename);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIConsoleService> cs =
@ -618,7 +685,7 @@ nsMemoryInfoDumper::DumpMemoryReportsToFileImpl(
NS_ENSURE_SUCCESS(rv, rv);
nsString path;
tmpFile->GetPath(path);
mrTmpFile->GetPath(path);
NS_ENSURE_SUCCESS(rv, rv);
nsString msg = NS_LITERAL_STRING(

View File

@ -710,7 +710,7 @@ struct MemoryReport {
int64_t amount;
};
#ifdef DEBUG
#if defined(DEBUG) && !defined(MOZ_DMD)
// This is just a wrapper for int64_t that implements nsISupports, so it can be
// passed to nsIMemoryMultiReporter::CollectReports.
class Int64Wrapper MOZ_FINAL : public nsISupports {
@ -746,7 +746,7 @@ NS_IMPL_ISUPPORTS1(
ExplicitNonHeapCountingCallback
, nsIMemoryMultiReporterCallback
)
#endif
#endif // defined(DEBUG) && !defined(MOZ_DMD)
NS_IMETHODIMP
nsMemoryReporterManager::GetExplicit(int64_t *aExplicit)
@ -805,7 +805,9 @@ nsMemoryReporterManager::GetExplicit(int64_t *aExplicit)
// (Actually, in debug builds we also do it the slow way and compare the
// result to the result obtained from GetExplicitNonHeap(). This
// guarantees the two measurement paths are equivalent. This is wise
// because it's easy for memory reporters to have bugs.)
// because it's easy for memory reporters to have bugs. But there's an
// exception if DMD is enabled, because that makes DMD think that all the
// blocks are double-counted.)
int64_t explicitNonHeapMultiSize = 0;
nsCOMPtr<nsISimpleEnumerator> e2;
@ -819,7 +821,7 @@ nsMemoryReporterManager::GetExplicit(int64_t *aExplicit)
explicitNonHeapMultiSize += n;
}
#ifdef DEBUG
#if defined(DEBUG) && !defined(MOZ_DMD)
nsRefPtr<ExplicitNonHeapCountingCallback> cb =
new ExplicitNonHeapCountingCallback();
nsRefPtr<Int64Wrapper> wrappedExplicitNonHeapMultiSize2 =
@ -842,7 +844,7 @@ nsMemoryReporterManager::GetExplicit(int64_t *aExplicit)
explicitNonHeapMultiSize,
explicitNonHeapMultiSize2).get());
}
#endif // DEBUG
#endif // defined(DEBUG) && !defined(MOZ_DMD)
*aExplicit = heapAllocated + explicitNonHeapNormalSize + explicitNonHeapMultiSize;
return NS_OK;
@ -1017,9 +1019,10 @@ NS_UnregisterMemoryMultiReporter (nsIMemoryMultiReporter *reporter)
return mgr->UnregisterMultiReporter(reporter);
}
namespace mozilla {
#if defined(MOZ_DMDV) || defined(MOZ_DMD)
#ifdef MOZ_DMDV
namespace mozilla {
namespace dmd {
class NullMultiReporterCallback : public nsIMemoryMultiReporterCallback
{
@ -1041,7 +1044,7 @@ NS_IMPL_ISUPPORTS1(
)
void
DMDVCheckAndDump()
RunReporters()
{
nsCOMPtr<nsIMemoryReporterManager> mgr =
do_GetService("@mozilla.org/memory-reporter-manager;1");
@ -1089,10 +1092,25 @@ DMDVCheckAndDump()
e2->GetNext(getter_AddRefs(r));
r->CollectReports(cb, nullptr);
}
}
} // namespace dmd
} // namespace mozilla
#endif // defined(MOZ_DMDV) || defined(MOZ_DMD)
#ifdef MOZ_DMDV
namespace mozilla {
namespace dmdv {
void
Dump()
{
VALGRIND_DMDV_CHECK_REPORTING;
}
} // namespace dmdv
} // namespace mozilla
#endif /* defined(MOZ_DMDV) */
}

View File

@ -1180,7 +1180,9 @@ NS_StackWalk(NS_WalkStackCallback aCallback, uint32_t aSkipFrames,
#elif defined(HAVE__UNWIND_BACKTRACE)
// libgcc_s.so symbols _Unwind_Backtrace@@GCC_3.3 and _Unwind_GetIP@@GCC_3.0
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unwind.h>
struct unwind_info {