summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog21
-rw-r--r--INSTALL48
-rw-r--r--Makefile.am217
-rw-r--r--Makefile.in1833
-rw-r--r--README13
-rw-r--r--README.windows6
-rw-r--r--aclocal.m41
-rwxr-xr-xconfigure1014
-rw-r--r--configure.ac154
-rw-r--r--doc/pprof_remote_servers.html21
-rw-r--r--doc/tcmalloc.html270
-rwxr-xr-xgoogle-perftools.sln49
-rw-r--r--m4/acx_nanosleep.m435
-rwxr-xr-xpackages/deb.sh7
-rw-r--r--packages/deb/changelog6
-rw-r--r--src/base/basictypes.h3
-rw-r--r--src/base/cycleclock.h4
-rw-r--r--src/base/dynamic_annotations.cc2
-rw-r--r--src/base/dynamic_annotations.h10
-rw-r--r--src/base/linux_syscall_support.h22
-rw-r--r--src/base/simple_mutex.h236
-rw-r--r--src/base/spinlock.h10
-rw-r--r--src/base/sysinfo.cc26
-rw-r--r--src/base/sysinfo.h8
-rw-r--r--src/base/thread_annotations.h26
-rw-r--r--src/base/vdso_support.cc509
-rw-r--r--src/base/vdso_support.h207
-rw-r--r--src/central_freelist.cc2
-rw-r--r--src/common.cc17
-rw-r--r--src/common.h6
-rw-r--r--src/config.h.in12
-rw-r--r--src/google/heap-checker.h38
-rw-r--r--src/google/malloc_extension.h50
-rw-r--r--src/google/malloc_extension_c.h38
-rw-r--r--src/google/stacktrace.h14
-rw-r--r--src/heap-checker.cc689
-rw-r--r--src/heap-profile-table.cc301
-rw-r--r--src/heap-profile-table.h122
-rw-r--r--src/heap-profiler.cc90
-rw-r--r--src/internal_logging.cc29
-rw-r--r--src/internal_logging.h44
-rw-r--r--src/malloc_extension.cc147
-rw-r--r--src/malloc_hook.cc10
-rw-r--r--src/memory_region_map.cc5
-rw-r--r--src/page_heap.cc4
-rwxr-xr-xsrc/pprof246
-rw-r--r--src/profiler.cc3
-rw-r--r--src/raw_printer.cc71
-rw-r--r--src/raw_printer.h89
-rwxr-xr-xsrc/sampler.cc132
-rwxr-xr-xsrc/sampler.h174
-rw-r--r--src/span.cc2
-rw-r--r--src/stack_trace_table.cc154
-rw-r--r--src/stack_trace_table.h88
-rw-r--r--src/stacktrace.cc53
-rw-r--r--src/stacktrace_config.h85
-rw-r--r--src/stacktrace_libunwind-inl.h3
-rw-r--r--src/stacktrace_win32-inl.h9
-rw-r--r--src/stacktrace_with_context.cc61
-rw-r--r--src/stacktrace_x86-inl.h245
-rw-r--r--src/stacktrace_x86_64-inl.h1
-rw-r--r--src/static_vars.cc4
-rw-r--r--src/static_vars.h7
-rw-r--r--src/system-alloc.cc13
-rw-r--r--src/tcmalloc.cc161
-rwxr-xr-xsrc/tests/heap-checker-death_unittest.sh4
-rw-r--r--src/tests/heap-checker_unittest.cc165
-rwxr-xr-xsrc/tests/heap-profiler_unittest.sh44
-rw-r--r--src/tests/malloc_extension_test.cc70
-rw-r--r--src/tests/pagemap_unittest.cc124
-rw-r--r--src/tests/raw_printer_test.cc60
-rw-r--r--src/tests/realloc_unittest.cc121
-rwxr-xr-xsrc/tests/sampler_test.cc653
-rw-r--r--src/tests/sampling_test.cc2
-rwxr-xr-xsrc/tests/sampling_test.sh14
-rw-r--r--src/tests/stack_trace_table_test.cc97
-rw-r--r--src/tests/tcmalloc_unittest.cc39
-rw-r--r--src/thread_cache.cc318
-rw-r--r--src/thread_cache.h162
-rw-r--r--src/windows/addr2line-pdb.c1
-rw-r--r--src/windows/config.h12
-rw-r--r--src/windows/patch_functions.cc92
-rw-r--r--src/windows/port.h8
-rwxr-xr-xvsprojects/addr2line-pdb/addr2line-pdb.vcproj8
-rwxr-xr-xvsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj80
-rwxr-xr-xvsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj20
-rwxr-xr-xvsprojects/malloc_extension_test/malloc_extension_test.vcproj159
-rwxr-xr-xvsprojects/nm-pdb/nm-pdb.vcproj8
-rwxr-xr-xvsprojects/pagemap_unittest/pagemap_unittest.vcproj156
-rwxr-xr-xvsprojects/realloc_unittest/realloc_unittest.vcproj153
-rwxr-xr-xvsprojects/sampler_test/sampler_test.vcproj156
-rwxr-xr-xvsprojects/stack_trace_table_test/stack_trace_table_test.vcproj155
-rwxr-xr-xvsprojects/tmu-static/tmu-static.vcproj86
93 files changed, 8581 insertions, 2363 deletions
diff --git a/ChangeLog b/ChangeLog
index 234d3e6..25202bb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,29 @@
+Wed Mar 11 11:25:34 2009 Google Inc. <opensource@google.com>
+
+ * google-perftools: version 1.1 release
+ * Dynamically resize thread caches -- nice perf. improvement (kash)
+ * Add VDSO support to give better stacktraces in linux (ppluzhnikov)
+ * Improve heap-profiling sampling algorithm (ford)
+ * Rewrite leak-checking code: should be faster and more robust (sanjay)
+ * Use ps2 instead of ps for dot: better page cropping for gv (csilvers)
+ * Disable malloc-failure warning messages by default (csilvers)
+ * Update config/Makefile to disable tests on a per-OS basis (csilvers)
+ * PORTING: Get perftools compiling under MSVC 7.1 again (csilvers)
+ * PORTING: Get perftools compiling under cygwin again (csilvers)
+ * PORTING: automatically set library flags for solaris x86 (csilvers)
+ * Add TCMALLOC_SKIP_SBRK to mirror TCMALLOC_SKIP_MMAP (csilvers)
+ * Add --enable flags to allow selective building (csilvers)
+ * Put addr2line-pdb and nm-pdb in proper output directory (csilvers)
+ * Remove deprecated DisableChecksIn (sanjay)
+ * DOCUMENTATION: Document most MallocExtension routines (csilvers)
+
Tue Jan 6 13:58:56 2009 Google Inc. <opensource@google.com>
+
* google-perftools: version 1.0 release
* Exactly the same as 1.0rc2
Sun Dec 14 17:10:35 2008 Google Inc. <opensource@google.com>
+
* google-perftools: version 1.0rc2 release
* Fix compile error on 64-bit systems (casting ptr to int) (csilvers)
diff --git a/INSTALL b/INSTALL
index 039d383..40a0349 100644
--- a/INSTALL
+++ b/INSTALL
@@ -23,8 +23,10 @@ perftools. libunwind can be found at
http://download.savannah.nongnu.org/releases/libunwind/libunwind-snap-070410.tar.gz
-Even if you already have libunwind installed, you will probably still
-need to install from the snapshot to get the latest version.
+Even if you already have libunwind installed, you should check the
+version. Versions older than this will not work properly; too-new
+versions introduce new code that does not work well with perftools
+(because libunwind can call malloc, which will lead to deadlock).
CAUTION: if you install libunwind from the url above, be aware that
you may have trouble if you try to statically link your binary with
@@ -57,6 +59,11 @@ Even with the use of libunwind, there are still known problems with
stack unwinding on 64-bit systems, particularly x86-64. See the
"64-BIT ISSUES" section in README.
+If you encounter problems, try compiling perftools with './configure
+--enable-frame-pointer'. Note you will need to compile your
+application with frame pointers (via 'gcc -fno-omit-frame-pointer
+...') in this case.
+
*** NOTE FOR ___tls_get_addr ERROR
@@ -111,7 +118,9 @@ tested (though see 64-bit notes above). Portions of perftools work on
the other systems. The basic memory-allocation library,
tcmalloc_minimal, works on all systems. The cpu-profiler also works
fairly widely. However, the heap-profiler and heap-checker are not
-yet as widely supported.
+yet as widely supported. In general, the 'configure' script will
+detect what OS you are building for, and only build the components
+that work on that OS.
Note that tcmalloc_minimal is perfectly usable as a malloc/new
replacement, so it is possible to use tcmalloc on all the systems
@@ -130,7 +139,7 @@ above, by linking in libtcmalloc_minimal.
% ./tcmalloc_minimal_unittest # to run this test
% [etc] # to run other tests
- Two caveats: first, frag_unittest tries to allocate 400M of memory,
+ Three caveats: first, frag_unittest tries to allocate 400M of memory,
and if you have less virtual memory on your system, the test may
fail with a bad_alloc exception.
@@ -141,6 +150,11 @@ above, by linking in libtcmalloc_minimal.
is working fine. This only affects programs that call fork(); for
most programs, the cpu profiler is entirely safe to use.
+ Third, perftools depends on /proc to get shared library
+ information. If you are running a FreeBSD system without proc,
+ perftools will not be able to map addresses to functions. Some
+ unittests will fail as a result.
+
libtcmalloc.so successfully builds, and the "advanced" tcmalloc
functionality all works except for the leak-checker, which has
Linux-specific code:
@@ -150,6 +164,10 @@ above, by linking in libtcmalloc_minimal.
% make -k heap-checker_unittest.sh \
heap-checker-death_unittest.sh # THESE DO NOT
+ Note that unless you specify --enable-heap-checker explicitly,
+ 'make' will not build the heap-checker unittests on a FreeBSD
+ system.
+
I have not tested other *BSD systems, but they are probably similar.
** Mac OS X:
@@ -169,11 +187,9 @@ above, by linking in libtcmalloc_minimal.
I've only tested using the GNU C++ compiler, not the Sun C++
compiler. Using g++ requires setting the PATH appropriately when
- configuring. As another issue, Solaris 10 has a bug (see
- src/solaris/libstdc++.la for more info), which we work around by
- adding a custom LDFLAGS argument:
+ configuring.
- % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin ./configure LDFLAGS="-Lsrc/solaris -lrt"
+ % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin ./configure
% PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin make [...]
Again, the binaries and libraries that successfully build are
@@ -193,9 +209,10 @@ above, by linking in libtcmalloc_minimal.
all. But as in other ports, the basic tcmalloc library
functionality, overriding malloc and new and such (and even
windows-specific functions like _aligned_malloc!), is working fine,
- at least with VC++ 8.0 (Visual Studio 2005), in both debug and
- release modes. See README.windows for instructions on how to
- install on Windows using Visual Studio.
+ at least with VC++ 7.1 (Visual Studio 2003) and VC++ 8.0
+ (Visual Studio 2005), in both debug and release modes. See
+ README.windows for instructions on how to install on Windows using
+ Visual Studio.
Cygwin can compile some but not all of perftools. Furthermore,
there is a problem with exception-unwinding in cygwin (it can call
@@ -204,13 +221,12 @@ above, by linking in libtcmalloc_minimal.
exception unwinding problem, but it only works in debug mode. I
hope to have a more proper fix in a later release. To configure
under cygwin, run
- ./configure CXXFLAGS=-g && make -k
+ ./configure CXXFLAGS=-g && make
Most of cygwin will compile (cygwin doesn't allow weak symbols, so
the heap-checker and a few other pieces of functionality will not
- compile). 'make -k' will compile those libraries and tests that
- can be compiled. You can run
- ./tcmalloc_minimal_unittest
- to make sure the basic functionality is working.
+ compile). 'make' will compile those libraries and tests that can
+ be compiled. You can run 'make check' to make sure the basic
+ functionality is working.
This Windows functionality is also available using MinGW and Msys,
In this case, you can use the regular './configure && make'
diff --git a/Makefile.am b/Makefile.am
index 89b67e5..00bbc1c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,9 +10,16 @@ ACLOCAL_AMFLAGS = -I m4
# This is so we can #include <google/foo>
AM_CPPFLAGS = -I$(top_srcdir)/src
+if !WITH_STACK_TRACE
+AM_CPPFLAGS += -DNO_TCMALLOC_SAMPLES
+endif !WITH_STACK_TRACE
+
# This is mostly based on configure options
AM_CXXFLAGS =
+# This is to fix a solaris bug
+AM_LDFLAGS = $(LIBSTDCXX_LA_LINKER_FLAG)
+
# These are good warnings to turn on by default,
if GCC
AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
@@ -40,7 +47,7 @@ AM_CXXFLAGS += -DNO_FRAME_POINTER
endif !ENABLE_FRAME_POINTERS
endif X86_64
-# For windows systems (mingw and cygwin), we need to tell all our
+# For windows systems (at least, mingw), we need to tell all our
# tests to link in libtcmalloc using -u. This is because libtcmalloc
# accomplishes its tasks via patching, leaving no work for the linker
# to identify, so the linker will ignore libtcmalloc by default unless
@@ -91,6 +98,8 @@ noinst_SCRIPTS =
# be installed, add it here. (Stuff in TESTS is automatically added later).
noinst_PROGRAMS =
+# Binaries we might build that should be installed
+bin_PROGRAMS =
## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS
@@ -117,6 +126,7 @@ SYSINFO_INCLUDES = src/base/sysinfo.h \
noinst_LTLIBRARIES += libsysinfo.la
libsysinfo_la_SOURCES = src/base/sysinfo.cc \
$(SYSINFO_INCLUDES)
+libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS)
# For MinGW, we use libwindows and not libspinlock. For every other
# unix system, we use libspinlock and don't need libwindows. Luckily,
@@ -144,7 +154,7 @@ LIBSPINLOCK = libwindows.la libsysinfo.la liblogging.la
# We also need to tell mingw that sysinfo.cc needs shlwapi.lib.
# (We do this via a #pragma for msvc, but need to do it here for mingw).
-libsysinfo_la_LIBADD = -lshlwapi
+libsysinfo_la_LIBADD += -lshlwapi
MAYBE_THREADS_CC =
SYSTEM_ALLOC_CC =
@@ -161,6 +171,7 @@ noinst_LTLIBRARIES += libspinlock.la
libspinlock_la_SOURCES = src/base/spinlock.cc \
src/base/atomicops-internals-x86.cc \
$(SPINLOCK_INCLUDES)
+libspinlock_la_LIBADD = $(NANOSLEEP_LIBS)
# spinlock also needs NumCPUs, from libsysinfo, which in turn needs liblogging
LIBSPINLOCK = libspinlock.la libsysinfo.la liblogging.la
@@ -182,7 +193,10 @@ low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \
src/malloc_hook.cc \
src/tests/low_level_alloc_unittest.cc \
$(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES)
-low_level_alloc_unittest_LDADD = libstacktrace.la
+# By default, MallocHook takes stack traces for use by the heap-checker.
+# We don't need that functionality here, so we turn it off to reduce deps.
+low_level_alloc_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES
+low_level_alloc_unittest_LDADD = $(LIBSPINLOCK)
if !MINGW
TESTS += atomicops_unittest
@@ -199,13 +213,17 @@ endif !MINGW
### ------- stack trace
+if WITH_STACK_TRACE
+
### The header files we use. We divide into categories based on directory
-S_STACKTRACE_INCLUDES = src/stacktrace_generic-inl.h \
+S_STACKTRACE_INCLUDES = src/stacktrace_config.h \
+ src/stacktrace_generic-inl.h \
src/stacktrace_libunwind-inl.h \
src/stacktrace_powerpc-inl.h \
src/stacktrace_x86_64-inl.h \
src/stacktrace_x86-inl.h \
- src/stacktrace_win32-inl.h
+ src/stacktrace_win32-inl.h \
+ src/base/vdso_support.h
SG_STACKTRACE_INCLUDES = src/google/stacktrace.h
STACKTRACE_INCLUDES = $(S_STACKTRACE_INCLUDES) $(SG_STACKTRACE_INCLUDES)
googleinclude_HEADERS += $(SG_STACKTRACE_INCLUDES)
@@ -213,9 +231,11 @@ googleinclude_HEADERS += $(SG_STACKTRACE_INCLUDES)
### Making the library
noinst_LTLIBRARIES += libstacktrace.la
libstacktrace_la_SOURCES = src/stacktrace.cc \
+ src/stacktrace_with_context.cc \
+ src/base/vdso_support.cc \
$(STACKTRACE_INCLUDES)
libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK)
-STACKTRACE_SYMBOLS = '(GetStackTrace)'
+STACKTRACE_SYMBOLS = '(GetStackTrace|GetStackFrames|GetStackTraceWithContext|)GetStackFramesWithContext)'
libstacktrace_la_LDFLAGS = -export-symbols-regex $(STACKTRACE_SYMBOLS)
### Unittests
@@ -231,26 +251,45 @@ stacktrace_unittest_LDADD = libstacktrace.la liblogging.la
### Documentation
dist_doc_DATA +=
+endif WITH_STACK_TRACE
### ------- pprof
+# If we are not compiling with stacktrace support, pprof is worthless
+if WITH_STACK_TRACE
+
bin_SCRIPTS = src/pprof
### Unittests
-if !MINGW
check_SCRIPTS = pprof_unittest
pprof_unittest: $(top_srcdir)/src/pprof
$(top_srcdir)/src/pprof -test
# Let unittests find pprof if they need to run it
TESTS_ENVIRONMENT += PPROF_PATH=$(top_srcdir)/src/pprof
-endif !MINGW
### Documentation
dist_man_MANS = doc/pprof.1
dist_doc_DATA += doc/pprof_remote_servers.html
+# On windows, we need our own versions of addr2line and nm to work with pprof
+# We always include the relevant files in 'make dist', but only conditionally
+# compile them.
+WINDOWS_PROJECTS += vsprojects/nm-pdb/nm-pdb.vcproj
+WINDOWS_PROJECTS += vsprojects/addr2line-pdb/addr2line-pdb.vcproj
+
+nm_pdb_SOURCES = src/windows/nm-pdb.c
+addr2line_pdb_SOURCES = src/windows/addr2line-pdb.c
+
+# TODO(csilvers): these don't currently compile under mingw/cygwin,
+# since they don't have dbghelp.h. Figure that out later.
+## if HAVE_WINDOWS_H
+## bin_PROGRAMS += nm-pdb addr2line-pdb
+## endif HAVE_WINDOWS_H
+WINDOWS_PROJECTS += $(nm_pdb_SOURCES) $(addr2line_pdb_SOURCES)
+
+endif WITH_STACK_TRACE
### ------- tcmalloc_minimal (thread-caching malloc)
@@ -264,6 +303,7 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/base/commandlineflags.h \
src/base/basictypes.h \
src/pagemap.h \
+ src/sampler.h \
src/central_freelist.h \
src/linked_list.h \
src/page_heap.h \
@@ -271,6 +311,7 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/span.h \
src/static_vars.h \
src/thread_cache.h \
+ src/stack_trace_table.h \
src/base/thread_annotations.h \
src/malloc_hook-inl.h \
src/maybe_threads.h
@@ -294,7 +335,9 @@ libtcmalloc_minimal_internal_la_SOURCES = src/common.cc \
src/memfs_malloc.cc \
src/central_freelist.cc \
src/page_heap.cc \
+ src/sampler.cc \
src/span.cc \
+ src/stack_trace_table.cc \
src/static_vars.cc \
src/thread_cache.cc \
src/malloc_hook.cc \
@@ -310,8 +353,7 @@ libtcmalloc_minimal_internal_la_LIBADD = $(PTHREAD_LIBS) $(LIBSPINLOCK)
lib_LTLIBRARIES += libtcmalloc_minimal.la
WINDOWS_PROJECTS += vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
-libtcmalloc_minimal_la_SOURCES = src/tcmalloc.cc \
- $(TCMALLOC_MINIMAL_INCLUDES)
+libtcmalloc_minimal_la_SOURCES = src/tcmalloc.cc $(TCMALLOC_MINIMAL_INCLUDES)
libtcmalloc_minimal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \
$(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS)
@@ -371,7 +413,7 @@ tcmalloc_minimal_large_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
# libraries anyway (so can't be LD_PRELOADed).
# TODO(csilvers): figure out how to nix ".exe" or otherwise work under mingw
if !MINGW
-TESTS += maybe_threads_unittest.sh
+TESTS += maybe_threads_unittest.sh$(EXEEXT)
maybe_threads_unittest_sh_SOURCES = src/tests/maybe_threads_unittest.sh
noinst_SCRIPTS += $(maybe_threads_unittest_sh_SOURCES)
# This script preloads libtcmalloc, and calls two other binaries as well
@@ -425,6 +467,17 @@ markidle_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
markidle_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
markidle_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+TESTS += malloc_extension_test
+WINDOWS_PROJECTS += vsprojects/malloc_extension_test/malloc_extension_test.vcproj
+malloc_extension_test_SOURCES = src/tests/malloc_extension_test.cc \
+ src/config_for_unittests.h \
+ src/base/logging.h \
+ src/google/malloc_extension.h \
+ src/google/malloc_extension_c.h
+malloc_extension_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+malloc_extension_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+malloc_extension_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+
if !MINGW
TESTS += memalign_unittest
memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \
@@ -436,6 +489,33 @@ memalign_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
memalign_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
endif !MINGW
+TESTS += pagemap_unittest
+WINDOWS_PROJECTS += vsprojects/pagemap_unittest/pagemap_unittest.vcproj
+pagemap_unittest_SOURCES = src/tests/pagemap_unittest.cc \
+ src/config_for_unittests.h \
+ src/base/logging.h \
+ src/pagemap.h
+pagemap_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+pagemap_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+pagemap_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+
+TESTS += realloc_unittest
+WINDOWS_PROJECTS += vsprojects/realloc_unittest/realloc_unittest.vcproj
+realloc_unittest_SOURCES = src/tests/realloc_unittest.cc \
+ src/config_for_unittests.h \
+ src/base/logging.h
+realloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+realloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+realloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+
+TESTS += stack_trace_table_test
+WINDOWS_PROJECTS += vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj
+stack_trace_table_test_SOURCES = src/tests/stack_trace_table_test.cc \
+ src/config_for_unittests.h
+stack_trace_table_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+stack_trace_table_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+stack_trace_table_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+
TESTS += thread_dealloc_unittest
WINDOWS_PROJECTS += vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj
thread_dealloc_unittest_SOURCES = src/tests/thread_dealloc_unittest.cc \
@@ -508,13 +588,13 @@ dist_doc_DATA += doc/overview.dot \
### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker)
-# The full tcmalloc does not work on windows yet
-if !MINGW
+if WITH_HEAP_PROFILER_OR_CHECKER
### The header files we use. We divide into categories based on directory
S_TCMALLOC_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) \
$(LOGGING_INCLUDES) \
src/addressmap-inl.h \
+ src/raw_printer.h \
src/base/elfcore.h \
src/base/googleinit.h \
src/base/linux_syscall_support.h \
@@ -530,27 +610,40 @@ TCMALLOC_INCLUDES = $(S_TCMALLOC_INCLUDES) $(SG_TCMALLOC_INCLUDES)
googleinclude_HEADERS += $(SG_TCMALLOC_INCLUDES)
### Making the library
+
+# As we describe at the top of this file, we want to turn off exceptions
+# for all files in this library -- except tcmalloc.cc which needs them
+# to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need
+# to separate into two libraries.
+noinst_LTLIBRARIES += libtcmalloc_internal.la
+libtcmalloc_internal_la_SOURCES = $(libtcmalloc_minimal_internal_la_SOURCES) \
+ $(TCMALLOC_INCLUDES) \
+ src/base/low_level_alloc.cc \
+ src/heap-profile-table.cc \
+ src/heap-profiler.cc \
+ src/raw_printer.cc \
+ src/memory_region_map.cc
+libtcmalloc_internal_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG \
+ $(AM_CXXFLAGS) $(NO_EXCEPTIONS)
+libtcmalloc_internal_la_LDFLAGS = $(PTHREAD_CFLAGS)
+libtcmalloc_internal_la_LIBADD = $(PTHREAD_LIBS) libstacktrace.la
+
lib_LTLIBRARIES += libtcmalloc.la
-# Note: heap-checker-bcad is last, in hopes its global ctor will run first
-# TODO(csilvers): break libtcmalloc.la into two pieces, like we do for
-# libtcmalloc_minimal.la. Right now we don't need it,
-# since the break-up is for a cygwin-specific bug, and
-# cygwin doesn't support libtcmalloc anyway. But one day?
-libtcmalloc_la_SOURCES = $(libtcmalloc_minimal_internal_la_SOURCES) \
- $(libtcmalloc_minimal_la_SOURCES) \
- $(TCMALLOC_INCLUDES) \
- src/base/linuxthreads.cc \
- src/base/low_level_alloc.cc \
- src/base/thread_lister.c \
- src/heap-checker.cc \
- src/heap-profile-table.cc \
- src/heap-profiler.cc \
- src/memory_region_map.cc \
- src/heap-checker-bcad.cc
+libtcmalloc_la_SOURCES = src/tcmalloc.cc $(TCMALLOC_INCLUDES)
libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
-libtcmalloc_la_LIBADD = $(PTHREAD_LIBS) \
- libstacktrace.la
+libtcmalloc_la_LIBADD = $(PTHREAD_LIBS) libtcmalloc_internal.la
+
+if WITH_HEAP_CHECKER
+# heap-checker-bcad is last, in hopes its global ctor will run first.
+# (Note this is added to libtcmalloc.la, not libtcmalloc_internal.la,
+# but that's ok; the internal/external distinction is only useful for
+# cygwin, and cygwin doesn't use HEAP_CHECKER anyway.)
+libtcmalloc_la_SOURCES += src/base/thread_lister.c \
+ src/base/linuxthreads.cc \
+ src/heap-checker.cc \
+ src/heap-checker-bcad.cc
+endif WITH_HEAP_CHECKER
LIBTCMALLOC = libtcmalloc.la
@@ -579,13 +672,13 @@ tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
$(TCMALLOC_UNITTEST_INCLUDES)
tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-if HAS_PC
+if WITH_CPU_PROFILER
tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
libprofiler.la liblogging.la $(PTHREAD_LIBS)
else
tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
liblogging.la $(PTHREAD_LIBS)
-endif !HAS_PC
+endif !WITH_CPU_PROFILER
TESTS += tcmalloc_large_unittest
tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
@@ -593,11 +686,26 @@ tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+TESTS += raw_printer_test
+raw_printer_test_SOURCES = src/tests/raw_printer_test.cc
+raw_printer_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+raw_printer_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+raw_printer_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+
+TESTS += sampler_test
+WINDOWS_PROJECTS += vsprojects/sampler_test/sampler_test.vcproj
+sampler_test_SOURCES = src/tests/sampler_test.cc \
+ src/config_for_unittests.h
+sampler_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+sampler_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+sampler_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) -lm
+
+
# These unittests often need to run binaries. They're in the current dir
TESTS_ENVIRONMENT += BINDIR=.
TESTS_ENVIRONMENT += TMPDIR=/tmp/perftools
-TESTS += sampling_test.sh
+TESTS += sampling_test.sh$(EXEEXT)
sampling_test_sh_SOURCES = src/tests/sampling_test.sh
noinst_SCRIPTS += $(sampling_test_sh_SOURCES)
sampling_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \
@@ -617,8 +725,11 @@ sampling_test_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
sampling_test_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
sampling_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+endif WITH_HEAP_PROFILER_OR_CHECKER
+
+if WITH_HEAP_PROFILER
-TESTS += heap-profiler_unittest.sh
+TESTS += heap-profiler_unittest.sh$(EXEEXT)
heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh
noinst_SCRIPTS += $(heap_profiler_unittest_sh_SOURCES)
heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \
@@ -636,7 +747,11 @@ heap_profiler_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
heap_profiler_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
heap_profiler_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
-TESTS += heap-checker_unittest.sh
+endif WITH_HEAP_PROFILER
+
+if WITH_HEAP_CHECKER
+
+TESTS += heap-checker_unittest.sh$(EXEEXT)
heap_checker_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh
noinst_SCRIPTS += $(heap_checker_unittest_sh_SOURCES)
heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \
@@ -644,7 +759,7 @@ heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOUR
rm -f $@
cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@
-TESTS += heap-checker-death_unittest.sh
+TESTS += heap-checker-death_unittest.sh$(EXEEXT)
heap_checker_death_unittest_sh_SOURCES = src/tests/heap-checker-death_unittest.sh
noinst_SCRIPTS += $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES)
heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCES) \
@@ -667,19 +782,21 @@ heap_checker_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
# tcmalloc has to be specified last!
heap_checker_unittest_LDADD = $(PTHREAD_LIBS) liblogging.la $(LIBTCMALLOC)
+endif WITH_HEAP_CHECKER
+
### Documentation (above and beyond tcmalloc_minimal documentation)
-dist_doc_DATA += doc/heapprofile.html \
- doc/heap-example1.png \
- doc/heap_checker.html
+if WITH_HEAP_PROFILER
+dist_doc_DATA += doc/heapprofile.html doc/heap-example1.png
+endif WITH_HEAP_PROFILER
+
+if WITH_HEAP_CHECKER
+dist_doc_DATA += doc/heap_checker.html
+endif WITH_HEAP_CHECKER
-endif !MINGW
### ------- CPU profiler
-# The CPU profiler doesn't work on windows yet. It also doesn't work
-# if there's no way to get the PC.
-if !MINGW
-if HAS_PC
+if WITH_CPU_PROFILER
### The header files we use. We divide into categories based on directory
S_CPU_PROFILER_INCLUDES = src/profiledata.h \
@@ -725,7 +842,7 @@ profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \
src/base/basictypes.h
profiledata_unittest_LDADD = $(LIBPROFILER)
-TESTS += profiler_unittest.sh
+TESTS += profiler_unittest.sh$(EXEEXT)
profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh
noinst_SCRIPTS += $(profiler_unittest_sh_SOURCES)
profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \
@@ -770,12 +887,7 @@ dist_doc_DATA += doc/cpuprofile.html \
doc/pprof-vsnprintf-big.gif \
doc/pprof-vsnprintf.gif
-endif HAS_PC
-endif !MINGW
-
-# Some windows-only projects
-WINDOWS_PROJECTS += vsprojects/nm-pdb/nm-pdb.vcproj
-WINDOWS_PROJECTS += vsprojects/addr2line-pdb/addr2line-pdb.vcproj
+endif WITH_CPU_PROFILER
## ^^^^ END OF RULES TO MAKE YOUR LIBRARIES, BINARIES, AND UNITTESTS
@@ -801,7 +913,6 @@ dist-hook:
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
$(SCRIPTS) libtool \
- src/windows/nm-pdb.c src/windows/addr2line-pdb.c \
src/windows/get_mangled_names.cc \
src/windows/config.h $(WINDOWS_PROJECTS) \
src/solaris/libstdc++.la
diff --git a/Makefile.in b/Makefile.in
index f0789b9..987c5e8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -44,45 +44,82 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-target_triplet = @target@
+@WITH_STACK_TRACE_FALSE@am__append_1 = -DNO_TCMALLOC_SAMPLES
# These are good warnings to turn on by default,
-@GCC_TRUE@am__append_1 = -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
+@GCC_TRUE@am__append_2 = -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
# These are x86-specific, having to do with frame-pointers
-@ENABLE_FRAME_POINTERS_TRUE@@X86_64_TRUE@am__append_2 = -fno-omit-frame-pointer
-@ENABLE_FRAME_POINTERS_FALSE@@X86_64_TRUE@am__append_3 = -DNO_FRAME_POINTER
-@MINGW_TRUE@am__append_4 = -Wl,-u__tcmalloc
-noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_9)
-@MINGW_TRUE@am__append_5 = libwindows.la
-@MINGW_FALSE@am__append_6 = libspinlock.la
-@MINGW_FALSE@am__append_7 = atomicops_unittest
+@ENABLE_FRAME_POINTERS_TRUE@@X86_64_TRUE@am__append_3 = -fno-omit-frame-pointer
+@ENABLE_FRAME_POINTERS_FALSE@@X86_64_TRUE@am__append_4 = -DNO_FRAME_POINTER
+@MINGW_TRUE@am__append_5 = -Wl,-u__tcmalloc
+noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ $(am__EXEEXT_4) $(am__EXEEXT_14)
+bin_PROGRAMS =
+@MINGW_TRUE@am__append_6 = libwindows.la
+
+# We also need to tell mingw that sysinfo.cc needs shlwapi.lib.
+# (We do this via a #pragma for msvc, but need to do it here for mingw).
+@MINGW_TRUE@am__append_7 = -lshlwapi
+@MINGW_FALSE@am__append_8 = libspinlock.la
+@MINGW_FALSE@am__append_9 = atomicops_unittest
+@WITH_STACK_TRACE_TRUE@am__append_10 = $(SG_STACKTRACE_INCLUDES)
+
+### Making the library
+@WITH_STACK_TRACE_TRUE@am__append_11 = libstacktrace.la
+
+### Unittests
+@WITH_STACK_TRACE_TRUE@am__append_12 = stacktrace_unittest
+
+### Documentation
+@WITH_STACK_TRACE_TRUE@am__append_13 = doc/pprof_remote_servers.html
# Let unittests find pprof if they need to run it
+@WITH_STACK_TRACE_TRUE@am__append_14 = PPROF_PATH=$(top_srcdir)/src/pprof
-# These unittests often need to run binaries. They're in the current dir
-@MINGW_FALSE@am__append_8 = PPROF_PATH=$(top_srcdir)/src/pprof \
-@MINGW_FALSE@ BINDIR=. TMPDIR=/tmp/perftools
+# On windows, we need our own versions of addr2line and nm to work with pprof
+# We always include the relevant files in 'make dist', but only conditionally
+# compile them.
+
+# TODO(csilvers): these don't currently compile under mingw/cygwin,
+# since they don't have dbghelp.h. Figure that out later.
+@WITH_STACK_TRACE_TRUE@am__append_15 = \
+@WITH_STACK_TRACE_TRUE@ vsprojects/nm-pdb/nm-pdb.vcproj \
+@WITH_STACK_TRACE_TRUE@ vsprojects/addr2line-pdb/addr2line-pdb.vcproj \
+@WITH_STACK_TRACE_TRUE@ $(nm_pdb_SOURCES) \
+@WITH_STACK_TRACE_TRUE@ $(addr2line_pdb_SOURCES)
# This tests it works to LD_PRELOAD libtcmalloc (tests maybe_threads.cc)
# In theory this should work under mingw, but mingw has trouble running
# shell scripts that end in .exe. And it doesn't seem to build shared
# libraries anyway (so can't be LD_PRELOADed).
# TODO(csilvers): figure out how to nix ".exe" or otherwise work under mingw
-@MINGW_FALSE@am__append_9 = maybe_threads_unittest.sh
-@MINGW_FALSE@am__append_10 = $(maybe_threads_unittest_sh_SOURCES) \
-@MINGW_FALSE@ $(sampling_test_sh_SOURCES) \
-@MINGW_FALSE@ $(heap_profiler_unittest_sh_SOURCES) \
-@MINGW_FALSE@ $(heap_checker_unittest_sh_SOURCES) \
-@MINGW_FALSE@ $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES)
-@MINGW_FALSE@am__append_11 = system_alloc_unittest
-@MINGW_FALSE@am__append_12 = memalign_unittest
+@MINGW_FALSE@am__append_16 = maybe_threads_unittest.sh$(EXEEXT)
+@MINGW_FALSE@am__append_17 = $(maybe_threads_unittest_sh_SOURCES)
+@MINGW_FALSE@am__append_18 = system_alloc_unittest
+@MINGW_FALSE@am__append_19 = memalign_unittest
EXTRA_PROGRAMS = ptmalloc_unittest1$(EXEEXT) \
ptmalloc_unittest2$(EXEEXT)
-@MINGW_FALSE@am__append_13 = $(SG_TCMALLOC_INCLUDES)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_20 = $(SG_TCMALLOC_INCLUDES)
### Making the library
-@MINGW_FALSE@am__append_14 = libtcmalloc.la
+
+# As we describe at the top of this file, we want to turn off exceptions
+# for all files in this library -- except tcmalloc.cc which needs them
+# to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need
+# to separate into two libraries.
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_21 = libtcmalloc_internal.la
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_22 = libtcmalloc.la
+
+# heap-checker-bcad is last, in hopes its global ctor will run first.
+# (Note this is added to libtcmalloc.la, not libtcmalloc_internal.la,
+# but that's ok; the internal/external distinction is only useful for
+# cygwin, and cygwin doesn't use HEAP_CHECKER anyway.)
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_23 = src/base/thread_lister.c \
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/linuxthreads.cc \
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-checker.cc \
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-checker-bcad.cc
+
### Unittests
@@ -90,51 +127,64 @@ EXTRA_PROGRAMS = ptmalloc_unittest1$(EXEEXT) \
# tcmalloc_minimal. (One would never do this on purpose, but perhaps
# by accident...) When we can compile libprofiler, we also link it in
# to make sure that works too.
-@MINGW_FALSE@am__append_15 = tcmalloc_unittest tcmalloc_both_unittest \
-@MINGW_FALSE@ tcmalloc_large_unittest sampling_test.sh \
-@MINGW_FALSE@ heap-profiler_unittest.sh \
-@MINGW_FALSE@ heap-checker_unittest.sh \
-@MINGW_FALSE@ heap-checker-death_unittest.sh
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_24 = tcmalloc_unittest \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_test \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test.sh$(EXEEXT)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_25 = vsprojects/sampler_test/sampler_test.vcproj
+
+# These unittests often need to run binaries. They're in the current dir
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_26 = BINDIR=. \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ TMPDIR=/tmp/perftools
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_27 = $(sampling_test_sh_SOURCES)
# This is the sub-program using by sampling_test.sh
# The -g is so pprof can get symbol information.
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_28 = sampling_test
+@WITH_HEAP_PROFILER_TRUE@am__append_29 = heap-profiler_unittest.sh$(EXEEXT)
+@WITH_HEAP_PROFILER_TRUE@am__append_30 = $(heap_profiler_unittest_sh_SOURCES)
# These are sub-programs used by heap-profiler_unittest.sh
+@WITH_HEAP_PROFILER_TRUE@am__append_31 = heap-profiler_unittest
+@WITH_HEAP_CHECKER_TRUE@am__append_32 = \
+@WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \
+@WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT)
+@WITH_HEAP_CHECKER_TRUE@am__append_33 = \
+@WITH_HEAP_CHECKER_TRUE@ $(heap_checker_unittest_sh_SOURCES) \
+@WITH_HEAP_CHECKER_TRUE@ $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES)
# These are sub-programs used by heap-checker_unittest.sh
-@MINGW_FALSE@am__append_16 = sampling_test heap-profiler_unittest \
-@MINGW_FALSE@ heap-checker_unittest
+@WITH_HEAP_CHECKER_TRUE@am__append_34 = heap-checker_unittest
### Documentation (above and beyond tcmalloc_minimal documentation)
-@MINGW_FALSE@am__append_17 = doc/heapprofile.html \
-@MINGW_FALSE@ doc/heap-example1.png \
-@MINGW_FALSE@ doc/heap_checker.html
-
-@HAS_PC_TRUE@@MINGW_FALSE@am__append_18 = $(SG_CPU_PROFILER_INCLUDES)
+@WITH_HEAP_PROFILER_TRUE@am__append_35 = doc/heapprofile.html doc/heap-example1.png
+@WITH_HEAP_CHECKER_TRUE@am__append_36 = doc/heap_checker.html
+@WITH_CPU_PROFILER_TRUE@am__append_37 = $(SG_CPU_PROFILER_INCLUDES)
### Making the library
-@HAS_PC_TRUE@@MINGW_FALSE@am__append_19 = libprofiler.la
+@WITH_CPU_PROFILER_TRUE@am__append_38 = libprofiler.la
### Unittests
-@HAS_PC_TRUE@@MINGW_FALSE@am__append_20 = getpc_test \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiledata_unittest \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler_unittest.sh
-@HAS_PC_TRUE@@MINGW_FALSE@am__append_21 = $(profiler_unittest_sh_SOURCES)
+@WITH_CPU_PROFILER_TRUE@am__append_39 = getpc_test \
+@WITH_CPU_PROFILER_TRUE@ profiledata_unittest \
+@WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT)
+@WITH_CPU_PROFILER_TRUE@am__append_40 = $(profiler_unittest_sh_SOURCES)
# These are sub-programs used by profiler_unittest.sh
-@HAS_PC_TRUE@@MINGW_FALSE@am__append_22 = profiler1_unittest profiler2_unittest profiler3_unittest \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler4_unittest
+@WITH_CPU_PROFILER_TRUE@am__append_41 = profiler1_unittest profiler2_unittest profiler3_unittest \
+@WITH_CPU_PROFILER_TRUE@ profiler4_unittest
-@HAS_PC_FALSE@profiler2_unittest_DEPENDENCIES =
-@MINGW_TRUE@profiler2_unittest_DEPENDENCIES =
+@WITH_CPU_PROFILER_FALSE@profiler2_unittest_DEPENDENCIES =
### Documentation
-@HAS_PC_TRUE@@MINGW_FALSE@am__append_23 = doc/cpuprofile.html \
-@HAS_PC_TRUE@@MINGW_FALSE@ doc/cpuprofile-fileformat.html \
-@HAS_PC_TRUE@@MINGW_FALSE@ doc/pprof-test-big.gif \
-@HAS_PC_TRUE@@MINGW_FALSE@ doc/pprof-test.gif \
-@HAS_PC_TRUE@@MINGW_FALSE@ doc/pprof-vsnprintf-big.gif \
-@HAS_PC_TRUE@@MINGW_FALSE@ doc/pprof-vsnprintf.gif
+@WITH_CPU_PROFILER_TRUE@am__append_42 = doc/cpuprofile.html \
+@WITH_CPU_PROFILER_TRUE@ doc/cpuprofile-fileformat.html \
+@WITH_CPU_PROFILER_TRUE@ doc/pprof-test-big.gif \
+@WITH_CPU_PROFILER_TRUE@ doc/pprof-test.gif \
+@WITH_CPU_PROFILER_TRUE@ doc/pprof-vsnprintf-big.gif \
+@WITH_CPU_PROFILER_TRUE@ doc/pprof-vsnprintf.gif
DIST_COMMON = README $(am__configure_deps) $(am__dist_doc_DATA_DIST) \
$(am__googleinclude_HEADERS_DIST) $(dist_man_MANS) \
@@ -145,6 +195,7 @@ DIST_COMMON = README $(am__configure_deps) $(am__dist_doc_DATA_DIST) \
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_have_attribute.m4 \
+ $(top_srcdir)/m4/acx_nanosleep.m4 \
$(top_srcdir)/m4/acx_pthread.m4 \
$(top_srcdir)/m4/compiler_characteristics.m4 \
$(top_srcdir)/m4/install_prefix.m4 \
@@ -166,8 +217,8 @@ am__vpath_adj = case $$p in \
esac;
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
- "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" \
- "$(DESTDIR)$(googleincludedir)"
+ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
+ "$(DESTDIR)$(docdir)" "$(DESTDIR)$(googleincludedir)"
libLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
liblogging_la_LIBADD =
@@ -175,8 +226,8 @@ am__objects_1 =
am_liblogging_la_OBJECTS = logging.lo dynamic_annotations.lo \
$(am__objects_1)
liblogging_la_OBJECTS = $(am_liblogging_la_OBJECTS)
-@HAS_PC_TRUE@@MINGW_FALSE@libprofiler_la_DEPENDENCIES = \
-@HAS_PC_TRUE@@MINGW_FALSE@ libstacktrace.la
+@WITH_CPU_PROFILER_TRUE@libprofiler_la_DEPENDENCIES = \
+@WITH_CPU_PROFILER_TRUE@ libstacktrace.la
am__libprofiler_la_SOURCES_DIST = src/profiler.cc src/profiledata.cc \
src/profiledata.h src/getpc.h src/base/basictypes.h \
src/base/commandlineflags.h src/base/googleinit.h \
@@ -188,15 +239,16 @@ am__libprofiler_la_SOURCES_DIST = src/profiler.cc src/profiledata.cc \
src/base/atomicops-internals-x86.h \
src/base/dynamic_annotations.h src/google/profiler.h \
src/google/stacktrace.h
-@HAS_PC_TRUE@@MINGW_FALSE@am__objects_2 = $(am__objects_1) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_1)
-@HAS_PC_TRUE@@MINGW_FALSE@am__objects_3 = $(am__objects_2) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_1)
-@HAS_PC_TRUE@@MINGW_FALSE@am_libprofiler_la_OBJECTS = profiler.lo \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiledata.lo $(am__objects_3)
+@WITH_CPU_PROFILER_TRUE@am__objects_2 = $(am__objects_1) \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
+@WITH_CPU_PROFILER_TRUE@am__objects_3 = $(am__objects_2) \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
+@WITH_CPU_PROFILER_TRUE@am_libprofiler_la_OBJECTS = profiler.lo \
+@WITH_CPU_PROFILER_TRUE@ profiledata.lo $(am__objects_3)
libprofiler_la_OBJECTS = $(am_libprofiler_la_OBJECTS)
-@HAS_PC_TRUE@@MINGW_FALSE@am_libprofiler_la_rpath = -rpath $(libdir)
-libspinlock_la_LIBADD =
+@WITH_CPU_PROFILER_TRUE@am_libprofiler_la_rpath = -rpath $(libdir)
+am__DEPENDENCIES_1 =
+@MINGW_FALSE@libspinlock_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am__libspinlock_la_SOURCES_DIST = src/base/spinlock.cc \
src/base/atomicops-internals-x86.cc src/base/spinlock.h \
src/base/atomicops.h src/base/atomicops-internals-macosx.h \
@@ -207,77 +259,133 @@ am__libspinlock_la_SOURCES_DIST = src/base/spinlock.cc \
@MINGW_FALSE@ atomicops-internals-x86.lo $(am__objects_1)
libspinlock_la_OBJECTS = $(am_libspinlock_la_OBJECTS)
@MINGW_FALSE@am_libspinlock_la_rpath =
-am__DEPENDENCIES_1 =
@MINGW_FALSE@am__DEPENDENCIES_2 = libspinlock.la libsysinfo.la \
@MINGW_FALSE@ liblogging.la
@MINGW_TRUE@am__DEPENDENCIES_2 = libwindows.la libsysinfo.la \
@MINGW_TRUE@ liblogging.la
-libstacktrace_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_2)
-am__objects_4 = $(am__objects_1) $(am__objects_1)
-am_libstacktrace_la_OBJECTS = stacktrace.lo $(am__objects_4)
+@WITH_STACK_TRACE_TRUE@libstacktrace_la_DEPENDENCIES = \
+@WITH_STACK_TRACE_TRUE@ $(am__DEPENDENCIES_1) \
+@WITH_STACK_TRACE_TRUE@ $(am__DEPENDENCIES_2)
+am__libstacktrace_la_SOURCES_DIST = src/stacktrace.cc \
+ src/stacktrace_with_context.cc src/base/vdso_support.cc \
+ src/stacktrace_config.h src/stacktrace_generic-inl.h \
+ src/stacktrace_libunwind-inl.h src/stacktrace_powerpc-inl.h \
+ src/stacktrace_x86_64-inl.h src/stacktrace_x86-inl.h \
+ src/stacktrace_win32-inl.h src/base/vdso_support.h \
+ src/google/stacktrace.h
+@WITH_STACK_TRACE_TRUE@am__objects_4 = $(am__objects_1) \
+@WITH_STACK_TRACE_TRUE@ $(am__objects_1)
+@WITH_STACK_TRACE_TRUE@am_libstacktrace_la_OBJECTS = stacktrace.lo \
+@WITH_STACK_TRACE_TRUE@ stacktrace_with_context.lo \
+@WITH_STACK_TRACE_TRUE@ vdso_support.lo $(am__objects_4)
libstacktrace_la_OBJECTS = $(am_libstacktrace_la_OBJECTS)
-libsysinfo_la_DEPENDENCIES =
+@WITH_STACK_TRACE_TRUE@am_libstacktrace_la_rpath =
+libsysinfo_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
am_libsysinfo_la_OBJECTS = sysinfo.lo $(am__objects_1)
libsysinfo_la_OBJECTS = $(am_libsysinfo_la_OBJECTS)
-@MINGW_FALSE@libtcmalloc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
-@MINGW_FALSE@ libstacktrace.la
-am__libtcmalloc_la_SOURCES_DIST = src/common.cc \
- src/internal_logging.cc src/system-alloc.cc \
- src/memfs_malloc.cc src/central_freelist.cc src/page_heap.cc \
- src/span.cc src/static_vars.cc src/thread_cache.cc \
- src/malloc_hook.cc src/malloc_extension.cc \
- src/maybe_threads.cc src/common.h src/internal_logging.h \
- src/system-alloc.h src/packed-cache-inl.h src/base/spinlock.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal.la
+am__libtcmalloc_la_SOURCES_DIST = src/tcmalloc.cc src/common.h \
+ src/internal_logging.h src/system-alloc.h \
+ src/packed-cache-inl.h src/base/spinlock.h \
src/base/atomicops.h src/base/atomicops-internals-macosx.h \
src/base/atomicops-internals-linuxppc.h \
src/base/atomicops-internals-x86-msvc.h \
src/base/atomicops-internals-x86.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
- src/pagemap.h src/central_freelist.h src/linked_list.h \
- src/page_heap.h src/page_heap_allocator.h src/span.h \
- src/static_vars.h src/thread_cache.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/stacktrace.h src/tcmalloc.cc src/base/logging.h \
+ src/pagemap.h src/sampler.h src/central_freelist.h \
+ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
+ src/span.h src/static_vars.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/maybe_threads.h src/base/logging.h \
src/base/dynamic_annotations.h src/addressmap-inl.h \
- src/base/elfcore.h src/base/googleinit.h \
+ src/raw_printer.h src/base/elfcore.h src/base/googleinit.h \
src/base/linux_syscall_support.h src/base/linuxthreads.h \
src/base/stl_allocator.h src/base/sysinfo.h \
src/base/thread_lister.h src/heap-profile-table.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/stacktrace.h \
src/google/heap-profiler.h src/google/heap-checker.h \
- src/base/linuxthreads.cc src/base/low_level_alloc.cc \
- src/base/thread_lister.c src/heap-checker.cc \
- src/heap-profile-table.cc src/heap-profiler.cc \
- src/memory_region_map.cc src/heap-checker-bcad.cc
-@MINGW_FALSE@am__objects_5 = libtcmalloc_la-system-alloc.lo
-@MINGW_FALSE@am__objects_6 = libtcmalloc_la-maybe_threads.lo
-am__objects_7 = $(am__objects_1)
-am__objects_8 = $(am__objects_7) $(am__objects_1)
-am__objects_9 = libtcmalloc_la-common.lo \
- libtcmalloc_la-internal_logging.lo $(am__objects_5) \
- libtcmalloc_la-memfs_malloc.lo \
- libtcmalloc_la-central_freelist.lo libtcmalloc_la-page_heap.lo \
- libtcmalloc_la-span.lo libtcmalloc_la-static_vars.lo \
- libtcmalloc_la-thread_cache.lo libtcmalloc_la-malloc_hook.lo \
- libtcmalloc_la-malloc_extension.lo $(am__objects_6) \
- $(am__objects_8)
-am__objects_10 = libtcmalloc_la-tcmalloc.lo $(am__objects_8)
-@MINGW_FALSE@am__objects_11 = $(am__objects_7) $(am__objects_1)
-@MINGW_FALSE@am__objects_12 = $(am__objects_1)
-@MINGW_FALSE@am__objects_13 = $(am__objects_11) $(am__objects_12)
-@MINGW_FALSE@am_libtcmalloc_la_OBJECTS = $(am__objects_9) \
-@MINGW_FALSE@ $(am__objects_10) $(am__objects_13) \
-@MINGW_FALSE@ libtcmalloc_la-linuxthreads.lo \
-@MINGW_FALSE@ libtcmalloc_la-low_level_alloc.lo \
-@MINGW_FALSE@ thread_lister.lo libtcmalloc_la-heap-checker.lo \
-@MINGW_FALSE@ libtcmalloc_la-heap-profile-table.lo \
-@MINGW_FALSE@ libtcmalloc_la-heap-profiler.lo \
-@MINGW_FALSE@ libtcmalloc_la-memory_region_map.lo \
-@MINGW_FALSE@ libtcmalloc_la-heap-checker-bcad.lo
+ src/base/thread_lister.c src/base/linuxthreads.cc \
+ src/heap-checker.cc src/heap-checker-bcad.cc
+am__objects_5 = $(am__objects_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_6 = $(am__objects_5) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_7 = $(am__objects_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_8 = $(am__objects_6) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_7)
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_9 = thread_lister.lo \
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_la-linuxthreads.lo \
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_la-heap-checker.lo \
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_la-heap-checker-bcad.lo
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_la_OBJECTS = libtcmalloc_la-tcmalloc.lo \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_8) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_9)
libtcmalloc_la_OBJECTS = $(am_libtcmalloc_la_OBJECTS)
-@MINGW_FALSE@am_libtcmalloc_la_rpath = -rpath $(libdir)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_la_rpath = -rpath \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(libdir)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libstacktrace.la
+am__libtcmalloc_internal_la_SOURCES_DIST = src/common.cc \
+ src/internal_logging.cc src/system-alloc.cc \
+ src/memfs_malloc.cc src/central_freelist.cc src/page_heap.cc \
+ src/sampler.cc src/span.cc src/stack_trace_table.cc \
+ src/static_vars.cc src/thread_cache.cc src/malloc_hook.cc \
+ src/malloc_extension.cc src/maybe_threads.cc src/common.h \
+ src/internal_logging.h src/system-alloc.h \
+ src/packed-cache-inl.h src/base/spinlock.h \
+ src/base/atomicops.h src/base/atomicops-internals-macosx.h \
+ src/base/atomicops-internals-linuxppc.h \
+ src/base/atomicops-internals-x86-msvc.h \
+ src/base/atomicops-internals-x86.h src/tcmalloc_guard.h \
+ src/base/commandlineflags.h src/base/basictypes.h \
+ src/pagemap.h src/sampler.h src/central_freelist.h \
+ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
+ src/span.h src/static_vars.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/stacktrace.h \
+ src/base/logging.h src/base/dynamic_annotations.h \
+ src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \
+ src/base/googleinit.h src/base/linux_syscall_support.h \
+ src/base/linuxthreads.h src/base/stl_allocator.h \
+ src/base/sysinfo.h src/base/thread_lister.h \
+ src/heap-profile-table.h src/google/heap-profiler.h \
+ src/google/heap-checker.h src/base/low_level_alloc.cc \
+ src/heap-profile-table.cc src/heap-profiler.cc \
+ src/raw_printer.cc src/memory_region_map.cc
+@MINGW_FALSE@am__objects_10 = libtcmalloc_internal_la-system-alloc.lo
+@MINGW_FALSE@am__objects_11 = \
+@MINGW_FALSE@ libtcmalloc_internal_la-maybe_threads.lo
+am__objects_12 = $(am__objects_5) $(am__objects_1)
+am__objects_13 = libtcmalloc_internal_la-common.lo \
+ libtcmalloc_internal_la-internal_logging.lo $(am__objects_10) \
+ libtcmalloc_internal_la-memfs_malloc.lo \
+ libtcmalloc_internal_la-central_freelist.lo \
+ libtcmalloc_internal_la-page_heap.lo \
+ libtcmalloc_internal_la-sampler.lo \
+ libtcmalloc_internal_la-span.lo \
+ libtcmalloc_internal_la-stack_trace_table.lo \
+ libtcmalloc_internal_la-static_vars.lo \
+ libtcmalloc_internal_la-thread_cache.lo \
+ libtcmalloc_internal_la-malloc_hook.lo \
+ libtcmalloc_internal_la-malloc_extension.lo $(am__objects_11) \
+ $(am__objects_12)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_internal_la_OBJECTS = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_13) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_8) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-low_level_alloc.lo \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-heap-profile-table.lo \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-heap-profiler.lo \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-raw_printer.lo \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_internal_la-memory_region_map.lo
+libtcmalloc_internal_la_OBJECTS = \
+ $(am_libtcmalloc_internal_la_OBJECTS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_libtcmalloc_internal_la_rpath =
libtcmalloc_minimal_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
libtcmalloc_minimal_internal.la
am__libtcmalloc_minimal_la_SOURCES_DIST = src/tcmalloc.cc src/common.h \
@@ -288,37 +396,38 @@ am__libtcmalloc_minimal_la_SOURCES_DIST = src/tcmalloc.cc src/common.h \
src/base/atomicops-internals-x86-msvc.h \
src/base/atomicops-internals-x86.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
- src/pagemap.h src/central_freelist.h src/linked_list.h \
- src/page_heap.h src/page_heap_allocator.h src/span.h \
- src/static_vars.h src/thread_cache.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/stacktrace.h
+ src/pagemap.h src/sampler.h src/central_freelist.h \
+ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
+ src/span.h src/static_vars.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/stacktrace.h
am_libtcmalloc_minimal_la_OBJECTS = \
- libtcmalloc_minimal_la-tcmalloc.lo $(am__objects_8)
+ libtcmalloc_minimal_la-tcmalloc.lo $(am__objects_12)
libtcmalloc_minimal_la_OBJECTS = $(am_libtcmalloc_minimal_la_OBJECTS)
libtcmalloc_minimal_internal_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2)
am__libtcmalloc_minimal_internal_la_SOURCES_DIST = src/common.cc \
src/internal_logging.cc src/system-alloc.cc \
src/memfs_malloc.cc src/central_freelist.cc src/page_heap.cc \
- src/span.cc src/static_vars.cc src/thread_cache.cc \
- src/malloc_hook.cc src/malloc_extension.cc \
- src/maybe_threads.cc src/common.h src/internal_logging.h \
- src/system-alloc.h src/packed-cache-inl.h src/base/spinlock.h \
+ src/sampler.cc src/span.cc src/stack_trace_table.cc \
+ src/static_vars.cc src/thread_cache.cc src/malloc_hook.cc \
+ src/malloc_extension.cc src/maybe_threads.cc src/common.h \
+ src/internal_logging.h src/system-alloc.h \
+ src/packed-cache-inl.h src/base/spinlock.h \
src/base/atomicops.h src/base/atomicops-internals-macosx.h \
src/base/atomicops-internals-linuxppc.h \
src/base/atomicops-internals-x86-msvc.h \
src/base/atomicops-internals-x86.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
- src/pagemap.h src/central_freelist.h src/linked_list.h \
- src/page_heap.h src/page_heap_allocator.h src/span.h \
- src/static_vars.h src/thread_cache.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/stacktrace.h
+ src/pagemap.h src/sampler.h src/central_freelist.h \
+ src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
+ src/span.h src/static_vars.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/stacktrace.h
@MINGW_FALSE@am__objects_14 = \
@MINGW_FALSE@ libtcmalloc_minimal_internal_la-system-alloc.lo
@MINGW_FALSE@am__objects_15 = \
@@ -330,12 +439,14 @@ am_libtcmalloc_minimal_internal_la_OBJECTS = \
libtcmalloc_minimal_internal_la-memfs_malloc.lo \
libtcmalloc_minimal_internal_la-central_freelist.lo \
libtcmalloc_minimal_internal_la-page_heap.lo \
+ libtcmalloc_minimal_internal_la-sampler.lo \
libtcmalloc_minimal_internal_la-span.lo \
+ libtcmalloc_minimal_internal_la-stack_trace_table.lo \
libtcmalloc_minimal_internal_la-static_vars.lo \
libtcmalloc_minimal_internal_la-thread_cache.lo \
libtcmalloc_minimal_internal_la-malloc_hook.lo \
libtcmalloc_minimal_internal_la-malloc_extension.lo \
- $(am__objects_15) $(am__objects_8)
+ $(am__objects_15) $(am__objects_12)
libtcmalloc_minimal_internal_la_OBJECTS = \
$(am_libtcmalloc_minimal_internal_la_OBJECTS)
libwindows_la_LIBADD =
@@ -353,40 +464,49 @@ am__libwindows_la_SOURCES_DIST = src/windows/port.h \
@MINGW_TRUE@ preamble_patcher.lo preamble_patcher_with_stub.lo
libwindows_la_OBJECTS = $(am_libwindows_la_OBJECTS)
@MINGW_TRUE@am_libwindows_la_rpath =
-@MINGW_FALSE@am__EXEEXT_1 = sampling_test$(EXEEXT) \
-@MINGW_FALSE@ heap-profiler_unittest$(EXEEXT) \
-@MINGW_FALSE@ heap-checker_unittest$(EXEEXT)
-@HAS_PC_TRUE@@MINGW_FALSE@am__EXEEXT_2 = profiler1_unittest$(EXEEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler2_unittest$(EXEEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler3_unittest$(EXEEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler4_unittest$(EXEEXT)
-@MINGW_FALSE@am__EXEEXT_3 = atomicops_unittest$(EXEEXT)
-@MINGW_FALSE@am__EXEEXT_4 = maybe_threads_unittest.sh$(EXEEXT)
-@MINGW_FALSE@am__EXEEXT_5 = system_alloc_unittest$(EXEEXT)
-@MINGW_FALSE@am__EXEEXT_6 = memalign_unittest$(EXEEXT)
-@MINGW_FALSE@am__EXEEXT_7 = tcmalloc_unittest$(EXEEXT) \
-@MINGW_FALSE@ tcmalloc_both_unittest$(EXEEXT) \
-@MINGW_FALSE@ tcmalloc_large_unittest$(EXEEXT) \
-@MINGW_FALSE@ sampling_test.sh$(EXEEXT) \
-@MINGW_FALSE@ heap-profiler_unittest.sh$(EXEEXT) \
-@MINGW_FALSE@ heap-checker_unittest.sh$(EXEEXT) \
-@MINGW_FALSE@ heap-checker-death_unittest.sh$(EXEEXT)
-@HAS_PC_TRUE@@MINGW_FALSE@am__EXEEXT_8 = getpc_test$(EXEEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiledata_unittest$(EXEEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler_unittest.sh$(EXEEXT)
-am__EXEEXT_9 = low_level_alloc_unittest$(EXEEXT) $(am__EXEEXT_3) \
- stacktrace_unittest$(EXEEXT) \
- tcmalloc_minimal_unittest$(EXEEXT) \
- tcmalloc_minimal_large_unittest$(EXEEXT) $(am__EXEEXT_4) \
- addressmap_unittest$(EXEEXT) $(am__EXEEXT_5) \
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_1 = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test$(EXEEXT)
+@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_2 = \
+@WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest$(EXEEXT)
+@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_3 = heap-checker_unittest$(EXEEXT)
+@WITH_CPU_PROFILER_TRUE@am__EXEEXT_4 = profiler1_unittest$(EXEEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler2_unittest$(EXEEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler3_unittest$(EXEEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler4_unittest$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_5 = atomicops_unittest$(EXEEXT)
+@WITH_STACK_TRACE_TRUE@am__EXEEXT_6 = stacktrace_unittest$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_7 = maybe_threads_unittest.sh$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_8 = system_alloc_unittest$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_9 = memalign_unittest$(EXEEXT)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_10 = tcmalloc_unittest$(EXEEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest$(EXEEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest$(EXEEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test$(EXEEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_test$(EXEEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test.sh$(EXEEXT)
+@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_11 = \
+@WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest.sh$(EXEEXT)
+@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_12 = \
+@WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \
+@WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT)
+@WITH_CPU_PROFILER_TRUE@am__EXEEXT_13 = getpc_test$(EXEEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiledata_unittest$(EXEEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT)
+am__EXEEXT_14 = low_level_alloc_unittest$(EXEEXT) $(am__EXEEXT_5) \
+ $(am__EXEEXT_6) tcmalloc_minimal_unittest$(EXEEXT) \
+ tcmalloc_minimal_large_unittest$(EXEEXT) $(am__EXEEXT_7) \
+ addressmap_unittest$(EXEEXT) $(am__EXEEXT_8) \
packed_cache_test$(EXEEXT) frag_unittest$(EXEEXT) \
- markidle_unittest$(EXEEXT) $(am__EXEEXT_6) \
- thread_dealloc_unittest$(EXEEXT) $(am__EXEEXT_7) \
- $(am__EXEEXT_8)
-PROGRAMS = $(noinst_PROGRAMS)
+ markidle_unittest$(EXEEXT) malloc_extension_test$(EXEEXT) \
+ $(am__EXEEXT_9) pagemap_unittest$(EXEEXT) \
+ realloc_unittest$(EXEEXT) stack_trace_table_test$(EXEEXT) \
+ thread_dealloc_unittest$(EXEEXT) $(am__EXEEXT_10) \
+ $(am__EXEEXT_11) $(am__EXEEXT_12) $(am__EXEEXT_13)
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am_addressmap_unittest_OBJECTS = \
addressmap_unittest-addressmap_unittest.$(OBJEXT) \
- $(am__objects_7)
+ $(am__objects_5)
addressmap_unittest_OBJECTS = $(am_addressmap_unittest_OBJECTS)
addressmap_unittest_DEPENDENCIES = liblogging.la
am__atomicops_unittest_SOURCES_DIST = src/tests/atomicops_unittest.cc \
@@ -395,8 +515,9 @@ am__atomicops_unittest_SOURCES_DIST = src/tests/atomicops_unittest.cc \
src/base/atomicops-internals-x86.h src/base/logging.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/base/dynamic_annotations.h
+@MINGW_FALSE@am__objects_16 = $(am__objects_1)
@MINGW_FALSE@am_atomicops_unittest_OBJECTS = \
-@MINGW_FALSE@ atomicops_unittest.$(OBJEXT) $(am__objects_12)
+@MINGW_FALSE@ atomicops_unittest.$(OBJEXT) $(am__objects_16)
atomicops_unittest_OBJECTS = $(am_atomicops_unittest_OBJECTS)
@MINGW_FALSE@atomicops_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_frag_unittest_OBJECTS = frag_unittest-frag_unittest.$(OBJEXT)
@@ -407,8 +528,7 @@ frag_unittest_OBJECTS = $(am_frag_unittest_OBJECTS)
frag_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
$(am__DEPENDENCIES_1)
am__getpc_test_SOURCES_DIST = src/tests/getpc_test.cc src/getpc.h
-@HAS_PC_TRUE@@MINGW_FALSE@am_getpc_test_OBJECTS = \
-@HAS_PC_TRUE@@MINGW_FALSE@ getpc_test.$(OBJEXT)
+@WITH_CPU_PROFILER_TRUE@am_getpc_test_OBJECTS = getpc_test.$(OBJEXT)
getpc_test_OBJECTS = $(am_getpc_test_OBJECTS)
getpc_test_LDADD = $(LDADD)
am__heap_checker_death_unittest_sh_SOURCES_DIST = \
@@ -423,13 +543,15 @@ am__heap_checker_unittest_SOURCES_DIST = \
src/base/googleinit.h src/google/heap-checker.h \
src/base/logging.h src/base/basictypes.h \
src/base/dynamic_annotations.h
-@MINGW_FALSE@am_heap_checker_unittest_OBJECTS = heap_checker_unittest-heap-checker_unittest.$(OBJEXT) \
-@MINGW_FALSE@ $(am__objects_12)
+@WITH_HEAP_CHECKER_TRUE@am__objects_17 = $(am__objects_1)
+@WITH_HEAP_CHECKER_TRUE@am_heap_checker_unittest_OBJECTS = heap_checker_unittest-heap-checker_unittest.$(OBJEXT) \
+@WITH_HEAP_CHECKER_TRUE@ $(am__objects_17)
heap_checker_unittest_OBJECTS = $(am_heap_checker_unittest_OBJECTS)
-@MINGW_FALSE@am__DEPENDENCIES_4 = libtcmalloc.la
-@MINGW_FALSE@heap_checker_unittest_DEPENDENCIES = \
-@MINGW_FALSE@ $(am__DEPENDENCIES_1) liblogging.la \
-@MINGW_FALSE@ $(am__DEPENDENCIES_4)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__DEPENDENCIES_4 = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc.la
+@WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_DEPENDENCIES = \
+@WITH_HEAP_CHECKER_TRUE@ $(am__DEPENDENCIES_1) liblogging.la \
+@WITH_HEAP_CHECKER_TRUE@ $(am__DEPENDENCIES_4)
am__heap_checker_unittest_sh_SOURCES_DIST = \
src/tests/heap-checker_unittest.sh
am_heap_checker_unittest_sh_OBJECTS =
@@ -439,11 +561,12 @@ heap_checker_unittest_sh_LDADD = $(LDADD)
am__heap_profiler_unittest_SOURCES_DIST = \
src/tests/heap-profiler_unittest.cc src/config_for_unittests.h \
src/google/heap-profiler.h
-@MINGW_FALSE@am_heap_profiler_unittest_OBJECTS = heap_profiler_unittest-heap-profiler_unittest.$(OBJEXT) \
-@MINGW_FALSE@ $(am__objects_1)
+@WITH_HEAP_PROFILER_TRUE@am_heap_profiler_unittest_OBJECTS = heap_profiler_unittest-heap-profiler_unittest.$(OBJEXT) \
+@WITH_HEAP_PROFILER_TRUE@ $(am__objects_1)
heap_profiler_unittest_OBJECTS = $(am_heap_profiler_unittest_OBJECTS)
-@MINGW_FALSE@heap_profiler_unittest_DEPENDENCIES = \
-@MINGW_FALSE@ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
+@WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_TRUE@ $(am__DEPENDENCIES_4) \
+@WITH_HEAP_PROFILER_TRUE@ $(am__DEPENDENCIES_1)
am__heap_profiler_unittest_sh_SOURCES_DIST = \
src/tests/heap-profiler_unittest.sh
am_heap_profiler_unittest_sh_OBJECTS =
@@ -461,12 +584,20 @@ am__low_level_alloc_unittest_SOURCES_DIST = \
src/base/atomicops-internals-x86-msvc.h \
src/base/atomicops-internals-x86.h src/base/logging.h \
src/base/commandlineflags.h src/base/dynamic_annotations.h
-am_low_level_alloc_unittest_OBJECTS = low_level_alloc.$(OBJEXT) \
- malloc_hook.$(OBJEXT) low_level_alloc_unittest.$(OBJEXT) \
- $(am__objects_4)
+am__objects_18 = $(am__objects_1) $(am__objects_1)
+am_low_level_alloc_unittest_OBJECTS = \
+ low_level_alloc_unittest-low_level_alloc.$(OBJEXT) \
+ low_level_alloc_unittest-malloc_hook.$(OBJEXT) \
+ low_level_alloc_unittest-low_level_alloc_unittest.$(OBJEXT) \
+ $(am__objects_18)
low_level_alloc_unittest_OBJECTS = \
$(am_low_level_alloc_unittest_OBJECTS)
-low_level_alloc_unittest_DEPENDENCIES = libstacktrace.la
+low_level_alloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_malloc_extension_test_OBJECTS = \
+ malloc_extension_test-malloc_extension_test.$(OBJEXT)
+malloc_extension_test_OBJECTS = $(am_malloc_extension_test_OBJECTS)
+malloc_extension_test_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_1)
am_markidle_unittest_OBJECTS = \
markidle_unittest-markidle_unittest.$(OBJEXT) \
markidle_unittest-testutil.$(OBJEXT)
@@ -491,57 +622,62 @@ memalign_unittest_OBJECTS = $(am_memalign_unittest_OBJECTS)
am_packed_cache_test_OBJECTS = packed-cache_test.$(OBJEXT)
packed_cache_test_OBJECTS = $(am_packed_cache_test_OBJECTS)
packed_cache_test_LDADD = $(LDADD)
+am_pagemap_unittest_OBJECTS = \
+ pagemap_unittest-pagemap_unittest.$(OBJEXT)
+pagemap_unittest_OBJECTS = $(am_pagemap_unittest_OBJECTS)
+pagemap_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_1)
am__profiledata_unittest_SOURCES_DIST = \
src/tests/profiledata_unittest.cc src/profiledata.h \
src/base/commandlineflags.h src/base/logging.h \
src/base/basictypes.h
-@HAS_PC_TRUE@@MINGW_FALSE@am_profiledata_unittest_OBJECTS = \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiledata_unittest.$(OBJEXT)
+@WITH_CPU_PROFILER_TRUE@am_profiledata_unittest_OBJECTS = \
+@WITH_CPU_PROFILER_TRUE@ profiledata_unittest.$(OBJEXT)
profiledata_unittest_OBJECTS = $(am_profiledata_unittest_OBJECTS)
-@HAS_PC_TRUE@@MINGW_FALSE@am__DEPENDENCIES_5 = libstacktrace.la \
-@HAS_PC_TRUE@@MINGW_FALSE@ libprofiler.la
-@HAS_PC_TRUE@@MINGW_FALSE@profiledata_unittest_DEPENDENCIES = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__DEPENDENCIES_5)
+@WITH_CPU_PROFILER_TRUE@am__DEPENDENCIES_5 = libstacktrace.la \
+@WITH_CPU_PROFILER_TRUE@ libprofiler.la
+@WITH_CPU_PROFILER_TRUE@profiledata_unittest_DEPENDENCIES = \
+@WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_5)
am__profiler1_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@HAS_PC_TRUE@@MINGW_FALSE@am__objects_16 = profiler1_unittest-profiler_unittest.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler1_unittest-testutil.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_1)
-@HAS_PC_TRUE@@MINGW_FALSE@am_profiler1_unittest_OBJECTS = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_16)
+@WITH_CPU_PROFILER_TRUE@am__objects_19 = profiler1_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler1_unittest-testutil.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
+@WITH_CPU_PROFILER_TRUE@am_profiler1_unittest_OBJECTS = \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_19)
profiler1_unittest_OBJECTS = $(am_profiler1_unittest_OBJECTS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler1_unittest_DEPENDENCIES = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__DEPENDENCIES_5)
+@WITH_CPU_PROFILER_TRUE@profiler1_unittest_DEPENDENCIES = \
+@WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_5)
am__profiler2_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@HAS_PC_TRUE@@MINGW_FALSE@am__objects_17 = profiler2_unittest-profiler_unittest.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler2_unittest-testutil.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_1)
-@HAS_PC_TRUE@@MINGW_FALSE@am_profiler2_unittest_OBJECTS = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_17)
+@WITH_CPU_PROFILER_TRUE@am__objects_20 = profiler2_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler2_unittest-testutil.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
+@WITH_CPU_PROFILER_TRUE@am_profiler2_unittest_OBJECTS = \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_20)
profiler2_unittest_OBJECTS = $(am_profiler2_unittest_OBJECTS)
am__profiler3_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@HAS_PC_TRUE@@MINGW_FALSE@am__objects_18 = profiler3_unittest-profiler_unittest.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler3_unittest-testutil.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_1)
-@HAS_PC_TRUE@@MINGW_FALSE@am_profiler3_unittest_OBJECTS = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_18)
+@WITH_CPU_PROFILER_TRUE@am__objects_21 = profiler3_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler3_unittest-testutil.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
+@WITH_CPU_PROFILER_TRUE@am_profiler3_unittest_OBJECTS = \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_21)
profiler3_unittest_OBJECTS = $(am_profiler3_unittest_OBJECTS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler3_unittest_DEPENDENCIES = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__DEPENDENCIES_5) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__DEPENDENCIES_1)
+@WITH_CPU_PROFILER_TRUE@profiler3_unittest_DEPENDENCIES = \
+@WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_5) \
+@WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_1)
am__profiler4_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@HAS_PC_TRUE@@MINGW_FALSE@am__objects_19 = profiler4_unittest-profiler_unittest.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler4_unittest-testutil.$(OBJEXT) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_1)
-@HAS_PC_TRUE@@MINGW_FALSE@am_profiler4_unittest_OBJECTS = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__objects_19)
+@WITH_CPU_PROFILER_TRUE@am__objects_22 = profiler4_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ profiler4_unittest-testutil.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
+@WITH_CPU_PROFILER_TRUE@am_profiler4_unittest_OBJECTS = \
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_22)
profiler4_unittest_OBJECTS = $(am_profiler4_unittest_OBJECTS)
am__profiler_unittest_sh_SOURCES_DIST = \
src/tests/profiler_unittest.sh
@@ -556,24 +692,59 @@ am_ptmalloc_unittest2_OBJECTS = ptmalloc_unittest2-t-test2.$(OBJEXT) \
$(am__objects_1)
ptmalloc_unittest2_OBJECTS = $(am_ptmalloc_unittest2_OBJECTS)
ptmalloc_unittest2_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__raw_printer_test_SOURCES_DIST = src/tests/raw_printer_test.cc
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_raw_printer_test_OBJECTS = raw_printer_test-raw_printer_test.$(OBJEXT)
+raw_printer_test_OBJECTS = $(am_raw_printer_test_OBJECTS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_4) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
+am_realloc_unittest_OBJECTS = \
+ realloc_unittest-realloc_unittest.$(OBJEXT)
+realloc_unittest_OBJECTS = $(am_realloc_unittest_OBJECTS)
+realloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_1)
+am__sampler_test_SOURCES_DIST = src/tests/sampler_test.cc \
+ src/config_for_unittests.h
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampler_test_OBJECTS = sampler_test-sampler_test.$(OBJEXT)
+sampler_test_OBJECTS = $(am_sampler_test_OBJECTS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_4) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
am__sampling_test_SOURCES_DIST = src/tests/sampling_test.cc \
src/config_for_unittests.h src/base/logging.h \
src/google/malloc_extension.h
-@MINGW_FALSE@am_sampling_test_OBJECTS = \
-@MINGW_FALSE@ sampling_test-sampling_test.$(OBJEXT) \
-@MINGW_FALSE@ $(am__objects_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampling_test_OBJECTS = sampling_test-sampling_test.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
sampling_test_OBJECTS = $(am_sampling_test_OBJECTS)
-@MINGW_FALSE@sampling_test_DEPENDENCIES = $(am__DEPENDENCIES_4) \
-@MINGW_FALSE@ $(am__DEPENDENCIES_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_4) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
am__sampling_test_sh_SOURCES_DIST = src/tests/sampling_test.sh
am_sampling_test_sh_OBJECTS =
sampling_test_sh_OBJECTS = $(am_sampling_test_sh_OBJECTS)
sampling_test_sh_LDADD = $(LDADD)
-am__objects_20 = $(am__objects_4) $(am__objects_1)
-am_stacktrace_unittest_OBJECTS = stacktrace_unittest.$(OBJEXT) \
- $(am__objects_20)
+am_stack_trace_table_test_OBJECTS = \
+ stack_trace_table_test-stack_trace_table_test.$(OBJEXT)
+stack_trace_table_test_OBJECTS = $(am_stack_trace_table_test_OBJECTS)
+stack_trace_table_test_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_1)
+am__stacktrace_unittest_SOURCES_DIST = \
+ src/tests/stacktrace_unittest.cc src/config_for_unittests.h \
+ src/base/commandlineflags.h src/stacktrace_config.h \
+ src/stacktrace_generic-inl.h src/stacktrace_libunwind-inl.h \
+ src/stacktrace_powerpc-inl.h src/stacktrace_x86_64-inl.h \
+ src/stacktrace_x86-inl.h src/stacktrace_win32-inl.h \
+ src/base/vdso_support.h src/google/stacktrace.h \
+ src/base/logging.h src/base/basictypes.h \
+ src/base/dynamic_annotations.h
+@WITH_STACK_TRACE_TRUE@am__objects_23 = $(am__objects_4) \
+@WITH_STACK_TRACE_TRUE@ $(am__objects_1)
+@WITH_STACK_TRACE_TRUE@am_stacktrace_unittest_OBJECTS = \
+@WITH_STACK_TRACE_TRUE@ stacktrace_unittest.$(OBJEXT) \
+@WITH_STACK_TRACE_TRUE@ $(am__objects_23)
stacktrace_unittest_OBJECTS = $(am_stacktrace_unittest_OBJECTS)
-stacktrace_unittest_DEPENDENCIES = libstacktrace.la liblogging.la
+@WITH_STACK_TRACE_TRUE@stacktrace_unittest_DEPENDENCIES = \
+@WITH_STACK_TRACE_TRUE@ libstacktrace.la liblogging.la
am__system_alloc_unittest_SOURCES_DIST = src/config_for_unittests.h \
src/tests/system-alloc_unittest.cc
@MINGW_FALSE@am_system_alloc_unittest_OBJECTS = system_alloc_unittest-system-alloc_unittest.$(OBJEXT)
@@ -584,25 +755,27 @@ am__tcmalloc_both_unittest_SOURCES_DIST = \
src/tests/tcmalloc_unittest.cc src/tests/testutil.h \
src/tests/testutil.cc src/config_for_unittests.h \
src/google/malloc_extension.h
-@MINGW_FALSE@am_tcmalloc_both_unittest_OBJECTS = tcmalloc_both_unittest-tcmalloc_unittest.$(OBJEXT) \
-@MINGW_FALSE@ tcmalloc_both_unittest-testutil.$(OBJEXT) \
-@MINGW_FALSE@ $(am__objects_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_both_unittest_OBJECTS = tcmalloc_both_unittest-tcmalloc_unittest.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest-testutil.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
tcmalloc_both_unittest_OBJECTS = $(am_tcmalloc_both_unittest_OBJECTS)
-@HAS_PC_FALSE@@MINGW_FALSE@tcmalloc_both_unittest_DEPENDENCIES = \
-@HAS_PC_FALSE@@MINGW_FALSE@ $(am__DEPENDENCIES_4) \
-@HAS_PC_FALSE@@MINGW_FALSE@ $(am__DEPENDENCIES_3) liblogging.la \
-@HAS_PC_FALSE@@MINGW_FALSE@ $(am__DEPENDENCIES_1)
-@HAS_PC_TRUE@@MINGW_FALSE@tcmalloc_both_unittest_DEPENDENCIES = \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__DEPENDENCIES_4) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(am__DEPENDENCIES_3) libprofiler.la \
-@HAS_PC_TRUE@@MINGW_FALSE@ liblogging.la $(am__DEPENDENCIES_1)
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_4) \
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_3) \
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_4) \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_3) \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libprofiler.la \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
am__tcmalloc_large_unittest_SOURCES_DIST = \
src/tests/tcmalloc_large_unittest.cc
-@MINGW_FALSE@am_tcmalloc_large_unittest_OBJECTS = tcmalloc_large_unittest-tcmalloc_large_unittest.$(OBJEXT)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_large_unittest_OBJECTS = tcmalloc_large_unittest-tcmalloc_large_unittest.$(OBJEXT)
tcmalloc_large_unittest_OBJECTS = \
$(am_tcmalloc_large_unittest_OBJECTS)
-@MINGW_FALSE@tcmalloc_large_unittest_DEPENDENCIES = \
-@MINGW_FALSE@ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_4) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
am_tcmalloc_minimal_large_unittest_OBJECTS = tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.$(OBJEXT)
tcmalloc_minimal_large_unittest_OBJECTS = \
$(am_tcmalloc_minimal_large_unittest_OBJECTS)
@@ -622,13 +795,14 @@ tcmalloc_minimal_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
am__tcmalloc_unittest_SOURCES_DIST = src/tests/tcmalloc_unittest.cc \
src/tcmalloc.h src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/malloc_extension.h
-@MINGW_FALSE@am_tcmalloc_unittest_OBJECTS = \
-@MINGW_FALSE@ tcmalloc_unittest-tcmalloc_unittest.$(OBJEXT) \
-@MINGW_FALSE@ tcmalloc_unittest-testutil.$(OBJEXT) \
-@MINGW_FALSE@ $(am__objects_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_unittest_OBJECTS = tcmalloc_unittest-tcmalloc_unittest.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_unittest-testutil.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
tcmalloc_unittest_OBJECTS = $(am_tcmalloc_unittest_OBJECTS)
-@MINGW_FALSE@tcmalloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_4) \
-@MINGW_FALSE@ liblogging.la $(am__DEPENDENCIES_1)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_DEPENDENCIES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_4) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
am_thread_dealloc_unittest_OBJECTS = \
thread_dealloc_unittest-thread_dealloc_unittest.$(OBJEXT) \
thread_dealloc_unittest-testutil.$(OBJEXT)
@@ -660,6 +834,7 @@ CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \
SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \
$(libspinlock_la_SOURCES) $(libstacktrace_la_SOURCES) \
$(libsysinfo_la_SOURCES) $(libtcmalloc_la_SOURCES) \
+ $(libtcmalloc_internal_la_SOURCES) \
$(libtcmalloc_minimal_la_SOURCES) \
$(libtcmalloc_minimal_internal_la_SOURCES) \
$(libwindows_la_SOURCES) $(addressmap_unittest_SOURCES) \
@@ -671,14 +846,17 @@ SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \
$(heap_profiler_unittest_SOURCES) \
$(heap_profiler_unittest_sh_SOURCES) \
$(low_level_alloc_unittest_SOURCES) \
- $(markidle_unittest_SOURCES) \
+ $(malloc_extension_test_SOURCES) $(markidle_unittest_SOURCES) \
$(maybe_threads_unittest_sh_SOURCES) \
$(memalign_unittest_SOURCES) $(packed_cache_test_SOURCES) \
- $(profiledata_unittest_SOURCES) $(profiler1_unittest_SOURCES) \
- $(profiler2_unittest_SOURCES) $(profiler3_unittest_SOURCES) \
- $(profiler4_unittest_SOURCES) $(profiler_unittest_sh_SOURCES) \
- $(ptmalloc_unittest1_SOURCES) $(ptmalloc_unittest2_SOURCES) \
+ $(pagemap_unittest_SOURCES) $(profiledata_unittest_SOURCES) \
+ $(profiler1_unittest_SOURCES) $(profiler2_unittest_SOURCES) \
+ $(profiler3_unittest_SOURCES) $(profiler4_unittest_SOURCES) \
+ $(profiler_unittest_sh_SOURCES) $(ptmalloc_unittest1_SOURCES) \
+ $(ptmalloc_unittest2_SOURCES) $(raw_printer_test_SOURCES) \
+ $(realloc_unittest_SOURCES) $(sampler_test_SOURCES) \
$(sampling_test_SOURCES) $(sampling_test_sh_SOURCES) \
+ $(stack_trace_table_test_SOURCES) \
$(stacktrace_unittest_SOURCES) \
$(system_alloc_unittest_SOURCES) \
$(tcmalloc_both_unittest_SOURCES) \
@@ -689,8 +867,10 @@ SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \
$(thread_dealloc_unittest_SOURCES)
DIST_SOURCES = $(liblogging_la_SOURCES) \
$(am__libprofiler_la_SOURCES_DIST) \
- $(am__libspinlock_la_SOURCES_DIST) $(libstacktrace_la_SOURCES) \
- $(libsysinfo_la_SOURCES) $(am__libtcmalloc_la_SOURCES_DIST) \
+ $(am__libspinlock_la_SOURCES_DIST) \
+ $(am__libstacktrace_la_SOURCES_DIST) $(libsysinfo_la_SOURCES) \
+ $(am__libtcmalloc_la_SOURCES_DIST) \
+ $(am__libtcmalloc_internal_la_SOURCES_DIST) \
$(am__libtcmalloc_minimal_la_SOURCES_DIST) \
$(am__libtcmalloc_minimal_internal_la_SOURCES_DIST) \
$(am__libwindows_la_SOURCES_DIST) \
@@ -703,10 +883,10 @@ DIST_SOURCES = $(liblogging_la_SOURCES) \
$(am__heap_profiler_unittest_SOURCES_DIST) \
$(am__heap_profiler_unittest_sh_SOURCES_DIST) \
$(am__low_level_alloc_unittest_SOURCES_DIST) \
- $(markidle_unittest_SOURCES) \
+ $(malloc_extension_test_SOURCES) $(markidle_unittest_SOURCES) \
$(am__maybe_threads_unittest_sh_SOURCES_DIST) \
$(am__memalign_unittest_SOURCES_DIST) \
- $(packed_cache_test_SOURCES) \
+ $(packed_cache_test_SOURCES) $(pagemap_unittest_SOURCES) \
$(am__profiledata_unittest_SOURCES_DIST) \
$(am__profiler1_unittest_SOURCES_DIST) \
$(am__profiler2_unittest_SOURCES_DIST) \
@@ -714,9 +894,12 @@ DIST_SOURCES = $(liblogging_la_SOURCES) \
$(am__profiler4_unittest_SOURCES_DIST) \
$(am__profiler_unittest_sh_SOURCES_DIST) \
$(ptmalloc_unittest1_SOURCES) $(ptmalloc_unittest2_SOURCES) \
+ $(am__raw_printer_test_SOURCES_DIST) \
+ $(realloc_unittest_SOURCES) $(am__sampler_test_SOURCES_DIST) \
$(am__sampling_test_SOURCES_DIST) \
$(am__sampling_test_sh_SOURCES_DIST) \
- $(stacktrace_unittest_SOURCES) \
+ $(stack_trace_table_test_SOURCES) \
+ $(am__stacktrace_unittest_SOURCES_DIST) \
$(am__system_alloc_unittest_SOURCES_DIST) \
$(am__tcmalloc_both_unittest_SOURCES_DIST) \
$(am__tcmalloc_large_unittest_SOURCES_DIST) \
@@ -813,8 +996,8 @@ F77 = @F77@
FFLAGS = @FFLAGS@
GCC_FALSE = @GCC_FALSE@
GCC_TRUE = @GCC_TRUE@
-HAS_PC_FALSE = @HAS_PC_FALSE@
-HAS_PC_TRUE = @HAS_PC_TRUE@
+HAVE_WINDOWS_H_FALSE = @HAVE_WINDOWS_H_FALSE@
+HAVE_WINDOWS_H_TRUE = @HAVE_WINDOWS_H_TRUE@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
@@ -822,6 +1005,7 @@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
+LIBSTDCXX_LA_LINKER_FLAG = @LIBSTDCXX_LA_LINKER_FLAG@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LN_S = @LN_S@
@@ -829,6 +1013,7 @@ LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MINGW_FALSE = @MINGW_FALSE@
MINGW_TRUE = @MINGW_TRUE@
+NANOSLEEP_LIBS = @NANOSLEEP_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
@@ -846,6 +1031,16 @@ SHELL = @SHELL@
STRIP = @STRIP@
UNWIND_LIBS = @UNWIND_LIBS@
VERSION = @VERSION@
+WITH_CPU_PROFILER_FALSE = @WITH_CPU_PROFILER_FALSE@
+WITH_CPU_PROFILER_TRUE = @WITH_CPU_PROFILER_TRUE@
+WITH_HEAP_CHECKER_FALSE = @WITH_HEAP_CHECKER_FALSE@
+WITH_HEAP_CHECKER_TRUE = @WITH_HEAP_CHECKER_TRUE@
+WITH_HEAP_PROFILER_FALSE = @WITH_HEAP_PROFILER_FALSE@
+WITH_HEAP_PROFILER_OR_CHECKER_FALSE = @WITH_HEAP_PROFILER_OR_CHECKER_FALSE@
+WITH_HEAP_PROFILER_OR_CHECKER_TRUE = @WITH_HEAP_PROFILER_OR_CHECKER_TRUE@
+WITH_HEAP_PROFILER_TRUE = @WITH_HEAP_PROFILER_TRUE@
+WITH_STACK_TRACE_FALSE = @WITH_STACK_TRACE_FALSE@
+WITH_STACK_TRACE_TRUE = @WITH_STACK_TRACE_TRUE@
X86_64_FALSE = @X86_64_FALSE@
X86_64_TRUE = @X86_64_TRUE@
ac_ct_AR = @ac_ct_AR@
@@ -891,20 +1086,19 @@ program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
-target = @target@
target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
# Make sure that when we re-make ./configure, we get the macros we need
ACLOCAL_AMFLAGS = -I m4
# This is so we can #include <google/foo>
-AM_CPPFLAGS = -I$(top_srcdir)/src
+AM_CPPFLAGS = -I$(top_srcdir)/src $(am__append_1)
# This is mostly based on configure options
-AM_CXXFLAGS = $(am__append_1) $(am__append_2) $(am__append_3)
+AM_CXXFLAGS = $(am__append_2) $(am__append_3) $(am__append_4)
+
+# This is to fix a solaris bug
+AM_LDFLAGS = $(LIBSTDCXX_LA_LINKER_FLAG)
@GCC_FALSE@NO_EXCEPTIONS =
# We know our low-level code cannot trigger an exception. On some
@@ -914,19 +1108,19 @@ AM_CXXFLAGS = $(am__append_1) $(am__append_2) $(am__append_3)
# we control all this code, and do not need exceptions for it.
@GCC_TRUE@NO_EXCEPTIONS = -fno-exceptions
-# For windows systems (mingw and cygwin), we need to tell all our
+# For windows systems (at least, mingw), we need to tell all our
# tests to link in libtcmalloc using -u. This is because libtcmalloc
# accomplishes its tasks via patching, leaving no work for the linker
# to identify, so the linker will ignore libtcmalloc by default unless
# we explicitly create a dependency via -u.
-TCMALLOC_FLAGS = $(am__append_4)
+TCMALLOC_FLAGS = $(am__append_5)
googleincludedir = $(includedir)/google
# The .h files you want to install (that is, .h files that people
# who install this package can include in their own applications.)
# We'll add to this later, on a library-by-library basis
-googleinclude_HEADERS = $(SG_STACKTRACE_INCLUDES) \
- $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_13) \
- $(am__append_18)
+googleinclude_HEADERS = $(am__append_10) \
+ $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_20) \
+ $(am__append_37)
docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
# This is for HTML and other documentation you want to install.
# Add your documentation files (in doc/) in addition to these
@@ -935,17 +1129,15 @@ docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
### Documentation
-### Documentation
-
# I don't know how to say "distribute the .dot files but don't install them";
# noinst doesn't seem to work with data. I separate them out anyway, in case
# one day we figure it out. Regardless, installing the dot files isn't the
# end of the world.
dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
README.windows TODO doc/index.html doc/designstyle.css \
- doc/pprof_remote_servers.html doc/tcmalloc.html \
- doc/overview.gif doc/pageheap.gif doc/spanmap.gif \
- doc/threadheap.gif doc/t-test1.times.txt \
+ $(am__append_13) doc/tcmalloc.html doc/overview.gif \
+ doc/pageheap.gif doc/spanmap.gif doc/threadheap.gif \
+ doc/t-test1.times.txt \
doc/tcmalloc-opspercpusec.vs.threads.1024.bytes.png \
doc/tcmalloc-opspercpusec.vs.threads.128.bytes.png \
doc/tcmalloc-opspercpusec.vs.threads.131072.bytes.png \
@@ -968,29 +1160,26 @@ dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
doc/tcmalloc-opspersec.vs.size.5.threads.png \
doc/tcmalloc-opspersec.vs.size.8.threads.png doc/overview.dot \
doc/pageheap.dot doc/spanmap.dot doc/threadheap.dot \
- $(am__append_17) $(am__append_23)
+ $(am__append_35) $(am__append_36) $(am__append_42)
# The libraries (.so's) you want to install
# We'll add to this later, on a library-by-library basis
-lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_14) \
- $(am__append_19)
+lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_22) \
+ $(am__append_38)
# This is for 'convenience libraries' -- basically just a container for sources
### Making the library
-### Making the library
-
# As we describe at the top of this file, we want to turn off exceptions
# for all files in this library -- except tcmalloc.cc which needs them
# to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need
# to separate into two libraries.
-noinst_LTLIBRARIES = liblogging.la libsysinfo.la $(am__append_5) \
- $(am__append_6) libstacktrace.la \
- libtcmalloc_minimal_internal.la
-
-# Some windows-only projects
+noinst_LTLIBRARIES = liblogging.la libsysinfo.la $(am__append_6) \
+ $(am__append_8) $(am__append_11) \
+ libtcmalloc_minimal_internal.la $(am__append_21)
WINDOWS_PROJECTS = google-perftools.sln \
vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj \
+ $(am__append_15) \
vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj \
vsprojects/tcmalloc_minimal_unittest/tcmalloc_minimal_unittest.vcproj \
vsprojects/tmu-static/tmu-static.vcproj \
@@ -999,9 +1188,12 @@ WINDOWS_PROJECTS = google-perftools.sln \
vsprojects/packed-cache_test/packed-cache_test.vcproj \
vsprojects/frag_unittest/frag_unittest.vcproj \
vsprojects/markidle_unittest/markidle_unittest.vcproj \
+ vsprojects/malloc_extension_test/malloc_extension_test.vcproj \
+ vsprojects/pagemap_unittest/pagemap_unittest.vcproj \
+ vsprojects/realloc_unittest/realloc_unittest.vcproj \
+ vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj \
vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj \
- vsprojects/nm-pdb/nm-pdb.vcproj \
- vsprojects/addr2line-pdb/addr2line-pdb.vcproj
+ $(am__append_25)
# unittests you want to run when people type 'make check'.
# Note: tests cannot take any arguments!
@@ -1016,24 +1208,25 @@ WINDOWS_PROJECTS = google-perftools.sln \
### Unittests
-### Unittests
-
# Commented out for the moment because malloc(very_big_num) is broken in
# standard libc! At least, in some situations, some of the time.
# These all tests components of tcmalloc_minimal
-TESTS = low_level_alloc_unittest $(am__append_7) stacktrace_unittest \
+TESTS = low_level_alloc_unittest $(am__append_9) $(am__append_12) \
tcmalloc_minimal_unittest tcmalloc_minimal_large_unittest \
- $(am__append_9) addressmap_unittest $(am__append_11) \
+ $(am__append_16) addressmap_unittest $(am__append_18) \
packed_cache_test frag_unittest markidle_unittest \
- $(am__append_12) thread_dealloc_unittest $(am__append_15) \
- $(am__append_20)
+ malloc_extension_test $(am__append_19) pagemap_unittest \
+ realloc_unittest stack_trace_table_test \
+ thread_dealloc_unittest $(am__append_24) $(am__append_29) \
+ $(am__append_32) $(am__append_39)
# TESTS_ENVIRONMENT sets environment variables for when you run unittest.
# We always get "srcdir" set for free.
# We'll add to this later, on a library-by-library basis.
-TESTS_ENVIRONMENT = $(am__append_8)
+TESTS_ENVIRONMENT = $(am__append_14) $(am__append_26)
# All script tests should be added here
-noinst_SCRIPTS = $(am__append_10) $(am__append_21)
+noinst_SCRIPTS = $(am__append_17) $(am__append_27) $(am__append_30) \
+ $(am__append_33) $(am__append_40)
### ------- library routines, in src/base
@@ -1056,6 +1249,7 @@ SYSINFO_INCLUDES = src/base/sysinfo.h \
libsysinfo_la_SOURCES = src/base/sysinfo.cc \
$(SYSINFO_INCLUDES)
+libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) $(am__append_7)
# For MinGW, we use libwindows and not libspinlock. For every other
# unix system, we use libspinlock and don't need libwindows. Luckily,
@@ -1082,10 +1276,6 @@ libsysinfo_la_SOURCES = src/base/sysinfo.cc \
# spinlock also needs NumCPUs, from libsysinfo, which in turn needs liblogging
@MINGW_FALSE@LIBSPINLOCK = libspinlock.la libsysinfo.la liblogging.la
@MINGW_TRUE@LIBSPINLOCK = libwindows.la libsysinfo.la liblogging.la
-
-# We also need to tell mingw that sysinfo.cc needs shlwapi.lib.
-# (We do this via a #pragma for msvc, but need to do it here for mingw).
-@MINGW_TRUE@libsysinfo_la_LIBADD = -lshlwapi
@MINGW_FALSE@MAYBE_THREADS_CC = src/maybe_threads.cc
@MINGW_TRUE@MAYBE_THREADS_CC =
@MINGW_FALSE@SYSTEM_ALLOC_CC = src/system-alloc.cc
@@ -1102,6 +1292,7 @@ libsysinfo_la_SOURCES = src/base/sysinfo.cc \
@MINGW_FALSE@ src/base/atomicops-internals-x86.cc \
@MINGW_FALSE@ $(SPINLOCK_INCLUDES)
+@MINGW_FALSE@libspinlock_la_LIBADD = $(NANOSLEEP_LIBS)
LOW_LEVEL_ALLOC_UNITTEST_INCLUDES = src/base/low_level_alloc.h \
src/base/basictypes.h \
src/google/malloc_hook.h \
@@ -1115,7 +1306,10 @@ low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \
src/tests/low_level_alloc_unittest.cc \
$(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES)
-low_level_alloc_unittest_LDADD = libstacktrace.la
+# By default, MallocHook takes stack traces for use by the heap-checker.
+# We don't need that functionality here, so we turn it off to reduce deps.
+low_level_alloc_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES
+low_level_alloc_unittest_LDADD = $(LIBSPINLOCK)
@MINGW_FALSE@ATOMICOPS_UNITTEST_INCLUDES = src/base/atomicops.h \
@MINGW_FALSE@ src/base/atomicops-internals-macosx.h \
@MINGW_FALSE@ src/base/atomicops-internals-x86-msvc.h \
@@ -1130,39 +1324,47 @@ low_level_alloc_unittest_LDADD = libstacktrace.la
### ------- stack trace
### The header files we use. We divide into categories based on directory
-S_STACKTRACE_INCLUDES = src/stacktrace_generic-inl.h \
- src/stacktrace_libunwind-inl.h \
- src/stacktrace_powerpc-inl.h \
- src/stacktrace_x86_64-inl.h \
- src/stacktrace_x86-inl.h \
- src/stacktrace_win32-inl.h
-
-SG_STACKTRACE_INCLUDES = src/google/stacktrace.h
-STACKTRACE_INCLUDES = $(S_STACKTRACE_INCLUDES) $(SG_STACKTRACE_INCLUDES)
-libstacktrace_la_SOURCES = src/stacktrace.cc \
- $(STACKTRACE_INCLUDES)
-
-libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK)
-STACKTRACE_SYMBOLS = '(GetStackTrace)'
-libstacktrace_la_LDFLAGS = -export-symbols-regex $(STACKTRACE_SYMBOLS)
-STACKTRACE_UNITTEST_INLCUDES = src/config_for_unittests.h \
- src/base/commandlineflags.h \
- $(STACKTRACE_INCLUDES) \
- $(LOGGING_INCLUDES)
-
-stacktrace_unittest_SOURCES = src/tests/stacktrace_unittest.cc \
- $(STACKTRACE_UNITTEST_INLCUDES)
-
-stacktrace_unittest_LDADD = libstacktrace.la liblogging.la
+@WITH_STACK_TRACE_TRUE@S_STACKTRACE_INCLUDES = src/stacktrace_config.h \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_generic-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_libunwind-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_powerpc-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_x86_64-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_x86-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_win32-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/base/vdso_support.h
+
+@WITH_STACK_TRACE_TRUE@SG_STACKTRACE_INCLUDES = src/google/stacktrace.h
+@WITH_STACK_TRACE_TRUE@STACKTRACE_INCLUDES = $(S_STACKTRACE_INCLUDES) $(SG_STACKTRACE_INCLUDES)
+@WITH_STACK_TRACE_TRUE@libstacktrace_la_SOURCES = src/stacktrace.cc \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_with_context.cc \
+@WITH_STACK_TRACE_TRUE@ src/base/vdso_support.cc \
+@WITH_STACK_TRACE_TRUE@ $(STACKTRACE_INCLUDES)
+
+@WITH_STACK_TRACE_TRUE@libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK)
+@WITH_STACK_TRACE_TRUE@STACKTRACE_SYMBOLS = '(GetStackTrace|GetStackFrames|GetStackTraceWithContext|)GetStackFramesWithContext)'
+@WITH_STACK_TRACE_TRUE@libstacktrace_la_LDFLAGS = -export-symbols-regex $(STACKTRACE_SYMBOLS)
+@WITH_STACK_TRACE_TRUE@STACKTRACE_UNITTEST_INLCUDES = src/config_for_unittests.h \
+@WITH_STACK_TRACE_TRUE@ src/base/commandlineflags.h \
+@WITH_STACK_TRACE_TRUE@ $(STACKTRACE_INCLUDES) \
+@WITH_STACK_TRACE_TRUE@ $(LOGGING_INCLUDES)
+
+@WITH_STACK_TRACE_TRUE@stacktrace_unittest_SOURCES = src/tests/stacktrace_unittest.cc \
+@WITH_STACK_TRACE_TRUE@ $(STACKTRACE_UNITTEST_INLCUDES)
+
+@WITH_STACK_TRACE_TRUE@stacktrace_unittest_LDADD = libstacktrace.la liblogging.la
### ------- pprof
-bin_SCRIPTS = src/pprof
+
+# If we are not compiling with stacktrace support, pprof is worthless
+@WITH_STACK_TRACE_TRUE@bin_SCRIPTS = src/pprof
### Unittests
-@MINGW_FALSE@check_SCRIPTS = pprof_unittest
+@WITH_STACK_TRACE_TRUE@check_SCRIPTS = pprof_unittest
### Documentation
-dist_man_MANS = doc/pprof.1
+@WITH_STACK_TRACE_TRUE@dist_man_MANS = doc/pprof.1
+@WITH_STACK_TRACE_TRUE@nm_pdb_SOURCES = src/windows/nm-pdb.c
+@WITH_STACK_TRACE_TRUE@addr2line_pdb_SOURCES = src/windows/addr2line-pdb.c
### ------- tcmalloc_minimal (thread-caching malloc)
@@ -1176,6 +1378,7 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/base/commandlineflags.h \
src/base/basictypes.h \
src/pagemap.h \
+ src/sampler.h \
src/central_freelist.h \
src/linked_list.h \
src/page_heap.h \
@@ -1183,6 +1386,7 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/span.h \
src/static_vars.h \
src/thread_cache.h \
+ src/stack_trace_table.h \
src/base/thread_annotations.h \
src/malloc_hook-inl.h \
src/maybe_threads.h
@@ -1199,7 +1403,9 @@ libtcmalloc_minimal_internal_la_SOURCES = src/common.cc \
src/memfs_malloc.cc \
src/central_freelist.cc \
src/page_heap.cc \
+ src/sampler.cc \
src/span.cc \
+ src/stack_trace_table.cc \
src/static_vars.cc \
src/thread_cache.cc \
src/malloc_hook.cc \
@@ -1214,9 +1420,7 @@ libtcmalloc_minimal_internal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \
libtcmalloc_minimal_internal_la_LDFLAGS = $(PTHREAD_CFLAGS)
libtcmalloc_minimal_internal_la_LIBADD = $(PTHREAD_LIBS) $(LIBSPINLOCK)
-libtcmalloc_minimal_la_SOURCES = src/tcmalloc.cc \
- $(TCMALLOC_MINIMAL_INCLUDES)
-
+libtcmalloc_minimal_la_SOURCES = src/tcmalloc.cc $(TCMALLOC_MINIMAL_INCLUDES)
libtcmalloc_minimal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \
$(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
@@ -1273,6 +1477,15 @@ markidle_unittest_SOURCES = src/tests/markidle_unittest.cc \
markidle_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
markidle_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
markidle_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+malloc_extension_test_SOURCES = src/tests/malloc_extension_test.cc \
+ src/config_for_unittests.h \
+ src/base/logging.h \
+ src/google/malloc_extension.h \
+ src/google/malloc_extension_c.h
+
+malloc_extension_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+malloc_extension_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+malloc_extension_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
@MINGW_FALSE@memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \
@MINGW_FALSE@ src/config_for_unittests.h \
@MINGW_FALSE@ src/tcmalloc.h \
@@ -1281,6 +1494,27 @@ markidle_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
@MINGW_FALSE@memalign_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
@MINGW_FALSE@memalign_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
@MINGW_FALSE@memalign_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+pagemap_unittest_SOURCES = src/tests/pagemap_unittest.cc \
+ src/config_for_unittests.h \
+ src/base/logging.h \
+ src/pagemap.h
+
+pagemap_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+pagemap_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+pagemap_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+realloc_unittest_SOURCES = src/tests/realloc_unittest.cc \
+ src/config_for_unittests.h \
+ src/base/logging.h
+
+realloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+realloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+realloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+stack_trace_table_test_SOURCES = src/tests/stack_trace_table_test.cc \
+ src/config_for_unittests.h
+
+stack_trace_table_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+stack_trace_table_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+stack_trace_table_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
thread_dealloc_unittest_SOURCES = src/tests/thread_dealloc_unittest.cc \
src/config_for_unittests.h \
src/tests/testutil.h src/tests/testutil.cc
@@ -1309,186 +1543,189 @@ ptmalloc_unittest2_LDADD = $(PTHREAD_LIBS)
### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker)
-# The full tcmalloc does not work on windows yet
-
### The header files we use. We divide into categories based on directory
-@MINGW_FALSE@S_TCMALLOC_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) \
-@MINGW_FALSE@ $(LOGGING_INCLUDES) \
-@MINGW_FALSE@ src/addressmap-inl.h \
-@MINGW_FALSE@ src/base/elfcore.h \
-@MINGW_FALSE@ src/base/googleinit.h \
-@MINGW_FALSE@ src/base/linux_syscall_support.h \
-@MINGW_FALSE@ src/base/linuxthreads.h \
-@MINGW_FALSE@ src/base/stl_allocator.h \
-@MINGW_FALSE@ src/base/sysinfo.h \
-@MINGW_FALSE@ src/base/thread_lister.h \
-@MINGW_FALSE@ src/heap-profile-table.h
-
-@MINGW_FALSE@SG_TCMALLOC_INCLUDES = $(SG_TCMALLOC_MINIMAL_INCLUDES) \
-@MINGW_FALSE@ src/google/heap-profiler.h \
-@MINGW_FALSE@ src/google/heap-checker.h
-
-@MINGW_FALSE@TCMALLOC_INCLUDES = $(S_TCMALLOC_INCLUDES) $(SG_TCMALLOC_INCLUDES)
-# Note: heap-checker-bcad is last, in hopes its global ctor will run first
-# TODO(csilvers): break libtcmalloc.la into two pieces, like we do for
-# libtcmalloc_minimal.la. Right now we don't need it,
-# since the break-up is for a cygwin-specific bug, and
-# cygwin doesn't support libtcmalloc anyway. But one day?
-@MINGW_FALSE@libtcmalloc_la_SOURCES = $(libtcmalloc_minimal_internal_la_SOURCES) \
-@MINGW_FALSE@ $(libtcmalloc_minimal_la_SOURCES) \
-@MINGW_FALSE@ $(TCMALLOC_INCLUDES) \
-@MINGW_FALSE@ src/base/linuxthreads.cc \
-@MINGW_FALSE@ src/base/low_level_alloc.cc \
-@MINGW_FALSE@ src/base/thread_lister.c \
-@MINGW_FALSE@ src/heap-checker.cc \
-@MINGW_FALSE@ src/heap-profile-table.cc \
-@MINGW_FALSE@ src/heap-profiler.cc \
-@MINGW_FALSE@ src/memory_region_map.cc \
-@MINGW_FALSE@ src/heap-checker-bcad.cc
-
-@MINGW_FALSE@libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
-@MINGW_FALSE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
-@MINGW_FALSE@libtcmalloc_la_LIBADD = $(PTHREAD_LIBS) \
-@MINGW_FALSE@ libstacktrace.la
-
-@MINGW_FALSE@LIBTCMALLOC = libtcmalloc.la
-@MINGW_FALSE@TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \
-@MINGW_FALSE@ src/google/malloc_extension.h
-
-@MINGW_FALSE@tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
-@MINGW_FALSE@ src/tcmalloc.h \
-@MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc \
-@MINGW_FALSE@ $(TCMALLOC_UNITTEST_INCLUDES)
-
-@MINGW_FALSE@tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@MINGW_FALSE@tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-@MINGW_FALSE@tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
-@MINGW_FALSE@tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
-@MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc \
-@MINGW_FALSE@ $(TCMALLOC_UNITTEST_INCLUDES)
-
-@MINGW_FALSE@tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@MINGW_FALSE@tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-@HAS_PC_FALSE@@MINGW_FALSE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
-@HAS_PC_FALSE@@MINGW_FALSE@ liblogging.la $(PTHREAD_LIBS)
-
-@HAS_PC_TRUE@@MINGW_FALSE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
-@HAS_PC_TRUE@@MINGW_FALSE@ libprofiler.la liblogging.la $(PTHREAD_LIBS)
-
-@MINGW_FALSE@tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
-@MINGW_FALSE@tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@MINGW_FALSE@tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-@MINGW_FALSE@tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
-@MINGW_FALSE@sampling_test_sh_SOURCES = src/tests/sampling_test.sh
-@MINGW_FALSE@SAMPLING_TEST_INCLUDES = src/config_for_unittests.h \
-@MINGW_FALSE@ src/base/logging.h \
-@MINGW_FALSE@ src/google/malloc_extension.h
-
-@MINGW_FALSE@sampling_test_SOURCES = src/tests/sampling_test.cc \
-@MINGW_FALSE@ $(SAMPLING_TEST_INCLUDES)
-
-@MINGW_FALSE@sampling_test_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@MINGW_FALSE@sampling_test_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-@MINGW_FALSE@sampling_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
-@MINGW_FALSE@heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh
-@MINGW_FALSE@HEAP_PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
-@MINGW_FALSE@ src/google/heap-profiler.h
-
-@MINGW_FALSE@heap_profiler_unittest_SOURCES = src/tests/heap-profiler_unittest.cc \
-@MINGW_FALSE@ $(HEAP_PROFILER_UNITTEST_INCLUDES)
-
-@MINGW_FALSE@heap_profiler_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@MINGW_FALSE@heap_profiler_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-@MINGW_FALSE@heap_profiler_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
-@MINGW_FALSE@heap_checker_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh
-@MINGW_FALSE@heap_checker_death_unittest_sh_SOURCES = src/tests/heap-checker-death_unittest.sh
-@MINGW_FALSE@HEAP_CHECKER_UNITTEST_INCLUDES = src/config_for_unittests.h \
-@MINGW_FALSE@ src/memory_region_map.h \
-@MINGW_FALSE@ src/base/commandlineflags.h \
-@MINGW_FALSE@ src/base/googleinit.h \
-@MINGW_FALSE@ src/google/heap-checker.h \
-@MINGW_FALSE@ $(LOGGING_INCLUDES)
-
-@MINGW_FALSE@heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc \
-@MINGW_FALSE@ $(HEAP_CHECKER_UNITTEST_INCLUDES)
-
-@MINGW_FALSE@heap_checker_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@MINGW_FALSE@heap_checker_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@S_TCMALLOC_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(LOGGING_INCLUDES) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/addressmap-inl.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/raw_printer.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/elfcore.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/googleinit.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/linux_syscall_support.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/linuxthreads.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/stl_allocator.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/sysinfo.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/thread_lister.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-profile-table.h
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@SG_TCMALLOC_INCLUDES = $(SG_TCMALLOC_MINIMAL_INCLUDES) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/heap-profiler.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/heap-checker.h
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@TCMALLOC_INCLUDES = $(S_TCMALLOC_INCLUDES) $(SG_TCMALLOC_INCLUDES)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_SOURCES = $(libtcmalloc_minimal_internal_la_SOURCES) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_INCLUDES) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/low_level_alloc.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-profile-table.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/heap-profiler.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/raw_printer.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/memory_region_map.cc
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) $(NO_EXCEPTIONS)
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LDFLAGS = $(PTHREAD_CFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LIBADD = $(PTHREAD_LIBS) libstacktrace.la
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_SOURCES = \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tcmalloc.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_INCLUDES) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_23)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LIBADD = $(PTHREAD_LIBS) libtcmalloc_internal.la
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@LIBTCMALLOC = libtcmalloc.la
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/malloc_extension.h
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tcmalloc.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_UNITTEST_INCLUDES)
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_UNITTEST_INCLUDES)
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la $(PTHREAD_LIBS)
+
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libprofiler.la liblogging.la $(PTHREAD_LIBS)
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_SOURCES = src/tests/raw_printer_test.cc
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@raw_printer_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_SOURCES = src/tests/sampler_test.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/config_for_unittests.h
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS) -lm
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_sh_SOURCES = src/tests/sampling_test.sh
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@SAMPLING_TEST_INCLUDES = src/config_for_unittests.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/base/logging.h \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/google/malloc_extension.h
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_SOURCES = src/tests/sampling_test.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(SAMPLING_TEST_INCLUDES)
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+@WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh
+@WITH_HEAP_PROFILER_TRUE@HEAP_PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@WITH_HEAP_PROFILER_TRUE@ src/google/heap-profiler.h
+
+@WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_SOURCES = src/tests/heap-profiler_unittest.cc \
+@WITH_HEAP_PROFILER_TRUE@ $(HEAP_PROFILER_UNITTEST_INCLUDES)
+
+@WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_HEAP_PROFILER_TRUE@heap_profiler_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+@WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh
+@WITH_HEAP_CHECKER_TRUE@heap_checker_death_unittest_sh_SOURCES = src/tests/heap-checker-death_unittest.sh
+@WITH_HEAP_CHECKER_TRUE@HEAP_CHECKER_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@WITH_HEAP_CHECKER_TRUE@ src/memory_region_map.h \
+@WITH_HEAP_CHECKER_TRUE@ src/base/commandlineflags.h \
+@WITH_HEAP_CHECKER_TRUE@ src/base/googleinit.h \
+@WITH_HEAP_CHECKER_TRUE@ src/google/heap-checker.h \
+@WITH_HEAP_CHECKER_TRUE@ $(LOGGING_INCLUDES)
+
+@WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc \
+@WITH_HEAP_CHECKER_TRUE@ $(HEAP_CHECKER_UNITTEST_INCLUDES)
+
+@WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
# tcmalloc has to be specified last!
-@MINGW_FALSE@heap_checker_unittest_LDADD = $(PTHREAD_LIBS) liblogging.la $(LIBTCMALLOC)
+@WITH_HEAP_CHECKER_TRUE@heap_checker_unittest_LDADD = $(PTHREAD_LIBS) liblogging.la $(LIBTCMALLOC)
### ------- CPU profiler
-# The CPU profiler doesn't work on windows yet. It also doesn't work
-# if there's no way to get the PC.
-
### The header files we use. We divide into categories based on directory
-@HAS_PC_TRUE@@MINGW_FALSE@S_CPU_PROFILER_INCLUDES = src/profiledata.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/getpc.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/basictypes.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/commandlineflags.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/googleinit.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/logging.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/simple_mutex.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/sysinfo.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(SPINLOCK_INCLUDES) \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(LOGGING_INCLUDES)
-
-@HAS_PC_TRUE@@MINGW_FALSE@SG_CPU_PROFILER_INCLUDES = src/google/profiler.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/google/stacktrace.h
-
-@HAS_PC_TRUE@@MINGW_FALSE@CPU_PROFILER_INCLUDES = $(S_CPU_PROFILER_INCLUDES) $(SG_CPU_PROFILER_INCLUDES)
-@HAS_PC_TRUE@@MINGW_FALSE@libprofiler_la_SOURCES = src/profiler.cc \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/profiledata.cc \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(CPU_PROFILER_INCLUDES)
-
-@HAS_PC_TRUE@@MINGW_FALSE@libprofiler_la_LIBADD = libstacktrace.la
+@WITH_CPU_PROFILER_TRUE@S_CPU_PROFILER_INCLUDES = src/profiledata.h \
+@WITH_CPU_PROFILER_TRUE@ src/getpc.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/basictypes.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/commandlineflags.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/googleinit.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/logging.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/simple_mutex.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/sysinfo.h \
+@WITH_CPU_PROFILER_TRUE@ $(SPINLOCK_INCLUDES) \
+@WITH_CPU_PROFILER_TRUE@ $(LOGGING_INCLUDES)
+
+@WITH_CPU_PROFILER_TRUE@SG_CPU_PROFILER_INCLUDES = src/google/profiler.h \
+@WITH_CPU_PROFILER_TRUE@ src/google/stacktrace.h
+
+@WITH_CPU_PROFILER_TRUE@CPU_PROFILER_INCLUDES = $(S_CPU_PROFILER_INCLUDES) $(SG_CPU_PROFILER_INCLUDES)
+@WITH_CPU_PROFILER_TRUE@libprofiler_la_SOURCES = src/profiler.cc \
+@WITH_CPU_PROFILER_TRUE@ src/profiledata.cc \
+@WITH_CPU_PROFILER_TRUE@ $(CPU_PROFILER_INCLUDES)
+
+@WITH_CPU_PROFILER_TRUE@libprofiler_la_LIBADD = libstacktrace.la
# We have to include ProfileData for profiledata_unittest
-@HAS_PC_TRUE@@MINGW_FALSE@CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStop|ProfilerEnable|ProfilerDisable|ProfilerFlush|ProfilerRegisterThread|ProfileData)'
-@HAS_PC_TRUE@@MINGW_FALSE@libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS)
+@WITH_CPU_PROFILER_TRUE@CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStop|ProfilerEnable|ProfilerDisable|ProfilerFlush|ProfilerRegisterThread|ProfileData)'
+@WITH_CPU_PROFILER_TRUE@libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS)
# See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this.
# Basically it's to work around systems where --rpath doesn't work right.
-@HAS_PC_TRUE@@MINGW_FALSE@LIBPROFILER = libstacktrace.la libprofiler.la
+@WITH_CPU_PROFILER_TRUE@LIBPROFILER = libstacktrace.la libprofiler.la
#WINDOWS_PROJECTS += vsprojects/getpc_test/getpc_test.vcproj
-@HAS_PC_TRUE@@MINGW_FALSE@getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h
+@WITH_CPU_PROFILER_TRUE@getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h
#WINDOWS_PROJECTS += vsprojects/profiledata_unittest/profiledata_unittest.vcproj
-@HAS_PC_TRUE@@MINGW_FALSE@profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/profiledata.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/commandlineflags.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/logging.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/base/basictypes.h
-
-@HAS_PC_TRUE@@MINGW_FALSE@profiledata_unittest_LDADD = $(LIBPROFILER)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh
-@HAS_PC_TRUE@@MINGW_FALSE@PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/google/profiler.h
-
-@HAS_PC_TRUE@@MINGW_FALSE@PROFILER_UNITTEST_SRCS = src/tests/profiler_unittest.cc \
-@HAS_PC_TRUE@@MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc \
-@HAS_PC_TRUE@@MINGW_FALSE@ $(PROFILER_UNITTEST_INCLUDES)
-
-@HAS_PC_TRUE@@MINGW_FALSE@profiler1_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler1_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler1_unittest_LDADD = $(LIBPROFILER)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler2_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler2_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler2_unittest_LDADD = -lstacktrace -lprofiler
+@WITH_CPU_PROFILER_TRUE@profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \
+@WITH_CPU_PROFILER_TRUE@ src/profiledata.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/commandlineflags.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/logging.h \
+@WITH_CPU_PROFILER_TRUE@ src/base/basictypes.h
+
+@WITH_CPU_PROFILER_TRUE@profiledata_unittest_LDADD = $(LIBPROFILER)
+@WITH_CPU_PROFILER_TRUE@profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh
+@WITH_CPU_PROFILER_TRUE@PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@WITH_CPU_PROFILER_TRUE@ src/google/profiler.h
+
+@WITH_CPU_PROFILER_TRUE@PROFILER_UNITTEST_SRCS = src/tests/profiler_unittest.cc \
+@WITH_CPU_PROFILER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \
+@WITH_CPU_PROFILER_TRUE@ $(PROFILER_UNITTEST_INCLUDES)
+
+@WITH_CPU_PROFILER_TRUE@profiler1_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@WITH_CPU_PROFILER_TRUE@profiler1_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
+@WITH_CPU_PROFILER_TRUE@profiler1_unittest_LDADD = $(LIBPROFILER)
+@WITH_CPU_PROFILER_TRUE@profiler2_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@WITH_CPU_PROFILER_TRUE@profiler2_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
+@WITH_CPU_PROFILER_TRUE@profiler2_unittest_LDADD = -lstacktrace -lprofiler
# We depend on -lprofiler but haven't yet said how to build it. Do so now.
-@HAS_PC_TRUE@@MINGW_FALSE@profiler2_unittest_DEPENDENCIES = $(LIBPROFILER)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler3_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler3_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler3_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler3_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler4_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler4_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler4_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-@HAS_PC_TRUE@@MINGW_FALSE@profiler4_unittest_LDADD = -lstacktrace -lprofiler $(PTHREAD_LIBS)
+@WITH_CPU_PROFILER_TRUE@profiler2_unittest_DEPENDENCIES = $(LIBPROFILER)
+@WITH_CPU_PROFILER_TRUE@profiler3_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@WITH_CPU_PROFILER_TRUE@profiler3_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_CPU_PROFILER_TRUE@profiler3_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@WITH_CPU_PROFILER_TRUE@profiler3_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS)
+@WITH_CPU_PROFILER_TRUE@profiler4_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@WITH_CPU_PROFILER_TRUE@profiler4_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_CPU_PROFILER_TRUE@profiler4_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@WITH_CPU_PROFILER_TRUE@profiler4_unittest_LDADD = -lstacktrace -lprofiler $(PTHREAD_LIBS)
# We depend on -lprofiler but haven't yet said how to build it. Do so now.
-@HAS_PC_TRUE@@MINGW_FALSE@profiler4_unittest_DEPENDENCIES = $(LIBPROFILER)
+@WITH_CPU_PROFILER_TRUE@profiler4_unittest_DEPENDENCIES = $(LIBPROFILER)
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
$(SCRIPTS) libtool \
- src/windows/nm-pdb.c src/windows/addr2line-pdb.c \
src/windows/get_mangled_names.cc \
src/windows/config.h $(WINDOWS_PROJECTS) \
src/solaris/libstdc++.la
@@ -1590,17 +1827,47 @@ libprofiler.la: $(libprofiler_la_OBJECTS) $(libprofiler_la_DEPENDENCIES)
libspinlock.la: $(libspinlock_la_OBJECTS) $(libspinlock_la_DEPENDENCIES)
$(CXXLINK) $(am_libspinlock_la_rpath) $(libspinlock_la_LDFLAGS) $(libspinlock_la_OBJECTS) $(libspinlock_la_LIBADD) $(LIBS)
libstacktrace.la: $(libstacktrace_la_OBJECTS) $(libstacktrace_la_DEPENDENCIES)
- $(CXXLINK) $(libstacktrace_la_LDFLAGS) $(libstacktrace_la_OBJECTS) $(libstacktrace_la_LIBADD) $(LIBS)
+ $(CXXLINK) $(am_libstacktrace_la_rpath) $(libstacktrace_la_LDFLAGS) $(libstacktrace_la_OBJECTS) $(libstacktrace_la_LIBADD) $(LIBS)
libsysinfo.la: $(libsysinfo_la_OBJECTS) $(libsysinfo_la_DEPENDENCIES)
$(CXXLINK) $(libsysinfo_la_LDFLAGS) $(libsysinfo_la_OBJECTS) $(libsysinfo_la_LIBADD) $(LIBS)
libtcmalloc.la: $(libtcmalloc_la_OBJECTS) $(libtcmalloc_la_DEPENDENCIES)
$(CXXLINK) $(am_libtcmalloc_la_rpath) $(libtcmalloc_la_LDFLAGS) $(libtcmalloc_la_OBJECTS) $(libtcmalloc_la_LIBADD) $(LIBS)
+libtcmalloc_internal.la: $(libtcmalloc_internal_la_OBJECTS) $(libtcmalloc_internal_la_DEPENDENCIES)
+ $(CXXLINK) $(am_libtcmalloc_internal_la_rpath) $(libtcmalloc_internal_la_LDFLAGS) $(libtcmalloc_internal_la_OBJECTS) $(libtcmalloc_internal_la_LIBADD) $(LIBS)
libtcmalloc_minimal.la: $(libtcmalloc_minimal_la_OBJECTS) $(libtcmalloc_minimal_la_DEPENDENCIES)
$(CXXLINK) -rpath $(libdir) $(libtcmalloc_minimal_la_LDFLAGS) $(libtcmalloc_minimal_la_OBJECTS) $(libtcmalloc_minimal_la_LIBADD) $(LIBS)
libtcmalloc_minimal_internal.la: $(libtcmalloc_minimal_internal_la_OBJECTS) $(libtcmalloc_minimal_internal_la_DEPENDENCIES)
$(CXXLINK) $(libtcmalloc_minimal_internal_la_LDFLAGS) $(libtcmalloc_minimal_internal_la_OBJECTS) $(libtcmalloc_minimal_internal_la_LIBADD) $(LIBS)
libwindows.la: $(libwindows_la_OBJECTS) $(libwindows_la_DEPENDENCIES)
$(CXXLINK) $(am_libwindows_la_rpath) $(libwindows_la_LDFLAGS) $(libwindows_la_OBJECTS) $(libwindows_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; for p in $$list; do \
@@ -1620,24 +1887,27 @@ frag_unittest$(EXEEXT): $(frag_unittest_OBJECTS) $(frag_unittest_DEPENDENCIES)
getpc_test$(EXEEXT): $(getpc_test_OBJECTS) $(getpc_test_DEPENDENCIES)
@rm -f getpc_test$(EXEEXT)
$(CXXLINK) $(getpc_test_LDFLAGS) $(getpc_test_OBJECTS) $(getpc_test_LDADD) $(LIBS)
-@MINGW_TRUE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_DEPENDENCIES)
-@MINGW_TRUE@ @rm -f heap-checker-death_unittest.sh$(EXEEXT)
-@MINGW_TRUE@ $(LINK) $(heap_checker_death_unittest_sh_LDFLAGS) $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_LDADD) $(LIBS)
+@WITH_HEAP_CHECKER_FALSE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_DEPENDENCIES)
+@WITH_HEAP_CHECKER_FALSE@ @rm -f heap-checker-death_unittest.sh$(EXEEXT)
+@WITH_HEAP_CHECKER_FALSE@ $(LINK) $(heap_checker_death_unittest_sh_LDFLAGS) $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_LDADD) $(LIBS)
heap-checker_unittest$(EXEEXT): $(heap_checker_unittest_OBJECTS) $(heap_checker_unittest_DEPENDENCIES)
@rm -f heap-checker_unittest$(EXEEXT)
$(CXXLINK) $(heap_checker_unittest_LDFLAGS) $(heap_checker_unittest_OBJECTS) $(heap_checker_unittest_LDADD) $(LIBS)
-@MINGW_TRUE@heap-checker_unittest.sh$(EXEEXT): $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_DEPENDENCIES)
-@MINGW_TRUE@ @rm -f heap-checker_unittest.sh$(EXEEXT)
-@MINGW_TRUE@ $(LINK) $(heap_checker_unittest_sh_LDFLAGS) $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_LDADD) $(LIBS)
+@WITH_HEAP_CHECKER_FALSE@heap-checker_unittest.sh$(EXEEXT): $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_DEPENDENCIES)
+@WITH_HEAP_CHECKER_FALSE@ @rm -f heap-checker_unittest.sh$(EXEEXT)
+@WITH_HEAP_CHECKER_FALSE@ $(LINK) $(heap_checker_unittest_sh_LDFLAGS) $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_LDADD) $(LIBS)
heap-profiler_unittest$(EXEEXT): $(heap_profiler_unittest_OBJECTS) $(heap_profiler_unittest_DEPENDENCIES)
@rm -f heap-profiler_unittest$(EXEEXT)
$(CXXLINK) $(heap_profiler_unittest_LDFLAGS) $(heap_profiler_unittest_OBJECTS) $(heap_profiler_unittest_LDADD) $(LIBS)
-@MINGW_TRUE@heap-profiler_unittest.sh$(EXEEXT): $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_DEPENDENCIES)
-@MINGW_TRUE@ @rm -f heap-profiler_unittest.sh$(EXEEXT)
-@MINGW_TRUE@ $(LINK) $(heap_profiler_unittest_sh_LDFLAGS) $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_LDADD) $(LIBS)
+@WITH_HEAP_PROFILER_FALSE@heap-profiler_unittest.sh$(EXEEXT): $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_DEPENDENCIES)
+@WITH_HEAP_PROFILER_FALSE@ @rm -f heap-profiler_unittest.sh$(EXEEXT)
+@WITH_HEAP_PROFILER_FALSE@ $(LINK) $(heap_profiler_unittest_sh_LDFLAGS) $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_LDADD) $(LIBS)
low_level_alloc_unittest$(EXEEXT): $(low_level_alloc_unittest_OBJECTS) $(low_level_alloc_unittest_DEPENDENCIES)
@rm -f low_level_alloc_unittest$(EXEEXT)
$(CXXLINK) $(low_level_alloc_unittest_LDFLAGS) $(low_level_alloc_unittest_OBJECTS) $(low_level_alloc_unittest_LDADD) $(LIBS)
+malloc_extension_test$(EXEEXT): $(malloc_extension_test_OBJECTS) $(malloc_extension_test_DEPENDENCIES)
+ @rm -f malloc_extension_test$(EXEEXT)
+ $(CXXLINK) $(malloc_extension_test_LDFLAGS) $(malloc_extension_test_OBJECTS) $(malloc_extension_test_LDADD) $(LIBS)
markidle_unittest$(EXEEXT): $(markidle_unittest_OBJECTS) $(markidle_unittest_DEPENDENCIES)
@rm -f markidle_unittest$(EXEEXT)
$(CXXLINK) $(markidle_unittest_LDFLAGS) $(markidle_unittest_OBJECTS) $(markidle_unittest_LDADD) $(LIBS)
@@ -1650,6 +1920,9 @@ memalign_unittest$(EXEEXT): $(memalign_unittest_OBJECTS) $(memalign_unittest_DEP
packed_cache_test$(EXEEXT): $(packed_cache_test_OBJECTS) $(packed_cache_test_DEPENDENCIES)
@rm -f packed_cache_test$(EXEEXT)
$(CXXLINK) $(packed_cache_test_LDFLAGS) $(packed_cache_test_OBJECTS) $(packed_cache_test_LDADD) $(LIBS)
+pagemap_unittest$(EXEEXT): $(pagemap_unittest_OBJECTS) $(pagemap_unittest_DEPENDENCIES)
+ @rm -f pagemap_unittest$(EXEEXT)
+ $(CXXLINK) $(pagemap_unittest_LDFLAGS) $(pagemap_unittest_OBJECTS) $(pagemap_unittest_LDADD) $(LIBS)
profiledata_unittest$(EXEEXT): $(profiledata_unittest_OBJECTS) $(profiledata_unittest_DEPENDENCIES)
@rm -f profiledata_unittest$(EXEEXT)
$(CXXLINK) $(profiledata_unittest_LDFLAGS) $(profiledata_unittest_OBJECTS) $(profiledata_unittest_LDADD) $(LIBS)
@@ -1665,24 +1938,33 @@ profiler3_unittest$(EXEEXT): $(profiler3_unittest_OBJECTS) $(profiler3_unittest_
profiler4_unittest$(EXEEXT): $(profiler4_unittest_OBJECTS) $(profiler4_unittest_DEPENDENCIES)
@rm -f profiler4_unittest$(EXEEXT)
$(CXXLINK) $(profiler4_unittest_LDFLAGS) $(profiler4_unittest_OBJECTS) $(profiler4_unittest_LDADD) $(LIBS)
-@HAS_PC_FALSE@profiler_unittest.sh$(EXEEXT): $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_DEPENDENCIES)
-@HAS_PC_FALSE@ @rm -f profiler_unittest.sh$(EXEEXT)
-@HAS_PC_FALSE@ $(LINK) $(profiler_unittest_sh_LDFLAGS) $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_LDADD) $(LIBS)
-@MINGW_TRUE@profiler_unittest.sh$(EXEEXT): $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_DEPENDENCIES)
-@MINGW_TRUE@ @rm -f profiler_unittest.sh$(EXEEXT)
-@MINGW_TRUE@ $(LINK) $(profiler_unittest_sh_LDFLAGS) $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_LDADD) $(LIBS)
+@WITH_CPU_PROFILER_FALSE@profiler_unittest.sh$(EXEEXT): $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_DEPENDENCIES)
+@WITH_CPU_PROFILER_FALSE@ @rm -f profiler_unittest.sh$(EXEEXT)
+@WITH_CPU_PROFILER_FALSE@ $(LINK) $(profiler_unittest_sh_LDFLAGS) $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_LDADD) $(LIBS)
ptmalloc_unittest1$(EXEEXT): $(ptmalloc_unittest1_OBJECTS) $(ptmalloc_unittest1_DEPENDENCIES)
@rm -f ptmalloc_unittest1$(EXEEXT)
$(LINK) $(ptmalloc_unittest1_LDFLAGS) $(ptmalloc_unittest1_OBJECTS) $(ptmalloc_unittest1_LDADD) $(LIBS)
ptmalloc_unittest2$(EXEEXT): $(ptmalloc_unittest2_OBJECTS) $(ptmalloc_unittest2_DEPENDENCIES)
@rm -f ptmalloc_unittest2$(EXEEXT)
$(LINK) $(ptmalloc_unittest2_LDFLAGS) $(ptmalloc_unittest2_OBJECTS) $(ptmalloc_unittest2_LDADD) $(LIBS)
+raw_printer_test$(EXEEXT): $(raw_printer_test_OBJECTS) $(raw_printer_test_DEPENDENCIES)
+ @rm -f raw_printer_test$(EXEEXT)
+ $(CXXLINK) $(raw_printer_test_LDFLAGS) $(raw_printer_test_OBJECTS) $(raw_printer_test_LDADD) $(LIBS)
+realloc_unittest$(EXEEXT): $(realloc_unittest_OBJECTS) $(realloc_unittest_DEPENDENCIES)
+ @rm -f realloc_unittest$(EXEEXT)
+ $(CXXLINK) $(realloc_unittest_LDFLAGS) $(realloc_unittest_OBJECTS) $(realloc_unittest_LDADD) $(LIBS)
+sampler_test$(EXEEXT): $(sampler_test_OBJECTS) $(sampler_test_DEPENDENCIES)
+ @rm -f sampler_test$(EXEEXT)
+ $(CXXLINK) $(sampler_test_LDFLAGS) $(sampler_test_OBJECTS) $(sampler_test_LDADD) $(LIBS)
sampling_test$(EXEEXT): $(sampling_test_OBJECTS) $(sampling_test_DEPENDENCIES)
@rm -f sampling_test$(EXEEXT)
$(CXXLINK) $(sampling_test_LDFLAGS) $(sampling_test_OBJECTS) $(sampling_test_LDADD) $(LIBS)
-@MINGW_TRUE@sampling_test.sh$(EXEEXT): $(sampling_test_sh_OBJECTS) $(sampling_test_sh_DEPENDENCIES)
-@MINGW_TRUE@ @rm -f sampling_test.sh$(EXEEXT)
-@MINGW_TRUE@ $(LINK) $(sampling_test_sh_LDFLAGS) $(sampling_test_sh_OBJECTS) $(sampling_test_sh_LDADD) $(LIBS)
+@WITH_HEAP_PROFILER_OR_CHECKER_FALSE@sampling_test.sh$(EXEEXT): $(sampling_test_sh_OBJECTS) $(sampling_test_sh_DEPENDENCIES)
+@WITH_HEAP_PROFILER_OR_CHECKER_FALSE@ @rm -f sampling_test.sh$(EXEEXT)
+@WITH_HEAP_PROFILER_OR_CHECKER_FALSE@ $(LINK) $(sampling_test_sh_LDFLAGS) $(sampling_test_sh_OBJECTS) $(sampling_test_sh_LDADD) $(LIBS)
+stack_trace_table_test$(EXEEXT): $(stack_trace_table_test_OBJECTS) $(stack_trace_table_test_DEPENDENCIES)
+ @rm -f stack_trace_table_test$(EXEEXT)
+ $(CXXLINK) $(stack_trace_table_test_LDFLAGS) $(stack_trace_table_test_OBJECTS) $(stack_trace_table_test_LDADD) $(LIBS)
stacktrace_unittest$(EXEEXT): $(stacktrace_unittest_OBJECTS) $(stacktrace_unittest_DEPENDENCIES)
@rm -f stacktrace_unittest$(EXEEXT)
$(CXXLINK) $(stacktrace_unittest_LDFLAGS) $(stacktrace_unittest_OBJECTS) $(stacktrace_unittest_LDADD) $(LIBS)
@@ -1743,26 +2025,29 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_modrm_map.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_opcode_map.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-central_freelist.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-page_heap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-sampler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-span.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-static_vars.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-checker.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-profile-table.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-profiler.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-internal_logging.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-linuxthreads.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-low_level_alloc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-malloc_extension.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-malloc_hook.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-maybe_threads.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-memfs_malloc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-memory_region_map.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-page_heap.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-span.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-static_vars.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-system-alloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-tcmalloc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-thread_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-central_freelist.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-internal_logging.Plo@am__quote@
@@ -1771,21 +2056,25 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-maybe_threads.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-memfs_malloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-page_heap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-system-alloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_internal_la-thread_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_minimal_la-tcmalloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc_hook.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc_extension_test-malloc_extension_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/markidle_unittest-markidle_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/markidle_unittest-testutil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalign_unittest-memalign_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalign_unittest-testutil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mini_disassembler.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packed-cache_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pagemap_unittest-pagemap_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/patch_functions.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preamble_patcher.Plo@am__quote@
@@ -1803,10 +2092,15 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler4_unittest-testutil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptmalloc_unittest1-t-test1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptmalloc_unittest2-t-test2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw_printer_test-raw_printer_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/realloc_unittest-realloc_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sampler_test-sampler_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sampling_test-sampling_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spinlock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace_with_context.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysinfo.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/system_alloc_unittest-system-alloc_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcmalloc_both_unittest-tcmalloc_unittest.Po@am__quote@
@@ -1820,6 +2114,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_dealloc_unittest-testutil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_dealloc_unittest-thread_dealloc_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_lister.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vdso_support.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@@ -1947,6 +2242,20 @@ stacktrace.lo: src/stacktrace.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace.lo `test -f 'src/stacktrace.cc' || echo '$(srcdir)/'`src/stacktrace.cc
+stacktrace_with_context.lo: src/stacktrace_with_context.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stacktrace_with_context.lo -MD -MP -MF "$(DEPDIR)/stacktrace_with_context.Tpo" -c -o stacktrace_with_context.lo `test -f 'src/stacktrace_with_context.cc' || echo '$(srcdir)/'`src/stacktrace_with_context.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stacktrace_with_context.Tpo" "$(DEPDIR)/stacktrace_with_context.Plo"; else rm -f "$(DEPDIR)/stacktrace_with_context.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stacktrace_with_context.cc' object='stacktrace_with_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace_with_context.lo `test -f 'src/stacktrace_with_context.cc' || echo '$(srcdir)/'`src/stacktrace_with_context.cc
+
+vdso_support.lo: src/base/vdso_support.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT vdso_support.lo -MD -MP -MF "$(DEPDIR)/vdso_support.Tpo" -c -o vdso_support.lo `test -f 'src/base/vdso_support.cc' || echo '$(srcdir)/'`src/base/vdso_support.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/vdso_support.Tpo" "$(DEPDIR)/vdso_support.Plo"; else rm -f "$(DEPDIR)/vdso_support.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/vdso_support.cc' object='vdso_support.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o vdso_support.lo `test -f 'src/base/vdso_support.cc' || echo '$(srcdir)/'`src/base/vdso_support.cc
+
sysinfo.lo: src/base/sysinfo.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sysinfo.lo -MD -MP -MF "$(DEPDIR)/sysinfo.Tpo" -c -o sysinfo.lo `test -f 'src/base/sysinfo.cc' || echo '$(srcdir)/'`src/base/sysinfo.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sysinfo.Tpo" "$(DEPDIR)/sysinfo.Plo"; else rm -f "$(DEPDIR)/sysinfo.Tpo"; exit 1; fi
@@ -1954,145 +2263,166 @@ sysinfo.lo: src/base/sysinfo.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sysinfo.lo `test -f 'src/base/sysinfo.cc' || echo '$(srcdir)/'`src/base/sysinfo.cc
-libtcmalloc_la-common.lo: src/common.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-common.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-common.Tpo" -c -o libtcmalloc_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-common.Tpo" "$(DEPDIR)/libtcmalloc_la-common.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-common.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common.cc' object='libtcmalloc_la-common.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_la-tcmalloc.lo: src/tcmalloc.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-tcmalloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo" -c -o libtcmalloc_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo" "$(DEPDIR)/libtcmalloc_la-tcmalloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tcmalloc.cc' object='libtcmalloc_la-tcmalloc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc
-libtcmalloc_la-internal_logging.lo: src/internal_logging.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-internal_logging.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-internal_logging.Tpo" -c -o libtcmalloc_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-internal_logging.Tpo" "$(DEPDIR)/libtcmalloc_la-internal_logging.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-internal_logging.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/internal_logging.cc' object='libtcmalloc_la-internal_logging.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_la-linuxthreads.lo: src/base/linuxthreads.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-linuxthreads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo" -c -o libtcmalloc_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo" "$(DEPDIR)/libtcmalloc_la-linuxthreads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/linuxthreads.cc' object='libtcmalloc_la-linuxthreads.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc
-libtcmalloc_la-system-alloc.lo: src/system-alloc.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-system-alloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-system-alloc.Tpo" -c -o libtcmalloc_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-system-alloc.Tpo" "$(DEPDIR)/libtcmalloc_la-system-alloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-system-alloc.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/system-alloc.cc' object='libtcmalloc_la-system-alloc.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_la-heap-checker.lo: src/heap-checker.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-checker.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo" -c -o libtcmalloc_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-checker.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker.cc' object='libtcmalloc_la-heap-checker.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc
-libtcmalloc_la-memfs_malloc.lo: src/memfs_malloc.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-memfs_malloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-memfs_malloc.Tpo" -c -o libtcmalloc_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-memfs_malloc.Tpo" "$(DEPDIR)/libtcmalloc_la-memfs_malloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-memfs_malloc.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/memfs_malloc.cc' object='libtcmalloc_la-memfs_malloc.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_la-heap-checker-bcad.lo: src/heap-checker-bcad.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-checker-bcad.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo" -c -o libtcmalloc_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker-bcad.cc' object='libtcmalloc_la-heap-checker-bcad.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc
-libtcmalloc_la-central_freelist.lo: src/central_freelist.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-central_freelist.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-central_freelist.Tpo" -c -o libtcmalloc_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-central_freelist.Tpo" "$(DEPDIR)/libtcmalloc_la-central_freelist.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-central_freelist.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/central_freelist.cc' object='libtcmalloc_la-central_freelist.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-common.lo: src/common.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-common.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-common.Tpo" -c -o libtcmalloc_internal_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-common.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-common.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-common.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common.cc' object='libtcmalloc_internal_la-common.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-common.lo `test -f 'src/common.cc' || echo '$(srcdir)/'`src/common.cc
-libtcmalloc_la-page_heap.lo: src/page_heap.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-page_heap.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-page_heap.Tpo" -c -o libtcmalloc_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-page_heap.Tpo" "$(DEPDIR)/libtcmalloc_la-page_heap.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-page_heap.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/page_heap.cc' object='libtcmalloc_la-page_heap.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-internal_logging.lo: src/internal_logging.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-internal_logging.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Tpo" -c -o libtcmalloc_internal_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-internal_logging.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/internal_logging.cc' object='libtcmalloc_internal_la-internal_logging.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-internal_logging.lo `test -f 'src/internal_logging.cc' || echo '$(srcdir)/'`src/internal_logging.cc
-libtcmalloc_la-span.lo: src/span.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-span.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-span.Tpo" -c -o libtcmalloc_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-span.Tpo" "$(DEPDIR)/libtcmalloc_la-span.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-span.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/span.cc' object='libtcmalloc_la-span.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-system-alloc.lo: src/system-alloc.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-system-alloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Tpo" -c -o libtcmalloc_internal_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-system-alloc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/system-alloc.cc' object='libtcmalloc_internal_la-system-alloc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-system-alloc.lo `test -f 'src/system-alloc.cc' || echo '$(srcdir)/'`src/system-alloc.cc
-libtcmalloc_la-static_vars.lo: src/static_vars.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-static_vars.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-static_vars.Tpo" -c -o libtcmalloc_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-static_vars.Tpo" "$(DEPDIR)/libtcmalloc_la-static_vars.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-static_vars.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/static_vars.cc' object='libtcmalloc_la-static_vars.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-memfs_malloc.lo: src/memfs_malloc.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-memfs_malloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Tpo" -c -o libtcmalloc_internal_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-memfs_malloc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/memfs_malloc.cc' object='libtcmalloc_internal_la-memfs_malloc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-memfs_malloc.lo `test -f 'src/memfs_malloc.cc' || echo '$(srcdir)/'`src/memfs_malloc.cc
-libtcmalloc_la-thread_cache.lo: src/thread_cache.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-thread_cache.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-thread_cache.Tpo" -c -o libtcmalloc_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-thread_cache.Tpo" "$(DEPDIR)/libtcmalloc_la-thread_cache.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-thread_cache.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/thread_cache.cc' object='libtcmalloc_la-thread_cache.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-central_freelist.lo: src/central_freelist.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-central_freelist.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Tpo" -c -o libtcmalloc_internal_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-central_freelist.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/central_freelist.cc' object='libtcmalloc_internal_la-central_freelist.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-central_freelist.lo `test -f 'src/central_freelist.cc' || echo '$(srcdir)/'`src/central_freelist.cc
-libtcmalloc_la-malloc_hook.lo: src/malloc_hook.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-malloc_hook.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-malloc_hook.Tpo" -c -o libtcmalloc_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-malloc_hook.Tpo" "$(DEPDIR)/libtcmalloc_la-malloc_hook.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-malloc_hook.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='libtcmalloc_la-malloc_hook.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-page_heap.lo: src/page_heap.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-page_heap.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Tpo" -c -o libtcmalloc_internal_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-page_heap.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/page_heap.cc' object='libtcmalloc_internal_la-page_heap.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc
-libtcmalloc_la-malloc_extension.lo: src/malloc_extension.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-malloc_extension.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-malloc_extension.Tpo" -c -o libtcmalloc_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-malloc_extension.Tpo" "$(DEPDIR)/libtcmalloc_la-malloc_extension.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-malloc_extension.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_extension.cc' object='libtcmalloc_la-malloc_extension.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-sampler.lo: src/sampler.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-sampler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-sampler.Tpo" -c -o libtcmalloc_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-sampler.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-sampler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-sampler.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/sampler.cc' object='libtcmalloc_internal_la-sampler.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc
-libtcmalloc_la-maybe_threads.lo: src/maybe_threads.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-maybe_threads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-maybe_threads.Tpo" -c -o libtcmalloc_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-maybe_threads.Tpo" "$(DEPDIR)/libtcmalloc_la-maybe_threads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-maybe_threads.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/maybe_threads.cc' object='libtcmalloc_la-maybe_threads.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-span.lo: src/span.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-span.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-span.Tpo" -c -o libtcmalloc_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-span.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-span.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-span.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/span.cc' object='libtcmalloc_internal_la-span.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc
-libtcmalloc_la-tcmalloc.lo: src/tcmalloc.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-tcmalloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo" -c -o libtcmalloc_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo" "$(DEPDIR)/libtcmalloc_la-tcmalloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-tcmalloc.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tcmalloc.cc' object='libtcmalloc_la-tcmalloc.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-stack_trace_table.lo: src/stack_trace_table.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-stack_trace_table.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Tpo" -c -o libtcmalloc_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-stack_trace_table.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stack_trace_table.cc' object='libtcmalloc_internal_la-stack_trace_table.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc
-libtcmalloc_la-linuxthreads.lo: src/base/linuxthreads.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-linuxthreads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo" -c -o libtcmalloc_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo" "$(DEPDIR)/libtcmalloc_la-linuxthreads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-linuxthreads.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/linuxthreads.cc' object='libtcmalloc_la-linuxthreads.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-static_vars.lo: src/static_vars.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-static_vars.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Tpo" -c -o libtcmalloc_internal_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-static_vars.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/static_vars.cc' object='libtcmalloc_internal_la-static_vars.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-linuxthreads.lo `test -f 'src/base/linuxthreads.cc' || echo '$(srcdir)/'`src/base/linuxthreads.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc
-libtcmalloc_la-low_level_alloc.lo: src/base/low_level_alloc.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-low_level_alloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-low_level_alloc.Tpo" -c -o libtcmalloc_la-low_level_alloc.lo `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-low_level_alloc.Tpo" "$(DEPDIR)/libtcmalloc_la-low_level_alloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-low_level_alloc.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='libtcmalloc_la-low_level_alloc.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-thread_cache.lo: src/thread_cache.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-thread_cache.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Tpo" -c -o libtcmalloc_internal_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-thread_cache.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/thread_cache.cc' object='libtcmalloc_internal_la-thread_cache.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-low_level_alloc.lo `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-thread_cache.lo `test -f 'src/thread_cache.cc' || echo '$(srcdir)/'`src/thread_cache.cc
-libtcmalloc_la-heap-checker.lo: src/heap-checker.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-checker.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo" -c -o libtcmalloc_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-checker.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-checker.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker.cc' object='libtcmalloc_la-heap-checker.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-malloc_hook.lo: src/malloc_hook.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-malloc_hook.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Tpo" -c -o libtcmalloc_internal_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_hook.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='libtcmalloc_internal_la-malloc_hook.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-checker.lo `test -f 'src/heap-checker.cc' || echo '$(srcdir)/'`src/heap-checker.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-malloc_hook.lo `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc
-libtcmalloc_la-heap-profile-table.lo: src/heap-profile-table.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-profile-table.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-profile-table.Tpo" -c -o libtcmalloc_la-heap-profile-table.lo `test -f 'src/heap-profile-table.cc' || echo '$(srcdir)/'`src/heap-profile-table.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-profile-table.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-profile-table.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-profile-table.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-profile-table.cc' object='libtcmalloc_la-heap-profile-table.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-malloc_extension.lo: src/malloc_extension.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-malloc_extension.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Tpo" -c -o libtcmalloc_internal_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-malloc_extension.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_extension.cc' object='libtcmalloc_internal_la-malloc_extension.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-profile-table.lo `test -f 'src/heap-profile-table.cc' || echo '$(srcdir)/'`src/heap-profile-table.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-malloc_extension.lo `test -f 'src/malloc_extension.cc' || echo '$(srcdir)/'`src/malloc_extension.cc
-libtcmalloc_la-heap-profiler.lo: src/heap-profiler.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-profiler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-profiler.Tpo" -c -o libtcmalloc_la-heap-profiler.lo `test -f 'src/heap-profiler.cc' || echo '$(srcdir)/'`src/heap-profiler.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-profiler.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-profiler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-profiler.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-profiler.cc' object='libtcmalloc_la-heap-profiler.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-maybe_threads.lo: src/maybe_threads.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-maybe_threads.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Tpo" -c -o libtcmalloc_internal_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-maybe_threads.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/maybe_threads.cc' object='libtcmalloc_internal_la-maybe_threads.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-profiler.lo `test -f 'src/heap-profiler.cc' || echo '$(srcdir)/'`src/heap-profiler.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc
-libtcmalloc_la-memory_region_map.lo: src/memory_region_map.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-memory_region_map.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-memory_region_map.Tpo" -c -o libtcmalloc_la-memory_region_map.lo `test -f 'src/memory_region_map.cc' || echo '$(srcdir)/'`src/memory_region_map.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-memory_region_map.Tpo" "$(DEPDIR)/libtcmalloc_la-memory_region_map.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-memory_region_map.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/memory_region_map.cc' object='libtcmalloc_la-memory_region_map.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-low_level_alloc.lo: src/base/low_level_alloc.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-low_level_alloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Tpo" -c -o libtcmalloc_internal_la-low_level_alloc.lo `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-low_level_alloc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='libtcmalloc_internal_la-low_level_alloc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-memory_region_map.lo `test -f 'src/memory_region_map.cc' || echo '$(srcdir)/'`src/memory_region_map.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-low_level_alloc.lo `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc
-libtcmalloc_la-heap-checker-bcad.lo: src/heap-checker-bcad.cc
-@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_la-heap-checker-bcad.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo" -c -o libtcmalloc_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo" "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-checker-bcad.cc' object='libtcmalloc_la-heap-checker-bcad.lo' libtool=yes @AMDEPBACKSLASH@
+libtcmalloc_internal_la-heap-profile-table.lo: src/heap-profile-table.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-heap-profile-table.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Tpo" -c -o libtcmalloc_internal_la-heap-profile-table.lo `test -f 'src/heap-profile-table.cc' || echo '$(srcdir)/'`src/heap-profile-table.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profile-table.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-profile-table.cc' object='libtcmalloc_internal_la-heap-profile-table.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_la-heap-checker-bcad.lo `test -f 'src/heap-checker-bcad.cc' || echo '$(srcdir)/'`src/heap-checker-bcad.cc
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-heap-profile-table.lo `test -f 'src/heap-profile-table.cc' || echo '$(srcdir)/'`src/heap-profile-table.cc
+
+libtcmalloc_internal_la-heap-profiler.lo: src/heap-profiler.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-heap-profiler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Tpo" -c -o libtcmalloc_internal_la-heap-profiler.lo `test -f 'src/heap-profiler.cc' || echo '$(srcdir)/'`src/heap-profiler.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-heap-profiler.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/heap-profiler.cc' object='libtcmalloc_internal_la-heap-profiler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-heap-profiler.lo `test -f 'src/heap-profiler.cc' || echo '$(srcdir)/'`src/heap-profiler.cc
+
+libtcmalloc_internal_la-raw_printer.lo: src/raw_printer.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-raw_printer.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Tpo" -c -o libtcmalloc_internal_la-raw_printer.lo `test -f 'src/raw_printer.cc' || echo '$(srcdir)/'`src/raw_printer.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-raw_printer.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/raw_printer.cc' object='libtcmalloc_internal_la-raw_printer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-raw_printer.lo `test -f 'src/raw_printer.cc' || echo '$(srcdir)/'`src/raw_printer.cc
+
+libtcmalloc_internal_la-memory_region_map.lo: src/memory_region_map.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_internal_la-memory_region_map.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Tpo" -c -o libtcmalloc_internal_la-memory_region_map.lo `test -f 'src/memory_region_map.cc' || echo '$(srcdir)/'`src/memory_region_map.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Tpo" "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_internal_la-memory_region_map.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/memory_region_map.cc' object='libtcmalloc_internal_la-memory_region_map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_internal_la-memory_region_map.lo `test -f 'src/memory_region_map.cc' || echo '$(srcdir)/'`src/memory_region_map.cc
libtcmalloc_minimal_la-tcmalloc.lo: src/tcmalloc.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_la-tcmalloc.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_la-tcmalloc.Tpo" -c -o libtcmalloc_minimal_la-tcmalloc.lo `test -f 'src/tcmalloc.cc' || echo '$(srcdir)/'`src/tcmalloc.cc; \
@@ -2143,6 +2473,13 @@ libtcmalloc_minimal_internal_la-page_heap.lo: src/page_heap.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-page_heap.lo `test -f 'src/page_heap.cc' || echo '$(srcdir)/'`src/page_heap.cc
+libtcmalloc_minimal_internal_la-sampler.lo: src/sampler.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-sampler.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Tpo" -c -o libtcmalloc_minimal_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-sampler.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/sampler.cc' object='libtcmalloc_minimal_internal_la-sampler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-sampler.lo `test -f 'src/sampler.cc' || echo '$(srcdir)/'`src/sampler.cc
+
libtcmalloc_minimal_internal_la-span.lo: src/span.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-span.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Tpo" -c -o libtcmalloc_minimal_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-span.Tpo"; exit 1; fi
@@ -2150,6 +2487,13 @@ libtcmalloc_minimal_internal_la-span.lo: src/span.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-span.lo `test -f 'src/span.cc' || echo '$(srcdir)/'`src/span.cc
+libtcmalloc_minimal_internal_la-stack_trace_table.lo: src/stack_trace_table.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-stack_trace_table.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Tpo" -c -o libtcmalloc_minimal_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-stack_trace_table.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stack_trace_table.cc' object='libtcmalloc_minimal_internal_la-stack_trace_table.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_internal_la-stack_trace_table.lo `test -f 'src/stack_trace_table.cc' || echo '$(srcdir)/'`src/stack_trace_table.cc
+
libtcmalloc_minimal_internal_la-static_vars.lo: src/static_vars.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_internal_la_CXXFLAGS) $(CXXFLAGS) -MT libtcmalloc_minimal_internal_la-static_vars.lo -MD -MP -MF "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Tpo" -c -o libtcmalloc_minimal_internal_la-static_vars.lo `test -f 'src/static_vars.cc' || echo '$(srcdir)/'`src/static_vars.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Tpo" "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Plo"; else rm -f "$(DEPDIR)/libtcmalloc_minimal_internal_la-static_vars.Tpo"; exit 1; fi
@@ -2318,47 +2662,61 @@ heap_profiler_unittest-heap-profiler_unittest.obj: src/tests/heap-profiler_unitt
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(heap_profiler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o heap_profiler_unittest-heap-profiler_unittest.obj `if test -f 'src/tests/heap-profiler_unittest.cc'; then $(CYGPATH_W) 'src/tests/heap-profiler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/heap-profiler_unittest.cc'; fi`
-low_level_alloc.o: src/base/low_level_alloc.cc
-@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc.o -MD -MP -MF "$(DEPDIR)/low_level_alloc.Tpo" -c -o low_level_alloc.o `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc.Tpo" "$(DEPDIR)/low_level_alloc.Po"; else rm -f "$(DEPDIR)/low_level_alloc.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='low_level_alloc.o' libtool=no @AMDEPBACKSLASH@
+low_level_alloc_unittest-low_level_alloc.o: src/base/low_level_alloc.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc.o -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" -c -o low_level_alloc_unittest-low_level_alloc.o `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='low_level_alloc_unittest-low_level_alloc.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc.o `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc.o `test -f 'src/base/low_level_alloc.cc' || echo '$(srcdir)/'`src/base/low_level_alloc.cc
-low_level_alloc.obj: src/base/low_level_alloc.cc
-@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc.Tpo" -c -o low_level_alloc.obj `if test -f 'src/base/low_level_alloc.cc'; then $(CYGPATH_W) 'src/base/low_level_alloc.cc'; else $(CYGPATH_W) '$(srcdir)/src/base/low_level_alloc.cc'; fi`; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc.Tpo" "$(DEPDIR)/low_level_alloc.Po"; else rm -f "$(DEPDIR)/low_level_alloc.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='low_level_alloc.obj' libtool=no @AMDEPBACKSLASH@
+low_level_alloc_unittest-low_level_alloc.obj: src/base/low_level_alloc.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" -c -o low_level_alloc_unittest-low_level_alloc.obj `if test -f 'src/base/low_level_alloc.cc'; then $(CYGPATH_W) 'src/base/low_level_alloc.cc'; else $(CYGPATH_W) '$(srcdir)/src/base/low_level_alloc.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/low_level_alloc.cc' object='low_level_alloc_unittest-low_level_alloc.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc.obj `if test -f 'src/base/low_level_alloc.cc'; then $(CYGPATH_W) 'src/base/low_level_alloc.cc'; else $(CYGPATH_W) '$(srcdir)/src/base/low_level_alloc.cc'; fi`
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc.obj `if test -f 'src/base/low_level_alloc.cc'; then $(CYGPATH_W) 'src/base/low_level_alloc.cc'; else $(CYGPATH_W) '$(srcdir)/src/base/low_level_alloc.cc'; fi`
-malloc_hook.o: src/malloc_hook.cc
-@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT malloc_hook.o -MD -MP -MF "$(DEPDIR)/malloc_hook.Tpo" -c -o malloc_hook.o `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_hook.Tpo" "$(DEPDIR)/malloc_hook.Po"; else rm -f "$(DEPDIR)/malloc_hook.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='malloc_hook.o' libtool=no @AMDEPBACKSLASH@
+low_level_alloc_unittest-malloc_hook.o: src/malloc_hook.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-malloc_hook.o -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" -c -o low_level_alloc_unittest-malloc_hook.o `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='low_level_alloc_unittest-malloc_hook.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o malloc_hook.o `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-malloc_hook.o `test -f 'src/malloc_hook.cc' || echo '$(srcdir)/'`src/malloc_hook.cc
-malloc_hook.obj: src/malloc_hook.cc
-@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT malloc_hook.obj -MD -MP -MF "$(DEPDIR)/malloc_hook.Tpo" -c -o malloc_hook.obj `if test -f 'src/malloc_hook.cc'; then $(CYGPATH_W) 'src/malloc_hook.cc'; else $(CYGPATH_W) '$(srcdir)/src/malloc_hook.cc'; fi`; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_hook.Tpo" "$(DEPDIR)/malloc_hook.Po"; else rm -f "$(DEPDIR)/malloc_hook.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='malloc_hook.obj' libtool=no @AMDEPBACKSLASH@
+low_level_alloc_unittest-malloc_hook.obj: src/malloc_hook.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-malloc_hook.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" -c -o low_level_alloc_unittest-malloc_hook.obj `if test -f 'src/malloc_hook.cc'; then $(CYGPATH_W) 'src/malloc_hook.cc'; else $(CYGPATH_W) '$(srcdir)/src/malloc_hook.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo" "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-malloc_hook.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/malloc_hook.cc' object='low_level_alloc_unittest-malloc_hook.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o malloc_hook.obj `if test -f 'src/malloc_hook.cc'; then $(CYGPATH_W) 'src/malloc_hook.cc'; else $(CYGPATH_W) '$(srcdir)/src/malloc_hook.cc'; fi`
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-malloc_hook.obj `if test -f 'src/malloc_hook.cc'; then $(CYGPATH_W) 'src/malloc_hook.cc'; else $(CYGPATH_W) '$(srcdir)/src/malloc_hook.cc'; fi`
-low_level_alloc_unittest.o: src/tests/low_level_alloc_unittest.cc
-@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest.o -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest.Tpo" -c -o low_level_alloc_unittest.o `test -f 'src/tests/low_level_alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/low_level_alloc_unittest.cc; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest.Tpo" "$(DEPDIR)/low_level_alloc_unittest.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/low_level_alloc_unittest.cc' object='low_level_alloc_unittest.o' libtool=no @AMDEPBACKSLASH@
+low_level_alloc_unittest-low_level_alloc_unittest.o: src/tests/low_level_alloc_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc_unittest.o -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" -c -o low_level_alloc_unittest-low_level_alloc_unittest.o `test -f 'src/tests/low_level_alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/low_level_alloc_unittest.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/low_level_alloc_unittest.cc' object='low_level_alloc_unittest-low_level_alloc_unittest.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest.o `test -f 'src/tests/low_level_alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/low_level_alloc_unittest.cc
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc_unittest.o `test -f 'src/tests/low_level_alloc_unittest.cc' || echo '$(srcdir)/'`src/tests/low_level_alloc_unittest.cc
-low_level_alloc_unittest.obj: src/tests/low_level_alloc_unittest.cc
-@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest.Tpo" -c -o low_level_alloc_unittest.obj `if test -f 'src/tests/low_level_alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/low_level_alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/low_level_alloc_unittest.cc'; fi`; \
-@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest.Tpo" "$(DEPDIR)/low_level_alloc_unittest.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/low_level_alloc_unittest.cc' object='low_level_alloc_unittest.obj' libtool=no @AMDEPBACKSLASH@
+low_level_alloc_unittest-low_level_alloc_unittest.obj: src/tests/low_level_alloc_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT low_level_alloc_unittest-low_level_alloc_unittest.obj -MD -MP -MF "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" -c -o low_level_alloc_unittest-low_level_alloc_unittest.obj `if test -f 'src/tests/low_level_alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/low_level_alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/low_level_alloc_unittest.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo" "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Po"; else rm -f "$(DEPDIR)/low_level_alloc_unittest-low_level_alloc_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/low_level_alloc_unittest.cc' object='low_level_alloc_unittest-low_level_alloc_unittest.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest.obj `if test -f 'src/tests/low_level_alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/low_level_alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/low_level_alloc_unittest.cc'; fi`
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(low_level_alloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o low_level_alloc_unittest-low_level_alloc_unittest.obj `if test -f 'src/tests/low_level_alloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/low_level_alloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/low_level_alloc_unittest.cc'; fi`
+
+malloc_extension_test-malloc_extension_test.o: src/tests/malloc_extension_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -MT malloc_extension_test-malloc_extension_test.o -MD -MP -MF "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" -c -o malloc_extension_test-malloc_extension_test.o `test -f 'src/tests/malloc_extension_test.cc' || echo '$(srcdir)/'`src/tests/malloc_extension_test.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/malloc_extension_test.cc' object='malloc_extension_test-malloc_extension_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -c -o malloc_extension_test-malloc_extension_test.o `test -f 'src/tests/malloc_extension_test.cc' || echo '$(srcdir)/'`src/tests/malloc_extension_test.cc
+
+malloc_extension_test-malloc_extension_test.obj: src/tests/malloc_extension_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -MT malloc_extension_test-malloc_extension_test.obj -MD -MP -MF "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" -c -o malloc_extension_test-malloc_extension_test.obj `if test -f 'src/tests/malloc_extension_test.cc'; then $(CYGPATH_W) 'src/tests/malloc_extension_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_test.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo" "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Po"; else rm -f "$(DEPDIR)/malloc_extension_test-malloc_extension_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/malloc_extension_test.cc' object='malloc_extension_test-malloc_extension_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(malloc_extension_test_CXXFLAGS) $(CXXFLAGS) -c -o malloc_extension_test-malloc_extension_test.obj `if test -f 'src/tests/malloc_extension_test.cc'; then $(CYGPATH_W) 'src/tests/malloc_extension_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/malloc_extension_test.cc'; fi`
markidle_unittest-markidle_unittest.o: src/tests/markidle_unittest.cc
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(markidle_unittest_CXXFLAGS) $(CXXFLAGS) -MT markidle_unittest-markidle_unittest.o -MD -MP -MF "$(DEPDIR)/markidle_unittest-markidle_unittest.Tpo" -c -o markidle_unittest-markidle_unittest.o `test -f 'src/tests/markidle_unittest.cc' || echo '$(srcdir)/'`src/tests/markidle_unittest.cc; \
@@ -2430,6 +2788,20 @@ packed-cache_test.obj: src/tests/packed-cache_test.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o packed-cache_test.obj `if test -f 'src/tests/packed-cache_test.cc'; then $(CYGPATH_W) 'src/tests/packed-cache_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/packed-cache_test.cc'; fi`
+pagemap_unittest-pagemap_unittest.o: src/tests/pagemap_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -MT pagemap_unittest-pagemap_unittest.o -MD -MP -MF "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" -c -o pagemap_unittest-pagemap_unittest.o `test -f 'src/tests/pagemap_unittest.cc' || echo '$(srcdir)/'`src/tests/pagemap_unittest.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Po"; else rm -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/pagemap_unittest.cc' object='pagemap_unittest-pagemap_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o pagemap_unittest-pagemap_unittest.o `test -f 'src/tests/pagemap_unittest.cc' || echo '$(srcdir)/'`src/tests/pagemap_unittest.cc
+
+pagemap_unittest-pagemap_unittest.obj: src/tests/pagemap_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -MT pagemap_unittest-pagemap_unittest.obj -MD -MP -MF "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" -c -o pagemap_unittest-pagemap_unittest.obj `if test -f 'src/tests/pagemap_unittest.cc'; then $(CYGPATH_W) 'src/tests/pagemap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/pagemap_unittest.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo" "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Po"; else rm -f "$(DEPDIR)/pagemap_unittest-pagemap_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/pagemap_unittest.cc' object='pagemap_unittest-pagemap_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pagemap_unittest_CXXFLAGS) $(CXXFLAGS) -c -o pagemap_unittest-pagemap_unittest.obj `if test -f 'src/tests/pagemap_unittest.cc'; then $(CYGPATH_W) 'src/tests/pagemap_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/pagemap_unittest.cc'; fi`
+
profiledata_unittest.o: src/tests/profiledata_unittest.cc
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiledata_unittest.o -MD -MP -MF "$(DEPDIR)/profiledata_unittest.Tpo" -c -o profiledata_unittest.o `test -f 'src/tests/profiledata_unittest.cc' || echo '$(srcdir)/'`src/tests/profiledata_unittest.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiledata_unittest.Tpo" "$(DEPDIR)/profiledata_unittest.Po"; else rm -f "$(DEPDIR)/profiledata_unittest.Tpo"; exit 1; fi
@@ -2556,6 +2928,48 @@ profiler4_unittest-testutil.obj: src/tests/testutil.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler4_unittest_CXXFLAGS) $(CXXFLAGS) -c -o profiler4_unittest-testutil.obj `if test -f 'src/tests/testutil.cc'; then $(CYGPATH_W) 'src/tests/testutil.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/testutil.cc'; fi`
+raw_printer_test-raw_printer_test.o: src/tests/raw_printer_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -MT raw_printer_test-raw_printer_test.o -MD -MP -MF "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" -c -o raw_printer_test-raw_printer_test.o `test -f 'src/tests/raw_printer_test.cc' || echo '$(srcdir)/'`src/tests/raw_printer_test.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" "$(DEPDIR)/raw_printer_test-raw_printer_test.Po"; else rm -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/raw_printer_test.cc' object='raw_printer_test-raw_printer_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -c -o raw_printer_test-raw_printer_test.o `test -f 'src/tests/raw_printer_test.cc' || echo '$(srcdir)/'`src/tests/raw_printer_test.cc
+
+raw_printer_test-raw_printer_test.obj: src/tests/raw_printer_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -MT raw_printer_test-raw_printer_test.obj -MD -MP -MF "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" -c -o raw_printer_test-raw_printer_test.obj `if test -f 'src/tests/raw_printer_test.cc'; then $(CYGPATH_W) 'src/tests/raw_printer_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/raw_printer_test.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo" "$(DEPDIR)/raw_printer_test-raw_printer_test.Po"; else rm -f "$(DEPDIR)/raw_printer_test-raw_printer_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/raw_printer_test.cc' object='raw_printer_test-raw_printer_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(raw_printer_test_CXXFLAGS) $(CXXFLAGS) -c -o raw_printer_test-raw_printer_test.obj `if test -f 'src/tests/raw_printer_test.cc'; then $(CYGPATH_W) 'src/tests/raw_printer_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/raw_printer_test.cc'; fi`
+
+realloc_unittest-realloc_unittest.o: src/tests/realloc_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT realloc_unittest-realloc_unittest.o -MD -MP -MF "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" -c -o realloc_unittest-realloc_unittest.o `test -f 'src/tests/realloc_unittest.cc' || echo '$(srcdir)/'`src/tests/realloc_unittest.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" "$(DEPDIR)/realloc_unittest-realloc_unittest.Po"; else rm -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/realloc_unittest.cc' object='realloc_unittest-realloc_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o realloc_unittest-realloc_unittest.o `test -f 'src/tests/realloc_unittest.cc' || echo '$(srcdir)/'`src/tests/realloc_unittest.cc
+
+realloc_unittest-realloc_unittest.obj: src/tests/realloc_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -MT realloc_unittest-realloc_unittest.obj -MD -MP -MF "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" -c -o realloc_unittest-realloc_unittest.obj `if test -f 'src/tests/realloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/realloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/realloc_unittest.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo" "$(DEPDIR)/realloc_unittest-realloc_unittest.Po"; else rm -f "$(DEPDIR)/realloc_unittest-realloc_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/realloc_unittest.cc' object='realloc_unittest-realloc_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(realloc_unittest_CXXFLAGS) $(CXXFLAGS) -c -o realloc_unittest-realloc_unittest.obj `if test -f 'src/tests/realloc_unittest.cc'; then $(CYGPATH_W) 'src/tests/realloc_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/realloc_unittest.cc'; fi`
+
+sampler_test-sampler_test.o: src/tests/sampler_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -MT sampler_test-sampler_test.o -MD -MP -MF "$(DEPDIR)/sampler_test-sampler_test.Tpo" -c -o sampler_test-sampler_test.o `test -f 'src/tests/sampler_test.cc' || echo '$(srcdir)/'`src/tests/sampler_test.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampler_test-sampler_test.Tpo" "$(DEPDIR)/sampler_test-sampler_test.Po"; else rm -f "$(DEPDIR)/sampler_test-sampler_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampler_test.cc' object='sampler_test-sampler_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -c -o sampler_test-sampler_test.o `test -f 'src/tests/sampler_test.cc' || echo '$(srcdir)/'`src/tests/sampler_test.cc
+
+sampler_test-sampler_test.obj: src/tests/sampler_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -MT sampler_test-sampler_test.obj -MD -MP -MF "$(DEPDIR)/sampler_test-sampler_test.Tpo" -c -o sampler_test-sampler_test.obj `if test -f 'src/tests/sampler_test.cc'; then $(CYGPATH_W) 'src/tests/sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampler_test.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampler_test-sampler_test.Tpo" "$(DEPDIR)/sampler_test-sampler_test.Po"; else rm -f "$(DEPDIR)/sampler_test-sampler_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/sampler_test.cc' object='sampler_test-sampler_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampler_test_CXXFLAGS) $(CXXFLAGS) -c -o sampler_test-sampler_test.obj `if test -f 'src/tests/sampler_test.cc'; then $(CYGPATH_W) 'src/tests/sampler_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampler_test.cc'; fi`
+
sampling_test-sampling_test.o: src/tests/sampling_test.cc
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_test_CXXFLAGS) $(CXXFLAGS) -MT sampling_test-sampling_test.o -MD -MP -MF "$(DEPDIR)/sampling_test-sampling_test.Tpo" -c -o sampling_test-sampling_test.o `test -f 'src/tests/sampling_test.cc' || echo '$(srcdir)/'`src/tests/sampling_test.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sampling_test-sampling_test.Tpo" "$(DEPDIR)/sampling_test-sampling_test.Po"; else rm -f "$(DEPDIR)/sampling_test-sampling_test.Tpo"; exit 1; fi
@@ -2570,6 +2984,20 @@ sampling_test-sampling_test.obj: src/tests/sampling_test.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sampling_test_CXXFLAGS) $(CXXFLAGS) -c -o sampling_test-sampling_test.obj `if test -f 'src/tests/sampling_test.cc'; then $(CYGPATH_W) 'src/tests/sampling_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/sampling_test.cc'; fi`
+stack_trace_table_test-stack_trace_table_test.o: src/tests/stack_trace_table_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -MT stack_trace_table_test-stack_trace_table_test.o -MD -MP -MF "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" -c -o stack_trace_table_test-stack_trace_table_test.o `test -f 'src/tests/stack_trace_table_test.cc' || echo '$(srcdir)/'`src/tests/stack_trace_table_test.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Po"; else rm -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/stack_trace_table_test.cc' object='stack_trace_table_test-stack_trace_table_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -c -o stack_trace_table_test-stack_trace_table_test.o `test -f 'src/tests/stack_trace_table_test.cc' || echo '$(srcdir)/'`src/tests/stack_trace_table_test.cc
+
+stack_trace_table_test-stack_trace_table_test.obj: src/tests/stack_trace_table_test.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -MT stack_trace_table_test-stack_trace_table_test.obj -MD -MP -MF "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" -c -o stack_trace_table_test-stack_trace_table_test.obj `if test -f 'src/tests/stack_trace_table_test.cc'; then $(CYGPATH_W) 'src/tests/stack_trace_table_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/stack_trace_table_test.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo" "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Po"; else rm -f "$(DEPDIR)/stack_trace_table_test-stack_trace_table_test.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/stack_trace_table_test.cc' object='stack_trace_table_test-stack_trace_table_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stack_trace_table_test_CXXFLAGS) $(CXXFLAGS) -c -o stack_trace_table_test-stack_trace_table_test.obj `if test -f 'src/tests/stack_trace_table_test.cc'; then $(CYGPATH_W) 'src/tests/stack_trace_table_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/stack_trace_table_test.cc'; fi`
+
stacktrace_unittest.o: src/tests/stacktrace_unittest.cc
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT stacktrace_unittest.o -MD -MP -MF "$(DEPDIR)/stacktrace_unittest.Tpo" -c -o stacktrace_unittest.o `test -f 'src/tests/stacktrace_unittest.cc' || echo '$(srcdir)/'`src/tests/stacktrace_unittest.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/stacktrace_unittest.Tpo" "$(DEPDIR)/stacktrace_unittest.Po"; else rm -f "$(DEPDIR)/stacktrace_unittest.Tpo"; exit 1; fi
@@ -2951,7 +3379,7 @@ check-TESTS: $(TESTS)
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
- $(mkdir_p) $(distdir)/$(top_srcdir) $(distdir)/doc $(distdir)/m4 $(distdir)/packages $(distdir)/packages/rpm $(distdir)/src $(distdir)/src/google $(distdir)/src/solaris $(distdir)/src/tests $(distdir)/src/windows $(distdir)/vsprojects/addr2line-pdb $(distdir)/vsprojects/addressmap_unittest $(distdir)/vsprojects/frag_unittest $(distdir)/vsprojects/libtcmalloc_minimal $(distdir)/vsprojects/low_level_alloc_unittest $(distdir)/vsprojects/markidle_unittest $(distdir)/vsprojects/nm-pdb $(distdir)/vsprojects/packed-cache_test $(distdir)/vsprojects/tcmalloc_minimal_large $(distdir)/vsprojects/tcmalloc_minimal_unittest $(distdir)/vsprojects/thread_dealloc_unittest $(distdir)/vsprojects/tmu-static
+ $(mkdir_p) $(distdir)/$(top_srcdir) $(distdir)/doc $(distdir)/m4 $(distdir)/packages $(distdir)/packages/rpm $(distdir)/src $(distdir)/src/google $(distdir)/src/solaris $(distdir)/src/tests $(distdir)/src/windows $(distdir)/vsprojects/addr2line-pdb $(distdir)/vsprojects/addressmap_unittest $(distdir)/vsprojects/frag_unittest $(distdir)/vsprojects/libtcmalloc_minimal $(distdir)/vsprojects/low_level_alloc_unittest $(distdir)/vsprojects/malloc_extension_test $(distdir)/vsprojects/markidle_unittest $(distdir)/vsprojects/nm-pdb $(distdir)/vsprojects/packed-cache_test $(distdir)/vsprojects/pagemap_unittest $(distdir)/vsprojects/realloc_unittest $(distdir)/vsprojects/sampler_test $(distdir)/vsprojects/stack_trace_table_test $(distdir)/vsprojects/tcmalloc_minimal_large $(distdir)/vsprojects/tcmalloc_minimal_unittest $(distdir)/vsprojects/thread_dealloc_unittest $(distdir)/vsprojects/tmu-static
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
@@ -3085,8 +3513,10 @@ check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(MANS) $(DATA) \
$(HEADERS)
+install-binPROGRAMS: install-libLTLIBRARIES
+
installdirs:
- for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(googleincludedir)"; do \
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(googleincludedir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \
done
install: install-am
@@ -3115,8 +3545,9 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
-clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
- clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ mostlyclean-am
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
@@ -3138,7 +3569,8 @@ info-am:
install-data-am: install-dist_docDATA install-googleincludeHEADERS \
install-man
-install-exec-am: install-binSCRIPTS install-libLTLIBRARIES
+install-exec-am: install-binPROGRAMS install-binSCRIPTS \
+ install-libLTLIBRARIES
install-info: install-info-am
@@ -3166,63 +3598,64 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-binSCRIPTS uninstall-dist_docDATA \
- uninstall-googleincludeHEADERS uninstall-info-am \
- uninstall-libLTLIBRARIES uninstall-man
+uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
+ uninstall-dist_docDATA uninstall-googleincludeHEADERS \
+ uninstall-info-am uninstall-libLTLIBRARIES uninstall-man
uninstall-man: uninstall-man1
.PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \
- clean clean-generic clean-libLTLIBRARIES clean-libtool \
- clean-noinstLTLIBRARIES clean-noinstPROGRAMS ctags dist \
- dist-all dist-bzip2 dist-gzip dist-hook dist-shar dist-tarZ \
- dist-zip distcheck distclean distclean-compile \
+ clean clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ ctags dist dist-all dist-bzip2 dist-gzip dist-hook dist-shar \
+ dist-tarZ dist-zip distcheck distclean distclean-compile \
distclean-generic distclean-hdr distclean-libtool \
distclean-tags distcleancheck distdir distuninstallcheck dvi \
dvi-am html html-am info info-am install install-am \
- install-binSCRIPTS install-data install-data-am \
- install-dist_docDATA install-exec install-exec-am \
- install-googleincludeHEADERS install-info install-info-am \
- install-libLTLIBRARIES install-man install-man1 install-strip \
- installcheck installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-compile \
- mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
- tags uninstall uninstall-am uninstall-binSCRIPTS \
+ install-binPROGRAMS install-binSCRIPTS install-data \
+ install-data-am install-dist_docDATA install-exec \
+ install-exec-am install-googleincludeHEADERS install-info \
+ install-info-am install-libLTLIBRARIES install-man \
+ install-man1 install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS \
uninstall-dist_docDATA uninstall-googleincludeHEADERS \
uninstall-info-am uninstall-libLTLIBRARIES uninstall-man \
uninstall-man1
@ENABLE_FRAME_POINTERS_FALSE@@X86_64_TRUE@ # TODO(csilvers): check if -fomit-frame-pointer might be in $(CXXFLAGS),
@ENABLE_FRAME_POINTERS_FALSE@@X86_64_TRUE@ # before setting this.
-@MINGW_FALSE@pprof_unittest: $(top_srcdir)/src/pprof
-@MINGW_FALSE@ $(top_srcdir)/src/pprof -test
+@WITH_STACK_TRACE_TRUE@pprof_unittest: $(top_srcdir)/src/pprof
+@WITH_STACK_TRACE_TRUE@ $(top_srcdir)/src/pprof -test
# This script preloads libtcmalloc, and calls two other binaries as well
@MINGW_FALSE@maybe_threads_unittest.sh$(EXEEXT): $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) \
@MINGW_FALSE@ $(LIBTCMALLOC_MINIMAL) \
@MINGW_FALSE@ low_level_alloc_unittest
@MINGW_FALSE@ rm -f $@
@MINGW_FALSE@ cp -p $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) $@
-@MINGW_FALSE@sampling_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \
-@MINGW_FALSE@ sampling_test
-@MINGW_FALSE@ rm -f $@
-@MINGW_FALSE@ cp -p $(top_srcdir)/$(sampling_test_sh_SOURCES) $@
-@MINGW_FALSE@heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \
-@MINGW_FALSE@ heap-profiler_unittest
-@MINGW_FALSE@ rm -f $@
-@MINGW_FALSE@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@
-@MINGW_FALSE@heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \
-@MINGW_FALSE@ heap-checker_unittest
-@MINGW_FALSE@ rm -f $@
-@MINGW_FALSE@ cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@
-@MINGW_FALSE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCES) \
-@MINGW_FALSE@ heap-checker_unittest
-@MINGW_FALSE@ rm -f $@
-@MINGW_FALSE@ cp -p $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) $@
-@HAS_PC_TRUE@@MINGW_FALSE@profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler1_unittest profiler2_unittest \
-@HAS_PC_TRUE@@MINGW_FALSE@ profiler3_unittest profiler4_unittest
-@HAS_PC_TRUE@@MINGW_FALSE@ rm -f $@
-@HAS_PC_TRUE@@MINGW_FALSE@ cp -p $(top_srcdir)/$(profiler_unittest_sh_SOURCES) $@
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_test.sh$(EXEEXT): $(top_srcdir)/$(sampling_test_sh_SOURCES) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ rm -f $@
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ cp -p $(top_srcdir)/$(sampling_test_sh_SOURCES) $@
+@WITH_HEAP_PROFILER_TRUE@heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \
+@WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest
+@WITH_HEAP_PROFILER_TRUE@ rm -f $@
+@WITH_HEAP_PROFILER_TRUE@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@
+@WITH_HEAP_CHECKER_TRUE@heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \
+@WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest
+@WITH_HEAP_CHECKER_TRUE@ rm -f $@
+@WITH_HEAP_CHECKER_TRUE@ cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@
+@WITH_HEAP_CHECKER_TRUE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCES) \
+@WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest
+@WITH_HEAP_CHECKER_TRUE@ rm -f $@
+@WITH_HEAP_CHECKER_TRUE@ cp -p $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) $@
+@WITH_CPU_PROFILER_TRUE@profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \
+@WITH_CPU_PROFILER_TRUE@ profiler1_unittest profiler2_unittest \
+@WITH_CPU_PROFILER_TRUE@ profiler3_unittest profiler4_unittest
+@WITH_CPU_PROFILER_TRUE@ rm -f $@
+@WITH_CPU_PROFILER_TRUE@ cp -p $(top_srcdir)/$(profiler_unittest_sh_SOURCES) $@
rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec
@cd packages && ./rpm.sh ${PACKAGE} ${VERSION}
diff --git a/README b/README
index c055336..703f269 100644
--- a/README
+++ b/README
@@ -24,6 +24,13 @@ to adjust the cpu-profiler behavior; cf "ENVIRONMENT VARIABLES" below.
The CPU profiler is available on all unix-based systems we've tested;
see INSTALL for more details. It is not currently available on Windows.
+NOTE: CPU profiling doesn't work after fork (unless you immediately
+ do an exec()-like call afterwards). Furthermore, if you do
+ fork, and the child calls exit(), it may corrupt the profile
+ data. You can use _exit() to work around this. We hope to have
+ a fix for both problems in the next release of perftools
+ (hopefully perftools 1.2).
+
TCMALLOC
--------
@@ -185,9 +192,7 @@ CPUPROFILE environment variable. If you do not turn on cpu-profiling,
you shouldn't see any crashes due to perftools.
The gory details: The underlying problem is in the backtrace()
-function, which is a built-in function in libc. (However, we
-*strongly* recommend for x86-64, that you use the libunwind
-functionality for backtraces instead; see the top of INSTALL.)
+function, which is a built-in function in libc.
Backtracing is fairly straightforward in the normal case, but can run
into problems when having to backtrace across a signal frame.
Unfortunately, the cpu-profiler uses signals in order to register a
@@ -196,7 +201,7 @@ signal frame.
In our experience, the only time there is trouble is when the signal
fires in the middle of pthread_mutex_lock. pthread_mutex_lock is
-called quite a bit from system libraries, particular at program
+called quite a bit from system libraries, particularly at program
startup and when creating a new thread.
The solution: The dwarf debugging format has support for 'cfi
diff --git a/README.windows b/README.windows
index c7016e4..f52ec3a 100644
--- a/README.windows
+++ b/README.windows
@@ -6,12 +6,6 @@ You can load this solution file into either VC++ 7.1 (Visual Studio
2003) or VC++ 8.0 (Visual Studio 2005) -- in the latter case, it will
automatically convert the files to the latest format for you.
-There are a few issues compiling with VC++ 7.1, due to its lack of
-support for __VA_ARGS__. If you need to compile perftools in that
-environment, send mail to google-perftools@googlegroups.com; there may
-be ways to work around this issue. The code compiles without problem
-in VC++ 8.0 (Visual Studio 2005).
-
When you build the solution, it will create a number of unittests,
which you can run by hand (or, more easily, under the Visual Studio
debugger) to make sure everything is working properly on your system.
diff --git a/aclocal.m4 b/aclocal.m4
index 19e23ae..3463e42 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -7266,6 +7266,7 @@ AC_SUBST([am__untar])
]) # _AM_PROG_TAR
m4_include([m4/ac_have_attribute.m4])
+m4_include([m4/acx_nanosleep.m4])
m4_include([m4/acx_pthread.m4])
m4_include([m4/compiler_characteristics.m4])
m4_include([m4/install_prefix.m4])
diff --git a/configure b/configure
index 94ed41a..a2659bd 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for google-perftools 1.0.
+# Generated by GNU Autoconf 2.59 for google-perftools 1.1.
#
# Report bugs to <opensource@google.com>.
#
@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='google-perftools'
PACKAGE_TARNAME='google-perftools'
-PACKAGE_VERSION='1.0'
-PACKAGE_STRING='google-perftools 1.0'
+PACKAGE_VERSION='1.1'
+PACKAGE_STRING='google-perftools 1.1'
PACKAGE_BUGREPORT='opensource@google.com'
ac_unique_file="README"
@@ -465,7 +465,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE GCC_TRUE GCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBTOOL_DEPS HAS_PC_TRUE HAS_PC_FALSE UNWIND_LIBS ENABLE_FRAME_POINTERS_TRUE ENABLE_FRAME_POINTERS_FALSE X86_64_TRUE X86_64_FALSE acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS MINGW_TRUE MINGW_FALSE LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE GCC_TRUE GCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBTOOL_DEPS HAVE_WINDOWS_H_TRUE HAVE_WINDOWS_H_FALSE UNWIND_LIBS ENABLE_FRAME_POINTERS_TRUE ENABLE_FRAME_POINTERS_FALSE X86_64_TRUE X86_64_FALSE NANOSLEEP_LIBS LIBSTDCXX_LA_LINKER_FLAG acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS MINGW_TRUE MINGW_FALSE WITH_CPU_PROFILER_TRUE WITH_CPU_PROFILER_FALSE WITH_HEAP_PROFILER_TRUE WITH_HEAP_PROFILER_FALSE WITH_HEAP_CHECKER_TRUE WITH_HEAP_CHECKER_FALSE WITH_HEAP_PROFILER_OR_CHECKER_TRUE WITH_HEAP_PROFILER_OR_CHECKER_FALSE WITH_STACK_TRACE_TRUE WITH_STACK_TRACE_FALSE LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures google-perftools 1.0 to adapt to many kinds of systems.
+\`configure' configures google-perftools 1.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1015,19 +1015,22 @@ Program names:
System types:
--build=BUILD configure for building on BUILD [guessed]
--host=HOST cross-compile to build programs to run on HOST [BUILD]
- --target=TARGET configure for building compilers for TARGET [HOST]
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of google-perftools 1.0:";;
+ short | recursive ) echo "Configuration of google-perftools 1.1:";;
esac
cat <<\_ACEOF
Optional Features:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-cpu-profiler do not build the cpu profiler
+ --disable-heap-profiler do not build the heap profiler
+ --disable-heap-checker do not build the heap checker
+ --enable-minimal build only tcmalloc-minimal
--disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors
--enable-shared[=PKGS]
@@ -1162,7 +1165,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-google-perftools configure 1.0
+google-perftools configure 1.1
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1176,7 +1179,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by google-perftools $as_me 1.0, which was
+It was created by google-perftools $as_me 1.1, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
@@ -1594,34 +1597,6 @@ host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-echo "$as_me:$LINENO: checking target system type" >&5
-echo $ECHO_N "checking target system type... $ECHO_C" >&6
-if test "${ac_cv_target+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_target_alias=$target_alias
-test "x$ac_cv_target_alias" = "x" &&
- ac_cv_target_alias=$ac_cv_host_alias
-ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
- { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
-echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
- { (exit 1); exit 1; }; }
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_target" >&5
-echo "${ECHO_T}$ac_cv_target" >&6
-target=$ac_cv_target
-target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-
-# The aliases save the names the user supplied, while $host etc.
-# will get canonicalized.
-test -n "$target_alias" &&
- test "$program_prefix$program_suffix$program_transform_name" = \
- NONENONEs,x,x, &&
- program_prefix=${target_alias}-
am__api_version="1.9"
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
@@ -1904,7 +1879,7 @@ fi
# Define the identity of the package.
PACKAGE='google-perftools'
- VERSION='1.0'
+ VERSION='1.1'
cat >>confdefs.h <<_ACEOF
@@ -2037,6 +2012,60 @@ am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
ac_config_headers="$ac_config_headers src/config.h"
+# The user can choose not to compile in the heap-profiler, the
+# heap-checker, or the cpu-profiler. There's also the possibility
+# for a 'fully minimal' compile, which leaves out the stacktrace
+# code as well. By default, we include all of these that the
+# target system supports.
+default_enable_cpu_profiler=yes
+default_enable_heap_profiler=yes
+default_enable_heap_checker=yes
+default_enable_minimal=no
+need_nanosleep=yes # Used later, to decide if to run ACX_NANOSLEEP
+case "$host" in
+ *-mingw*) default_enable_minimal=yes; need_nanosleep=no;;
+ # TODO(csilvers): cygwin *can* do heap-profiler: just need to work on fileio
+ *-cygwin*) default_enable_heap_checker=no; default_enable_cpu_profiler=no; \
+ default_enable_heap_profiler=no;;
+ *-freebsd*) default_enable_heap_checker=no;;
+ *-darwin*) default_enable_heap_checker=no;;
+esac
+
+# Check whether --enable-cpu-profiler or --disable-cpu-profiler was given.
+if test "${enable_cpu_profiler+set}" = set; then
+ enableval="$enable_cpu_profiler"
+
+else
+ enable_cpu_profiler="$default_enable_cpu_profiler"
+fi;
+# Check whether --enable-heap-profiler or --disable-heap-profiler was given.
+if test "${enable_heap_profiler+set}" = set; then
+ enableval="$enable_heap_profiler"
+
+else
+ enable_heap_profiler="$default_enable_heap_profiler"
+fi;
+# Check whether --enable-heap-checker or --disable-heap-checker was given.
+if test "${enable_heap_checker+set}" = set; then
+ enableval="$enable_heap_checker"
+
+else
+ enable_heap_checker="$default_enable_heap_checker"
+fi;
+# Check whether --enable-minimal or --disable-minimal was given.
+if test "${enable_minimal+set}" = set; then
+ enableval="$enable_minimal"
+
+else
+ enable_minimal="$default_enable_minimal"
+fi;
+if test "$enable_minimal" = yes; then
+ enable_cpu_profiler=no
+ enable_heap_profiler=no
+ enable_heap_checker=no
+fi
+
+
# Checks for programs.
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
@@ -4407,7 +4436,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 4410 "configure"' > conftest.$ac_ext
+ echo '#line 4439 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -5304,7 +5333,7 @@ fi
# Provide some information about the compiler.
-echo "$as_me:5307:" \
+echo "$as_me:5336:" \
"checking for Fortran 77 compiler version" >&5
ac_compiler=`set X $ac_compile; echo $2`
{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
@@ -6365,11 +6394,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6368: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6397: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:6372: \$? = $ac_status" >&5
+ echo "$as_me:6401: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -6633,11 +6662,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6636: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6665: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:6640: \$? = $ac_status" >&5
+ echo "$as_me:6669: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -6737,11 +6766,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6740: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6769: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:6744: \$? = $ac_status" >&5
+ echo "$as_me:6773: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9095,7 +9124,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 9098 "configure"
+#line 9127 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9195,7 +9224,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 9198 "configure"
+#line 9227 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11533,11 +11562,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:11536: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:11565: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:11540: \$? = $ac_status" >&5
+ echo "$as_me:11569: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -11637,11 +11666,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:11640: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:11669: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:11644: \$? = $ac_status" >&5
+ echo "$as_me:11673: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -13225,11 +13254,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13228: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13257: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:13232: \$? = $ac_status" >&5
+ echo "$as_me:13261: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -13329,11 +13358,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13332: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13361: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13336: \$? = $ac_status" >&5
+ echo "$as_me:13365: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -15552,11 +15581,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15555: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15584: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:15559: \$? = $ac_status" >&5
+ echo "$as_me:15588: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -15820,11 +15849,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15823: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15852: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:15827: \$? = $ac_status" >&5
+ echo "$as_me:15856: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -15924,11 +15953,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15927: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15956: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15931: \$? = $ac_status" >&5
+ echo "$as_me:15960: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -18917,6 +18946,7 @@ _ACEOF
fi
+# TODO(csilvers): we could remove a lot when WITH_CPU_PROFILER etc is "no".
echo "$as_me:$LINENO: checking for __int64" >&5
echo $ECHO_N "checking for __int64... $ECHO_C" >&6
if test "${ac_cv_type___int64+set}" = set; then
@@ -19046,6 +19076,71 @@ _ACEOF
fi
+echo "$as_me:$LINENO: checking for Elf32_Versym" >&5
+echo $ECHO_N "checking for Elf32_Versym... $ECHO_C" >&6
+if test "${ac_cv_type_Elf32_Versym+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <elf.h>
+
+int
+main ()
+{
+if ((Elf32_Versym *) 0)
+ return 0;
+if (sizeof (Elf32_Versym))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_Elf32_Versym=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_Elf32_Versym=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_Elf32_Versym" >&5
+echo "${ECHO_T}$ac_cv_type_Elf32_Versym" >&6
+if test $ac_cv_type_Elf32_Versym = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_ELF32_VERSYM 1
+_ACEOF
+
+
+fi
+ # for vdso_support.h
for ac_func in sbrk
do
@@ -20590,6 +20685,155 @@ fi
done
# also needed by leak-checker
+for ac_header in windows.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to opensource@google.com ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+ # let us know if we're cygwin or mingw
+
for ac_header in sys/syscall.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
@@ -20739,6 +20983,304 @@ fi
done
+for ac_header in sys/socket.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to opensource@google.com ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+ # optional; for forking out to symbolizer
+
+for ac_header in sys/wait.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to opensource@google.com ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+ # optional; for forking out to symbolizer
+
for ac_header in fcntl.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
@@ -21699,6 +22241,18 @@ fi
+# Let the Makefile know if we can build windows programs
+
+
+if test "$ac_cv_header_windows_h" = yes; then
+ HAVE_WINDOWS_H_TRUE=
+ HAVE_WINDOWS_H_FALSE='#'
+else
+ HAVE_WINDOWS_H_TRUE='#'
+ HAVE_WINDOWS_H_FALSE=
+fi
+
+
# We need to check for mmap. cygwin supports mmap, but the autoconf
# test doesn't work on cygwin:
# http://www.cygwin.com/ml/cygwin/2002-04/msg00412.html
@@ -22200,33 +22754,36 @@ rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
# We want to access the "PC" (Program Counter) register from a struct
# ucontext. Every system has its own way of doing that. We try all the
# possibilities we know about. Note REG_PC should come first (REG_RIP
-# is also defined on solaris, but does the wrong thing).
-echo "$as_me:$LINENO: checking how to access the program counter from a struct ucontext" >&5
+# is also defined on solaris, but does the wrong thing). But don't
+# bother if we're not doing cpu-profiling.
+# [*] means that we've not actually tested one of these systems
+if test "$enable_cpu_profiler" = yes; then
+ echo "$as_me:$LINENO: checking how to access the program counter from a struct ucontext" >&5
echo $ECHO_N "checking how to access the program counter from a struct ucontext... $ECHO_C" >&6
-pc_fields=" uc_mcontext.gregs[REG_PC]" # Solaris x86 (32 + 64 bit)
-pc_fields="$pc_fields uc_mcontext.gregs[REG_EIP]" # Linux (i386)
-pc_fields="$pc_fields uc_mcontext.gregs[REG_RIP]" # Linux (x86_64)
-pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64)
-pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[PT_NIP]" # Linux (ppc)
-pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386)
-pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [untested])
-pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4)
-pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5)
-pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64)
-pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (>=10.5 [untested])
-pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [untested])
-pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (>=10.5 [untested])
-pc_field_found=false
-for pc_field in $pc_fields; do
- if ! $pc_field_found; then
- cat >conftest.$ac_ext <<_ACEOF
+ pc_fields=" uc_mcontext.gregs[REG_PC]" # Solaris x86 (32+64 bit)
+ pc_fields="$pc_fields uc_mcontext.gregs[REG_EIP]" # Linux (i386)
+ pc_fields="$pc_fields uc_mcontext.gregs[REG_RIP]" # Linux (x86_64)
+ pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64)
+ pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[PT_NIP]" # Linux (ppc)
+ pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386)
+ pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [*])
+ pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4)
+ pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5)
+ pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64)
+ pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (x86_64>=10.5 [*])
+ pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [*])
+ pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (ppc>=10.5 [*])
+ pc_field_found=false
+ for pc_field in $pc_fields; do
+ if ! $pc_field_found; then
+ cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#define _GNU_SOURCE 1
- #include <ucontext.h>
+ #include <ucontext.h>
int
main ()
{
@@ -22261,32 +22818,24 @@ cat >>confdefs.h <<_ACEOF
#define PC_FROM_UCONTEXT $pc_field
_ACEOF
- echo "$as_me:$LINENO: result: $pc_field" >&5
+ echo "$as_me:$LINENO: result: $pc_field" >&5
echo "${ECHO_T}$pc_field" >&6
- pc_field_found=true
+ pc_field_found=true
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
- fi
-done
-if ! $pc_field_found; then
- { echo "$as_me:$LINENO: WARNING: Could not find the PC. Will not try to compile libprofiler..." >&5
+ fi
+ done
+ if ! $pc_field_found; then
+ { echo "$as_me:$LINENO: WARNING: Could not find the PC. Will not try to compile libprofiler..." >&5
echo "$as_me: WARNING: Could not find the PC. Will not try to compile libprofiler..." >&2;}
+ enable_cpu_profiler=no
+ fi
fi
-
-if test "$pc_field_found" = true; then
- HAS_PC_TRUE=
- HAS_PC_FALSE='#'
-else
- HAS_PC_TRUE='#'
- HAS_PC_FALSE=
-fi
-
-
# We want to link in libunwind if it exists
echo "$as_me:$LINENO: checking for backtrace in -lunwind" >&5
echo $ECHO_N "checking for backtrace in -lunwind... $ECHO_C" >&6
@@ -22665,7 +23214,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC__MINOR__ < 1) || (__GNUC__ == 4 && __GNUC__MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2))
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2))
#error gcc has this bug: http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
#endif
int
@@ -22714,6 +23263,147 @@ fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
+# Nanosleep requires extra libraries on some architectures (solaris).
+# This sets NANOSLEEP_LIBS. nanosleep doesn't exist on mingw, which
+# is fine for us because we don't compile libspinlock, which uses it.
+if test "$need_nanosleep" = yes; then
+ echo "$as_me:$LINENO: checking if nanosleep requires any libraries" >&5
+echo $ECHO_N "checking if nanosleep requires any libraries... $ECHO_C" >&6
+
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ acx_nanosleep_ok="no"
+ NANOSLEEP_LIBS=
+ # For most folks, this should just work
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+int
+main ()
+{
+static struct timespec ts; nanosleep(&ts, NULL);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ acx_nanosleep_ok=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ # For solaris, we may need -lrt
+ if test "x$acx_nanosleep_ok" != "xyes"; then
+ OLD_LIBS="$LIBS"
+ LIBS="-lrt $LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <time.h>
+int
+main ()
+{
+static struct timespec ts; nanosleep(&ts, NULL);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ acx_nanosleep_ok=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test "x$acx_nanosleep_ok" = "xyes"; then
+ NANOSLEEP_LIBS="-lrt"
+ fi
+ LIBS="$OLD_LIBS"
+ fi
+ if test "x$acx_nanosleep_ok" != "xyes"; then
+ { { echo "$as_me:$LINENO: error: cannot find the nanosleep function" >&5
+echo "$as_me: error: cannot find the nanosleep function" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ echo "$as_me:$LINENO: result: ${NANOSLEEP_LIBS:-no}" >&5
+echo "${ECHO_T}${NANOSLEEP_LIBS:-no}" >&6
+ fi
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+fi
+
+# Solaris 10 6/06 has a bug where /usr/sfw/lib/libstdc++.la is empty.
+# If so, we replace it with our own version.
+LIBSTDCXX_LA_LINKER_FLAG=
+if test -f /usr/sfw/lib/libstdc++.la && ! test -s /usr/sfw/lib/libstdc++.la
+then
+ LIBSTDCXX_LA_LINKER_FLAG='-L$(top_srcdir)/src/solaris'
+fi
+
+
# We also need to check if the kernel supports __thread, which requires uname()
echo "$as_me:$LINENO: checking whether uname is declared" >&5
echo $ECHO_N "checking whether uname is declared... $ECHO_C" >&6
@@ -23898,7 +24588,7 @@ _ACEOF
-if expr $target : '.*-mingw' >/dev/null 2>&1; then
+if expr $host : '.*-mingw' >/dev/null 2>&1; then
MINGW_TRUE=
MINGW_FALSE='#'
else
@@ -23907,6 +24597,65 @@ else
fi
+# Export the --enable flags we set above. We do this at the end so
+# other configure rules can enable or disable targets based on what
+# they find.
+
+
+if test "$enable_cpu_profiler" = yes; then
+ WITH_CPU_PROFILER_TRUE=
+ WITH_CPU_PROFILER_FALSE='#'
+else
+ WITH_CPU_PROFILER_TRUE='#'
+ WITH_CPU_PROFILER_FALSE=
+fi
+
+
+
+if test "$enable_heap_profiler" = yes; then
+ WITH_HEAP_PROFILER_TRUE=
+ WITH_HEAP_PROFILER_FALSE='#'
+else
+ WITH_HEAP_PROFILER_TRUE='#'
+ WITH_HEAP_PROFILER_FALSE=
+fi
+
+
+
+if test "$enable_heap_checker" = yes; then
+ WITH_HEAP_CHECKER_TRUE=
+ WITH_HEAP_CHECKER_FALSE='#'
+else
+ WITH_HEAP_CHECKER_TRUE='#'
+ WITH_HEAP_CHECKER_FALSE=
+fi
+
+# We make tcmalloc.so if either heap-profiler or heap-checker is asked for.
+
+
+if test "$enable_heap_profiler" = yes -o \
+ "$enable_heap_checker" = yes; then
+ WITH_HEAP_PROFILER_OR_CHECKER_TRUE=
+ WITH_HEAP_PROFILER_OR_CHECKER_FALSE='#'
+else
+ WITH_HEAP_PROFILER_OR_CHECKER_TRUE='#'
+ WITH_HEAP_PROFILER_OR_CHECKER_FALSE=
+fi
+
+# If we don't use any profilers, we don't need stack traces (or pprof)
+
+
+if test "$enable_cpu_profiler" = yes -o \
+ "$enable_heap_profiler" = yes -o \
+ "$enable_heap_checker" = yes; then
+ WITH_STACK_TRACE_TRUE=
+ WITH_STACK_TRACE_FALSE='#'
+else
+ WITH_STACK_TRACE_TRUE='#'
+ WITH_STACK_TRACE_FALSE=
+fi
+
+
# Write generated configuration file
ac_config_files="$ac_config_files Makefile"
@@ -24029,10 +24778,10 @@ echo "$as_me: error: conditional \"GCC\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
-if test -z "${HAS_PC_TRUE}" && test -z "${HAS_PC_FALSE}"; then
- { { echo "$as_me:$LINENO: error: conditional \"HAS_PC\" was never defined.
+if test -z "${HAVE_WINDOWS_H_TRUE}" && test -z "${HAVE_WINDOWS_H_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HAVE_WINDOWS_H\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"HAS_PC\" was never defined.
+echo "$as_me: error: conditional \"HAVE_WINDOWS_H\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
@@ -24057,6 +24806,41 @@ echo "$as_me: error: conditional \"MINGW\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${WITH_CPU_PROFILER_TRUE}" && test -z "${WITH_CPU_PROFILER_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"WITH_CPU_PROFILER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"WITH_CPU_PROFILER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${WITH_HEAP_PROFILER_TRUE}" && test -z "${WITH_HEAP_PROFILER_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"WITH_HEAP_PROFILER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"WITH_HEAP_PROFILER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${WITH_HEAP_CHECKER_TRUE}" && test -z "${WITH_HEAP_CHECKER_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"WITH_HEAP_CHECKER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"WITH_HEAP_CHECKER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${WITH_HEAP_PROFILER_OR_CHECKER_TRUE}" && test -z "${WITH_HEAP_PROFILER_OR_CHECKER_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"WITH_HEAP_PROFILER_OR_CHECKER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"WITH_HEAP_PROFILER_OR_CHECKER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${WITH_STACK_TRACE_TRUE}" && test -z "${WITH_STACK_TRACE_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"WITH_STACK_TRACE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"WITH_STACK_TRACE\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
: ${CONFIG_STATUS=./config.status}
ac_clean_files_save=$ac_clean_files
@@ -24328,7 +25112,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by google-perftools $as_me 1.0, which was
+This file was extended by google-perftools $as_me 1.1, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -24391,7 +25175,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-google-perftools config.status 1.0
+google-perftools config.status 1.1
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@@ -24597,10 +25381,6 @@ s,@host@,$host,;t t
s,@host_cpu@,$host_cpu,;t t
s,@host_vendor@,$host_vendor,;t t
s,@host_os@,$host_os,;t t
-s,@target@,$target,;t t
-s,@target_cpu@,$target_cpu,;t t
-s,@target_vendor@,$target_vendor,;t t
-s,@target_os@,$target_os,;t t
s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
s,@INSTALL_DATA@,$INSTALL_DATA,;t t
@@ -24661,19 +25441,31 @@ s,@FFLAGS@,$FFLAGS,;t t
s,@ac_ct_F77@,$ac_ct_F77,;t t
s,@LIBTOOL@,$LIBTOOL,;t t
s,@LIBTOOL_DEPS@,$LIBTOOL_DEPS,;t t
-s,@HAS_PC_TRUE@,$HAS_PC_TRUE,;t t
-s,@HAS_PC_FALSE@,$HAS_PC_FALSE,;t t
+s,@HAVE_WINDOWS_H_TRUE@,$HAVE_WINDOWS_H_TRUE,;t t
+s,@HAVE_WINDOWS_H_FALSE@,$HAVE_WINDOWS_H_FALSE,;t t
s,@UNWIND_LIBS@,$UNWIND_LIBS,;t t
s,@ENABLE_FRAME_POINTERS_TRUE@,$ENABLE_FRAME_POINTERS_TRUE,;t t
s,@ENABLE_FRAME_POINTERS_FALSE@,$ENABLE_FRAME_POINTERS_FALSE,;t t
s,@X86_64_TRUE@,$X86_64_TRUE,;t t
s,@X86_64_FALSE@,$X86_64_FALSE,;t t
+s,@NANOSLEEP_LIBS@,$NANOSLEEP_LIBS,;t t
+s,@LIBSTDCXX_LA_LINKER_FLAG@,$LIBSTDCXX_LA_LINKER_FLAG,;t t
s,@acx_pthread_config@,$acx_pthread_config,;t t
s,@PTHREAD_CC@,$PTHREAD_CC,;t t
s,@PTHREAD_LIBS@,$PTHREAD_LIBS,;t t
s,@PTHREAD_CFLAGS@,$PTHREAD_CFLAGS,;t t
s,@MINGW_TRUE@,$MINGW_TRUE,;t t
s,@MINGW_FALSE@,$MINGW_FALSE,;t t
+s,@WITH_CPU_PROFILER_TRUE@,$WITH_CPU_PROFILER_TRUE,;t t
+s,@WITH_CPU_PROFILER_FALSE@,$WITH_CPU_PROFILER_FALSE,;t t
+s,@WITH_HEAP_PROFILER_TRUE@,$WITH_HEAP_PROFILER_TRUE,;t t
+s,@WITH_HEAP_PROFILER_FALSE@,$WITH_HEAP_PROFILER_FALSE,;t t
+s,@WITH_HEAP_CHECKER_TRUE@,$WITH_HEAP_CHECKER_TRUE,;t t
+s,@WITH_HEAP_CHECKER_FALSE@,$WITH_HEAP_CHECKER_FALSE,;t t
+s,@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@,$WITH_HEAP_PROFILER_OR_CHECKER_TRUE,;t t
+s,@WITH_HEAP_PROFILER_OR_CHECKER_FALSE@,$WITH_HEAP_PROFILER_OR_CHECKER_FALSE,;t t
+s,@WITH_STACK_TRACE_TRUE@,$WITH_STACK_TRACE_TRUE,;t t
+s,@WITH_STACK_TRACE_FALSE@,$WITH_STACK_TRACE_FALSE,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t
CEOF
diff --git a/configure.ac b/configure.ac
index d0417a8..e815e51 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,14 +4,60 @@
# make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57)
-AC_INIT(google-perftools, 1.0, opensource@google.com)
+AC_INIT(google-perftools, 1.1, opensource@google.com)
# The argument here is just something that should be in the current directory
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
-AC_CANONICAL_TARGET
+AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([dist-zip])
AM_CONFIG_HEADER(src/config.h)
+# The user can choose not to compile in the heap-profiler, the
+# heap-checker, or the cpu-profiler. There's also the possibility
+# for a 'fully minimal' compile, which leaves out the stacktrace
+# code as well. By default, we include all of these that the
+# target system supports.
+default_enable_cpu_profiler=yes
+default_enable_heap_profiler=yes
+default_enable_heap_checker=yes
+default_enable_minimal=no
+need_nanosleep=yes # Used later, to decide if to run ACX_NANOSLEEP
+case "$host" in
+ *-mingw*) default_enable_minimal=yes; need_nanosleep=no;;
+ # TODO(csilvers): cygwin *can* do heap-profiler: just need to work on fileio
+ *-cygwin*) default_enable_heap_checker=no; default_enable_cpu_profiler=no; \
+ default_enable_heap_profiler=no;;
+ *-freebsd*) default_enable_heap_checker=no;;
+ *-darwin*) default_enable_heap_checker=no;;
+esac
+
+AC_ARG_ENABLE([cpu-profiler],
+ [AS_HELP_STRING([--disable-cpu-profiler],
+ [do not build the cpu profiler])],
+ [],
+ [enable_cpu_profiler="$default_enable_cpu_profiler"])
+AC_ARG_ENABLE([heap-profiler],
+ [AS_HELP_STRING([--disable-heap-profiler],
+ [do not build the heap profiler])],
+ [],
+ [enable_heap_profiler="$default_enable_heap_profiler"])
+AC_ARG_ENABLE([heap-checker],
+ [AS_HELP_STRING([--disable-heap-checker],
+ [do not build the heap checker])],
+ [],
+ [enable_heap_checker="$default_enable_heap_checker"])
+AC_ARG_ENABLE([minimal],
+ [AS_HELP_STRING([--enable-minimal],
+ [build only tcmalloc-minimal])],
+ [],
+ [enable_minimal="$default_enable_minimal"])
+if test "$enable_minimal" = yes; then
+ enable_cpu_profiler=no
+ enable_heap_profiler=no
+ enable_heap_checker=no
+fi
+
+
# Checks for programs.
AC_PROG_CC
AC_PROG_CPP
@@ -27,8 +73,10 @@ AX_C___ATTRIBUTE__
# Check whether some low-level functions/files are available
AC_HEADER_STDC
+# TODO(csilvers): we could remove a lot when WITH_CPU_PROFILER etc is "no".
AC_CHECK_TYPES([__int64]) # defined in some windows platforms
AC_CHECK_TYPES([struct mallinfo],,, [#include <malloc.h>])
+AC_CHECK_TYPES([Elf32_Versym],,, [#include <elf.h>]) # for vdso_support.h
AC_CHECK_FUNCS(sbrk) # for tcmalloc to get memory
AC_CHECK_FUNCS(geteuid) # for turning off services when run as root
AC_CHECK_HEADERS(malloc.h) # some systems define stuff there, others not
@@ -40,7 +88,10 @@ AC_CHECK_HEADERS(ucontext.h) # for profiler.cc (cpu profiler)
AC_CHECK_HEADERS(conflict-signal.h) # defined on some windows platforms
AC_CHECK_HEADERS(sys/prctl.h) # for thread_lister (needed by leak-checker)
AC_CHECK_HEADERS(linux/ptrace.h)# also needed by leak-checker
+AC_CHECK_HEADERS(windows.h) # let us know if we're cygwin or mingw
AC_CHECK_HEADERS(sys/syscall.h)
+AC_CHECK_HEADERS(sys/socket.h) # optional; for forking out to symbolizer
+AC_CHECK_HEADERS(sys/wait.h) # optional; for forking out to symbolizer
AC_CHECK_HEADERS(fcntl.h) # for tcmalloc_unittest
AC_CHECK_HEADERS(grp.h) # for heapchecker_unittest
AC_CHECK_HEADERS(pwd.h) # for heapchecker_unittest
@@ -56,6 +107,9 @@ AC_CHECK_DECLS([cfree,
#include <stdlib.h>
#include <malloc.h>])
+# Let the Makefile know if we can build windows programs
+AM_CONDITIONAL(HAVE_WINDOWS_H, test "$ac_cv_header_windows_h" = yes)
+
# We need to check for mmap. cygwin supports mmap, but the autoconf
# test doesn't work on cygwin:
# http://www.cygwin.com/ml/cygwin/2002-04/msg00412.html
@@ -83,37 +137,41 @@ AC_TRY_COMPILE([#include <stdint.h>],
# We want to access the "PC" (Program Counter) register from a struct
# ucontext. Every system has its own way of doing that. We try all the
# possibilities we know about. Note REG_PC should come first (REG_RIP
-# is also defined on solaris, but does the wrong thing).
-AC_MSG_CHECKING([how to access the program counter from a struct ucontext])
-pc_fields=" uc_mcontext.gregs[[REG_PC]]" # Solaris x86 (32 + 64 bit)
-pc_fields="$pc_fields uc_mcontext.gregs[[REG_EIP]]" # Linux (i386)
-pc_fields="$pc_fields uc_mcontext.gregs[[REG_RIP]]" # Linux (x86_64)
-pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64)
-pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[[PT_NIP]]" # Linux (ppc)
-pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386)
-pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [untested])
-pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4)
-pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5)
-pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64)
-pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (>=10.5 [untested])
-pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [untested])
-pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (>=10.5 [untested])
-pc_field_found=false
-for pc_field in $pc_fields; do
+# is also defined on solaris, but does the wrong thing). But don't
+# bother if we're not doing cpu-profiling.
+# [*] means that we've not actually tested one of these systems
+if test "$enable_cpu_profiler" = yes; then
+ AC_MSG_CHECKING([how to access the program counter from a struct ucontext])
+ pc_fields=" uc_mcontext.gregs[[REG_PC]]" # Solaris x86 (32+64 bit)
+ pc_fields="$pc_fields uc_mcontext.gregs[[REG_EIP]]" # Linux (i386)
+ pc_fields="$pc_fields uc_mcontext.gregs[[REG_RIP]]" # Linux (x86_64)
+ pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64)
+ pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[[PT_NIP]]" # Linux (ppc)
+ pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386)
+ pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [*])
+ pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4)
+ pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5)
+ pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64)
+ pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (x86_64>=10.5 [*])
+ pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [*])
+ pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (ppc>=10.5 [*])
+ pc_field_found=false
+ for pc_field in $pc_fields; do
+ if ! $pc_field_found; then
+ AC_TRY_COMPILE([#define _GNU_SOURCE 1
+ #include <ucontext.h>],
+ [ucontext_t u; return u.$pc_field == 0;],
+ AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field,
+ How to access the PC from a struct ucontext)
+ AC_MSG_RESULT([$pc_field])
+ pc_field_found=true)
+ fi
+ done
if ! $pc_field_found; then
- AC_TRY_COMPILE([#define _GNU_SOURCE 1
- #include <ucontext.h>],
- [ucontext_t u; return u.$pc_field == 0;],
- AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field,
- How to access the PC from a struct ucontext)
- AC_MSG_RESULT([$pc_field])
- pc_field_found=true)
+ AC_MSG_WARN(Could not find the PC. Will not try to compile libprofiler...)
+ enable_cpu_profiler=no
fi
-done
-if ! $pc_field_found; then
- AC_MSG_WARN(Could not find the PC. Will not try to compile libprofiler...)
fi
-AM_CONDITIONAL(HAS_PC, test "$pc_field_found" = true)
# We want to link in libunwind if it exists
AC_CHECK_LIB(unwind, backtrace, UNWIND_LIBS=-lunwind, UNWIND_LIBS=)
@@ -154,7 +212,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM(, [void *sp = __builtin_stack_pointer()])],
# involving TLS and -fPIC (which our libraries will use) on x86:
# http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
AC_MSG_CHECKING([for __thread])
-AC_LINK_IFELSE([AC_LANG_PROGRAM([#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC__MINOR__ < 1) || (__GNUC__ == 4 && __GNUC__MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2))
+AC_LINK_IFELSE([AC_LANG_PROGRAM([#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ < 2))
#error gcc has this bug: http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
#endif], [static __thread int p = 0])],
[AC_DEFINE(HAVE_TLS, 1,
@@ -162,6 +220,23 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([#if defined(__GNUC__) && (defined(__i386__) ||
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])])
+# Nanosleep requires extra libraries on some architectures (solaris).
+# This sets NANOSLEEP_LIBS. nanosleep doesn't exist on mingw, which
+# is fine for us because we don't compile libspinlock, which uses it.
+if test "$need_nanosleep" = yes; then
+ ACX_NANOSLEEP
+ AC_SUBST(NANOSLEEP_LIBS)
+fi
+
+# Solaris 10 6/06 has a bug where /usr/sfw/lib/libstdc++.la is empty.
+# If so, we replace it with our own version.
+LIBSTDCXX_LA_LINKER_FLAG=
+if test -f /usr/sfw/lib/libstdc++.la && ! test -s /usr/sfw/lib/libstdc++.la
+then
+ LIBSTDCXX_LA_LINKER_FLAG='-L$(top_srcdir)/src/solaris'
+fi
+AC_SUBST(LIBSTDCXX_LA_LINKER_FLAG)
+
# We also need to check if the kernel supports __thread, which requires uname()
AC_CHECK_DECLS(uname,,, [#include <sys/utsname.h>])
@@ -199,7 +274,22 @@ AH_BOTTOM([
#include "windows/mingw.h"
#endif
])
-AM_CONDITIONAL(MINGW, expr $target : '.*-mingw' >/dev/null 2>&1)
+AM_CONDITIONAL(MINGW, expr $host : '.*-mingw' >/dev/null 2>&1)
+
+# Export the --enable flags we set above. We do this at the end so
+# other configure rules can enable or disable targets based on what
+# they find.
+AM_CONDITIONAL(WITH_CPU_PROFILER, test "$enable_cpu_profiler" = yes)
+AM_CONDITIONAL(WITH_HEAP_PROFILER, test "$enable_heap_profiler" = yes)
+AM_CONDITIONAL(WITH_HEAP_CHECKER, test "$enable_heap_checker" = yes)
+# We make tcmalloc.so if either heap-profiler or heap-checker is asked for.
+AM_CONDITIONAL(WITH_HEAP_PROFILER_OR_CHECKER,
+ test "$enable_heap_profiler" = yes -o \
+ "$enable_heap_checker" = yes)
+# If we don't use any profilers, we don't need stack traces (or pprof)
+AM_CONDITIONAL(WITH_STACK_TRACE, test "$enable_cpu_profiler" = yes -o \
+ "$enable_heap_profiler" = yes -o \
+ "$enable_heap_checker" = yes)
# Write generated configuration file
AC_CONFIG_FILES([Makefile])
diff --git a/doc/pprof_remote_servers.html b/doc/pprof_remote_servers.html
index b2697bc..4fd08e2 100644
--- a/doc/pprof_remote_servers.html
+++ b/doc/pprof_remote_servers.html
@@ -65,17 +65,26 @@ can change it if you'd like.</p>
<code>pprof</code>. <code>MallocExtension</code> is defined in the
header file <code>google/malloc_extension.h</code>.</p>
-<p>Here's an example, from an actual Google webserver, of what the
-output should look like:</p>
+<p>Here's an example of what the output should look like:</p>
<pre>
-heap profile: 9369: 126987529 [ 9369: 126987529] @ heap
- 2: 1024 [ 2: 1024] @ 0x87da913 0x8923ad4 0x891d4c2 0x892de12 0x8930519 0x83a16c2 0x836cb38 0x834cd1c 0x8349ba5 0x10a3177 0x8349961
- 1: 36 [ 1: 36] @ 0x87da913 0x83a0929 0x836cb38 0x834cd1c 0x8349ba5 0x10a3177 0x8349961
- 308: 10092544 [ 308: 10092544] @ 0x87da913 0x8970d66 0x8970e64 0x896e8e2 0x88e69d2 0x88e6add 0x88e6dec 0x88e7384 0x88e73fa 0x8838793 0x8838b36 0x88395f8 0x88f5a4b 0x890d03a 0x890d65a 0x8917666 0x890d1f3 0x890e6e4 0x8349c1b 0x10a3177 0x8349961
+heap profile: 1923: 127923432 [ 1923: 127923432] @ heap_v2/524288
+ 1: 312 [ 1: 312] @ 0x2aaaabaf5ccc 0x2aaaaba4cd2c 0x2aaaac08c09a
+ 928: 122586016 [ 928: 122586016] @ 0x2aaaabaf682c 0x400680 0x400bdd 0x2aaaab1c368a 0x2aaaab1c8f77 0x2aaaab1c0396 0x2aaaab1c86ed 0x4007ff 0x2aaaaca62afa
+ 1: 16 [ 1: 16] @ 0x2aaaabaf5ccc 0x2aaaabb04bac 0x2aaaabc1b262 0x2aaaabc21496 0x2aaaabc214bb
[...]
</pre>
+<p> Older code may produce "version 1" heap profiles which look like this:<p/>
+<pre>
+heap profile: 14933: 791700132 [ 14933: 791700132] @ heap
+ 1: 848688 [ 1: 848688] @ 0xa4b142 0x7f5bfc 0x87065e 0x4056e9 0x4125f8 0x42b4f1 0x45b1ba 0x463248 0x460871 0x45cb7c 0x5f1744 0x607cee 0x5f4a5e 0x40080f 0x2aaaabad7afa
+ 1: 1048576 [ 1: 1048576] @ 0xa4a9b2 0x7fd025 0x4ca6d8 0x4ca814 0x4caa88 0x2aaaab104cf0 0x404e20 0x4125f8 0x42b4f1 0x45b1ba 0x463248 0x460871 0x45cb7c 0x5f1744 0x607cee 0x5f4a5e 0x40080f 0x2aaaabad7afa
+ 2942: 388629374 [ 2942: 388629374] @ 0xa4b142 0x4006a0 0x400bed 0x5f0cfa 0x5f1744 0x607cee 0x5f4a5e 0x40080f 0x2aaaabad7afa
+[...]
+</pre>
+<p> pprof accepts both old and new heap profiles and automatically detects which one you are using.</p>
+
<h2> <code><b>/pprof/growth</b></code> </h2>
<p><code>pprof</code> asks for the url <code>/pprof/growth</code> to
diff --git a/doc/tcmalloc.html b/doc/tcmalloc.html
index eb5a27b..17d1095 100644
--- a/doc/tcmalloc.html
+++ b/doc/tcmalloc.html
@@ -17,7 +17,7 @@
<address>Sanjay Ghemawat</address>
-<h2>Motivation</h2>
+<h2><A name=motivation>Motivation</A></h2>
<p>TCMalloc is faster than the glibc 2.3 malloc (available as a
separate library called ptmalloc2) and other mallocs that I have
@@ -55,7 +55,7 @@ each object and (I think) rounds up the size to a multiple of 8 bytes
and ends up using <code>16N</code> bytes.</p>
-<h2>Usage</h2>
+<h2><A NAME="Usage">Usage</A></h2>
<p>To use TCMalloc, just link TCMalloc into your application via the
"-ltcmalloc" linker flag.</p>
@@ -77,7 +77,7 @@ static binary), you can link in <code>libtcmalloc_minimal</code>
instead.</p>
-<h2>Overview</h2>
+<h2><A NAME="Overview">Overview</A></h2>
<p>TCMalloc assigns each thread a thread-local cache. Small
allocations are satisfied from the thread-local cache. Objects are
@@ -97,14 +97,16 @@ each equally sized. For example a run of one page (4K) can be carved
up into 32 objects of size 128 bytes each.</p>
-<h2>Small Object Allocation</h2>
+<h2><A NAME="Small_Object_Allocation">Small Object Allocation</A></h2>
-<p>Each small object size maps to one of approximately 170 allocatable
-size-classes. For example, all allocations in the range 961 to 1024
+<p>Each small object size maps to one of approximately 60 allocatable
+size-classes. For example, all allocations in the range 833 to 1024
bytes are rounded up to 1024. The size-classes are spaced so that
small sizes are separated by 8 bytes, larger sizes by 16 bytes, even
-larger sizes by 32 bytes, and so forth. The maximal spacing (for
-sizes &gt;= ~2K) is 256 bytes.</p>
+larger sizes by 32 bytes, and so forth. The maximal spacing is
+controlled so that not too much space is wasted when an allocation
+request falls just past the end of a size class and has to be rounded
+up to the next class.</p>
<p>A thread cache contains a singly linked list of free objects per
size-class.</p>
@@ -129,8 +131,72 @@ of objects of this size-class. (3) Place the new objects on the
central free list. (4) As before, move some of these objects to the
thread-local free list.</p>
+<h3><A NAME="Sizing_Thread_Cache_Free_Lists">
+ Sizing Thread Cache Free Lists</A></h3>
+
+<p>It is important to size the thread cache free lists correctly. If
+the free list is too small, we'll need to go to the central free list
+too often. If the free list is too big, we'll waste memory as objects
+sit idle in the free list.</p>
+
+<p>Note that the thread caches are just as important for deallocation
+as they are for allocation. Without a cache, each deallocation would
+require moving the memory to the central free list. Also, some threads
+have asymmetric alloc/free behavior (e.g. producer and consumer threads),
+so sizing the free list correctly gets trickier.</p>
+
+<p>To size the free lists appropriately, we use a slow-start algorithm
+to determine the maximum length of each individual free list. As the
+free list is used more frequently, its maximum length grows. However,
+if a free list is used more for deallocation than allocation, its
+maximum length will grow only up to a point where the whole list can
+be efficiently moved to the central free list at once.</p>
+
+<p>The psuedo-code below illustrates this slow-start algorithm. Note
+that <code>num_objects_to_move</code> is specific to each size class.
+By moving a list of objects with a well-known length, the central
+cache can efficiently pass these lists between thread caches. If
+a thread cache wants fewer than <code>num_objects_to_move</code>,
+the operation on the central free list has linear time complexity.
+The downside of always using <code>num_objects_to_move</code> as
+the number of objects to transfer to and from the central cache is
+that it wastes memory in threads that don't need all of those objects.
-<h2>Large Object Allocation</h2>
+<pre>
+Start each freelist max_length at 1.
+
+Allocation
+ if freelist empty {
+ fetch min(max_length, num_objects_to_move) from central list;
+ if max_length < num_objects_to_move { // slow-start
+ max_length++;
+ } else {
+ max_length += num_objects_to_move;
+ }
+ }
+
+Deallocation
+ if length > max_length {
+ // Don't try to release num_objects_to_move if we don't have that many.
+ release min(max_length, num_objects_to_move) objects to central list
+ if max_length < num_objects_to_move {
+ // Slow-start up to num_objects_to_move.
+ max_length++;
+ } else if max_length > num_objects_to_move {
+ // If we consistently go over max_length, shrink max_length.
+ overages++;
+ if overages > kMaxOverages {
+ max_length -= num_objects_to_move;
+ overages = 0;
+ }
+ }
+ }
+</pre>
+
+See also the section on <a href="#Garbage_Collection">Garbage Collection</a>
+to see how it affects the <code>max_length</code>.
+
+<h2><A NAME="Large_Object_Allocation">Large Object Allocation</A></h2>
<p>A large object size (&gt; 32K) is rounded up to a page size (4K)
and is handled by a central page heap. The central page heap is again
@@ -153,7 +219,7 @@ run is re-inserted back into the appropriate free list in the
page heap.</p>
-<h2>Spans</h2>
+<h2><A NAME="Spans">Spans</A></h2>
<p>The heap managed by TCMalloc consists of a set of pages. A run of
contiguous pages is represented by a <code>Span</code> object. A span
@@ -180,7 +246,7 @@ central array, which seems acceptable.</p>
<p>On 64-bit machines, we use a 3-level radix tree.</p>
-<h2>Deallocation</h2>
+<h2><A NAME="Deallocation">Deallocation</A></h2>
<p>When an object is deallocated, we compute its page number and look
it up in the central array to find the corresponding span object. The
@@ -217,16 +283,18 @@ equals the total number of small objects in the span, this span is now
completely free and is returned to the page heap.</p>
-<h2>Garbage Collection of Thread Caches</h2>
+<h2><A NAME="Garbage_Collection">Garbage Collection of Thread Caches</A></h2>
-<p>A thread cache is garbage collected when the combined size of all
-objects in the cache exceeds 2MB. The garbage collection threshold is
-automatically decreased as the number of threads increases so that we
-don't waste an inordinate amount of memory in a program with lots of
-threads.</p>
+<p>Garbage collecting objects from a thread cache keeps the size of
+the cache under control and returns unused objects to the central free
+lists. Some threads need large caches to perform well while others
+can get by with little or no cache at all. When a thread cache goes
+over its <code>max_size</code>, garbage collection kicks in and then the
+thread competes with the other threads for a larger cache.</p>
-<p>We walk over all free lists in the cache and move some number of
-objects from the free list to the corresponding central list.</p>
+<p>Garbage collection is run only during a deallocation. We walk over
+all free lists in the cache and move some number of objects from the
+free list to the corresponding central list.</p>
<p>The number of objects to be moved from a free list is determined
using a per-list low-water-mark <code>L</code>. <code>L</code>
@@ -241,8 +309,42 @@ stops using a particular size, all objects of that size will quickly
move from the thread cache to the central free list where they can be
used by other threads.</p>
+<p>If a thread consistently deallocates more objects of a certain size
+than it allocates, this <code>L/2</code> behavior will cause at least
+<code>L/2</code> objects to always sit in the free list. To avoid
+wasting memory this way, we shrink the maximum length of the freelist
+to converge on <code>num_objects_to_move</code> (see also
+<a href="#Sizing_Thread_Cache_Free_Lists">Sizing Thread Cache Free Lists</a>).
+
+<pre>
+Garbage Collection
+ if (L != 0 && max_length > num_objects_to_move) {
+ max_length = max(max_length - num_objects_to_move, num_objects_to_move)
+ }
+</pre>
-<h2>Performance Notes</h2>
+<p>The fact that the thread cache went over its <code>max_size</code> is
+an indication that the thread would benefit from a larger cache. Simply
+increasing <code>max_size</code> would use an inordinate amount of memory
+in programs that have lots of active threads. Developers can bound the
+memory used with the flag --tcmalloc_max_total_thread_cache_bytes.</p>
+
+<p>Each thread cache starts with a small <code>max_size</code>
+(e.g. 64KB) so that idle threads won't pre-allocate memory they don't
+need. Each time the cache runs a garbage collection, it will also try
+to grow its <code>max_size</code>. If the sum of the thread cache
+sizes is less than --tcmalloc_max_total_thread_cache_bytes,
+<code>max_size</code> grows easily. If not, thread cache 1 will try
+to steal from thread cache 2 (picked round-robin) by decreasing thread
+cache 2's <code>max_size</code>. In this way, threads that are more
+active will steal memory from other threads more often than they are
+have memory stolen from themselves. Mostly idle threads end up with
+small caches and active threads end up with big caches. Note that
+this stealing can cause the sum of the thread cache sizes to be
+greater than --tcmalloc_max_total_thread_cache_bytes until thread
+cache 2 deallocates some memory to trigger a garbage collection.</p>
+
+<h2><A NAME="performance">Performance Notes</A></h2>
<h3>PTMalloc2 unittest</h3>
@@ -349,7 +451,7 @@ time is being burned spinning waiting for locks in the heavily
multi-threaded case).</p>
-<H2>Modifying Runtime Behavior</H2>
+<H2><A NAME="runtime">Modifying Runtime Behavior</A></H2>
<p>You can more finely control the behavior of the tcmalloc via
environment variables.</p>
@@ -358,11 +460,11 @@ environment variables.</p>
<tr valign=top>
<td><code>TCMALLOC_SAMPLE_PARAMETER</code></td>
- <td>default: 262147</td>
+ <td>default: 524288</td>
<td>
- Twice the approximate gap between sampling actions. That is, we
- take one sample approximately once every
- <code>tcmalloc_sample_parmeter/2</code> bytes of allocation.
+ The approximate gap between sampling actions. That is, we take
+ one sample approximately every
+ <code>tcmalloc_sample_parameter</code> bytes of allocation.
</td>
</tr>
@@ -395,6 +497,22 @@ environment variables.</p>
</tr>
<tr valign=top>
+ <td><code>TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=<i>x</i></code></td>
+ <td>default: 16777216</td>
+ <td>
+ Bound on the total amount of bytes allocated to thread caches. This
+ bound is not strict, so it is possible for the cache to go over this
+ bound in certain circumstances. This value defaults to 16MB. For
+ applications with many threads, this may not be a large enough cache,
+ which can affect performance. If you suspect your application is not
+ scaling to many threads due to lock contention in TCMalloc, you can
+ try increasing this value. This may improve performance, at a cost
+ of extra memory use by TCMalloc. See <a href="#Garbage_Collection">
+ Garbage Collection</a> for more details.
+ </td>
+</tr>
+
+<tr valign=top>
<td><code>TCMALLOC_DEVMEM_START</code></td>
<td>default: 0</td>
<td>
@@ -433,9 +551,107 @@ environment variables.</p>
</table>
-<h2>Caveats</h2>
+<H2><A NAME="compiletime">Modifying Behavior In Code</A></H2>
+
+<p>The <code>MallocExtension</code> class, in
+<code>malloc_extension.h</code>, provides a few knobs that you can
+tweak in your program, to affect tcmalloc's behavior.</p>
+
+<h3>Releasing Memory Back to the System</h3>
+
+<p>By default, tcmalloc will release no-longer-used memory back to the
+kernel gradually, over time. The <a
+href="#runtime">tcmalloc_release_rate</a> flag controls how quickly
+this happens. You can also force a release at a given point in the
+progam execution like so:</p>
+<pre>
+ MallocExtension::instance()->ReleaseFreeMemory();
+</pre>
+
+<p>You can also call <code>SetMemoryReleaseRate()</code> to change the
+<code>tcmalloc_release_rate</code> value at runtime, or
+<code>GetMemoryReleaseRate</code> to see what the current release rate
+is.</p>
+
+<h3>Memory Introspection</h3>
+
+<p>There are several routines for getting a human-readable form of the
+current memory usage:</p>
+<pre>
+ MallocExtension::instance()->GetStats(buffer, buffer_length);
+ MallocExtension::instance()->GetHeapSample(&string);
+ MallocExtension::instance()->GetHeapGrowthStacks(&string);
+</pre>
+
+<p>The last two create files in the same format as the heap-profiler,
+and can be passed as data files to pprof. The first is human-readable
+and is meant for debugging.</p>
+
+<h3>Generic Tcmalloc Status</h3>
+
+<p>TCMalloc has support for setting and retrieving arbitrary
+'properties':</p>
+<pre>
+ MallocExtension::instance()->SetNumericProperty(property_name, value);
+ MallocExtension::instance()->GetNumericProperty(property_name, &value);
+</pre>
+
+<p>It is possible for an application to set and get these properties,
+but the most useful is when a library sets the properties so the
+application can read them. Here are the properties TCMalloc defines;
+you can access them with a call like
+<code>MallocExtension::instance()->GetNumericProperty("generic.heap_size",
+&value);</code>:</p>
+
+<table frame=box rules=sides cellpadding=5 width=100%>
+
+<tr valign=top>
+ <td><code>generic.current_allocated_bytes</code></td>
+ <td>
+ Number of bytes used by the application. This will not typically
+ match the memory use reported by the OS, because it does not
+ include TCMalloc overhead or memory fragmentation.
+ </td>
+</tr>
+
+<tr valign=top>
+ <td><code>generic.heap_size</code></td>
+ <td>
+ Bytes of system memory reserved by TCMalloc.
+ </td>
+</tr>
+
+<tr valign=top>
+ <td><code>tcmalloc.slack_bytes</code></td>
+ <td>
+ A measure of memory fragmentation (how much memory is reserved by
+ TCMalloc but unlikely to ever be able to serve an allocation
+ request).
+ </td>
+</tr>
+
+<tr valign=top>
+ <td><code>tcmalloc.max_total_thread_cache_bytes</code></td>
+ <td>
+ A limit to how much memory TCMalloc dedicates for small objects.
+ Higher numbers trade off more memory use for -- in some situations
+ -- improved efficiency.
+ </td>
+</tr>
+
+<tr valign=top>
+ <td><code>tcmalloc.current_total_thread_cache_bytes</code></td>
+ <td>
+ A measure of some of the memory TCMalloc is using (for
+ small objects).
+ </td>
+</tr>
+
+</table>
+
+<h2><A NAME="caveats">Caveats</A></h2>
-<p>For some systems, TCMalloc may not work correctly on with
+<p>For some systems, TCMalloc may not work correctly with
applications that aren't linked against <code>libpthread.so</code> (or
the equivalent on your OS). It should work on Linux using glibc 2.3,
but other OS/libc combinations have not been tested.</p>
diff --git a/google-perftools.sln b/google-perftools.sln
index 779120b..2184420 100755
--- a/google-perftools.sln
+++ b/google-perftools.sln
@@ -26,6 +26,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "low_level_alloc_unittest",
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "malloc_extension_test", "vsprojects\malloc_extension_test\malloc_extension_test.vcproj", "{3765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "markidle_unittest", "vsprojects\markidle_unittest\markidle_unittest.vcproj", "{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}"
ProjectSection(ProjectDependencies) = postProject
{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}
@@ -35,6 +40,26 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "packed-cache_test", "vsproj
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pagemap_unittest", "vsprojects\pagemap_unittest\pagemap_unittest.vcproj", "{9765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "realloc_unittest", "vsprojects\realloc_unittest\realloc_unittest.vcproj", "{4765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sampler_test", "vsprojects\sampler_test\sampler_test.vcproj", "{B765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stack_trace_table_test", "vsprojects\stack_trace_table_test\stack_trace_table_test.vcproj", "{A4754725-DE0D-4214-8979-324247AAD78E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thread_dealloc_unittest", "vsprojects\thread_dealloc_unittest\thread_dealloc_unittest.vcproj", "{6CFFBD0F-09E3-4282-A711-0564451FDF74}"
ProjectSection(ProjectDependencies) = postProject
{55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F} = {55E2B3AE-3CA1-4DB6-97F7-0A044D6F446F}
@@ -86,18 +111,34 @@ Global
{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32
{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32
{A765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32
+ {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32
+ {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32
+ {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32
+ {3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.ActiveCfg = Debug|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.Build.0 = Debug|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.ActiveCfg = Release|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.Build.0 = Release|Win32
- {BA416723-325E-46E4-9F9A-BEF6FB928DFA}.Debug.ActiveCfg = Debug|Win32
- {BA416723-325E-46E4-9F9A-BEF6FB928DFA}.Debug.Build.0 = Debug|Win32
- {BA416723-325E-46E4-9F9A-BEF6FB928DFA}.Release.ActiveCfg = Release|Win32
- {BA416723-325E-46E4-9F9A-BEF6FB928DFA}.Release.Build.0 = Release|Win32
{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug.ActiveCfg = Debug|Win32
{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug.Build.0 = Debug|Win32
{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release.ActiveCfg = Release|Win32
{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release.Build.0 = Release|Win32
+ {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32
+ {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32
+ {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32
+ {9765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32
+ {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32
+ {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32
+ {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32
+ {4765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32
+ {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32
+ {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32
+ {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32
+ {B765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32
+ {A4754725-DE0D-4214-8979-324247AAD78E}.Debug.ActiveCfg = Debug|Win32
+ {A4754725-DE0D-4214-8979-324247AAD78E}.Debug.Build.0 = Debug|Win32
+ {A4754725-DE0D-4214-8979-324247AAD78E}.Release.ActiveCfg = Release|Win32
+ {A4754725-DE0D-4214-8979-324247AAD78E}.Release.Build.0 = Release|Win32
{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug.ActiveCfg = Debug|Win32
{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Debug.Build.0 = Debug|Win32
{6CFFBD0F-09E3-4282-A711-0564451FDF74}.Release.ActiveCfg = Release|Win32
diff --git a/m4/acx_nanosleep.m4 b/m4/acx_nanosleep.m4
new file mode 100644
index 0000000..1d44392
--- /dev/null
+++ b/m4/acx_nanosleep.m4
@@ -0,0 +1,35 @@
+# Check for support for nanosleep. It's defined in <time.h>, but on
+# some systems, such as solaris, you need to link in a library to use it.
+# We set acx_nanosleep_ok if nanosleep is supported; in that case,
+# NANOSLEEP_LIBS is set to whatever libraries are needed to support
+# nanosleep.
+
+AC_DEFUN([ACX_NANOSLEEP],
+[AC_MSG_CHECKING(if nanosleep requires any libraries)
+ AC_LANG_SAVE
+ AC_LANG_C
+ acx_nanosleep_ok="no"
+ NANOSLEEP_LIBS=
+ # For most folks, this should just work
+ AC_TRY_LINK([#include <time.h>],
+ [static struct timespec ts; nanosleep(&ts, NULL);],
+ [acx_nanosleep_ok=yes])
+ # For solaris, we may need -lrt
+ if test "x$acx_nanosleep_ok" != "xyes"; then
+ OLD_LIBS="$LIBS"
+ LIBS="-lrt $LIBS"
+ AC_TRY_LINK([#include <time.h>],
+ [static struct timespec ts; nanosleep(&ts, NULL);],
+ [acx_nanosleep_ok=yes])
+ if test "x$acx_nanosleep_ok" = "xyes"; then
+ NANOSLEEP_LIBS="-lrt"
+ fi
+ LIBS="$OLD_LIBS"
+ fi
+ if test "x$acx_nanosleep_ok" != "xyes"; then
+ AC_MSG_ERROR([cannot find the nanosleep function])
+ else
+ AC_MSG_RESULT(${NANOSLEEP_LIBS:-no})
+ fi
+ AC_LANG_RESTORE
+])
diff --git a/packages/deb.sh b/packages/deb.sh
index e6f4aca..31b423c 100755
--- a/packages/deb.sh
+++ b/packages/deb.sh
@@ -31,7 +31,8 @@ fi
topdir="${PWD%/*}"
# Find the tar archive built by "make dist"
-archive="$PACKAGE-$VERSION"
+archive="${PACKAGE}-${VERSION}"
+archive_with_underscore="${PACKAGE}_${VERSION}"
if [ -z "${archive}" ]; then
echo "Cannot find ../$PACKAGE*.tar.gz. Run \"make dist\" first." 1>&2
exit 0
@@ -49,11 +50,13 @@ cd tmp
# packages to the parent of the source directory. We accommodate these
# requirements by building directly from the tar file.
ln -s "${topdir}/${archive}.tar.gz" "${LIB}${archive}.orig.tar.gz"
+# Some version of debuilder want foo.orig.tar.gz with _ between versions.
+ln -s "${topdir}/${archive}.tar.gz" "${LIB}${archive_with_underscore}.orig.tar.gz"
tar zfx "${LIB}${archive}.orig.tar.gz"
[ -n "${LIB}" ] && mv "${archive}" "${LIB}${archive}"
cd "${LIB}${archive}"
# This is one of those 'specific requirements': where the deb control files live
-ln -s "packages/deb" "debian"
+cp -a "packages/deb" "debian"
# Now, we can call Debian's standard build tool
debuild -uc -us
diff --git a/packages/deb/changelog b/packages/deb/changelog
index 390f371..6deb094 100644
--- a/packages/deb/changelog
+++ b/packages/deb/changelog
@@ -1,3 +1,9 @@
+google-perftools (1.1-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Google Inc. <opensource@google.com> Wed, 11 Mar 2009 11:25:34 -0700
+
google-perftools (1.0-1) unstable; urgency=low
* New upstream release.
diff --git a/src/base/basictypes.h b/src/base/basictypes.h
index 3fb7b08..9a55422 100644
--- a/src/base/basictypes.h
+++ b/src/base/basictypes.h
@@ -112,6 +112,9 @@ const int64 kint64min = ( ((( int64) kint32min) << 32) | 0 );
TypeName(const TypeName&); \
void operator=(const TypeName&)
+// An alternate name that leaves out the moral judgment... :-)
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) DISALLOW_EVIL_CONSTRUCTORS(TypeName)
+
// The COMPILE_ASSERT macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the
// size of a static array:
diff --git a/src/base/cycleclock.h b/src/base/cycleclock.h
index e188d43..8af664e 100644
--- a/src/base/cycleclock.h
+++ b/src/base/cycleclock.h
@@ -75,9 +75,9 @@ struct CycleClock {
: "=A" (ret) );
return ret;
#elif defined(__x86_64__) || defined(__amd64__)
- uint32 low, high;
+ uint64 low, high;
__asm__ volatile ("rdtsc" : "=a" (low), "=d" (high));
- return (static_cast<uint64>(high) << 32) | low;
+ return (high << 32) | low;
#elif defined(__powerpc__) || defined(__ppc__)
// This returns a time-base, which is not always precisely a cycle-count.
int64 tbl, tbu0, tbu1;
diff --git a/src/base/dynamic_annotations.cc b/src/base/dynamic_annotations.cc
index 68e9ec3..ec057bc 100644
--- a/src/base/dynamic_annotations.cc
+++ b/src/base/dynamic_annotations.cc
@@ -75,6 +75,8 @@ extern "C" void AnnotateMutexIsUsedAsCondVar(const char *file, int line,
const volatile void *mu){}
extern "C" void AnnotateTraceMemory(const char *file, int line,
const volatile void *arg){}
+extern "C" void AnnotateThreadName(const char *file, int line,
+ const char *name){}
extern "C" void AnnotateIgnoreReadsBegin(const char *file, int line){}
extern "C" void AnnotateIgnoreReadsEnd(const char *file, int line){}
extern "C" void AnnotateIgnoreWritesBegin(const char *file, int line){}
diff --git a/src/base/dynamic_annotations.h b/src/base/dynamic_annotations.h
index 405a6c8..d4794c1 100644
--- a/src/base/dynamic_annotations.h
+++ b/src/base/dynamic_annotations.h
@@ -84,8 +84,7 @@
// Report that we are about to signal on the condition variable at address
// "cv". When used with user-defined synchronization mechanism at address
// "cv", indicates that a ANNOTATE_CONDVAR_WAIT(cv) "happened-after" this
- // event. This call should be applied to the mutex in critical sections
- // that make LockWhen() and Await() conditions true.
+ // event.
#define ANNOTATE_CONDVAR_SIGNAL(cv) \
AnnotateCondVarSignal(__FILE__, __LINE__, cv)
@@ -195,6 +194,10 @@
#define ANNOTATE_TRACE_MEMORY(address) \
AnnotateTraceMemory(__FILE__, __LINE__, address)
+ // Report the current thread name to a race detector.
+ #define ANNOTATE_THREAD_NAME(name) \
+ AnnotateThreadName(__FILE__, __LINE__, name)
+
// -------------------------------------------------------------
// Annotations useful when implementing locks. They are not
// normally needed by modules that merely use locks.
@@ -250,6 +253,7 @@
#define ANNOTATE_BENIGN_RACE(address, description) // empty
#define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) // empty
#define ANNOTATE_TRACE_MEMORY(arg) // empty
+ #define ANNOTATE_THREAD_NAME(name) // empty
#define ANNOTATE_IGNORE_READS_BEGIN() // empty
#define ANNOTATE_IGNORE_READS_END() // empty
#define ANNOTATE_IGNORE_WRITES_BEGIN() // empty
@@ -300,6 +304,8 @@ extern "C" void AnnotateMutexIsUsedAsCondVar(const char *file, int line,
const volatile void *mu);
extern "C" void AnnotateTraceMemory(const char *file, int line,
const volatile void *arg);
+extern "C" void AnnotateThreadName(const char *file, int line,
+ const char *name);
extern "C" void AnnotateIgnoreReadsBegin(const char *file, int line);
extern "C" void AnnotateIgnoreReadsEnd(const char *file, int line);
extern "C" void AnnotateIgnoreWritesBegin(const char *file, int line);
diff --git a/src/base/linux_syscall_support.h b/src/base/linux_syscall_support.h
index cd45db2..512805b 100644
--- a/src/base/linux_syscall_support.h
+++ b/src/base/linux_syscall_support.h
@@ -678,6 +678,9 @@ struct kernel_statfs {
#ifndef __NR_move_pages
#define __NR_move_pages 317
#endif
+#ifndef __NR_getcpu
+#define __NR_getcpu 318
+#endif
#ifndef __NR_fallocate
#define __NR_fallocate 324
#endif
@@ -774,6 +777,9 @@ struct kernel_statfs {
#ifndef __NR_move_pages
#define __NR_move_pages (__NR_SYSCALL_BASE + 344)
#endif
+#ifndef __NR_getcpu
+#define __NR_getcpu (__NR_SYSCALL_BASE + 345)
+#endif
/* End of ARM 3 definitions */
#elif defined(__x86_64__)
#ifndef __NR_pread64
@@ -939,6 +945,9 @@ struct kernel_statfs {
#ifndef __NR_move_pages
#define __NR_move_pages (__NR_Linux + 308)
#endif
+#ifndef __NR_getcpu
+#define __NR_getcpu (__NR_Linux + 312)
+#endif
#ifndef __NR_ioprio_set
#define __NR_ioprio_set (__NR_Linux + 314)
#endif
@@ -1009,6 +1018,9 @@ struct kernel_statfs {
#ifndef __NR_move_pages
#define __NR_move_pages (__NR_Linux + 267)
#endif
+#ifndef __NR_getcpu
+#define __NR_getcpu (__NR_Linux + 271)
+#endif
#ifndef __NR_ioprio_set
#define __NR_ioprio_set (__NR_Linux + 273)
#endif
@@ -1079,6 +1091,9 @@ struct kernel_statfs {
#ifndef __NR_move_pages
#define __NR_move_pages (__NR_Linux + 271)
#endif
+#ifndef __NR_getcpu
+#define __NR_getcpu (__NR_Linux + 275)
+#endif
#ifndef __NR_ioprio_set
#define __NR_ioprio_set (__NR_Linux + 277)
#endif
@@ -1188,6 +1203,9 @@ struct kernel_statfs {
#ifndef __NR_move_pages
#define __NR_move_pages 301
#endif
+#ifndef __NR_getcpu
+#define __NR_getcpu 302
+#endif
/* End of powerpc defininitions */
#endif
@@ -2349,6 +2367,10 @@ struct kernel_statfs {
const void *, b, size_t, c)
LSS_INLINE _syscall3(ssize_t, writev, int, f,
const struct kernel_iovec*, v, size_t, c)
+ #if defined(__NR_getcpu)
+ LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu,
+ unsigned *, node, void *, unused);
+ #endif
#if defined(__x86_64__) || \
(defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32)
LSS_INLINE _syscall3(int, recvmsg, int, s,
diff --git a/src/base/simple_mutex.h b/src/base/simple_mutex.h
index 73460ed..d59f5a0 100644
--- a/src/base/simple_mutex.h
+++ b/src/base/simple_mutex.h
@@ -1,58 +1,110 @@
-/* Copyright (c) 2007, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ---
- * Author: Craig Silverstein.
- *
- * A simple mutex wrapper, supporting locks and read-write locks.
- * You should assume the locks are *not* re-entrant.
- *
- * To use: you should define the following macros in your configure.ac:
- * ACX_PTHREAD
- * AC_RWLOCK
- * The latter is defined in ../autoconf.
- *
- * This class is meant to be internal-only, so it's defined in the
- * global namespace. If you want to expose it, you'll want to move
- * it to the Google namespace.
- *
- * NOTE: TryLock() is broken for NO_THREADS mode, at least in NDEBUG
- * mode.
- */
-
-#ifndef GOOGLE_SIMPLE_MUTEX_H_
-#define GOOGLE_SIMPLE_MUTEX_H_
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+// Author: Craig Silverstein.
+//
+// A simple mutex wrapper, supporting locks and read-write locks.
+// You should assume the locks are *not* re-entrant.
+//
+// To use: you should define the following macros in your configure.ac:
+// ACX_PTHREAD
+// AC_RWLOCK
+// The latter is defined in ../autoconf.
+//
+// This class is meant to be internal-only, so it's defined in the
+// global namespace. If you want to expose it, you'll want to move
+// it to the Google namespace.
+//
+// NOTE: TryLock() is broken for NO_THREADS mode, at least in NDEBUG
+// mode.
+//
+// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
+// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
+// Because of that, we might as well use windows locks for
+// cygwin. They seem to be more reliable than the cygwin pthreads layer.
+//
+// TRICKY IMPLEMENTATION NOTE:
+// This class is designed to be safe to use during
+// dynamic-initialization -- that is, by global constructors that are
+// run before main() starts. The issue in this case is that
+// dynamic-initialization happens in an unpredictable order, and it
+// could be that someone else's dynamic initializer could call a
+// function that tries to acquire this mutex -- but that all happens
+// before this mutex's constructor has run. (This can happen even if
+// the mutex and the function that uses the mutex are in the same .cc
+// file.) Basically, because Mutex does non-trivial work in its
+// constructor, it's not, in the naive implementation, safe to use
+// before dynamic initialization has run on it.
+//
+// The solution used here is to pair the actual mutex primitive with a
+// bool that is set to true when the mutex is dynamically initialized.
+// (Before that it's false.) Then we modify all mutex routines to
+// look at the bool, and not try to lock/unlock until the bool makes
+// it to true (which happens after the Mutex constructor has run.)
+//
+// This works because before main() starts -- particularly, during
+// dynamic initialization -- there are no threads, so a) it's ok that
+// the mutex operations are a no-op, since we don't need locking then
+// anyway; and b) we can be quite confident our bool won't change
+// state between a call to Lock() and a call to Unlock() (that would
+// require a global constructor in one translation unit to call Lock()
+// and another global constructor in another translation unit to call
+// Unlock() later, which is pretty perverse).
+//
+// That said, it's tricky, and can conceivably fail; it's safest to
+// avoid trying to acquire a mutex in a global constructor, if you
+// can. One way it can fail is that a really smart compiler might
+// initialize the bool to true at static-initialization time (too
+// early) rather than at dynamic-initialization time. To discourage
+// that, we set is_safe_ to true in code (not the constructor
+// colon-initializer) and set it to true via a function that always
+// evaluates to true, but that the compiler can't know always
+// evaluates to true. This should be good enough.
+
+#ifndef GOOGLE_MUTEX_H_
+#define GOOGLE_MUTEX_H_
#include "config.h" // to figure out pthreads support
#if defined(NO_THREADS)
typedef int MutexType; // to keep a lock-count
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+# define WIN32_LEAN_AND_MEAN // We only need minimal includes
+ // We need Windows NT or later for TryEnterCriticalSection(). If you
+ // don't need that functionality, you can remove these _WIN32_WINNT
+ // lines, and change TryLock() to assert(0) or something.
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0400
+# endif
+# include <windows.h>
+ typedef CRITICAL_SECTION MutexType;
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
// Needed for pthread_rwlock_*. If it causes problems, you could take it
// out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
@@ -66,18 +118,6 @@
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
typedef pthread_mutex_t MutexType;
-#elif defined(_WIN32)
-# define WIN32_LEAN_AND_MEAN // We only need minimal includes
-# ifdef GMUTEX_TRYLOCK
- // We need Windows NT or later for TryEnterCriticalSection(). If you
- // don't need that functionality, you can remove these _WIN32_WINNT
- // lines, and change TryLock() to assert(0) or something.
-# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0400
-# endif
-# endif
-# include <windows.h>
- typedef CRITICAL_SECTION MutexType;
#else
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
@@ -104,6 +144,12 @@ class Mutex {
private:
MutexType mutex_;
+ // We want to make sure that the compiler sets is_safe_ to true only
+ // when we tell it to, and never makes assumptions is_safe_ is
+ // always true. volatile is the most reliable way to do that.
+ volatile bool is_safe_;
+
+ inline void SetIsSafe() { is_safe_ = true; }
// Catch the error of writing Mutex when intending MutexLock.
Mutex(Mutex *ignored) {}
@@ -134,47 +180,59 @@ bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+
+Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
+Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
+void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
+void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
+bool Mutex::TryLock() { return is_safe_ ?
+ TryEnterCriticalSection(&mutex_) != 0 : true; }
+void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
+void Mutex::ReaderUnlock() { Unlock(); }
+
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#include <stdlib.h> // for abort()
-#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
-
-Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
-Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
-void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
-void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
-bool Mutex::TryLock() { return pthread_rwlock_trywrlock(&mutex_) == 0; }
-void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
-void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_rwlock_trywrlock(&mutex_) == 0 : true; }
+void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
+void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#undef SAFE_PTHREAD
#elif defined(HAVE_PTHREAD)
#include <stdlib.h> // for abort()
-#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
-Mutex::Mutex() { SAFE_PTHREAD(pthread_mutex_init(&mutex_, NULL)); }
-Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy(&mutex_)); }
-void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock(&mutex_)); }
-void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock(&mutex_)); }
-bool Mutex::TryLock() { return pthread_mutex_trylock(&mutex_) == 0; }
-void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_mutex_trylock(&mutex_) == 0 : true; }
+void Mutex::ReaderLock() { Lock(); }
void Mutex::ReaderUnlock() { Unlock(); }
#undef SAFE_PTHREAD
-#elif defined(_WIN32)
-
-Mutex::Mutex() { InitializeCriticalSection(&mutex_); }
-Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
-void Mutex::Lock() { EnterCriticalSection(&mutex_); }
-void Mutex::Unlock() { LeaveCriticalSection(&mutex_); }
-bool Mutex::TryLock() { return TryEnterCriticalSection(&mutex_) != 0; }
-void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
-void Mutex::ReaderUnlock() { Unlock(); }
-
#endif
-
// --------------------------------------------------------------------------
// Some helper classes
diff --git a/src/base/spinlock.h b/src/base/spinlock.h
index 3ffeb4d..f1a6d69 100644
--- a/src/base/spinlock.h
+++ b/src/base/spinlock.h
@@ -47,15 +47,7 @@
#include "base/basictypes.h"
#include "base/atomicops.h"
#include "base/dynamic_annotations.h"
-
-// One day, we may use __attribute__ stuff on gcc to annotate these functions
-#define LOCKABLE
-#define SCOPED_LOCKABLE
-#define EXCLUSIVE_LOCK_FUNCTION(...)
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
-#define UNLOCK_FUNCTION(...)
-
-
+#include "base/thread_annotations.h"
class LOCKABLE SpinLock {
public:
diff --git a/src/base/sysinfo.cc b/src/base/sysinfo.cc
index ac2de3a..1f542ae 100644
--- a/src/base/sysinfo.cc
+++ b/src/base/sysinfo.cc
@@ -392,6 +392,32 @@ int NumCPUs(void) {
}
// ----------------------------------------------------------------------
+// HasPosixThreads()
+// Return true if we're running POSIX (e.g., NPTL on Linux)
+// threads, as opposed to a non-POSIX thread libary. The thing
+// that we care about is whether a thread's pid is the same as
+// the thread that spawned it. If so, this function returns
+// true.
+// ----------------------------------------------------------------------
+bool HasPosixThreads() {
+#if defined(__linux__)
+#ifndef _CS_GNU_LIBPTHREAD_VERSION
+#define _CS_GNU_LIBPTHREAD_VERSION 3
+#endif
+ char buf[32];
+ // We assume that, if confstr() doesn't know about this name, then
+ // the same glibc is providing LinuxThreads.
+ if (confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf)) == 0)
+ return false;
+ return strncmp(buf, "NPTL", 4) == 0;
+#elif defined(_WIN32) || defined(__MINGW32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+ return false;
+#else // other OS
+ return true; // Assume that everything else has Posix
+#endif // else OS_LINUX
+}
+
+// ----------------------------------------------------------------------
#if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYGWIN__ || defined __CYGWIN32__
static void ConstructFilename(const char* spec, pid_t pid,
diff --git a/src/base/sysinfo.h b/src/base/sysinfo.h
index 6f629ef..86d998c 100644
--- a/src/base/sysinfo.h
+++ b/src/base/sysinfo.h
@@ -73,6 +73,14 @@ extern int NumCPUs();
extern double CyclesPerSecond(void);
+// Return true if we're running POSIX (e.g., NPTL on Linux) threads,
+// as opposed to a non-POSIX thread libary. The thing that we care
+// about is whether a thread's pid is the same as the thread that
+// spawned it. If so, this function returns true.
+// Thread-safe.
+// Note: We consider false negatives to be OK.
+bool HasPosixThreads();
+
#ifndef SWIG // SWIG doesn't like struct Buffer and variable arguments.
// A ProcMapsIterator abstracts access to /proc/maps for a given
diff --git a/src/base/thread_annotations.h b/src/base/thread_annotations.h
index b4e9f5f..ded13d6 100644
--- a/src/base/thread_annotations.h
+++ b/src/base/thread_annotations.h
@@ -121,23 +121,29 @@
// When the compiler is not GCC, these annotations are simply no-ops.
+// NOTE: in theory, the macros that take "arg" below *could* take
+// multiple arguments, but in practice so far they only take one.
+// Since not all non-gcc compilers support ... -- notably MSVC 7.1 --
+// I just hard-code in a single arg. If this assumption ever breaks,
+// we can change it back to "...", or handle it some other way.
+
#define GUARDED_BY(x) // no-op
#define GUARDED_VAR // no-op
#define PT_GUARDED_BY(x) // no-op
#define PT_GUARDED_VAR // no-op
-#define ACQUIRED_AFTER(...) // no-op
-#define ACQUIRED_BEFORE(...) // no-op
-#define EXCLUSIVE_LOCKS_REQUIRED(...) // no-op
-#define SHARED_LOCKS_REQUIRED(...) // no-op
-#define LOCKS_EXCLUDED(...) // no-op
+#define ACQUIRED_AFTER(arg) // no-op
+#define ACQUIRED_BEFORE(arg) // no-op
+#define EXCLUSIVE_LOCKS_REQUIRED(arg) // no-op
+#define SHARED_LOCKS_REQUIRED(arg) // no-op
+#define LOCKS_EXCLUDED(arg) // no-op
#define LOCK_RETURNED(x) // no-op
#define LOCKABLE // no-op
#define SCOPED_LOCKABLE // no-op
-#define EXCLUSIVE_LOCK_FUNCTION(...) // no-op
-#define SHARED_LOCK_FUNCTION(...) // no-op
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) // no-op
-#define SHARED_TRYLOCK_FUNCTION(...) // no-op
-#define UNLOCK_FUNCTION(...) // no-op
+#define EXCLUSIVE_LOCK_FUNCTION(arg) // no-op
+#define SHARED_LOCK_FUNCTION(arg) // no-op
+#define EXCLUSIVE_TRYLOCK_FUNCTION(arg) // no-op
+#define SHARED_TRYLOCK_FUNCTION(arg) // no-op
+#define UNLOCK_FUNCTION(arg) // no-op
#define NO_THREAD_SAFETY_ANALYSIS // no-op
#endif // defined(__GNUC__) && defined(__SUPPORT_TS_ANNOTATION__)
diff --git a/src/base/vdso_support.cc b/src/base/vdso_support.cc
new file mode 100644
index 0000000..c113bbc
--- /dev/null
+++ b/src/base/vdso_support.cc
@@ -0,0 +1,509 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Paul Pluzhnikov
+//
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+//
+
+#include "base/vdso_support.h"
+
+#ifdef HAVE_VDSO_SUPPORT // defined in vdso_support.h
+
+#include <fcntl.h>
+
+#include "base/atomicops.h" // for MemoryBarrier
+#include "base/logging.h"
+#include "base/linux_syscall_support.h"
+#include "base/dynamic_annotations.h"
+#include "base/basictypes.h" // for COMPILE_ASSERT
+
+using base::subtle::MemoryBarrier;
+
+#ifndef AT_SYSINFO_EHDR
+#define AT_SYSINFO_EHDR 33
+#endif
+
+namespace base {
+
+namespace {
+template <int N> class ElfClass {
+ public:
+ static const int kElfClass = -1;
+ static int ElfBind(const ElfW(Sym) *) {
+ CHECK(false); // << "Unexpected word size";
+ return 0;
+ }
+ static int ElfType(const ElfW(Sym) *) {
+ CHECK(false); // << "Unexpected word size";
+ return 0;
+ }
+};
+
+template <> class ElfClass<32> {
+ public:
+ static const int kElfClass = ELFCLASS32;
+ static int ElfBind(const ElfW(Sym) *symbol) {
+ return ELF32_ST_BIND(symbol->st_info);
+ }
+ static int ElfType(const ElfW(Sym) *symbol) {
+ return ELF32_ST_TYPE(symbol->st_info);
+ }
+};
+
+template <> class ElfClass<64> {
+ public:
+ static const int kElfClass = ELFCLASS64;
+ static int ElfBind(const ElfW(Sym) *symbol) {
+ return ELF64_ST_BIND(symbol->st_info);
+ }
+ static int ElfType(const ElfW(Sym) *symbol) {
+ return ELF64_ST_TYPE(symbol->st_info);
+ }
+};
+
+typedef ElfClass<__WORDSIZE> CurrentElfClass;
+
+// Extract an element from one of the ELF tables, cast it to desired type.
+// This is just a simple arithmetic and a glorified cast.
+// Callers are responsible for bounds checking.
+template <class T>
+const T* GetTableElement(const ElfW(Ehdr) *ehdr,
+ ElfW(Off) table_offset,
+ ElfW(Word) element_size,
+ size_t index) {
+ return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
+ + table_offset
+ + index * element_size);
+}
+} // namespace
+
+const void *const VDSOSupport::kInvalidBase =
+ reinterpret_cast<const void *>(~0L);
+
+const void *VDSOSupport::vdso_base_ = kInvalidBase;
+VDSOSupport::GetCpuFn VDSOSupport::getcpu_fn_ = &InitAndGetCPU;
+
+VDSOSupport::ElfMemImage::ElfMemImage(const void *base) {
+ Init(base);
+}
+
+int VDSOSupport::ElfMemImage::GetNumSymbols() const {
+ if (!dynsym_) {
+ return 0;
+ }
+ return dynsym_->sh_size / dynsym_->sh_entsize;
+}
+
+const ElfW(Sym) *VDSOSupport::ElfMemImage::GetDynsym(int index) const {
+ CHECK_LT(index, GetNumSymbols());
+ return GetTableElement<ElfW(Sym)>(ehdr_,
+ dynsym_->sh_offset,
+ dynsym_->sh_entsize,
+ index);
+}
+
+const ElfW(Versym) *VDSOSupport::ElfMemImage::GetVersym(int index) const {
+ CHECK_LT(index, GetNumSymbols());
+ return GetTableElement<ElfW(Versym)>(ehdr_,
+ versym_->sh_offset,
+ versym_->sh_entsize,
+ index);
+}
+
+const ElfW(Phdr) *VDSOSupport::ElfMemImage::GetPhdr(int index) const {
+ CHECK_LT(index, ehdr_->e_phnum);
+ return GetTableElement<ElfW(Phdr)>(ehdr_,
+ ehdr_->e_phoff,
+ ehdr_->e_phentsize,
+ index);
+}
+
+const ElfW(Shdr) *VDSOSupport::ElfMemImage::GetSection(int index) const {
+ CHECK_LT(index, ehdr_->e_shnum);
+ return GetTableElement<ElfW(Shdr)>(ehdr_,
+ ehdr_->e_shoff,
+ ehdr_->e_shentsize,
+ index);
+}
+
+const char *VDSOSupport::ElfMemImage::GetSectionData(
+ const ElfW(Shdr) *section,
+ ElfW(Word) offset) const {
+ CHECK_LT(offset, section->sh_size);
+ return GetTableElement<char>(ehdr_, section->sh_offset, 1, offset);
+}
+
+const char *VDSOSupport::ElfMemImage::GetDynstr(ElfW(Word) offset) const {
+ CHECK_LT(offset, dynstr_->sh_size);
+ return GetTableElement<char>(ehdr_, dynstr_->sh_offset, 1, offset);
+}
+
+const void *VDSOSupport::ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
+ if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
+ // Symbol corresponds to "special" (e.g. SHN_ABS) section.
+ return reinterpret_cast<const void *>(sym->st_value);
+ }
+ CHECK_LT(link_base_, sym->st_value);
+ return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
+}
+
+const ElfW(Verdef) *VDSOSupport::ElfMemImage::GetVerdef(int index) const {
+ size_t offset = 0;
+ const ElfW(Verdef) *version_definition =
+ GetTableElement<ElfW(Verdef)>(ehdr_, verdef_->sh_offset, 1, offset);
+ while (version_definition->vd_ndx < index && version_definition->vd_next) {
+ offset += version_definition->vd_next;
+ CHECK_LT(offset, verdef_->sh_size);
+ version_definition =
+ GetTableElement<ElfW(Verdef)>(ehdr_, verdef_->sh_offset, 1, offset);
+ }
+ return version_definition->vd_ndx == index ? version_definition : NULL;
+}
+
+const ElfW(Verdaux) *VDSOSupport::ElfMemImage::GetVerdefAux(
+ const ElfW(Verdef) *verdef) const {
+ return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
+}
+
+const char *VDSOSupport::ElfMemImage::GetVerstr(ElfW(Word) offset) const {
+ return GetSectionData(GetSection(verdef_->sh_link), offset);
+}
+
+void VDSOSupport::ElfMemImage::Init(const void *base) {
+ ehdr_ = NULL;
+ dynsym_ = NULL;
+ dynstr_ = NULL;
+ versym_ = NULL;
+ verdef_ = NULL;
+ link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
+ if (!base) {
+ return;
+ }
+ if (memcmp(base, ELFMAG, SELFMAG)) {
+ RAW_DCHECK(false, "no ELF magic"); // at %p", base);
+ return;
+ }
+ const char *const base_as_char = reinterpret_cast<const char *>(base);
+ int elf_class = base_as_char[EI_CLASS];
+ if (elf_class != CurrentElfClass::kElfClass) {
+ DCHECK_EQ(elf_class, CurrentElfClass::kElfClass);
+ return;
+ }
+ switch (base_as_char[EI_DATA]) {
+ case ELFDATA2LSB: {
+ if (__LITTLE_ENDIAN != __BYTE_ORDER) {
+ DCHECK_EQ(__LITTLE_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
+ return;
+ }
+ break;
+ }
+ case ELFDATA2MSB: {
+ if (__BIG_ENDIAN != __BYTE_ORDER) {
+ DCHECK_EQ(__BIG_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
+ return;
+ }
+ break;
+ }
+ default: {
+ RAW_DCHECK(false, "unexpected data encoding"); // << base_as_char[EI_DATA];
+ return;
+ }
+ }
+
+ ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
+ for (int i = 0; i < ehdr_->e_phnum; ++i) {
+ const ElfW(Phdr) *const program_header = GetPhdr(i);
+ if (program_header->p_type == PT_LOAD) {
+ link_base_ = program_header->p_vaddr;
+ break;
+ }
+ }
+ if (link_base_ == ~0L) {
+ // Didn't find a PT_LOAD.
+ RAW_DCHECK(false, "no PT_LOADs in VDSO");
+ // Mark this image as not present. Can not recur infinitely.
+ Init(0);
+ return;
+ }
+ for (int i = 0; i < ehdr_->e_shnum; ++i) {
+ const ElfW(Shdr) *section = GetSection(i);
+ switch (section->sh_type) {
+ case SHT_DYNSYM: {
+ dynsym_ = section;
+ break;
+ }
+ case SHT_STRTAB: {
+ const char *const section_name =
+ GetSectionData(GetSection(ehdr_->e_shstrndx), section->sh_name);
+ if (strcmp(".dynstr", section_name) == 0) {
+ dynstr_ = section;
+ break;
+ }
+ break;
+ }
+ case SHT_GNU_versym: {
+ versym_ = section;
+ break;
+ }
+ case SHT_GNU_verdef: {
+ verdef_ = section;
+ break;
+ }
+ default: {
+ // Unrecognized sections explicitly ignored.
+ break;
+ }
+ }
+ }
+ if (!dynsym_ || !dynstr_ || !versym_ || !verdef_ ||
+ ((dynsym_->sh_size / dynsym_->sh_entsize) !=
+ (versym_->sh_size / versym_->sh_entsize))) {
+ RAW_DCHECK(dynsym_, "invalid VDSO (no dynsym)");
+ RAW_DCHECK(dynstr_, "invalid VDSO (no dynstr)");
+ RAW_DCHECK(versym_, "invalid VDSO (no versym)");
+ RAW_DCHECK(verdef_, "invalid VDSO (no verdef)");
+ DCHECK_EQ(dynsym_->sh_size / dynsym_->sh_entsize,
+ versym_->sh_size / versym_->sh_entsize);
+ // Mark this image as not present. Can not recur infinitely.
+ Init(0);
+ return;
+ }
+}
+
+VDSOSupport::VDSOSupport() : image_(vdso_base_) {
+}
+
+// NOTE: we can't use GoogleOnceInit() below, because we can be
+// called by tcmalloc, and none of the *once* stuff may be functional yet.
+//
+// In addition, we hope that attribute constructor (which this function has)
+// causes this code to run before there are any threads.
+//
+// Finally, even if there is a race here, it is harmless, because
+// the operation should be idempotent.
+void VDSOSupport::Init() {
+ if (vdso_base_ == kInvalidBase) {
+ // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
+ // on stack, and so glibc works as if VDSO was not present.
+ // But going directly to kernel via /proc/self/auxv below bypasses
+ // Valgrind zapping. So we check for Valgrind separately.
+ if (RunningOnValgrind()) {
+ vdso_base_ = NULL;
+ getcpu_fn_ = &GetCPUViaSyscall;
+ return;
+ }
+ int fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd == -1) {
+ // Kernel too old to have a VDSO.
+ vdso_base_ = NULL;
+ getcpu_fn_ = &GetCPUViaSyscall;
+ return;
+ }
+ ElfW(auxv_t) aux;
+ while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
+ if (aux.a_type == AT_SYSINFO_EHDR) {
+ COMPILE_ASSERT(sizeof(vdso_base_) == sizeof(aux.a_un.a_val),
+ unexpected_sizeof_pointer_NE_sizeof_a_val);
+ vdso_base_ = reinterpret_cast<void *>(aux.a_un.a_val);
+ break;
+ }
+ }
+ close(fd);
+ if (vdso_base_ == kInvalidBase) {
+ // Didn't find AT_SYSINFO_EHDR in auxv[].
+ vdso_base_ = NULL;
+ }
+ }
+ GetCpuFn fn = &GetCPUViaSyscall; // default if VDSO not present.
+ if (vdso_base_) {
+ VDSOSupport vdso;
+ SymbolInfo info;
+ if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+ // Casting from an int to a pointer is not legal C++. To emphasize
+ // this, we use a C-style cast rather than a C++-style cast.
+ fn = (GetCpuFn)(info.address);
+ }
+ }
+ // Subtle: this code runs outside of any locks; prevent compiler
+ // from assigning to getcpu_fn_ more than once.
+ MemoryBarrier();
+ getcpu_fn_ = fn;
+}
+
+const void *VDSOSupport::SetBase(const void *base) {
+ const void *old_base = vdso_base_;
+ vdso_base_ = base;
+ image_.Init(base);
+ // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO.
+ getcpu_fn_ = &InitAndGetCPU;
+ return old_base;
+}
+
+bool VDSOSupport::LookupSymbol(const char *name,
+ const char *version,
+ int type,
+ SymbolInfo *info) const {
+ for (SymbolIterator it = begin(); it != end(); ++it) {
+ if (strcmp(it->name, name) == 0 && strcmp(it->version, version) == 0 &&
+ CurrentElfClass::ElfType(it->symbol) == type) {
+ if (info) {
+ *info = *it;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool VDSOSupport::LookupSymbolByAddress(const void *address,
+ SymbolInfo *info_out) const {
+ for (SymbolIterator it = begin(); it != end(); ++it) {
+ const char *const symbol_start =
+ reinterpret_cast<const char *>(it->address);
+ const char *const symbol_end = symbol_start + it->symbol->st_size;
+ if (symbol_start <= address && address < symbol_end) {
+ if (info_out) {
+ // Client wants to know details for that symbol (the usual case).
+ if (CurrentElfClass::ElfBind(it->symbol) == STB_GLOBAL) {
+ // Strong symbol; just return it.
+ *info_out = *it;
+ return true;
+ } else {
+ // Weak or local. Record it, but keep looking for a strong one.
+ *info_out = *it;
+ }
+ } else {
+ // Client only cares if there is an overlapping symbol.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+VDSOSupport::SymbolIterator::SymbolIterator(const void *const image, int index)
+ : index_(index), image_(image) {
+}
+
+const VDSOSupport::SymbolInfo *VDSOSupport::SymbolIterator::operator->() const {
+ return &info_;
+}
+
+const VDSOSupport::SymbolInfo& VDSOSupport::SymbolIterator::operator*() const {
+ return info_;
+}
+
+bool VDSOSupport::SymbolIterator::operator==(const SymbolIterator &rhs) const {
+ return this->image_ == rhs.image_ && this->index_ == rhs.index_;
+}
+
+bool VDSOSupport::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
+ return !(*this == rhs);
+}
+
+VDSOSupport::SymbolIterator &VDSOSupport::SymbolIterator::operator++() {
+ this->Update(1);
+ return *this;
+}
+
+VDSOSupport::SymbolIterator VDSOSupport::begin() const {
+ SymbolIterator it(&image_, 0);
+ it.Update(0);
+ return it;
+}
+
+VDSOSupport::SymbolIterator VDSOSupport::end() const {
+ return SymbolIterator(&image_, image_.GetNumSymbols());
+}
+
+void VDSOSupport::SymbolIterator::Update(int increment) {
+ const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
+ CHECK(image->IsPresent() || increment == 0);
+ if (!image->IsPresent()) {
+ return;
+ }
+ index_ += increment;
+ if (index_ >= image->GetNumSymbols()) {
+ index_ = image->GetNumSymbols();
+ return;
+ }
+ const ElfW(Sym) *symbol = image->GetDynsym(index_);
+ const ElfW(Versym) *version_symbol = image->GetVersym(index_);
+ CHECK(symbol && version_symbol);
+ const char *const symbol_name = image->GetDynstr(symbol->st_name);
+ const ElfW(Versym) version_index = version_symbol[0];
+ const ElfW(Verdef) *version_definition = image->GetVerdef(version_index);
+ const char *version_name = "";
+ if (version_definition) {
+ // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
+ // optional 2nd if the version has a parent.
+ CHECK_LE(1, version_definition->vd_cnt);
+ CHECK_LE(version_definition->vd_cnt, 2);
+ const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
+ version_name = image->GetVerstr(version_aux->vda_name);
+ }
+ info_.name = symbol_name;
+ info_.version = version_name;
+ info_.address = image->GetSymAddr(symbol);
+ info_.symbol = symbol;
+}
+
+// NOLINT on 'long' because this routine mimics kernel api.
+long VDSOSupport::GetCPUViaSyscall(unsigned *cpu, void *, void *) { // NOLINT
+#if defined(__NR_getcpu)
+ return sys_getcpu(cpu, NULL, NULL);
+#else
+ // x86_64 never implemented sys_getcpu(), except as a VDSO call.
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+// Use fast __vdso_getcpu if available.
+long VDSOSupport::InitAndGetCPU(unsigned *cpu, void *x, void *y) { // NOLINT
+ Init();
+ CHECK_NE(getcpu_fn_, &InitAndGetCPU); // << "Init() did not set getcpu_fn_";
+ return (*getcpu_fn_)(cpu, x, y);
+}
+
+// This function must be very fast, and may be called from very
+// low level (e.g. tcmalloc). Hence I avoid things like
+// GoogleOnceInit() and ::operator new.
+int GetCPU(void) {
+ unsigned cpu;
+ int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, NULL, NULL);
+ return ret_code == 0 ? cpu : ret_code;
+}
+}
+
+#endif // HAVE_VDSO_SUPPORT
diff --git a/src/base/vdso_support.h b/src/base/vdso_support.h
new file mode 100644
index 0000000..228b177
--- /dev/null
+++ b/src/base/vdso_support.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Paul Pluzhnikov
+//
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSO stands for "Virtual Dynamic Shared Object" -- a page of
+// executable code, which looks like a shared library, but doesn't
+// necessarily exist anywhere on disk, and which gets mmap()ed into
+// every process by kernels which support VDSO, such as 2.6.x for 32-bit
+// executables, and 2.6.24 and above for 64-bit executables.
+//
+// More details could be found here:
+// http://www.trilithium.com/johan/2005/08/linux-gate/
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+//
+// Example usage:
+// VDSOSupport vdso;
+// VDSOSupport::SymbolInfo info;
+// typedef (*FN)(unsigned *, void *, void *);
+// FN fn = NULL;
+// if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+// fn = reinterpret_cast<FN>(info.address);
+// }
+
+#ifndef BASE_VDSO_SUPPORT_H_
+#define BASE_VDSO_SUPPORT_H_
+
+#include "config.h"
+
+// Maybe one day we can rewrite this file not to require the elf
+// symbol extensions in glibc, but for right now we need them.
+#if defined(__ELF__) && defined(HAVE_ELF32_VERSYM)
+
+#define HAVE_VDSO_SUPPORT 1
+
+#include <stdlib.h> // for NULL
+#include <link.h> // for ElfW
+#include "base/basictypes.h"
+
+namespace base {
+
+// NOTE: this class may be used from within tcmalloc, and can not
+// use any memory allocation routines.
+class VDSOSupport {
+ public:
+ // Sentinel: there could never be a VDSO at this address.
+ static const void *const kInvalidBase;
+
+ // Information about a single vdso symbol.
+ // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
+ // Do not free() them or modify through them.
+ struct SymbolInfo {
+ const char *name; // E.g. "__vdso_getcpu"
+ const char *version; // E.g. "LINUX_2.6", could be ""
+ // for unversioned symbol.
+ const void *address; // Relocated symbol address.
+ const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table.
+ };
+
+ // Supports iteration over all dynamic symbols.
+ class SymbolIterator {
+ public:
+ friend struct VDSOSupport;
+ const SymbolInfo *operator->() const;
+ const SymbolInfo &operator*() const;
+ SymbolIterator& operator++();
+ bool operator!=(const SymbolIterator &rhs) const;
+ bool operator==(const SymbolIterator &rhs) const;
+ private:
+ SymbolIterator(const void *const image, int index);
+ void Update(int incr);
+ SymbolInfo info_;
+ int index_;
+ const void *const image_;
+ };
+
+ VDSOSupport();
+
+ // Answers whether we have a vdso at all.
+ bool IsPresent() const { return image_.IsPresent(); }
+
+ // Allow to iterate over all VDSO symbols.
+ SymbolIterator begin() const;
+ SymbolIterator end() const;
+
+ // Look up versioned dynamic symbol in the kernel VDSO.
+ // Returns false if VDSO is not present, or doesn't contain given
+ // symbol/version/type combination.
+ // If info_out != NULL, additional details are filled in.
+ bool LookupSymbol(const char *name, const char *version,
+ int symbol_type, SymbolInfo *info_out) const;
+
+ // Find info about symbol (if any) which overlaps given address.
+ // Returns true if symbol was found; false if VDSO isn't present
+ // or doesn't have a symbol overlapping given address.
+ // If info_out != NULL, additional details are filled in.
+ bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+ // Used only for testing. Replace real VDSO base with a mock.
+ // Returns previous value of vdso_base_. After you are done testing,
+ // you are expected to call SetBase() with previous value, in order to
+ // reset state to the way it was.
+ const void *SetBase(const void *s);
+
+ // Computes vdso_base_ as early as possible.
+ static void Init() __attribute__((__constructor__));
+
+ private:
+ // An in-memory ELF image (may not exist on disk).
+ class ElfMemImage {
+ public:
+ explicit ElfMemImage(const void *base);
+ void Init(const void *base);
+ bool IsPresent() const { return ehdr_ != NULL; }
+ const ElfW(Phdr)* GetPhdr(int index) const;
+ const ElfW(Shdr)* GetSection(int index) const;
+ const ElfW(Sym)* GetDynsym(int index) const;
+ const ElfW(Versym)* GetVersym(int index) const;
+ const ElfW(Verdef)* GetVerdef(int index) const;
+ const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
+ const char* GetSectionData(const ElfW(Shdr) *,
+ ElfW(Word) offset) const;
+ const char* GetDynstr(ElfW(Word) offset) const;
+ const void* GetSymAddr(const ElfW(Sym) *sym) const;
+ const char* GetVerstr(ElfW(Word) offset) const;
+ int GetNumSymbols() const;
+ private:
+ const ElfW(Ehdr) *ehdr_;
+ const ElfW(Shdr) *dynsym_;
+ const ElfW(Shdr) *dynstr_;
+ const ElfW(Shdr) *versym_;
+ const ElfW(Shdr) *verdef_;
+ ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
+ };
+
+ // image_ represents VDSO ELF image in memory.
+ // image_.ehdr_ == NULL implies there is no VDSO.
+ ElfMemImage image_;
+
+ // Cached value of auxv AT_SYSINFO_EHDR, computed once.
+ // This is a tri-state:
+ // kInvalidBase => value hasn't been determined yet.
+ // 0 => there is no VDSO.
+ // else => vma of VDSO Elf{32,64}_Ehdr.
+ static const void *vdso_base_;
+
+ // NOLINT on 'long' because these routines mimic kernel api.
+ // The 'cache' parameter may be used by some versions of the kernel,
+ // and should be NULL or point to a static buffer containing at
+ // least two 'long's.
+ static long InitAndGetCPU(unsigned *cpu, void *cache, // NOLINT 'long'.
+ void *unused);
+ static long GetCPUViaSyscall(unsigned *cpu, void *cache, // NOLINT 'long'.
+ void *unused);
+ typedef long (*GetCpuFn)(unsigned *cpu, void *cache, // NOLINT 'long'.
+ void *unused);
+
+ // This function pointer may point to InitAndGetCPU,
+ // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
+ static GetCpuFn getcpu_fn_;
+
+ friend int GetCPU(void); // Needs access to getcpu_fn_.
+
+ DISALLOW_COPY_AND_ASSIGN(VDSOSupport);
+};
+
+// Same as sched_getcpu() on later glibc versions.
+// Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present,
+// otherwise use syscall(SYS_getcpu,...).
+// May return -1 with errno == ENOSYS if the kernel doesn't
+// support SYS_getcpu.
+int GetCPU();
+} // namespace base
+
+#endif // __ELF__ and HAVE_ELF32_VERSYM
+
+#endif // BASE_VDSO_SUPPORT_H_
diff --git a/src/central_freelist.cc b/src/central_freelist.cc
index 8fdfc10..674ff9b 100644
--- a/src/central_freelist.cc
+++ b/src/central_freelist.cc
@@ -270,7 +270,7 @@ void CentralFreeList::Populate() {
if (span) Static::pageheap()->RegisterSizeClass(span, size_class_);
}
if (span == NULL) {
- MESSAGE("allocation failed: %d\n", errno);
+ MESSAGE("tcmalloc: allocation failed", npages << kPageShift);
lock_.Lock();
return;
}
diff --git a/src/common.cc b/src/common.cc
index fabcab1..d89ba83 100644
--- a/src/common.cc
+++ b/src/common.cc
@@ -30,6 +30,7 @@
// ---
// Author: Sanjay Ghemawat <opensource@google.com>
+#include "config.h"
#include "system-alloc.h"
#include "config.h"
#include "common.h"
@@ -179,20 +180,20 @@ void SizeMap::Init() {
}
}
-void SizeMap::Dump() {
+void SizeMap::Dump(TCMalloc_Printer* out) {
// Dump class sizes and maximum external wastage per size class
for (size_t cl = 1; cl < kNumClasses; ++cl) {
const int alloc_size = class_to_pages_[cl] << kPageShift;
const int alloc_objs = alloc_size / class_to_size_[cl];
const int min_used = (class_to_size_[cl-1] + 1) * alloc_objs;
const int max_waste = alloc_size - min_used;
- MESSAGE("SC %3d [ %8d .. %8d ] from %8d ; %2.0f%% maxwaste\n",
- int(cl),
- int(class_to_size_[cl-1] + 1),
- int(class_to_size_[cl]),
- int(class_to_pages_[cl] << kPageShift),
- max_waste * 100.0 / alloc_size
- );
+ out->printf("SC %3d [ %8d .. %8d ] from %8d ; %2.0f%% maxwaste\n",
+ int(cl),
+ int(class_to_size_[cl-1] + 1),
+ int(class_to_size_[cl]),
+ int(class_to_pages_[cl] << kPageShift),
+ max_waste * 100.0 / alloc_size
+ );
}
}
diff --git a/src/common.h b/src/common.h
index 6164dfa..1721ded 100644
--- a/src/common.h
+++ b/src/common.h
@@ -69,6 +69,8 @@ static const size_t kNumClasses = 61;
// should not hurt to make this list somewhat big because the
// scavenging code will shrink it down when its contents are not in use.
static const int kMaxFreeListLength = 256;
+// Same as above but used when --tcmalloc_use_dynamic_thread_cache_sizes=true.
+static const int kMaxDynamicFreeListLength = 8192;
static const Length kMaxValidPages = (~static_cast<Length>(0)) >> kPageShift;
@@ -90,7 +92,7 @@ class SizeMap {
// it too big may temporarily cause unnecessary memory wastage in the
// per-thread free list until the scavenger cleans up the list.
int num_objects_to_move_[kNumClasses];
-
+
//-------------------------------------------------------------------
// Mapping from size to size_class and vice versa
//-------------------------------------------------------------------
@@ -171,7 +173,7 @@ class SizeMap {
}
// Dump contents of the computed size map
- void Dump();
+ void Dump(TCMalloc_Printer* out);
};
// Allocates "bytes" worth of memory and returns it. Increments
diff --git a/src/config.h.in b/src/config.h.in
index 142dd4d..d225d49 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -42,6 +42,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
+/* Define to 1 if the system has the type `Elf32_Versym'. */
+#undef HAVE_ELF32_VERSYM
+
/* Define to 1 if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
@@ -120,6 +123,9 @@
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
@@ -129,6 +135,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
/* Define to 1 if compiler supports __thread */
#undef HAVE_TLS
@@ -141,6 +150,9 @@
/* Define to 1 if you have the <unwind.h> header file. */
#undef HAVE_UNWIND_H
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
/* define if your compiler has __attribute__ */
#undef HAVE___ATTRIBUTE__
diff --git a/src/google/heap-checker.h b/src/google/heap-checker.h
index af27c4c..89a2512 100644
--- a/src/google/heap-checker.h
+++ b/src/google/heap-checker.h
@@ -224,38 +224,22 @@ class PERFTOOLS_DLL_DECL HeapLeakChecker {
// ----------------------------------------------------------------------- //
// Various helpers
- // Type for DumpProfileLocked
- enum ProfileType { START_PROFILE, END_PROFILE };
+ // Create the name of the heap profile file.
+ // Should be deleted via Allocator::Free().
+ char* MakeProfileNameLocked();
- // Create the name of the heap profile file of profile_type;
- // to be deleted via Allocator::Free().
- char* MakeProfileNameLocked(ProfileType profile_type);
-
- // Helper for dumping start/end heap leak checking profiles
- // and getting the byte/object counts.
- void DumpProfileLocked(ProfileType profile_type, const void* self_stack_top,
- size_t* alloc_bytes, size_t* alloc_objects);
// Helper for constructors
- void Create(const char *name);
+ void Create(const char *name, bool make_start_snapshot);
// Types for DoNoLeaks and its helpers.
enum CheckType { SAME_HEAP, NO_LEAKS };
enum CheckFullness { USE_PPROF, USE_COUNTS };
enum ReportMode { PPROF_REPORT, NO_REPORT };
- // Helpers for *NoLeaks and *SameHeap
+ // Helper for *NoLeaks and *SameHeap
bool DoNoLeaks(CheckType check_type,
CheckFullness fullness,
ReportMode report_mode);
- struct LeakCheckResult; // defined in .cc
- LeakCheckResult DoLeakCheckLocked();
- bool DoNoLeaksOnceLocked(CheckType check_type,
- CheckFullness fullness,
- ReportMode report_mode);
-
- // Handle a leak profile file: delete it if !keep_profiles_.
- void HandleProfile(ProfileType profile_type);
- void HandleProfileLocked(ProfileType profile_type);
// These used to be public, but they are now deprecated.
// Will remove entirely when all internal uses are fixed.
@@ -273,7 +257,9 @@ class PERFTOOLS_DLL_DECL HeapLeakChecker {
// Helper for DisableChecksIn
static void DisableChecksInLocked(const char* pattern);
- // Helper for DisableChecksToHereFrom
+ // Disable checks based on stack trace entry at a depth <=
+ // max_depth. Used to hide allocations done inside some special
+ // libraries.
static void DisableChecksFromToLocked(const void* start_address,
const void* end_address,
int max_depth);
@@ -382,8 +368,12 @@ class PERFTOOLS_DLL_DECL HeapLeakChecker {
class SpinLock* lock_; // to make HeapLeakChecker objects thread-safe
const char* name_; // our remembered name (we own it)
// NULL means this leak checker is a noop
- size_t start_inuse_bytes_; // bytes in use at our construction
- size_t start_inuse_allocs_; // allocations in use at our construction
+
+ // Snapshot taken when the checker was created. May be NULL
+ // for the global heap checker object. We use void* instead of
+ // HeapProfileTable::Snapshot* to avoid including heap-profile-table.h.
+ void* start_snapshot_;
+
bool has_checked_; // if we have done the leak check, so these are ready:
ssize_t inuse_bytes_increase_; // bytes-in-use increase for this checker
ssize_t inuse_allocs_increase_; // allocations-in-use increase
diff --git a/src/google/malloc_extension.h b/src/google/malloc_extension.h
index e1d3425..2e05329 100644
--- a/src/google/malloc_extension.h
+++ b/src/google/malloc_extension.h
@@ -55,6 +55,9 @@
static const int kMallocHistogramSize = 64;
+// One day, we could support other types of writers (perhaps for C?)
+typedef std::string MallocExtensionWriter;
+
// The default implementations of the following routines do nothing.
// All implementations should be thread-safe; the current one
// (TCMallocImplementation) is.
@@ -84,23 +87,17 @@ class PERFTOOLS_DLL_DECL MallocExtension {
// REQUIRES: buffer_length > 0.
virtual void GetStats(char* buffer, int buffer_length);
- // Get a string that contains a sample of live objects and the stack
- // traces that allocated these objects. The format of the returned
- // string is equivalent to the output of the heap profiler and can
+ // Outputs to "writer" a sample of live objects and the stack traces
+ // that allocated these objects. The format of the returned output
+ // is equivalent to the output of the heap profiler and can
// therefore be passed to "pprof".
- //
- // The generated data is *appended* to "*result". I.e., the old
- // contents of "*result" are preserved.
- virtual void GetHeapSample(std::string* result);
+ virtual void GetHeapSample(MallocExtensionWriter* writer);
- // Get a string that contains the stack traces that caused growth in
- // the addres sspace size. The format of the returned string is
+ // Outputs to "writer" the stack traces that caused growth in the
+ // address space size. The format of the returned output is
// equivalent to the output of the heap profiler and can therefore
// be passed to "pprof".
- //
- // The generated data is *appended* to "*result". I.e., the old
- // contents of "*result" are preserved.
- virtual void GetHeapGrowthStacks(std::string* result);
+ virtual void GetHeapGrowthStacks(MallocExtensionWriter* writer);
// -------------------------------------------------------------------
// Control operations for getting and setting malloc implementation
@@ -181,6 +178,24 @@ class PERFTOOLS_DLL_DECL MallocExtension {
// Gets the release rate. Returns a value < 0 if unknown.
virtual double GetMemoryReleaseRate();
+ // Returns the estimated number of bytes that will be allocated for
+ // a request of "size" bytes. This is an estimate: an allocation of
+ // SIZE bytes may reserve more bytes, but will never reserve less.
+ // (Currently only implemented in tcmalloc, other implementations
+ // always return SIZE.)
+ virtual size_t GetEstimatedAllocatedSize(size_t size);
+
+ // Returns the actual number of bytes reserved by tcmalloc for the
+ // pointer p. This number may be equal to or greater than
+ // the number of bytes requested when p was allocated.
+ // p must have been allocated by this malloc implementation,
+ // must not be an interior pointer -- that is, must be exactly
+ // the pointer returned to by malloc() et al., not some offset
+ // from that -- and should not have been freed yet. p may be NULL.
+ // (Currently only implemented in tcmalloc; other implementations
+ // will return 0.)
+ virtual size_t GetAllocatedSize(void* p);
+
// The current malloc implementation. Always non-NULL.
static MallocExtension* instance();
@@ -189,13 +204,14 @@ class PERFTOOLS_DLL_DECL MallocExtension {
static void Register(MallocExtension* implementation);
protected:
- // Get a list of stack traces of sampled allocation points.
- // Returns a pointer to a "new[]-ed" result array.
+ // Get a list of stack traces of sampled allocation points. Returns
+ // a pointer to a "new[]-ed" result array, and stores the sample
+ // period in "sample_period".
//
// The state is stored as a sequence of adjacent entries
// in the returned array. Each entry has the following form:
// uintptr_t count; // Number of objects with following trace
- // uintptr_t size; // Size of object
+ // uintptr_t size; // Total size of objects with following trace
// uintptr_t depth; // Number of PC values in stack trace
// void* stack[depth]; // PC values that form the stack trace
//
@@ -207,7 +223,7 @@ class PERFTOOLS_DLL_DECL MallocExtension {
//
// This is an internal extension. Callers should use the more
// convenient "GetHeapSample(string*)" method defined above.
- virtual void** ReadStackTraces();
+ virtual void** ReadStackTraces(int* sample_period);
// Like ReadStackTraces(), but returns stack traces that caused growth
// in the address space size.
diff --git a/src/google/malloc_extension_c.h b/src/google/malloc_extension_c.h
index dd6fdec..b5e4df5 100644
--- a/src/google/malloc_extension_c.h
+++ b/src/google/malloc_extension_c.h
@@ -42,31 +42,41 @@
#include <stddef.h>
#include <sys/types.h>
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef PERFTOOLS_DLL_DECL
+# ifdef _WIN32
+# define PERFTOOLS_DLL_DECL __declspec(dllimport)
+# else
+# define PERFTOOLS_DLL_DECL
+# endif
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
-bool MallocExtension_VerifyAllMemory();
-bool MallocExtension_VerifyAllMemory();
-bool MallocExtension_VerifyNewMemory(void* p);
-bool MallocExtension_VerifyArrayNewMemory(void* p);
-bool MallocExtension_VerifyMallocMemory(void* p);
-bool MallocExtension_MallocMemoryStats(int* blocks, size_t* total,
+bool PERFTOOLS_DLL_DECL MallocExtension_VerifyAllMemory();
+bool PERFTOOLS_DLL_DECL MallocExtension_VerifyAllMemory();
+bool PERFTOOLS_DLL_DECL MallocExtension_VerifyNewMemory(void* p);
+bool PERFTOOLS_DLL_DECL MallocExtension_VerifyArrayNewMemory(void* p);
+bool PERFTOOLS_DLL_DECL MallocExtension_VerifyMallocMemory(void* p);
+bool PERFTOOLS_DLL_DECL MallocExtension_MallocMemoryStats(int* blocks, size_t* total,
int histogram[kMallocHistogramSize]);
-void MallocExtension_GetStats(char* buffer, int buffer_length);
+void PERFTOOLS_DLL_DECL MallocExtension_GetStats(char* buffer, int buffer_length);
-/* NOTE: commented out because they require a c++ string.
- * TODO(csilvers): write a C version of these routines, that perhaps
- * take a fixed-size buffer.
+/* TODO(csilvers): write a C version of these routines, that perhaps
+ * takes a function ptr and a void *.
*/
/* void MallocExtension_GetHeapSample(string* result); */
/* void MallocExtension_GetHeapGrowthStacks(string* result); */
-bool MallocExtension_GetNumericProperty(const char* property, size_t* value);
-bool MallocExtension_SetNumericProperty(const char* property, size_t value);
-void MallocExtension_MarkThreadIdle();
-void MallocExtension_ReleaseFreeMemory();
+bool PERFTOOLS_DLL_DECL MallocExtension_GetNumericProperty(const char* property, size_t* value);
+bool PERFTOOLS_DLL_DECL MallocExtension_SetNumericProperty(const char* property, size_t value);
+void PERFTOOLS_DLL_DECL MallocExtension_MarkThreadIdle();
+void PERFTOOLS_DLL_DECL MallocExtension_ReleaseFreeMemory();
+size_t PERFTOOLS_DLL_DECL MallocExtension_GetEstimatedAllocatedSize(size_t size);
+size_t PERFTOOLS_DLL_DECL MallocExtension_GetAllocatedSize(void* p);
#ifdef __cplusplus
} // extern "C"
diff --git a/src/google/stacktrace.h b/src/google/stacktrace.h
index 598a308..8188ce3 100644
--- a/src/google/stacktrace.h
+++ b/src/google/stacktrace.h
@@ -80,6 +80,13 @@
extern PERFTOOLS_DLL_DECL int GetStackFrames(void** pcs, int* sizes, int max_depth,
int skip_count);
+// Same as above, but to be used from a signal handler. The "uc" parameter
+// should be the pointer to ucontext_t which was passed as the 3rd parameter
+// to sa_sigaction signal handler. It may help the unwinder to get a
+// better stack trace under certain conditions. The "uc" may safely be NULL.
+extern PERFTOOLS_DLL_DECL int GetStackFramesWithContext(void** pcs, int* sizes, int max_depth,
+ int skip_count, const void *uc);
+
// This is similar to the GetStackFrames routine, except that it returns
// the stack trace only, and not the stack frame sizes as well.
// Example:
@@ -99,4 +106,11 @@ extern PERFTOOLS_DLL_DECL int GetStackFrames(void** pcs, int* sizes, int max_dep
extern PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth,
int skip_count);
+// Same as above, but to be used from a signal handler. The "uc" parameter
+// should be the pointer to ucontext_t which was passed as the 3rd parameter
+// to sa_sigaction signal handler. It may help the unwinder to get a
+// better stack trace under certain conditions. The "uc" may safely be NULL.
+extern PERFTOOLS_DLL_DECL int GetStackTraceWithContext(void** result, int max_depth,
+ int skip_count, const void *uc);
+
#endif /* GOOGLE_STACKTRACE_H_ */
diff --git a/src/heap-checker.cc b/src/heap-checker.cc
index 084f1ec..ef37df2 100644
--- a/src/heap-checker.cc
+++ b/src/heap-checker.cc
@@ -152,8 +152,10 @@ DEFINE_bool(heap_check_ignore_global_live,
DEFINE_bool(heap_check_identify_leaks,
EnvToBool("HEAP_CHECK_IDENTIFY_LEAKS", false),
- "If heap check should generate the addresses of the leaked objects "
- "in the memory leak profiles");
+ "If heap check should generate the addresses of the leaked "
+ "objects in the memory leak profiles. This may be useful "
+ "in tracking down leaks where only a small fraction of "
+ "objects allocated at the same stack trace are leaked.");
DEFINE_bool(heap_check_ignore_thread_live,
EnvToBool("HEAP_CHECK_IGNORE_THREAD_LIVE", true),
@@ -228,6 +230,7 @@ static const string* profile_name_prefix = NULL;
// Gets assigned once when leak checking is turned on,
// then main_heap_checker is never deleted.
static HeapLeakChecker* main_heap_checker = NULL;
+
// Whether we will use main_heap_checker to do a check at program exit
// automatically. In any case user can ask for more checks on main_heap_checker
// via GlobalChecker().
@@ -242,6 +245,7 @@ static HeapProfileTable* heap_profile = NULL;
// If we are doing (or going to do) any kind of heap-checking.
static bool heap_checker_on = false;
+
// pid of the process that does whole-program heap leak checking
static pid_t heap_checker_pid = 0;
@@ -341,13 +345,6 @@ struct AllocObject {
: ptr(p), size(s), place(l) { }
};
-typedef basic_string<char, char_traits<char>,
- STL_Allocator<char, HeapLeakChecker::Allocator>
- > HCL_string;
-// the disabled regexp accumulated
-// via HeapLeakChecker::DisableChecksIn
-static HCL_string* disabled_regexp = NULL;
-
// All objects (memory ranges) ignored via HeapLeakChecker::IgnoreObject
// Key is the object's address; value is its size.
typedef map<uintptr_t, size_t, less<uintptr_t>,
@@ -370,6 +367,11 @@ typedef vector<AllocObject,
> LiveObjectsStack;
static LiveObjectsStack* live_objects = NULL;
+// A special string type that uses my allocator
+typedef basic_string<char, char_traits<char>,
+ STL_Allocator<char, HeapLeakChecker::Allocator>
+ > HCL_string;
+
// A placeholder to fill-in the starting values for live_objects
// for each library so we can keep the library-name association for logging.
typedef map<HCL_string, LiveObjectsStack, less<HCL_string>,
@@ -540,9 +542,11 @@ static void NewHook(const void* ptr, size_t size) {
if (addr < min_heap_address) min_heap_address = addr;
addr += size;
if (addr > max_heap_address) max_heap_address = addr;
- heap_profile->RecordAlloc(ptr, size, 0);
- if (ignore) {
- heap_profile->MarkAsIgnored(ptr);
+ if (heap_checker_on) {
+ heap_profile->RecordAlloc(ptr, size, 0);
+ if (ignore) {
+ heap_profile->MarkAsIgnored(ptr);
+ }
}
}
RAW_VLOG(8, "Alloc Recorded: %p of %"PRIuS"", ptr, size);
@@ -553,7 +557,7 @@ static void DeleteHook(const void* ptr) {
if (ptr != NULL) {
RAW_VLOG(7, "Recording Free %p", ptr);
{ SpinLockHolder l(&heap_checker_lock);
- heap_profile->RecordFree(ptr);
+ if (heap_checker_on) heap_profile->RecordFree(ptr);
}
RAW_VLOG(8, "Free Recorded: %p", ptr);
}
@@ -793,8 +797,8 @@ void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library,
// (any library can be, of course, but this one often is because speed
// is so important for making crypto usable). We ignore all its
// allocations because we can't see the call stacks. We'd prefer
- // HeapLeakChecker::DisableChecksIn("default_malloc_ex"
- // "|default_realloc_ex")
+ // to ignore allocations done in files/symbols that match
+ // "default_malloc_ex|default_realloc_ex"
// but that doesn't work when the end-result binary is stripped.
) {
depth = 1; // only disable allocation calls directly from the library code
@@ -1400,38 +1404,7 @@ static SpinLock alignment_checker_lock(SpinLock::LINKER_INITIALIZED);
// static
void HeapLeakChecker::DisableChecksIn(const char* pattern) {
- SpinLockHolder l(&heap_checker_lock);
- if (!heap_checker_on) return;
- DisableChecksInLocked(pattern);
-}
-
-// static
-void* HeapLeakChecker::GetDisableChecksStart() {
- { SpinLockHolder l(&heap_checker_lock);
- if (!heap_checker_on) return NULL;
- }
- void* start_address = NULL;
- if (GetStackTrace(&start_address, 1, 1) != 1) {
- RAW_LOG(FATAL, "Can't get stack trace");
- }
- return start_address;
-}
-
-// static
-void HeapLeakChecker::DisableChecksToHereFrom(const void* start_address) {
- { SpinLockHolder l(&heap_checker_lock);
- if (!heap_checker_on) return;
- }
- void* end_address_ptr = NULL;
- if (GetStackTrace(&end_address_ptr, 1, 1) != 1) {
- RAW_LOG(FATAL, "Can't get stack trace");
- }
- const void* end_address = end_address_ptr;
- if (start_address > end_address) swap(start_address, end_address);
- SpinLockHolder l(&heap_checker_lock);
- DisableChecksFromToLocked(start_address, end_address, 10000);
- // practically no stack depth limit:
- // our heap_profile keeps much shorter stack traces
+ RAW_LOG(WARNING, "DisableChecksIn(%s) is ignored", pattern);
}
// static
@@ -1480,63 +1453,25 @@ void HeapLeakChecker::UnIgnoreObject(const void* ptr) {
// HeapLeakChecker non-static functions
//----------------------------------------------------------------------
-char* HeapLeakChecker::MakeProfileNameLocked(ProfileType profile_type) {
+char* HeapLeakChecker::MakeProfileNameLocked() {
RAW_DCHECK(lock_.IsHeld(), "");
RAW_DCHECK(heap_checker_lock.IsHeld(), "");
const int len = profile_name_prefix->size() + strlen(name_) + 5 +
strlen(HeapProfileTable::kFileExt) + 1;
char* file_name = reinterpret_cast<char*>(Allocator::Allocate(len));
- snprintf(file_name, len, "%s.%s%s%s",
+ snprintf(file_name, len, "%s.%s-end%s",
profile_name_prefix->c_str(), name_,
- profile_type == START_PROFILE ? "-beg" : "-end",
HeapProfileTable::kFileExt);
return file_name;
}
-void HeapLeakChecker::DumpProfileLocked(ProfileType profile_type,
- const void* self_stack_top,
- size_t* alloc_bytes,
- size_t* alloc_objects) {
- RAW_DCHECK(lock_->IsHeld(), "");
- RAW_DCHECK(heap_checker_lock.IsHeld(), "");
- RAW_VLOG(1, "%s check \"%s\"%s",
- (profile_type == START_PROFILE ? "Starting"
- : "At an end point for"),
- name_,
- (pointer_source_alignment == 1 ? " w/o pointer alignment" : ""));
- // Sanity check that nobody is messing with the hooks we need:
- // Important to have it here: else we can misteriously SIGSEGV
- // in IgnoreLiveObjectsLocked inside ListAllProcessThreads's callback
- // by looking into a region that got unmapped w/o our knowledge.
- MemoryRegionMap::CheckMallocHooks();
- if (MallocHook::GetNewHook() != NewHook ||
- MallocHook::GetDeleteHook() != DeleteHook) {
- RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. "
- "Are you using another MallocHook client? "
- "Use --heap_check=\"\" to avoid this conflict.");
- }
- // Make the heap profile, other threads are locked out.
- const int alloc_count = Allocator::alloc_count();
- IgnoreAllLiveObjectsLocked(self_stack_top);
- char* file_name = MakeProfileNameLocked(profile_type);
- HeapProfileTable::Stats stats;
- bool ok = heap_profile->DumpNonLiveProfile(
- file_name, FLAGS_heap_check_identify_leaks, &stats);
- RAW_CHECK(ok, "No sense to continue");
- *alloc_bytes = stats.alloc_size - stats.free_size;
- *alloc_objects = stats.allocs - stats.frees;
- Allocator::Free(file_name);
- // Check that we made no leaks ourselves:
- if (Allocator::alloc_count() != alloc_count) {
- RAW_LOG(FATAL, "Internal HeapChecker leak of %d objects",
- Allocator::alloc_count() - alloc_count);
- }
-}
-
-void HeapLeakChecker::Create(const char *name) {
+void HeapLeakChecker::Create(const char *name, bool make_start_snapshot) {
SpinLockHolder l(lock_);
name_ = NULL; // checker is inactive
+ start_snapshot_ = NULL;
has_checked_ = false;
+ inuse_bytes_increase_ = 0;
+ inuse_allocs_increase_ = 0;
keep_profiles_ = false;
char* n = new char[strlen(name) + 1]; // do this before we lock
IgnoreObject(n); // otherwise it might be treated as live due to our stack
@@ -1548,13 +1483,16 @@ void HeapLeakChecker::Create(const char *name) {
RAW_DCHECK(strchr(name, '/') == NULL, "must be a simple name");
memcpy(n, name, strlen(name) + 1);
name_ = n; // checker is active
- // Use our stack ptr to make stack data live:
- int a_local_var;
- DumpProfileLocked(START_PROFILE, &a_local_var,
- &start_inuse_bytes_, &start_inuse_allocs_);
+ if (make_start_snapshot) {
+ start_snapshot_ = heap_profile->TakeSnapshot();
+ }
+
+ const HeapProfileTable::Stats& t = heap_profile->total();
+ const size_t start_inuse_bytes = t.alloc_size - t.free_size;
+ const size_t start_inuse_allocs = t.allocs - t.frees;
RAW_VLOG(1, "Start check \"%s\" profile: %"PRIuS" bytes "
- "in %"PRIuS" objects",
- name_, start_inuse_bytes_, start_inuse_allocs_);
+ "in %"PRIuS" objects",
+ name_, start_inuse_bytes, start_inuse_allocs);
} else {
RAW_LOG(WARNING, "Heap checker is not active, "
"hence checker \"%s\" will do nothing!", name);
@@ -1569,11 +1507,23 @@ void HeapLeakChecker::Create(const char *name) {
HeapLeakChecker::HeapLeakChecker(const char *name) : lock_(new SpinLock) {
RAW_DCHECK(strcmp(name, "_main_") != 0, "_main_ is reserved");
- Create(name);
+ Create(name, true/*create start_snapshot_*/);
}
HeapLeakChecker::HeapLeakChecker() : lock_(new SpinLock) {
- Create("_main_");
+ if (FLAGS_heap_check_before_constructors) {
+ // We want to check for leaks of objects allocated during global
+ // constructors (i.e., objects allocated already). So we do not
+ // create a baseline snapshot and hence check for leaks of objects
+ // that may have already been created.
+ Create("_main_", false);
+ } else {
+ // We want to ignore leaks of objects allocated during global
+ // constructors (i.e., objects allocated already). So we snapshot
+ // the current heap contents and use them as a baseline that is
+ // not reported by the leak checker.
+ Create("_main_", true);
+ }
}
ssize_t HeapLeakChecker::BytesLeaked() const {
@@ -1592,116 +1542,58 @@ ssize_t HeapLeakChecker::ObjectsLeaked() const {
return inuse_allocs_increase_;
}
-// pprof command execution mode:
-enum RunMode {
- TO_RUN_NOW, // to be run from within the test itself
- TO_RUN_BY_USER // to be run manually by a human via cut and paste
-};
-
// Save pid of main thread for using in naming dump files
static int32 main_thread_pid = getpid();
#ifdef HAVE_PROGRAM_INVOCATION_NAME
extern char* program_invocation_name;
extern char* program_invocation_short_name;
static const char* invocation_name() { return program_invocation_short_name; }
-static const char* invocation_path() { return program_invocation_name; }
+static string invocation_path() { return program_invocation_name; }
#else
static const char* invocation_name() { return "<your binary>"; }
-static const char* invocation_path() { return "<your binary>"; }
+static string invocation_path() { return "<your binary>"; }
#endif
-static void MakeCommand(RunMode run_mode,
- const char* basename,
- bool check_type_is_no_leaks,
- bool use_initial_profile,
- const string& prefix,
- const string& pprof_path,
- string* beg_profile,
- string* end_profile,
- string* command) {
- string ignore_re;
- if (disabled_regexp) {
- ignore_re += " --ignore='^";
- ignore_re += disabled_regexp->c_str();
- ignore_re += "$'";
- }
- *command += pprof_path;
- if (use_initial_profile) {
- // compare against initial profile only if need to
- *beg_profile = prefix + "." + basename +
- "-beg" + HeapProfileTable::kFileExt;
- *command += string(" --base=\"") + *beg_profile + "\"";
- }
- if (check_type_is_no_leaks) *command += string(" --drop_negative");
- *end_profile = prefix + "." + basename + "-end" + HeapProfileTable::kFileExt;
- *command += string(" ") +
- invocation_path() +
- " \"" + *end_profile + "\"" + ignore_re + " --inuse_objects";
- if (!FLAGS_heap_check_identify_leaks) {
- *command += " --lines"; // important to catch leaks when we do not see them
- // via allocated byte/object count differences
- } else {
- *command += " --addresses"; // stronger than --lines and prints
- // unresolvable object addresses
- }
- *command += " --heapcheck";
-}
-
-static int GetStatusOutput(const char* command, string* output) {
- // We don't want the heapchecker to run in the child helper
- // processes that we fork() as part of this process' heap check.
-
- // setenv() can call realloc(), so we don't want to call it while
- // the heap profiling is disabled. Instead just overwrite the final
- // char of the env var name, so it has a different name and gets
- // ignored in the child. We assume the env looks like 'VAR=VALUE\0VAR=VALUE'
- char *env_heapcheck = getenv("HEAPCHECK");
- char *env_ldpreload = getenv("LD_PRELOAD");
-
- if (env_heapcheck) {
- assert(env_heapcheck[-1] == '=');
- env_heapcheck[-2] = '?';
- }
- if (env_ldpreload) {
- assert(env_ldpreload[-1] == '=');
- env_ldpreload[-2] = '?';
- }
-
- FILE* f = popen(command, "r");
- if (f == NULL) {
- fprintf(stderr, "popen(%s) failed!\n", command); // This shouldn't happen
- exit(1);
- }
-
- if (env_heapcheck) env_heapcheck[-2] = 'K'; // last letter in heapchecK
- if (env_ldpreload) env_heapcheck[-2] = 'D'; // last letter in ldpreloaD
-
- const int kMaxOutputLine = 10000;
- char line[kMaxOutputLine];
- while (fgets(line, sizeof(line), f) != NULL) {
- if (output)
- *output += line;
- }
-
- return pclose(f);
-}
-
-// RAW_LOG 'str' line by line to prevent its truncation in RAW_LOG:
-static void RawLogLines(LogSeverity severity, const string& str) {
- int p = 0;
- while (1) {
- int l = str.find('\n', p);
- if (l == string::npos) {
- if (str[p]) { // print last line if non empty
- RAW_LOG(severity, "%s", str.c_str() + p);
- }
- break;
- }
- const_cast<string&>(str)[l] = '\0'; // safe for our use case
- RAW_LOG(severity, "%s", str.c_str() + p);
- const_cast<string&>(str)[l] = '\n';
- p = l + 1;
- }
+// Prints commands that users can run to get more information
+// about the reported leaks. We have to suggest extra commands
+// for programs run on borg/mrtest/blaze.
+static void SuggestPprofCommand(const char* pprof_file_arg) {
+ // Copy argument since we may mutate it later
+ string pprof_file = pprof_file_arg;
+
+ // Extra help information to print for the user when the test is
+ // being run in a way where the straightforward pprof command will
+ // not suffice.
+ string extra_help;
+
+ // Common header info to print for remote runs
+ const string remote_header =
+ "This program is being executed remotely and therefore the pprof\n"
+ "command printed above will not work. Either run this program\n"
+ "locally, or adjust the pprof command as follows to allow it to\n"
+ "work on your local machine:\n";
+
+ // Extra command for fetching remote data
+ string fetch_cmd;
+
+ RAW_LOG(WARNING,
+ "\n\n"
+ "If the preceding stack traces are not enough to find "
+ "the leaks, try running THIS shell command:\n\n"
+ "%s%s %s \"%s\" --inuse_objects --lines --heapcheck "
+ " --edgefraction=1e-10 --nodefraction=1e-10 --gv\n"
+ "\n"
+ "%s"
+ "If you are still puzzled about why the leaks are "
+ "there, try rerunning this program with "
+ "HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with "
+ "HEAP_CHECK_MAX_POINTER_OFFSET=-1\n",
+ fetch_cmd.c_str(),
+ flags_heap_profile_pprof->c_str(),
+ invocation_path().c_str(),
+ pprof_file.c_str(),
+ extra_help.c_str()
+ );
}
bool HeapLeakChecker::DoNoLeaks(CheckType check_type,
@@ -1711,284 +1603,127 @@ bool HeapLeakChecker::DoNoLeaks(CheckType check_type,
// The locking also helps us keep the messages
// for the two checks close together.
SpinLockHolder al(&alignment_checker_lock);
- bool result;
- if (FLAGS_heap_check_test_pointer_alignment) {
- pointer_source_alignment = 1;
- bool result_wo_align = DoNoLeaksOnceLocked(check_type, fullness, NO_REPORT);
- pointer_source_alignment = kPointerSourceAlignment;
- result = DoNoLeaksOnceLocked(check_type, fullness, report_mode);
- if (!result) {
- if (result_wo_align) {
- RAW_LOG(WARNING, "Found no leaks without pointer alignment: "
- "something might be placing pointers at "
- "unaligned addresses! This needs to be fixed.");
- } else {
- RAW_LOG(INFO, "Found leaks without pointer alignment as well: "
- "unaligned pointers must not be the cause of leaks.");
- RAW_LOG(INFO, "--heap_check_test_pointer_alignment did not help to "
- "diagnose the leaks.");
- }
- }
- } else {
- result = DoNoLeaksOnceLocked(check_type, fullness, report_mode);
- if (!result) {
- if (!FLAGS_heap_check_identify_leaks) {
- RAW_LOG(INFO, "setenv HEAP_CHECK_IDENTIFY_LEAKS=1 and rerun to identify "
- "the addresses of all leaked objects; "
- "will be reported as fake immediate allocation callers");
+
+ HeapProfileTable::Snapshot* leaks = NULL;
+ char* pprof_file = NULL;
+
+ {
+ // Heap activity in other threads is paused during this function
+ // (i.e. until we got all profile difference info).
+ SpinLockHolder l(&heap_checker_lock);
+ if (heap_checker_on == false) {
+ if (name_ != NULL) { // leak checking enabled when created the checker
+ RAW_LOG(WARNING, "Heap leak checker got turned off after checker "
+ "\"%s\" has been created, no leak check is being done for it!",
+ name_);
}
- RAW_LOG(INFO, "If you are totally puzzled about why the leaks are there, "
- "try rerunning it with "
- "setenv HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with "
- "setenv HEAP_CHECK_MAX_POINTER_OFFSET=-1");
+ return true;
}
- }
- if (result && FLAGS_heap_check_max_pointer_offset == -1) {
- RAW_LOG(WARNING, "Found no leaks without max_pointer_offset restriction: "
- "it's possible that the default value of "
- "heap_check_max_pointer_offset flag is too low. "
- "Do you use pointers with larger than that offsets "
- "pointing in the middle of heap-allocated objects?");
- }
- return result;
-}
-// What DoLeakCheckLocked below returns.
-struct HeapLeakChecker::LeakCheckResult {
- bool did_nothing;
- const string* profile_prefix;
- const string* pprof_path;
- int64 live_objects;
- int64 live_bytes;
- bool use_initial_profile;
-};
+ // Keep track of number of internally allocated objects so we
+ // can detect leaks in the heap-leak-checket itself
+ const int initial_allocs = Allocator::alloc_count();
-// Part of DoNoLeaksOnceLocked below:
-// does the things requiring heap_checker_lock and MemoryRegionMap::Lock
-// and returns some info to be accessed w/o these locks.
-HeapLeakChecker::LeakCheckResult HeapLeakChecker::DoLeakCheckLocked() {
- RAW_DCHECK(lock_->IsHeld(), "");
- RAW_DCHECK(alignment_checker_lock.IsHeld(), "");
- LeakCheckResult result;
- // Heap activity in other threads is paused during this function
- // (i.e. until we got all profile difference info).
- SpinLockHolder l(&heap_checker_lock);
- if (heap_checker_on == false) {
- if (name_ != NULL) { // had leak checking enabled when created the checker
- RAW_LOG(FATAL, "Heap leak checker must stay enabled during "
- "the lifetime of a HeapLeakChecker object");
+ if (name_ == NULL) {
+ RAW_LOG(FATAL, "Heap leak checker must not be turned on "
+ "after construction of a HeapLeakChecker");
}
- result.did_nothing = true;
- return result;
- }
- result.did_nothing = false;
- if (name_ == NULL) {
- RAW_LOG(FATAL, "Heap profiling must be not turned on "
- "after construction of a HeapLeakChecker");
- }
- MemoryRegionMap::LockHolder ml;
- // Use our stack ptr to make stack data live:
- int a_local_var;
- size_t end_inuse_bytes;
- size_t end_inuse_allocs;
- DumpProfileLocked(END_PROFILE, &a_local_var,
- &end_inuse_bytes, &end_inuse_allocs);
- // DumpProfileLocked via IgnoreAllLiveObjectsLocked sets these:
- result.live_objects = live_objects_total;
- result.live_bytes = live_bytes_total;
- result.use_initial_profile =
- !(FLAGS_heap_check_before_constructors && this == main_heap_checker);
- if (!result.use_initial_profile) { // compare against empty initial profile
- start_inuse_bytes_ = 0;
- start_inuse_allocs_ = 0;
- }
- RAW_VLOG(1, "End check \"%s\" profile: %"PRIuS" bytes in %"PRIuS" objects",
- name_, end_inuse_bytes, end_inuse_allocs);
- inuse_bytes_increase_ = static_cast<ssize_t>(end_inuse_bytes -
- start_inuse_bytes_);
- inuse_allocs_increase_ = static_cast<ssize_t>(end_inuse_allocs -
- start_inuse_allocs_);
- has_checked_ = true;
- // These two will not disappear or change after the heap_checker_lock is
- // released getting out of this scope
- // (they are set once before control can get here):
- result.profile_prefix = profile_name_prefix;
- result.pprof_path = flags_heap_profile_pprof;
- return result;
-}
-// Expects lock_ and alignment_checker_lock held, and acquires
-// heap_checker_lock and MemoryRegionMap::Lock via DoLeakCheckLocked.
-// Used only by DoNoLeaks above.
-bool HeapLeakChecker::DoNoLeaksOnceLocked(CheckType check_type,
- CheckFullness fullness,
- ReportMode report_mode) {
- RAW_DCHECK(lock_->IsHeld(), "");
- RAW_DCHECK(alignment_checker_lock.IsHeld(), "");
-
- const LeakCheckResult result = DoLeakCheckLocked();
- if (result.did_nothing) return true;
-
- // Now we see from the two allocated byte/object differences
- // and the dumped heap profiles if there are really leaks
- // and report the result:
-
- bool see_leaks =
- check_type == SAME_HEAP
- ? (inuse_bytes_increase_ != 0 || inuse_allocs_increase_ != 0)
- : (inuse_bytes_increase_ > 0 || inuse_allocs_increase_ > 0);
- bool reported_no_leaks = false;
- if (see_leaks || fullness == USE_PPROF) {
- const bool pprof_can_ignore = disabled_regexp != NULL;
- string beg_profile;
- string end_profile;
- string command;
- MakeCommand(TO_RUN_NOW, name_, check_type == NO_LEAKS,
- result.use_initial_profile,
- *result.profile_prefix, *result.pprof_path,
- &beg_profile, &end_profile, &command);
- string dot_file = end_profile;
- dot_file.resize(dot_file.size() - 4 - strlen(HeapProfileTable::kFileExt));
- dot_file += HeapProfileTable::kFileExt;
- dot_file += ".dot";
- string const dot_command =
- command + " --edgefraction=1e-10 --nodefraction=1e-10 --dot"
- " > " + dot_file;
- command += " --text";
- // Make the user-executed command-line:
- string local_beg_profile;
- string local_end_profile;
- string local_command;
- string const profile_name = *result.profile_prefix;
- string const local_pprof_path = *result.pprof_path;
- MakeCommand(TO_RUN_BY_USER, name_, check_type == NO_LEAKS,
- result.use_initial_profile, profile_name, local_pprof_path,
- &local_beg_profile, &local_end_profile, &local_command);
- string gv_command;
- string gv_command_note;
- gv_command = local_command;
- gv_command += " --edgefraction=1e-10 --nodefraction=1e-10 --gv";
-
- if (see_leaks) {
- RAW_LOG(WARNING, "Heap memory leaks of %"PRIdS" bytes and/or "
- "%"PRIdS" allocations detected by check \"%s\".",
- inuse_bytes_increase_, inuse_allocs_increase_, name_);
- RAW_LOG(WARNING, "TO INVESTIGATE leaks RUN e.g. THIS shell command:\n"
- "\n%s\n", gv_command.c_str());
- }
- string output;
- bool checked_leaks = true;
- if ((see_leaks && report_mode == PPROF_REPORT) ||
- fullness == USE_PPROF) {
- if (access(result.pprof_path->c_str(), X_OK|R_OK) != 0) {
- RAW_LOG(WARNING, "Skipping pprof check: could not run it at %s",
- result.pprof_path->c_str());
- checked_leaks = false;
- } else {
- RAW_VLOG(2, "Running pprof command: \"%s\"", command.c_str());
- // We expect 0 exit code and an empty stdout and stderr
- // from pprof that saw empty profile (difference):
- checked_leaks = GetStatusOutput(command.c_str(), &output) == 0;
- RAW_VLOG(2, "pprof produced \"%s\"", output.c_str());
- }
- if (see_leaks && pprof_can_ignore && output.empty() && checked_leaks) {
- RAW_LOG(WARNING, "These must be leaks that we disabled"
- " (pprof succeeded)! This check WILL FAIL"
- " if the binary is strip'ped!");
- see_leaks = false;
- reported_no_leaks = true;
- }
- // Do not fail the check just due to us being a stripped binary:
- if (!see_leaks && strstr(output.c_str(), "nm: ") != NULL &&
- strstr(output.c_str(), ": no symbols") != NULL) {
- RAW_LOG(WARNING, "Dropping irrelevant pprof output \"%s\"",
- output.c_str());
- output.clear();
- }
- }
- // Make sure the profiles we created are still there.
- if (access(end_profile.c_str(), R_OK) != 0 ||
- (!beg_profile.empty() && access(beg_profile.c_str(), R_OK) != 0)) {
- RAW_LOG(FATAL, "One of the heap profiles is gone: %s %s",
- beg_profile.c_str(), end_profile.c_str());
- }
- if (!(see_leaks || checked_leaks)) {
- // Crash if something went wrong with executing pprof
- // and we rely on pprof to do its work:
- RAW_LOG(FATAL, "The following pprof command failed\n%s\n"
- "with this output:\n%s",
- command.c_str(), output.c_str());
- }
- if (see_leaks && result.use_initial_profile) {
- RAW_LOG(WARNING, "CAVEAT: Some of the reported leaks might have "
- "occurred before check \"%s\" was started!", name_);
+ MemoryRegionMap::LockHolder ml;
+ int a_local_var; // Use our stack ptr to make stack data live:
+
+ // Sanity check that nobody is messing with the hooks we need:
+ // Important to have it here: else we can misteriously SIGSEGV
+ // in IgnoreLiveObjectsLocked inside ListAllProcessThreads's callback
+ // by looking into a region that got unmapped w/o our knowledge.
+ MemoryRegionMap::CheckMallocHooks();
+ if (MallocHook::GetNewHook() != NewHook ||
+ MallocHook::GetDeleteHook() != DeleteHook) {
+ RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. "
+ "Are you using another MallocHook client? "
+ "Use --heap_check=\"\" to avoid this conflict.");
}
- if (!see_leaks && !output.empty()) {
- RAW_LOG(WARNING, "Tricky heap memory leaks of "
- "no bytes and no allocations "
- "detected by check \"%s\".", name_);
- RAW_LOG(WARNING, "TO INVESTIGATE leaks RUN e.g. THIS shell command:\n"
- "\n%s\n", gv_command.c_str());
- if (result.use_initial_profile) {
- RAW_LOG(WARNING, "CAVEAT: Some of the reported leaks might have "
- "occurred before check \"%s\" was started!", name_);
+
+ // Make the heap profile, other threads are locked out.
+ HeapProfileTable::Snapshot* base =
+ reinterpret_cast<HeapProfileTable::Snapshot*>(start_snapshot_);
+ IgnoreAllLiveObjectsLocked(&a_local_var);
+ leaks = heap_profile->NonLiveSnapshot(base);
+
+ inuse_bytes_increase_ = static_cast<ssize_t>(leaks->total().alloc_size);
+ inuse_allocs_increase_ = static_cast<ssize_t>(leaks->total().allocs);
+ if (leaks->Empty()) {
+ heap_profile->ReleaseSnapshot(leaks);
+ leaks = NULL;
+
+ // We can only check for internal leaks along the no-user-leak
+ // path since in the leak path we temporarily release
+ // heap_checker_lock and another thread can come in and disturb
+ // allocation counts.
+ if (Allocator::alloc_count() != initial_allocs) {
+ RAW_LOG(FATAL, "Internal HeapChecker leak of %d objects ; %d -> %d",
+ Allocator::alloc_count() - initial_allocs,
+ initial_allocs, Allocator::alloc_count());
}
- see_leaks = true;
- }
- if (see_leaks && !gv_command_note.empty()) {
- RAW_LOG(WARNING, "NOTE:\n\n%s", gv_command_note.c_str());
- }
- if (see_leaks && report_mode == PPROF_REPORT) {
- if (checked_leaks) {
- RAW_LOG(ERROR, "Below is (less informative) textual version "
- "of this pprof command's output:");
- RawLogLines(ERROR, output);
- string dot_output;
- RAW_VLOG(2, "Running pprof dot command: \"%s\"", dot_command.c_str());
- int code = GetStatusOutput(dot_command.c_str(), &dot_output);
- if (code != 0 || !dot_output.empty()) {
- RAW_LOG(ERROR,
- "This dot pprof command failed: \"%s\"\n"
- "with exit code %d, output: \"%s\"",
- dot_command.c_str(), code, dot_output.c_str());
- }
+ } else if (FLAGS_heap_check_test_pointer_alignment) {
+ // Try with reduced pointer aligment
+ pointer_source_alignment = 1;
+ IgnoreAllLiveObjectsLocked(&a_local_var);
+ HeapProfileTable::Snapshot* leaks_wo_align =
+ heap_profile->NonLiveSnapshot(base);
+ pointer_source_alignment = kPointerSourceAlignment;
+ if (leaks_wo_align->Empty()) {
+ RAW_LOG(WARNING, "Found no leaks without pointer alignment: "
+ "something might be placing pointers at "
+ "unaligned addresses! This needs to be fixed.");
} else {
- RAW_LOG(ERROR, "The following pprof command failed\n%s\n"
- "with this output:\n%s",
- command.c_str(), output.c_str());
+ RAW_LOG(INFO, "Found leaks without pointer alignment as well: "
+ "unaligned pointers must not be the cause of leaks.");
+ RAW_LOG(INFO, "--heap_check_test_pointer_alignment did not help "
+ "to diagnose the leaks.");
}
+ heap_profile->ReleaseSnapshot(leaks_wo_align);
+ }
+
+ if (leaks != NULL) {
+ pprof_file = MakeProfileNameLocked();
}
}
- if (!see_leaks && !reported_no_leaks) {
+
+ has_checked_ = true;
+ if (leaks == NULL) {
+ if (FLAGS_heap_check_max_pointer_offset == -1) {
+ RAW_LOG(WARNING,
+ "Found no leaks without max_pointer_offset restriction: "
+ "it's possible that the default value of "
+ "heap_check_max_pointer_offset flag is too low. "
+ "Do you use pointers with larger than that offsets "
+ "pointing in the middle of heap-allocated objects?");
+ }
+ const HeapProfileTable::Stats& stats = heap_profile->total();
RAW_VLOG(heap_checker_info_level,
"No leaks found for check \"%s\" "
"(but no 100%% guarantee that there aren't any): "
"found %"PRId64" reachable heap objects of %"PRId64" bytes",
- name_, result.live_objects, result.live_bytes);
- }
- // Keep when had leaks or needed to look into profiles to convince ourselves
- // that there were no leaks:
- keep_profiles_ = see_leaks || reported_no_leaks;
- HandleProfileLocked(END_PROFILE);
- return !see_leaks;
-}
+ name_,
+ int64(stats.allocs - stats.frees),
+ int64(stats.alloc_size - stats.free_size));
+ } else {
+ leaks->ReportLeaks(name_, pprof_file);
+ if (FLAGS_heap_check_identify_leaks) {
+ leaks->ReportIndividualObjects();
+ }
-void HeapLeakChecker::HandleProfile(ProfileType profile_type) {
- SpinLockHolder l(lock_);
- HandleProfileLocked(profile_type);
-}
+ SuggestPprofCommand(pprof_file);
-void HeapLeakChecker::HandleProfileLocked(ProfileType profile_type) {
- const char* type = profile_type == START_PROFILE ? "beg" : "end";
- if (keep_profiles_) {
- RAW_VLOG(2, "Keeping %s profile for %s", type, name_);
- } else {
- SpinLockHolder l(&heap_checker_lock);
- char* beg_profile = MakeProfileNameLocked(profile_type);
- RAW_VLOG(2, "Removing %s profile %s", type, beg_profile);
- unlink(beg_profile);
- Allocator::Free(beg_profile);
+ {
+ SpinLockHolder l(&heap_checker_lock);
+ heap_profile->ReleaseSnapshot(leaks);
+ Allocator::Free(pprof_file);
+ }
}
+
+ return (leaks == NULL);
}
HeapLeakChecker::~HeapLeakChecker() {
@@ -1997,7 +1732,14 @@ HeapLeakChecker::~HeapLeakChecker() {
RAW_LOG(FATAL, "Some *NoLeaks|SameHeap method"
" must be called on any created HeapLeakChecker");
}
- HandleProfile(START_PROFILE);
+
+ // Deallocate any snapshot taken at start
+ if (start_snapshot_ != NULL) {
+ SpinLockHolder l(&heap_checker_lock);
+ heap_profile->ReleaseSnapshot(
+ reinterpret_cast<HeapProfileTable::Snapshot*>(start_snapshot_));
+ }
+
UnIgnoreObject(name_);
delete[] name_;
name_ = NULL;
@@ -2105,13 +1847,6 @@ static bool internal_init_start_has_run = false;
}
}
- // make an indestructible copy for heap leak checking
- // happening after global variable destruction
- string* pprof_path = new string(FLAGS_heap_profile_pprof);
- { SpinLockHolder l(&heap_checker_lock);
- flags_heap_profile_pprof = pprof_path;
- }
-
// Set all flags
if (FLAGS_heap_check == "minimal") {
// The least we can check.
@@ -2213,7 +1948,7 @@ static bool internal_init_start_has_run = false;
// If this happens, it is a BUILD bug to be fixed.
RAW_VLOG(heap_checker_info_level,
- "WARNING: Heap leak checker is active "
+ "WARNING: Perftools heap leak checker is active "
"-- Performance may suffer");
if (FLAGS_heap_check != "local") {
@@ -2406,7 +2141,7 @@ void HeapLeakChecker::TurnItselfOffLocked() {
FLAGS_heap_check = ""; // for users who test for it
if (constructor_heap_profiling) {
RAW_CHECK(heap_checker_on, "");
- RAW_VLOG(heap_checker_info_level, "Turning heap leak checking off");
+ RAW_VLOG(heap_checker_info_level, "Turning perftools heap leak checking off");
heap_checker_on = false;
// Unset our hooks checking they were the ones set:
if (MallocHook::SetNewHook(NULL) != NewHook ||
@@ -2417,7 +2152,6 @@ void HeapLeakChecker::TurnItselfOffLocked() {
}
Allocator::DeleteAndNull(&heap_profile);
// free our optional global data:
- Allocator::DeleteAndNullIfNot(&disabled_regexp);
Allocator::DeleteAndNullIfNot(&ignored_objects);
Allocator::DeleteAndNullIfNot(&disabled_ranges);
Allocator::DeleteAndNullIfNot(&global_region_caller_ranges);
@@ -2529,14 +2263,12 @@ void HeapLeakChecker_AfterDestructors() {
}
if (FLAGS_heap_check_after_destructors) {
if (HeapLeakChecker::DoMainHeapCheck()) {
- poll(NULL, 0, 500);
+ poll(0, 0, 500);
// Need this hack to wait for other pthreads to exit.
// Otherwise tcmalloc find errors
// on a free() call from pthreads.
}
}
- HeapLeakChecker* hc = HeapLeakChecker::GlobalChecker();
- if (hc) hc->HandleProfile(HeapLeakChecker::START_PROFILE);
SpinLockHolder l(&heap_checker_lock);
RAW_CHECK(!do_main_heap_check, "should have done it");
}
@@ -2548,19 +2280,6 @@ void HeapLeakChecker_AfterDestructors() {
// These functions are at the end of the file to prevent their inlining:
// static
-void HeapLeakChecker::DisableChecksInLocked(const char* pattern) {
- RAW_DCHECK(heap_checker_lock.IsHeld(), "");
- // make disabled_regexp
- if (disabled_regexp == NULL) {
- disabled_regexp = new(Allocator::Allocate(sizeof(HCL_string))) HCL_string;
- }
- RAW_VLOG(1, "Disabling leak checking in stack traces "
- "under frames maching \"%s\"", pattern);
- if (disabled_regexp->size()) *disabled_regexp += '|';
- *disabled_regexp += pattern;
-}
-
-// static
void HeapLeakChecker::DisableChecksFromToLocked(const void* start_address,
const void* end_address,
int max_depth) {
diff --git a/src/heap-profile-table.cc b/src/heap-profile-table.cc
index f0ca062..aaa4a2f 100644
--- a/src/heap-profile-table.cc
+++ b/src/heap-profile-table.cc
@@ -37,6 +37,12 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h> // for write()
#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h> // for socketpair() -- needed by Symbolize
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h> // for wait() -- needed by Symbolize
+#endif
#include <fcntl.h> // for open()
#ifdef HAVE_GLOB_H
#include <glob.h>
@@ -48,12 +54,15 @@
#include <inttypes.h> // for PRIxPTR
#endif
#include <errno.h>
+#include <stdarg.h>
#include <string>
+#include <map>
#include <algorithm> // for sort(), equal(), and copy()
#include "heap-profile-table.h"
#include "base/logging.h"
+#include "raw_printer.h"
#include <google/stacktrace.h>
#include <google/malloc_hook.h>
#include "base/commandlineflags.h"
@@ -64,6 +73,7 @@ using std::sort;
using std::equal;
using std::copy;
using std::string;
+using std::map;
using tcmalloc::FillProcSelfMaps; // from sysinfo.h
using tcmalloc::DumpProcSelfMaps; // from sysinfo.h
@@ -74,6 +84,15 @@ DEFINE_bool(cleanup_old_heap_profiles,
EnvToBool("HEAP_PROFILE_CLEANUP", true),
"At initialization time, delete old heap profiles.");
+DEFINE_string(heap_profile_table_pprof,
+ EnvToString("PPROF_PATH", "pprof"),
+ "Path to pprof to call for reporting function names.");
+
+// heap_profile_table_pprof may be referenced after destructors are
+// called (since that's when leak-checking is done), so we make
+// a more-permanent copy that won't ever get destroyed.
+static string* g_pprof_path = new string(FLAGS_heap_profile_table_pprof);
+
//----------------------------------------------------------------------
// header of the dumped heap profile
@@ -257,17 +276,21 @@ void HeapProfileTable::MarkAsIgnored(const void* ptr) {
// We'd be happier using snprintfer, but we don't to reduce dependencies.
int HeapProfileTable::UnparseBucket(const Bucket& b,
char* buf, int buflen, int bufsize,
+ const char* extra,
Stats* profile_stats) {
- profile_stats->allocs += b.allocs;
- profile_stats->alloc_size += b.alloc_size;
- profile_stats->frees += b.frees;
- profile_stats->free_size += b.free_size;
+ if (profile_stats != NULL) {
+ profile_stats->allocs += b.allocs;
+ profile_stats->alloc_size += b.alloc_size;
+ profile_stats->frees += b.frees;
+ profile_stats->free_size += b.free_size;
+ }
int printed =
- snprintf(buf + buflen, bufsize - buflen, "%6d: %8"PRId64" [%6d: %8"PRId64"] @",
+ snprintf(buf + buflen, bufsize - buflen, "%6d: %8"PRId64" [%6d: %8"PRId64"] @%s",
b.allocs - b.frees,
b.alloc_size - b.free_size,
b.allocs,
- b.alloc_size);
+ b.alloc_size,
+ extra);
// If it looks like the snprintf failed, ignore the fact we printed anything
if (printed < 0 || printed >= bufsize - buflen) return buflen;
buflen += printed;
@@ -336,9 +359,11 @@ int HeapProfileTable::FillOrderedProfile(char buf[], int size) const {
memset(&stats, 0, sizeof(stats));
int bucket_length = snprintf(buf, size, "%s", kProfileHeader);
if (bucket_length < 0 || bucket_length >= size) return 0;
- bucket_length = UnparseBucket(total_, buf, bucket_length, size, &stats);
+ bucket_length = UnparseBucket(total_, buf, bucket_length, size,
+ " heapprofile", &stats);
for (int i = 0; i < num_buckets_; i++) {
- bucket_length = UnparseBucket(*list[i], buf, bucket_length, size, &stats);
+ bucket_length = UnparseBucket(*list[i], buf, bucket_length, size, "",
+ &stats);
}
RAW_DCHECK(bucket_length < size, "");
@@ -364,30 +389,41 @@ void HeapProfileTable::DumpNonLiveIterator(const void* ptr, AllocValue* v,
memset(&b, 0, sizeof(b));
b.allocs = 1;
b.alloc_size = v->bytes;
- const void* stack[kMaxStackDepth + 1];
- b.depth = v->bucket()->depth + static_cast<int>(args.dump_alloc_addresses);
- b.stack = stack;
- if (args.dump_alloc_addresses) stack[0] = ptr;
- memcpy(stack + static_cast<int>(args.dump_alloc_addresses),
- v->bucket()->stack, sizeof(stack[0]) * v->bucket()->depth);
+ b.depth = v->bucket()->depth;
+ b.stack = v->bucket()->stack;
char buf[1024];
- int len = UnparseBucket(b, buf, 0, sizeof(buf), args.profile_stats);
+ int len = UnparseBucket(b, buf, 0, sizeof(buf), "", args.profile_stats);
RawWrite(args.fd, buf, len);
}
-bool HeapProfileTable::DumpNonLiveProfile(const char* file_name,
- bool dump_alloc_addresses,
- Stats* profile_stats) const {
+// Callback from NonLiveSnapshot; adds entry to arg->dest
+// if not the entry is not live and is not present in arg->base.
+void HeapProfileTable::AddIfNonLive(const void* ptr, AllocValue* v,
+ AddNonLiveArgs* arg) {
+ if (v->live()) {
+ v->set_live(false);
+ } else {
+ if (arg->base != NULL && arg->base->map_.Find(ptr) != NULL) {
+ // Present in arg->base, so do not save
+ } else {
+ arg->dest->Add(ptr, *v);
+ }
+ }
+}
+
+bool HeapProfileTable::WriteProfile(const char* file_name,
+ const Bucket& total,
+ AllocationMap* allocations) {
RAW_VLOG(1, "Dumping non-live heap profile to %s", file_name);
RawFD fd = RawOpenForWriting(file_name);
if (fd != kIllegalRawFD) {
RawWrite(fd, kProfileHeader, strlen(kProfileHeader));
char buf[512];
- int len = UnparseBucket(total_, buf, 0, sizeof(buf), profile_stats);
+ int len = UnparseBucket(total, buf, 0, sizeof(buf), " heapprofile",
+ NULL);
RawWrite(fd, buf, len);
- memset(profile_stats, 0, sizeof(*profile_stats));
- const DumpArgs args(fd, dump_alloc_addresses, profile_stats);
- allocation_->Iterate<const DumpArgs&>(DumpNonLiveIterator, args);
+ const DumpArgs args(fd, NULL);
+ allocations->Iterate<const DumpArgs&>(DumpNonLiveIterator, args);
RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader));
DumpProcSelfMaps(fd);
RawClose(fd);
@@ -421,3 +457,224 @@ void HeapProfileTable::CleanupOldProfiles(const char* prefix) {
RAW_LOG(WARNING, "Unable to remove old heap profiles (can't run glob())");
#endif
}
+
+HeapProfileTable::Snapshot* HeapProfileTable::TakeSnapshot() {
+ Snapshot* s = new (alloc_(sizeof(Snapshot))) Snapshot(alloc_, dealloc_);
+ allocation_->Iterate(AddToSnapshot, s);
+ return s;
+}
+
+void HeapProfileTable::ReleaseSnapshot(Snapshot* s) {
+ s->~Snapshot();
+ dealloc_(s);
+}
+
+// Callback from TakeSnapshot; adds a single entry to snapshot
+void HeapProfileTable::AddToSnapshot(const void* ptr, AllocValue* v,
+ Snapshot* snapshot) {
+ snapshot->Add(ptr, *v);
+}
+
+HeapProfileTable::Snapshot* HeapProfileTable::NonLiveSnapshot(
+ Snapshot* base) {
+ RAW_VLOG(2, "NonLiveSnapshot input: %d %d\n",
+ int(total_.allocs - total_.frees),
+ int(total_.alloc_size - total_.free_size));
+
+ Snapshot* s = new (alloc_(sizeof(Snapshot))) Snapshot(alloc_, dealloc_);
+ AddNonLiveArgs args;
+ args.dest = s;
+ args.base = base;
+ allocation_->Iterate<AddNonLiveArgs*>(AddIfNonLive, &args);
+ RAW_VLOG(2, "NonLiveSnapshot output: %d %d\n",
+ int(s->total_.allocs - s->total_.frees),
+ int(s->total_.alloc_size - s->total_.free_size));
+ return s;
+}
+
+// Information kept per unique bucket seen
+struct HeapProfileTable::Snapshot::Entry {
+ int count;
+ int bytes;
+ Bucket* bucket;
+ Entry() : count(0), bytes(0) { }
+
+ // Order by decreasing bytes
+ bool operator<(const Entry& x) const {
+ return this->bytes > x.bytes;
+ }
+};
+
+// State used to generate leak report. We keep a mapping from Bucket pointer
+// the collected stats for that bucket.
+struct HeapProfileTable::Snapshot::ReportState {
+ map<Bucket*, Entry> buckets_;
+};
+
+// Callback from ReportLeaks; updates ReportState.
+void HeapProfileTable::Snapshot::ReportCallback(const void* ptr,
+ AllocValue* v,
+ ReportState* state) {
+ Entry* e = &state->buckets_[v->bucket()]; // Creates empty Entry first time
+ e->bucket = v->bucket();
+ e->count++;
+ e->bytes += v->bytes;
+}
+
+// It would be much more efficient to call Symbolize on a bunch of pc's
+// at once, rather than calling one at a time, but this way it's simpler
+// to code, and efficiency probably isn't a top concern when reporting
+// found leaks at program-exit time.
+// Note that the forking/etc is not thread-safe or re-entrant. That's
+// ok for the purpose we need -- reporting leaks detected by heap-checker
+// -- but be careful if you decide to use this routine for other purposes.
+static bool Symbolize(void *pc, char *out, int out_size) {
+#if !defined(HAVE_UNISTD_H) || !defined(HAVE_SYS_SOCKET_H) || !defined(HAVE_SYS_WAIT_H)
+ return false;
+#elif !defined(HAVE_PROGRAM_INVOCATION_NAME)
+ return false; // TODO(csilvers): get argv[0] somehow
+#else
+ // All this work is to do two-way communication. ugh.
+ extern char* program_invocation_name; // gcc provides this
+ int child_in[2]; // file descriptors
+ int child_out[2]; // for now, we don't worry about child_err
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, child_in) == -1) {
+ return false;
+ }
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, child_out) == -1) {
+ close(child_in[0]);
+ close(child_in[1]);
+ return false;
+ }
+ switch (fork()) {
+ case -1: { // error
+ close(child_in[0]);
+ close(child_in[1]);
+ close(child_out[0]);
+ close(child_out[1]);
+ return false;
+ }
+ case 0: { // child
+ close(child_in[1]); // child uses the 0's, parent uses the 1's
+ close(child_out[1]); // child uses the 0's, parent uses the 1's
+ close(0);
+ close(1);
+ if (dup2(child_in[0], 0) == -1) _exit(1);
+ if (dup2(child_out[0], 1) == -1) _exit(2);
+ execlp(g_pprof_path->c_str(), g_pprof_path->c_str(),
+ "--symbols", program_invocation_name, NULL);
+ _exit(3); // if execvp fails, it's bad news for us
+ }
+ default: { // parent
+ close(child_in[0]); // child uses the 0's, parent uses the 1's
+ close(child_out[0]); // child uses the 0's, parent uses the 1's
+ DumpProcSelfMaps(child_in[1]); // what pprof expects on stdin
+ char pcstr[64]; // enough for a single address
+ snprintf(pcstr, sizeof(pcstr), // pprof expects format to be 0xXXXXXX...
+ "0x%" PRIxPTR "\n", reinterpret_cast<uintptr_t>(pc));
+ write(child_in[1], pcstr, strlen(pcstr));
+ close(child_in[1]); // that's all we need to write
+ int total_bytes_read = 0;
+ while (1) {
+ int bytes_read = read(child_out[1], out + total_bytes_read,
+ out_size - total_bytes_read);
+ if (bytes_read < 0) {
+ close(child_out[1]);
+ return false;
+ } else if (bytes_read == 0) {
+ close(child_out[1]);
+ wait(NULL);
+ break;
+ } else {
+ total_bytes_read += bytes_read;
+ }
+ }
+ // We have successfully read the output of pprof into out. Make sure
+ // we got the full symbol (we can tell because it ends with a \n).
+ if (total_bytes_read == 0 || out[total_bytes_read - 1] != '\n')
+ return false;
+ out[total_bytes_read - 1] = '\0'; // remove the trailing newline
+ return true;
+ }
+ }
+ return false; // shouldn't be reachable
+#endif
+}
+
+void HeapProfileTable::Snapshot::ReportLeaks(const char* checker_name,
+ const char* filename) {
+ // This is only used by the heap leak checker, but is intimately
+ // tied to the allocation map that belongs in this module and is
+ // therefore placed here.
+ RAW_LOG(ERROR, "Leak check %s detected leaks of %"PRIuS" bytes "
+ "in %"PRIuS" objects",
+ checker_name,
+ size_t(total_.alloc_size),
+ size_t(total_.allocs));
+
+ // Group objects by Bucket
+ ReportState state;
+ map_.Iterate(&ReportCallback, &state);
+
+ // Sort buckets by decreasing leaked size
+ const int n = state.buckets_.size();
+ Entry* entries = new Entry[n];
+ int dst = 0;
+ for (map<Bucket*,Entry>::const_iterator iter = state.buckets_.begin();
+ iter != state.buckets_.end();
+ ++iter) {
+ entries[dst++] = iter->second;
+ }
+ sort(entries, entries + n);
+
+ // Report a bounded number of leaks to keep the leak report from
+ // growing too long.
+ const int to_report = (n > 20) ? 20 : n;
+ RAW_LOG(ERROR, "The %d largest leaks:", to_report);
+
+ // Print
+ char sym_buffer[1024];
+ static const int kBufSize = 2<<10;
+ char buffer[kBufSize];
+ for (int i = 0; i < to_report; i++) {
+ const Entry& e = entries[i];
+ base::RawPrinter printer(buffer, kBufSize);
+ printer.Printf("Leak of %d bytes in %d objects allocated from:\n",
+ e.bytes, e.count);
+ for (int j = 0; j < e.bucket->depth; j++) {
+ const void* pc = e.bucket->stack[j];
+ const char* sym;
+ if (Symbolize(const_cast<void*>(pc), sym_buffer, sizeof(sym_buffer))) {
+ sym = sym_buffer;
+ } else {
+ sym = "";
+ }
+ printer.Printf("\t@ %p %s\n", pc, sym);
+ }
+ RAW_LOG(ERROR, "%s", buffer);
+ }
+ if (to_report < n) {
+ RAW_LOG(ERROR, "Skipping leaks numbered %d..%d",
+ to_report, n-1);
+ }
+ delete[] entries;
+
+ // TODO: Dump the sorted Entry list instead of dumping raw data?
+ // (should be much shorter)
+ if (!HeapProfileTable::WriteProfile(filename, total_, &map_)) {
+ RAW_LOG(ERROR, "Could not write pprof profile to %s", filename);
+ }
+}
+
+void HeapProfileTable::Snapshot::ReportObject(const void* ptr,
+ AllocValue* v,
+ char* unused) {
+ // Perhaps also log the allocation stack trace (unsymbolized)
+ // on this line in case somebody finds it useful.
+ RAW_LOG(ERROR, "leaked %"PRIuS" byte object %p", v->bytes, ptr);
+}
+
+void HeapProfileTable::Snapshot::ReportIndividualObjects() {
+ char unused;
+ map_.Iterate(ReportObject, &unused);
+}
diff --git a/src/heap-profile-table.h b/src/heap-profile-table.h
index 968ff90..acbe14b 100644
--- a/src/heap-profile-table.h
+++ b/src/heap-profile-table.h
@@ -125,8 +125,7 @@ class HeapProfileTable {
// If "ptr" points to a recorded allocation and it's not marked as live
// mark it as live and return true. Else return false.
- // All allocations start as non-live, DumpNonLiveProfile below
- // also makes all allocations non-live.
+ // All allocations start as non-live.
bool MarkAsLive(const void* ptr);
// If "ptr" points to a recorded allocation, mark it as "ignored".
@@ -162,25 +161,26 @@ class HeapProfileTable {
// We do not provision for 0-terminating 'buf'.
int FillOrderedProfile(char buf[], int size) const;
- // Allocation data dump filtering callback:
- // gets passed object pointer and size
- // needs to return true iff the object is to be filtered out of the dump.
- typedef bool (*DumpFilter)(const void* ptr, size_t size);
-
- // Dump non-live portion of the current heap profile
- // for leak checking purposes to file_name.
- // Also reset all objects to non-live state
- // and write the sums of allocated byte and object counts in the dump
- // to *alloc_bytes and *alloc_objects.
- // dump_alloc_addresses controls if object addresses are dumped.
- // Ignores any objects that have the "ignore" bit set.
- bool DumpNonLiveProfile(const char* file_name,
- bool dump_alloc_addresses,
- Stats* profile_stats) const;
-
// Cleanup any old profile files matching prefix + ".*" + kFileExt.
static void CleanupOldProfiles(const char* prefix);
+ // Return a snapshot of the current contents of *this.
+ // Caller must call ReleaseSnapshot() on result when no longer needed.
+ // The result is only valid while this exists and until
+ // the snapshot is discarded by calling ReleaseSnapshot().
+ class Snapshot;
+ Snapshot* TakeSnapshot();
+
+ // Release a previously taken snapshot. snapshot must not
+ // be used after this call.
+ void ReleaseSnapshot(Snapshot* snapshot);
+
+ // Return a snapshot of every non-live, non-ignored object in *this.
+ // If "base" is non-NULL, skip any objects present in "base".
+ // As a side-effect, clears the "live" bit on every live object in *this.
+ // Caller must call ReleaseSnapshot() on result when no longer needed.
+ Snapshot* NonLiveSnapshot(Snapshot* base);
+
private:
// data types ----------------------------
@@ -234,11 +234,10 @@ class HeapProfileTable {
// Arguments that need to be passed DumpNonLiveIterator callback below.
struct DumpArgs {
RawFD fd; // file to write to
- bool dump_alloc_addresses; // if we are dumping allocation's addresses
- Stats* profile_stats; // stats to update
+ Stats* profile_stats; // stats to update (may be NULL)
- DumpArgs(RawFD a, bool b, Stats* d)
- : fd(a), dump_alloc_addresses(b), profile_stats(d) { }
+ DumpArgs(RawFD a, Stats* d)
+ : fd(a), profile_stats(d) { }
};
// helpers ----------------------------
@@ -247,9 +246,16 @@ class HeapProfileTable {
// We return the amount of space in buf that we use. We start printing
// at buf + buflen, and promise not to go beyond buf + bufsize.
// We do not provision for 0-terminating 'buf'.
- // We update *profile_stats by counting bucket b.
+ //
+ // If profile_stats is non-NULL, we update *profile_stats by
+ // counting bucket b.
+ //
+ // "extra" is appended to the unparsed bucket. Typically it is empty,
+ // but may be set to something like " heapprofile" for the total
+ // bucket to indicate the type of the profile.
static int UnparseBucket(const Bucket& b,
char* buf, int buflen, int bufsize,
+ const char* extra,
Stats* profile_stats);
// Get the bucket for the caller stack trace 'key' of depth 'depth'
@@ -279,6 +285,27 @@ class HeapProfileTable {
// The caller is responsible for dellocating the returned list.
Bucket** MakeSortedBucketList() const;
+ // Helper for TakeSnapshot. Saves object to snapshot.
+ static void AddToSnapshot(const void* ptr, AllocValue* v, Snapshot* s);
+
+ // Arguments passed to AddIfNonLive
+ struct AddNonLiveArgs {
+ Snapshot* dest;
+ Snapshot* base;
+ };
+
+ // Helper for NonLiveSnapshot. Adds the object to the destination
+ // snapshot if it is non-live.
+ static void AddIfNonLive(const void* ptr, AllocValue* v,
+ AddNonLiveArgs* arg);
+
+ // Write contents of "*allocations" as a heap profile to
+ // "file_name". "total" must contain the total of all entries in
+ // "*allocations".
+ static bool WriteProfile(const char* file_name,
+ const Bucket& total,
+ AllocationMap* allocations);
+
// data ----------------------------
// Memory (de)allocator that we use.
@@ -302,4 +329,53 @@ class HeapProfileTable {
DISALLOW_EVIL_CONSTRUCTORS(HeapProfileTable);
};
+class HeapProfileTable::Snapshot {
+ public:
+ const Stats& total() const { return total_; }
+
+ // Report anything in this snapshot as a leak.
+ // May use new/delete for temporary storage.
+ // Also writes a heap profile to "filename" that contains
+ // all of the objects in this snapshot.
+ void ReportLeaks(const char* checker_name, const char* filename);
+
+ // Report the addresses of all leaked objects.
+ // May use new/delete for temporary storage.
+ void ReportIndividualObjects();
+
+ bool Empty() const {
+ return (total_.allocs == 0) && (total_.alloc_size == 0);
+ }
+
+ private:
+ friend class HeapProfileTable;
+
+ // Total count/size are stored in a Bucket so we can reuse UnparseBucket
+ Bucket total_;
+
+ // We share the Buckets managed by the parent table, but have our
+ // own object->bucket map.
+ AllocationMap map_;
+
+ Snapshot(Allocator alloc, DeAllocator dealloc) : map_(alloc, dealloc) {
+ memset(&total_, 0, sizeof(total_));
+ }
+
+ // Callback used to populate a Snapshot object with entries found
+ // in another allocation map.
+ inline void Add(const void* ptr, const AllocValue& v) {
+ map_.Insert(ptr, v);
+ total_.allocs++;
+ total_.alloc_size += v.bytes;
+ }
+
+ // Helpers for sorting and generating leak reports
+ struct Entry;
+ struct ReportState;
+ static void ReportCallback(const void* ptr, AllocValue* v, ReportState*);
+ static void ReportObject(const void* ptr, AllocValue* v, char*);
+
+ DISALLOW_COPY_AND_ASSIGN(Snapshot);
+};
+
#endif // BASE_HEAP_PROFILE_TABLE_H_
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index 7b936ca..81176f7 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -92,13 +92,21 @@ using STL_NAMESPACE::sort;
DEFINE_int64(heap_profile_allocation_interval,
EnvToInt64("HEAP_PROFILE_ALLOCATION_INTERVAL", 1 << 30 /*1GB*/),
- "Dump heap profiling information once every specified "
- "number of bytes allocated by the program.");
+ "If non-zero, dump heap profiling information once every "
+ "specified number of bytes allocated by the program since "
+ "the last dump.");
+DEFINE_int64(heap_profile_deallocation_interval,
+ EnvToInt64("HEAP_PROFILE_DEALLOCATION_INTERVAL", 0),
+ "If non-zero, dump heap profiling information once every "
+ "specified number of bytes deallocated by the program "
+ "since the last dump.");
+// We could also add flags that report whenever inuse_bytes changes by
+// X or -X, but there hasn't been a need for that yet, so we haven't.
DEFINE_int64(heap_profile_inuse_interval,
EnvToInt64("HEAP_PROFILE_INUSE_INTERVAL", 100 << 20 /*100MB*/),
- "Dump heap profiling information whenever the high-water "
- "memory usage mark increases by the specified number of "
- "bytes.");
+ "If non-zero, dump heap profiling information whenever "
+ "the high-water memory usage mark increases by the specified "
+ "number of bytes.");
DEFINE_bool(mmap_log,
EnvToBool("HEAP_PROFILE_MMAP_LOG", false),
"Should mmap/munmap calls be logged?");
@@ -157,7 +165,8 @@ static bool dumping = false; // Dumping status to prevent recursion
static char* filename_prefix = NULL; // Prefix used for profile file names
// (NULL if no need for dumping yet)
static int dump_count = 0; // How many dumps so far
-static int64 last_dump = 0; // When did we last dump
+static int64 last_dump_alloc = 0; // alloc_size when did we last dump
+static int64 last_dump_free = 0; // free_size when did we last dump
static int64 high_water_mark = 0; // In-use-bytes at last high-water dump
static HeapProfileTable* heap_profile = NULL; // the heap profile table
@@ -282,34 +291,52 @@ static void DumpProfileLocked(const char* reason) {
// Profile collection
//----------------------------------------------------------------------
+// Dump a profile after either an allocation or deallocation, if
+// the memory use has changed enough since the last dump.
+static void MaybeDumpProfileLocked() {
+ if (!dumping) {
+ const HeapProfileTable::Stats& total = heap_profile->total();
+ const int64 inuse_bytes = total.alloc_size - total.free_size;
+ bool need_to_dump = false;
+ char buf[128];
+ if (FLAGS_heap_profile_allocation_interval > 0 &&
+ total.alloc_size >=
+ last_dump_alloc + FLAGS_heap_profile_allocation_interval) {
+ snprintf(buf, sizeof(buf), ("%"PRId64" MB allocated cumulatively, "
+ "%"PRId64" MB currently in use"),
+ total.alloc_size >> 20, inuse_bytes >> 20);
+ need_to_dump = true;
+ } else if (FLAGS_heap_profile_deallocation_interval > 0 &&
+ total.free_size >=
+ last_dump_free + FLAGS_heap_profile_deallocation_interval) {
+ snprintf(buf, sizeof(buf), ("%"PRId64" MB freed cumulatively, "
+ "%"PRId64" MB currently in use"),
+ total.free_size >> 20, inuse_bytes >> 20);
+ need_to_dump = true;
+ } else if (FLAGS_heap_profile_inuse_interval > 0 &&
+ inuse_bytes >
+ high_water_mark + FLAGS_heap_profile_inuse_interval) {
+ snprintf(buf, sizeof(buf), "%"PRId64" MB currently in use",
+ inuse_bytes >> 20);
+ need_to_dump = true;
+ }
+ if (need_to_dump) {
+ DumpProfileLocked(buf);
+
+ last_dump_alloc = total.alloc_size;
+ last_dump_free = total.free_size;
+ if (inuse_bytes > high_water_mark)
+ high_water_mark = inuse_bytes;
+ }
+ }
+}
+
// Record an allocation in the profile.
static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) {
SpinLockHolder l(&heap_lock);
if (is_on) {
heap_profile->RecordAlloc(ptr, bytes, skip_count + 1);
- const HeapProfileTable::Stats& total = heap_profile->total();
- const int64 inuse_bytes = total.alloc_size - total.free_size;
- if (!dumping) {
- bool need_to_dump = false;
- char buf[128];
- if (total.alloc_size >=
- last_dump + FLAGS_heap_profile_allocation_interval) {
- snprintf(buf, sizeof(buf), "%"PRId64" MB allocated",
- total.alloc_size >> 20);
- // Track that we made a "total allocation size" dump
- last_dump = total.alloc_size;
- need_to_dump = true;
- } else if (inuse_bytes >
- high_water_mark + FLAGS_heap_profile_inuse_interval) {
- snprintf(buf, sizeof(buf), "%"PRId64" MB in use", inuse_bytes >> 20);
- // Track that we made a "high water mark" dump
- high_water_mark = inuse_bytes;
- need_to_dump = true;
- }
- if (need_to_dump) {
- DumpProfileLocked(buf);
- }
- }
+ MaybeDumpProfileLocked();
}
}
@@ -318,6 +345,7 @@ static void RecordFree(const void* ptr) {
SpinLockHolder l(&heap_lock);
if (is_on) {
heap_profile->RecordFree(ptr);
+ MaybeDumpProfileLocked();
}
}
@@ -469,7 +497,9 @@ extern "C" void HeapProfilerStart(const char* prefix) {
heap_profile = new(ProfilerMalloc(sizeof(HeapProfileTable)))
HeapProfileTable(ProfilerMalloc, ProfilerFree);
- last_dump = 0;
+ last_dump_alloc = 0;
+ last_dump_free = 0;
+ high_water_mark = 0;
// We do not reset dump_count so if the user does a sequence of
// HeapProfilerStart/HeapProfileStop, we will get a continuous
diff --git a/src/internal_logging.cc b/src/internal_logging.cc
index e80f1e3..6bee8fb 100644
--- a/src/internal_logging.cc
+++ b/src/internal_logging.cc
@@ -59,17 +59,14 @@ void TCMalloc_MESSAGE(const char* filename,
static const int kStatsBufferSize = 16 << 10;
static char stats_buffer[kStatsBufferSize] = { 0 };
-void TCMalloc_CRASH(bool dump_stats,
- const char* filename,
- int line_number,
- const char* format, ...) {
+static void TCMalloc_CRASH_internal(bool dump_stats,
+ const char* filename,
+ int line_number,
+ const char* format, va_list ap) {
char buf[kLogBufSize];
const int n = snprintf(buf, sizeof(buf), "%s:%d] ", filename, line_number);
if (n < kLogBufSize) {
- va_list ap;
- va_start(ap, format);
vsnprintf(buf + n, kLogBufSize - n, format, ap);
- va_end(ap);
}
write(STDERR_FILENO, buf, strlen(buf));
if (dump_stats) {
@@ -80,6 +77,24 @@ void TCMalloc_CRASH(bool dump_stats,
abort();
}
+void TCMalloc_CRASH(bool dump_stats,
+ const char* filename,
+ int line_number,
+ const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ TCMalloc_CRASH_internal(dump_stats, filename, line_number, format, ap);
+ va_end(ap);
+}
+
+
+void TCMalloc_CrashReporter::PrintfAndDie(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ TCMalloc_CRASH_internal(dump_stats_, file_, line_, format, ap);
+ va_end(ap);
+}
+
void TCMalloc_Printer::printf(const char* format, ...) {
if (left_ > 0) {
va_list ap;
diff --git a/src/internal_logging.h b/src/internal_logging.h
index 59ff568..b9b3e2a 100644
--- a/src/internal_logging.h
+++ b/src/internal_logging.h
@@ -37,6 +37,9 @@
#include "config.h"
#include <stdlib.h> // for abort()
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> // for write()
+#endif
//-------------------------------------------------------------------
// Utility routines
@@ -53,9 +56,17 @@ extern void TCMalloc_MESSAGE(const char* filename,
#endif
;
-// Short form for convenience
-#define MESSAGE(format, ...) \
- TCMalloc_MESSAGE(__FILE__, __LINE__, format, __VA_ARGS__)
+// Right now, the only non-fatal messages we want to report are when
+// an allocation fails (we'll return NULL eventually, but sometimes
+// want more prominent notice to help debug). message should be
+// a literal string with no %<whatever> format directives.
+#ifdef TCMALLOC_WARNINGS
+#define MESSAGE(message, num_bytes) \
+ TCMalloc_MESSAGE(__FILE__, __LINE__, message " (%"PRIuS" bytes)\n", \
+ static_cast<size_t>(num_bytes))
+#else
+#define MESSAGE(message, num_bytes)
+#endif
// Dumps the specified message and then calls abort(). If
// "dump_stats" is specified, the first call will also dump the
@@ -69,11 +80,30 @@ extern void TCMalloc_CRASH(bool dump_stats,
#endif
;
-#define CRASH(format, ...) \
- TCMalloc_CRASH(false, __FILE__, __LINE__, format, __VA_ARGS__)
+// This is a class that makes using the macro easier. With this class,
+// CRASH("%d", i) expands to TCMalloc_CrashReporter.PrintfAndDie("%d", i).
+class PERFTOOLS_DLL_DECL TCMalloc_CrashReporter {
+ public:
+ TCMalloc_CrashReporter(bool dump_stats, const char* file, int line)
+ : dump_stats_(dump_stats), file_(file), line_(line) {
+ }
+ void PrintfAndDie(const char* format, ...)
+#ifdef HAVE___ATTRIBUTE__
+ __attribute__ ((__format__ (__printf__, 2, 3))) // 2,3 due to "this"
+#endif
+;
+
+ private:
+ bool dump_stats_;
+ const char* file_;
+ int line_;
+};
+
+#define CRASH \
+ TCMalloc_CrashReporter(false, __FILE__, __LINE__).PrintfAndDie
-#define CRASH_WITH_STATS(format, ...) \
- TCMalloc_CRASH(true, __FILE__, __LINE__, format, __VA_ARGS__)
+#define CRASH_WITH_STATS \
+ TCMalloc_CrashReporter(true, __FILE__, __LINE__).PrintfAndDie
// Like assert(), but executed even in NDEBUG mode
#undef CHECK_CONDITION
diff --git a/src/malloc_extension.cc b/src/malloc_extension.cc
index 11e0bdb..cd121d7 100644
--- a/src/malloc_extension.cc
+++ b/src/malloc_extension.cc
@@ -43,7 +43,6 @@
#include <sys/types.h>
#endif
#include <string>
-#include HASH_SET_H // defined in config.h
#include "base/dynamic_annotations.h"
#include "base/sysinfo.h" // for FillProcSelfMaps
#include "google/malloc_extension.h"
@@ -125,7 +124,7 @@ bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total,
return true;
}
-void** MallocExtension::ReadStackTraces() {
+void** MallocExtension::ReadStackTraces(int* sample_period) {
return NULL;
}
@@ -149,6 +148,14 @@ double MallocExtension::GetMemoryReleaseRate() {
return -1.0;
}
+size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) {
+ return size;
+}
+
+size_t MallocExtension::GetAllocatedSize(void* p) {
+ return 0;
+}
+
// The current malloc extension object. We also keep a pointer to
// the default implementation so that the heap-leak checker does not
// complain about a memory leak.
@@ -196,55 +203,8 @@ void* PC(void** entry, int i) {
return entry[3+i];
}
-// Hash table routines for grouping all entries with same stack trace
-struct StackTraceHash {
- size_t operator()(void** entry) const {
- uintptr_t h = 0;
- for (int i = 0; i < Depth(entry); i++) {
- h += reinterpret_cast<uintptr_t>(PC(entry, i));
- h += h << 10;
- h ^= h >> 6;
- }
- h += h << 3;
- h ^= h >> 11;
- return h;
- }
- // Less operator for MSVC's hash containers.
- bool operator()(void** entry1, void** entry2) const {
- if (Depth(entry1) != Depth(entry2))
- return Depth(entry1) < Depth(entry2);
- for (int i = 0; i < Depth(entry1); i++) {
- if (PC(entry1, i) != PC(entry2, i)) {
- return PC(entry1, i) < PC(entry2, i);
- }
- }
- return false; // entries are equal
- }
- // These two public members are required by msvc. 4 and 8 are the
- // default values.
- static const size_t bucket_size = 4;
- static const size_t min_buckets = 8;
-};
-
-struct StackTraceEqual {
- bool operator()(void** entry1, void** entry2) const {
- if (Depth(entry1) != Depth(entry2)) return false;
- for (int i = 0; i < Depth(entry1); i++) {
- if (PC(entry1, i) != PC(entry2, i)) {
- return false;
- }
- }
- return true;
- }
-};
-
-#ifdef _WIN32
-typedef HASH_NAMESPACE::hash_set<void**, StackTraceHash> StackTraceTable;
-#else
-typedef HASH_NAMESPACE::hash_set<void**, StackTraceHash, StackTraceEqual> StackTraceTable;
-#endif
-
-void PrintCountAndSize(string* result, uintptr_t count, uintptr_t size) {
+void PrintCountAndSize(MallocExtensionWriter* writer,
+ uintptr_t count, uintptr_t size) {
char buf[100];
snprintf(buf, sizeof(buf),
"%6lld: %8lld [%6lld: %8lld] @",
@@ -252,10 +212,11 @@ void PrintCountAndSize(string* result, uintptr_t count, uintptr_t size) {
static_cast<long long>(size),
static_cast<long long>(count),
static_cast<long long>(size));
- *result += buf;
+ writer->append(buf, strlen(buf));
}
-void PrintHeader(string* result, const char* label, void** entries) {
+void PrintHeader(MallocExtensionWriter* writer,
+ const char* label, void** entries) {
// Compute the total count and total size
uintptr_t total_count = 0;
uintptr_t total_size = 0;
@@ -264,85 +225,79 @@ void PrintHeader(string* result, const char* label, void** entries) {
total_size += Size(entry);
}
- *result += string("heap profile: ");
- PrintCountAndSize(result, total_count, total_size);
- *result += string(" ") + label + "\n";
+ const char* const kTitle = "heap profile: ";
+ writer->append(kTitle, strlen(kTitle));
+ PrintCountAndSize(writer, total_count, total_size);
+ writer->append(" ", 1);
+ writer->append(label, strlen(label));
+ writer->append("\n", 1);
}
-void PrintStackEntry(string* result, void** entry) {
- PrintCountAndSize(result, Count(entry), Size(entry));
+void PrintStackEntry(MallocExtensionWriter* writer, void** entry) {
+ PrintCountAndSize(writer, Count(entry), Size(entry));
for (int i = 0; i < Depth(entry); i++) {
char buf[32];
snprintf(buf, sizeof(buf), " %p", PC(entry, i));
- *result += buf;
+ writer->append(buf, strlen(buf));
}
- *result += "\n";
+ writer->append("\n", 1);
}
}
-void MallocExtension::GetHeapSample(string* result) {
- void** entries = ReadStackTraces();
+void MallocExtension::GetHeapSample(MallocExtensionWriter* writer) {
+ int sample_period = 0;
+ void** entries = ReadStackTraces(&sample_period);
if (entries == NULL) {
- *result += "This malloc implementation does not support sampling.\n"
- "As of 2005/01/26, only tcmalloc supports sampling, and you\n"
- "are probably running a binary that does not use tcmalloc.\n";
+ const char* const kErrorMsg =
+ "This malloc implementation does not support sampling.\n"
+ "As of 2005/01/26, only tcmalloc supports sampling, and\n"
+ "you are probably running a binary that does not use\n"
+ "tcmalloc.\n";
+ writer->append(kErrorMsg, strlen(kErrorMsg));
return;
}
- // Group together all entries with same stack trace
- StackTraceTable table;
+ char label[32];
+ sprintf(label, "heap_v2/%d", sample_period);
+ PrintHeader(writer, label, entries);
for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
- StackTraceTable::iterator iter = table.find(entry);
- if (iter == table.end()) {
- // New occurrence
- table.insert(entry);
- } else {
- void** canonical = *iter;
- canonical[0] = reinterpret_cast<void*>(Count(canonical) + Count(entry));
- canonical[1] = reinterpret_cast<void*>(Size(canonical) + Size(entry));
- }
+ PrintStackEntry(writer, entry);
}
-
- PrintHeader(result, "heap", entries);
- for (StackTraceTable::iterator iter = table.begin();
- iter != table.end();
- ++iter) {
- PrintStackEntry(result, *iter);
- }
-
- DumpAddressMap(result);
delete[] entries;
+
+ DumpAddressMap(writer);
}
-void MallocExtension::GetHeapGrowthStacks(string* result) {
+void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter* writer) {
void** entries = ReadHeapGrowthStackTraces();
if (entries == NULL) {
- *result += "This malloc implementation does not support "
- "ReadHeapGrowthStackTraces().\n"
- "As of 2005/09/27, only tcmalloc supports this, and you\n"
- "are probably running a binary that does not use tcmalloc.\n";
+ const char* const kErrorMsg =
+ "This malloc implementation does not support "
+ "ReadHeapGrowthStackTraces().\n"
+ "As of 2005/09/27, only tcmalloc supports this, and you\n"
+ "are probably running a binary that does not use tcmalloc.\n";
+ writer->append(kErrorMsg, strlen(kErrorMsg));
return;
}
// Do not canonicalize the stack entries, so that we get a
// time-ordered list of stack traces, which may be useful if the
// client wants to focus on the latest stack traces.
-
- PrintHeader(result, "growth", entries);
+ PrintHeader(writer, "growth", entries);
for (void** entry = entries; Count(entry) != 0; entry += 3 + Depth(entry)) {
- PrintStackEntry(result, entry);
+ PrintStackEntry(writer, entry);
}
delete[] entries;
- DumpAddressMap(result);
+ DumpAddressMap(writer);
}
// These are C shims that work on the current instance.
#define C_SHIM(fn, retval, paramlist, arglist) \
- extern "C" retval MallocExtension_##fn paramlist { \
+ extern "C" PERFTOOLS_DLL_DECL retval MallocExtension_##fn paramlist { \
return MallocExtension::instance()->fn arglist; \
}
@@ -363,3 +318,5 @@ C_SHIM(SetNumericProperty, bool,
C_SHIM(MarkThreadIdle, void, (), ());
C_SHIM(ReleaseFreeMemory, void, (), ());
+C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size));
+C_SHIM(GetAllocatedSize, size_t, (void* p), (p));
diff --git a/src/malloc_hook.cc b/src/malloc_hook.cc
index f1249ba..92ca3c1 100644
--- a/src/malloc_hook.cc
+++ b/src/malloc_hook.cc
@@ -46,7 +46,15 @@
#include "base/logging.h"
#include "malloc_hook-inl.h"
#include <google/malloc_hook.h>
-#include <google/stacktrace.h>
+
+// This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if
+// you're porting to a system where you really can't get a stacktrace.
+#ifdef NO_TCMALLOC_SAMPLES
+ // We use #define so code compiles even if you #include stacktrace.h somehow.
+# define GetStackTrace(stack, depth, skip) (0)
+#else
+# include <google/stacktrace.h>
+#endif
// __THROW is defined in glibc systems. It means, counter-intuitively,
// "This function will never throw an exception." It's an optional
diff --git a/src/memory_region_map.cc b/src/memory_region_map.cc
index ed42e14..8794227 100644
--- a/src/memory_region_map.cc
+++ b/src/memory_region_map.cc
@@ -484,6 +484,11 @@ void MemoryRegionMap::RecordRegionAddition(const void* start, size_t size) {
void MemoryRegionMap::RecordRegionRemoval(const void* start, size_t size) {
Lock();
+ if (regions_ == NULL) { // We must have just unset the hooks,
+ // but this thread was already inside the hook.
+ Unlock();
+ return;
+ }
HandleSavedRegionsLocked(&InsertRegionLocked);
// first handle adding saved regions if any
uintptr_t start_addr = reinterpret_cast<uintptr_t>(start);
diff --git a/src/page_heap.cc b/src/page_heap.cc
index 0054db3..8045833 100644
--- a/src/page_heap.cc
+++ b/src/page_heap.cc
@@ -347,14 +347,14 @@ void PageHeap::Dump(TCMalloc_Printer* out) {
int r_spans = 0;
out->printf("Normal large spans:\n");
for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) {
- out->printf(" [ %6" PRIuS " pages ] %6.1f MB\n",
+ out->printf(" [ %6" PRIuPTR " pages ] %6.1f MB\n",
s->length, PagesToMB(s->length));
n_pages += s->length;
n_spans++;
}
out->printf("Unmapped large spans:\n");
for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) {
- out->printf(" [ %6" PRIuS " pages ] %6.1f MB\n",
+ out->printf(" [ %6" PRIuPTR " pages ] %6.1f MB\n",
s->length, PagesToMB(s->length));
r_pages += s->length;
r_spans++;
diff --git a/src/pprof b/src/pprof
index e5254ee..e3d0907 100755
--- a/src/pprof
+++ b/src/pprof
@@ -72,7 +72,7 @@ use strict;
use warnings;
use Getopt::Long;
-my $PPROF_VERSION = "1.0";
+my $PPROF_VERSION = "1.1";
# These are the object tools we use which can come from a
# user-specified location using --tools, from the PPROF_TOOLS
@@ -83,8 +83,8 @@ my %obj_tool_map = (
"addr2line" => "addr2line",
"c++filt" => "c++filt",
## ConfigureObjTools may add architecture-specific entries:
- #"nm_pdb" => "nm_pdb", # for reading windows (PDB-format) executables
- #"addr2line_pdb" => "addr2line_pdb", # ditto
+ #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
+ #"addr2line_pdb" => "addr2line-pdb", # ditto
#"otool" => "otool", # equivalent of objdump on OS X
);
my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local
@@ -123,14 +123,19 @@ pprof [options] <program> <profiles>
pprof [options] <profile>
<profile> is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE
- Each profile name can be:
+ Each name can be:
/path/to/profile - a path to a profile file
host:port[/<service>] - a location of a service to get profile from
- The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, $GROWTH_PAGE, $CONTENTION_PAGE,
- $WALL_PAGE, or $FILTEREDPROFILE_PAGE.
+ The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, $GROWTH_PAGE,
+ $CONTENTION_PAGE, $WALL_PAGE, or $FILTEREDPROFILE_PAGE.
For instance: "pprof http://myserver.com:80$HEAP_PAGE".
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
+pprof --symbols <program>
+ Maps addresses to symbol names. In this mode, stdin should be a
+ list of library mappings, in the same format as is found in the heap-
+ and cpu-profile files (this loosely matches that of /proc/self/maps
+ on linux), followed by a list of hex addresses to map, one per line.
For more help with querying remote servers, including how to add the
necessary server-side support code, see this filename (or one like it):
@@ -157,6 +162,7 @@ Output type:
--gv Generate Postscript and display
--list=<regexp> Generate source listing of matching routines
--disasm=<regexp> Generate disassembly of matching routines
+ --symbols Print demangled symbol names found at given addresses
--dot Generate DOT file to stdout
--ps Generate Postcript to stdout
--pdf Generate PDF to stdout
@@ -171,9 +177,9 @@ Heap-Profile Options:
--drop_negative Ignore negative differences
Contention-profile options:
- --total_delay Display total delay at each region [default]
- --contentions Display number of delays at each region
- --mean_delay Display mean delay at each region
+ --total_delay Display total delay at each region [default]
+ --contentions Display number of delays at each region
+ --mean_delay Display mean delay at each region
Call-graph Options:
--nodecount=<n> Show at most so many nodes [default=80]
@@ -264,6 +270,7 @@ sub Init() {
$main::opt_callgrind = 0;
$main::opt_list = "";
$main::opt_disasm = "";
+ $main::opt_symbols = 0;
$main::opt_gv = 0;
$main::opt_dot = 0;
$main::opt_ps = 0;
@@ -322,6 +329,7 @@ sub Init() {
"callgrind!" => \$main::opt_callgrind,
"list=s" => \$main::opt_list,
"disasm=s" => \$main::opt_disasm,
+ "symbols!" => \$main::opt_symbols,
"gv!" => \$main::opt_gv,
"dot!" => \$main::opt_dot,
"ps!" => \$main::opt_ps,
@@ -360,8 +368,8 @@ sub Init() {
exit(0);
}
- # Disassembly/listing mode requires address-level info
- if ($main::opt_disasm || $main::opt_list) {
+ # Disassembly/listing/symbols mode requires address-level info
+ if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) {
$main::opt_functions = 0;
$main::opt_lines = 0;
$main::opt_addresses = 1;
@@ -396,6 +404,7 @@ sub Init() {
$main::opt_callgrind +
($main::opt_list eq '' ? 0 : 1) +
($main::opt_disasm eq '' ? 0 : 1) +
+ ($main::opt_symbols == 0 ? 0 : 1) +
$main::opt_gv +
$main::opt_dot +
$main::opt_ps +
@@ -437,6 +446,9 @@ sub Init() {
}
# Set $main::prog later...
scalar(@ARGV) || usage("Did not specify profile file");
+ } elsif ($main::opt_symbols) {
+ # --symbols needs a binary-name (to run nm on, etc) but not profiles
+ $main::prog = shift(@ARGV) || usage("Did not specify program");
} else {
$main::prog = shift(@ARGV) || usage("Did not specify program");
scalar(@ARGV) || usage("Did not specify profile file");
@@ -482,9 +494,15 @@ sub Main() {
@main::profile_files = ();
$main::op_time = time();
+ # Printing symbols is special and requires a lot less info that most.
+ if ($main::opt_symbols) {
+ PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin
+ return;
+ }
+
# Fetch all profile data
FetchDynamicProfiles();
-
+
# Read one profile, pick the last item on the list
my $data = ReadProfile($main::prog, pop(@main::profile_files));
my $profile = $data->{profile};
@@ -515,7 +533,7 @@ sub Main() {
if ($main::use_symbol_page) {
$symbols = FetchSymbols($pcs);
} else {
- $symbols = ExtractSymbols($libs, $profile, $pcs);
+ $symbols = ExtractSymbols($libs, $pcs);
}
my $calls = ExtractCalls($symbols, $profile);
@@ -983,6 +1001,38 @@ sub Disassemble {
return @result;
}
+# The input file should contain lines of the form /proc/maps-like
+# output (same format as expected from the profiles) or that looks
+# like hex addresses (like "0xDEADBEEF"). We will parse all
+# /proc/maps output, and for all the hex addresses, we will output
+# "short" symbol names, one per line, in the same order as the input.
+sub PrintSymbols {
+ my $maps_and_symbols_file = shift;
+
+ # ParseLibraries expects pcs to be in a set. Fine by us...
+ my @pclist = (); # pcs in sorted order
+ my $pcs = {};
+ my $map = "";
+ foreach my $line (<$maps_and_symbols_file>) {
+ $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
+ if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
+ push(@pclist, HexExtend($1));
+ $pcs->{$pclist[-1]} = 1;
+ } else {
+ $map .= $line;
+ }
+ }
+
+ my $libs = ParseLibraries($main::prog, $map, $pcs);
+ my $symbols = ExtractSymbols($libs, $pcs);
+
+ foreach my $pc (@pclist) {
+ # ->[0] is the shortname, ->[2] is the full name
+ print(($symbols->{$pc}->[0] || "??") . "\n");
+ }
+}
+
+
# For sorting functions by name
sub ByName {
return ShortFunctionName($a) cmp ShortFunctionName($b);
@@ -1370,11 +1420,11 @@ sub PrintDot {
# Open DOT output file
my $output;
if ($main::opt_gv) {
- $output = "| $DOT -Tps >" . PsTempName($main::next_tmpfile);
+ $output = "| $DOT -Tps2 >" . PsTempName($main::next_tmpfile);
} elsif ($main::opt_ps) {
- $output = "| $DOT -Tps";
+ $output = "| $DOT -Tps2";
} elsif ($main::opt_pdf) {
- $output = "| $DOT -Tps | $PS2PDF - -";
+ $output = "| $DOT -Tps2 | $PS2PDF - -";
} elsif ($main::opt_gif) {
$output = "| $DOT -Tgif";
} else {
@@ -1999,8 +2049,8 @@ sub CheckSymbolPage {
sub IsProfileURL {
my $profile_name = shift;
- my ($host, $port, $type) = ParseProfileURL($profile_name);
- return defined($host) and defined($port) and defined($type);
+ my ($host, $port, $path) = ParseProfileURL($profile_name);
+ return defined($host) and defined($port) and defined($path);
}
sub ParseProfileURL {
@@ -2018,12 +2068,12 @@ sub ParseProfileURL {
# We fetch symbols from the first profile argument.
sub SymbolPageURL {
- my ($host, $port, $type) = ParseProfileURL($main::pfile_args[0]);
+ my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]);
return "http://$host:$port$SYMBOL_PAGE";
}
sub FetchProgramName() {
- my ($host, $port, $type) = ParseProfileURL($main::pfile_args[0]);
+ my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]);
my $url = "http://$host:$port$PROGRAM_NAME_PAGE";
my $command_line = "$WGET -qO- '$url'";
open(CMDLINE, "$command_line |") or error($command_line);
@@ -2085,13 +2135,13 @@ sub FetchSymbols {
close(SYMBOL);
my $symbols = {};
- for my $pc (@pcs) {
+ foreach my $pc (@pcs) {
my $fullname;
# For 64 bits binaries, symbols are extracted with 8 leading zeroes.
- # Then /symbolz reads the long symbols in as uint64, and outputs
+ # Then /symbol reads the long symbols in as uint64, and outputs
# the result with a "0x%08llx" format which get rid of the zeroes.
# By removing all the leading zeroes in both $pc and the symbols from
- # /symbolz, the symbols match and are retrievable from the map.
+ # /symbol, the symbols match and are retrievable from the map.
my $shortpc = $pc;
$shortpc =~ s/^0*//;
if (defined($map{$shortpc})) {
@@ -2113,7 +2163,7 @@ sub BaseName {
sub MakeProfileBaseName {
my ($binary_name, $profile_name) = @_;
- my ($host, $port, $type) = ParseProfileURL($profile_name);
+ my ($host, $port, $path) = ParseProfileURL($profile_name);
my $binary_shortname = BaseName($binary_name);
return sprintf("%s.%s.%s-port%s",
$binary_shortname, $main::op_time, $host, $port);
@@ -2128,17 +2178,17 @@ sub FetchDynamicProfile {
if (!IsProfileURL($profile_name)) {
return $profile_name;
} else {
- my ($host, $port, $type) = ParseProfileURL($profile_name);
- if ($type eq "" || $type eq "/") {
+ my ($host, $port, $path) = ParseProfileURL($profile_name);
+ if ($path eq "" || $path eq "/") {
# Missing type specifier defaults to cpu-profile
- $type = $PROFILE_PAGE;
+ $path = $PROFILE_PAGE;
}
my $profile_file = MakeProfileBaseName($binary_name, $profile_name);
my $url;
my $wget_timeout;
- if ($type eq $PROFILE_PAGE) {
+ if ($path eq $PROFILE_PAGE) {
$url = sprintf("http://$host:$port$PROFILE_PAGE?seconds=%d",
$main::opt_seconds);
$wget_timeout = sprintf("--timeout=%d",
@@ -2146,10 +2196,10 @@ sub FetchDynamicProfile {
} else {
# For non-CPU profiles, we add a type-extension to
# the target profile file name.
- my $suffix = $type;
+ my $suffix = $path;
$suffix =~ s,/,.,g;
$profile_file .= "$suffix";
- $url = "http://$host:$port$type";
+ $url = "http://$host:$port$path";
$wget_timeout = "";
}
@@ -2166,13 +2216,13 @@ sub FetchDynamicProfile {
}
my $cmd = "$WGET $wget_timeout -q -O $tmp_profile '$url'";
- if ($type eq $PROFILE_PAGE) {
+ if ($path eq $PROFILE_PAGE) {
print STDERR "Gathering CPU profile from $host:$port for $main::opt_seconds seconds to\n ${real_profile}\n";
if ($encourage_patience) {
print STDERR "Be patient...\n";
}
} else {
- print STDERR "Fetching $type profile from $host:$port to\n ${real_profile}\n";
+ print STDERR "Fetching $path profile from $host:$port to\n ${real_profile}\n";
}
(system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
@@ -2258,17 +2308,20 @@ sub ReadProfile {
binmode PROFILE; # New perls do UTF-8 processing
my $header = <PROFILE>;
$header =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- my $contention_marker = substr($CONTENTION_PAGE, 1); # remove leading /
- if ($header =~ m/^heap profile:.*growthz/) {
+ $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
+ my $contention_marker = $&;
+ $GROWTH_PAGE =~ m,[^/]+$,;
+ my $growth_marker = $&;
+ if ($header =~ m/^heap profile:.*$growth_marker/o) {
$main::profile_type = 'growth';
return ReadHeapProfile($prog, $fname, $header);
} elsif ($header =~ m/^heap profile:/) {
$main::profile_type = 'heap';
return ReadHeapProfile($prog, $fname, $header);
- } elsif ($header =~ m/^--- *$contention_marker/o ) {
+ } elsif ($header =~ m/^--- *$contention_marker/o) {
$main::profile_type = 'contention';
return ReadSynchProfile($prog, $fname);
- } elsif ($header =~ m/^--- *Stacks:/ ) {
+ } elsif ($header =~ m/^--- *Stacks:/) {
print STDERR
"Old format contention profile: mistakenly reports " .
"condition variable signals as lock contentions.\n";
@@ -2431,27 +2484,49 @@ sub ReadHeapProfile {
# heap profile: 1246: 8800744 [ 1246: 8800744] @ <heap-url>/266053
# There are two pairs <count: size>, the first inuse objects/space, and the
# second allocated objects/space. This is followed optionally by a profile
- # type, and if that is present, optionally by a sampling frequency. The
- # interpretation of the sampling frequency is that the profiler, for each
- # sample, calculates a uniformly distributed random integer less than the
- # given value, and records the next sample after that many bytes have been
- # allocated. Therefore, the expected sample interval is half of the given
- # frequency. By default, if not specified, the expected sample interval is
- # 128KB. Only remote-heap-page profiles are adjusted for sample size.
- my $should_adjust_sample = 0;
+ # type, and if that is present, optionally by a sampling frequency.
+ # For remote heap profiles (v1):
+ # The interpretation of the sampling frequency is that the profiler, for
+ # each sample, calculates a uniformly distributed random integer less than
+ # the given value, and records the next sample after that many bytes have
+ # been allocated. Therefore, the expected sample interval is half of the
+ # given frequency. By default, if not specified, the expected sample
+ # interval is 128KB. Only remote-heap-page profiles are adjusted for
+ # sample size.
+ # For remote heap profiles (v2):
+ # The sampling frequency is the rate of a Poisson process. This means that
+ # the probability of sampling an allocation of size X with sampling rate Y
+ # is 1 - exp(-X/Y)
+ # For version 2, a typical header line might look like this:
+ # heap profile: 1922: 127792360 [ 1922: 127792360] @ <heap-url>_v2/524288
+ # the trailing number (524288) is the sampling rate. (Version 1 showed
+ # double the 'rate' here)
+ my $sampling_algorithm = 0;
my $sample_adjustment = 0;
chomp($header);
my $type = "unknown";
if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") {
if (defined($6) && ($6 ne '')) {
$type = $6;
- # The regex test here is to see if type is a substring of HEAP_PAGE
- if (($HEAP_PAGE =~ /$type/)) {
- $should_adjust_sample = 1;
- if (defined($8) && ($8 ne '')) {
- $sample_adjustment = int($8)/2;
- printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
- $sample_adjustment);
+ my $sample_period = $8;
+ # $type is "heapprofile" for profiles generated by the
+ # heap-profiler, and either "heap" or "heap_v2" for profiles
+ # generated by sampling directly within tcmalloc. It can also
+ # be "growth" for heap-growth profiles. The first is typically
+ # found for profiles generated locally, and the others for
+ # remote profiles.
+ if (($type eq "heapprofile") || ($type !~ /heap/) ) {
+ # No need to adjust for the sampling rate with heap-profiler-derived data
+ $sampling_algorithm = 0;
+ } elsif ($type =~ /_v2/) {
+ $sampling_algorithm = 2; # version 2 sampling
+ if (defined($sample_period) && ($sample_period ne '')) {
+ $sample_adjustment = int($sample_period);
+ }
+ } else {
+ $sampling_algorithm = 1; # version 1 sampling
+ if (defined($sample_period) && ($sample_period ne '')) {
+ $sample_adjustment = int($sample_period)/2;
}
}
} else {
@@ -2460,20 +2535,30 @@ sub ReadHeapProfile {
# same as the in-use stats ($n1,$s1). It is remotely conceivable
# that a non-remote-heap profile may pass this check, but it is hard
# to imagine how that could happen.
+ # In this case it's so old it's guaranteed to be remote-heap version 1.
my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
if (($n1 == $n2) && ($s1 == $s2)) {
# This is likely to be a remote-heap based sample profile
- $should_adjust_sample = 1;
+ $sampling_algorithm = 1;
}
}
}
- # For remote-heap generated profiles, adjust the counts and sizes to
- # account for the sample rate (we sample once every 128KB by default).
- if ($should_adjust_sample && ($sample_adjustment == 0)) {
- # Turn on profile adjustment.
- $sample_adjustment = 128*1024;
- print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
+ if ($sampling_algorithm > 0) {
+ # For remote-heap generated profiles, adjust the counts and sizes to
+ # account for the sample rate (we sample once every 128KB by default).
+ if ($sample_adjustment == 0) {
+ # Turn on profile adjustment.
+ $sample_adjustment = 128*1024;
+ print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
+ } else {
+ printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
+ $sample_adjustment);
+ }
+ if ($sampling_algorithm > 1) {
+ # We don't bother printing anything for the original version (version 1)
+ printf STDERR "Heap version $sampling_algorithm\n";
+ }
}
my $profile = {};
@@ -2518,16 +2603,34 @@ sub ReadHeapProfile {
my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
if ($sample_adjustment) {
- my $ratio;
- $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
- if ($ratio < 1) {
- $n1 /= $ratio;
- $s1 /= $ratio;
- }
- $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
- if ($ratio < 1) {
- $n2 /= $ratio;
- $s2 /= $ratio;
+ if ($sampling_algorithm == 2) {
+ # Remote-heap version 2
+ # The sampling frequency is the rate of a Poisson process.
+ # This means that the probability of sampling an allocation of
+ # size X with sampling rate Y is 1 - exp(-X/Y)
+ my $ratio;
+ $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
+ my $scale_factor;
+ $scale_factor = 1/(1 - exp(-$ratio));
+ $n1 *= $scale_factor;
+ $s1 *= $scale_factor;
+ $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
+ $scale_factor = 1/(1 - exp(-$ratio));
+ $n2 *= $scale_factor;
+ $s2 *= $scale_factor;
+ } else {
+ # Remote-heap version 1
+ my $ratio;
+ $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
+ if ($ratio < 1) {
+ $n1 /= $ratio;
+ $s1 /= $ratio;
+ }
+ $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
+ if ($ratio < 1) {
+ $n2 /= $ratio;
+ $s2 /= $ratio;
+ }
}
}
@@ -2613,7 +2716,7 @@ sub ReadSynchProfile {
# Currently nothing is done with this value in pprof
# So we just silently ignore it for now
} else {
- printf STDERR ("Ignoring unnknown variable in /contentionz output: " .
+ printf STDERR ("Ignoring unnknown variable in /contention output: " .
"'%s' = '%s'\n",$variable,$value);
}
} else {
@@ -3061,7 +3164,6 @@ sub AddressInc {
# Extract symbols for all PC values found in profile
sub ExtractSymbols {
my $libs = shift;
- my $profile = shift;
my $pcset = shift;
my $symbols = {};
@@ -3270,8 +3372,8 @@ sub ConfigureObjTools {
# the opensource release, which is capable of parsing
# Windows-style PDB executables. It should live in the path, or
# in the same directory as pprof.
- $obj_tool_map{"nm_pdb"} = "nm_pdb";
- $obj_tool_map{"addr2line_pdb"} = "addr2line_pdb";
+ $obj_tool_map{"nm_pdb"} = "nm-pdb";
+ $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
}
if ($file_type =~ /Mach-O/) {
diff --git a/src/profiler.cc b/src/profiler.cc
index 17277a7..8675348 100644
--- a/src/profiler.cc
+++ b/src/profiler.cc
@@ -444,7 +444,8 @@ void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext) {
// removed by "pprof" at analysis time. Instead of skipping the top
// frames, we could skip nothing, but that would increase the
// profile size unnecessarily.
- int depth = GetStackTrace(stack + 1, arraysize(stack) - 1, 2);
+ int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
+ 2, signal_ucontext);
depth++; // To account for pc value in stack[0];
instance_.collector_.Add(depth, stack);
diff --git a/src/raw_printer.cc b/src/raw_printer.cc
new file mode 100644
index 0000000..7e0cc17
--- /dev/null
+++ b/src/raw_printer.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: sanjay@google.com (Sanjay Ghemawat)
+
+#include "config.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include "raw_printer.h"
+#include "base/logging.h"
+
+namespace base {
+
+RawPrinter::RawPrinter(char* buf, int length)
+ : base_(buf),
+ ptr_(buf),
+ limit_(buf + length - 1) {
+ RAW_DCHECK(length > 0, "");
+ *ptr_ = '\0';
+ *limit_ = '\0';
+}
+
+void RawPrinter::Printf(const char* format, ...) {
+ if (limit_ > ptr_) {
+ va_list ap;
+ va_start(ap, format);
+ int avail = limit_ - ptr_;
+ // We pass avail+1 to vsnprintf() since that routine needs room
+ // to store the trailing \0.
+ const int r = vsnprintf(ptr_, avail+1, format, ap);
+ va_end(ap);
+ if (r < 0) {
+ // Perhaps an old glibc that returns -1 on truncation?
+ ptr_ = limit_;
+ } else if (r > avail) {
+ // Truncation
+ ptr_ = limit_;
+ } else {
+ ptr_ += r;
+ }
+ }
+}
+
+}
diff --git a/src/raw_printer.h b/src/raw_printer.h
new file mode 100644
index 0000000..08f324b
--- /dev/null
+++ b/src/raw_printer.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Sanjay Ghemawat
+//
+// A printf() wrapper that writes into a fixed length buffer.
+// Useful in low-level code that does not want to use allocating
+// routines like StringPrintf().
+//
+// The implementation currently uses vsnprintf(). This seems to
+// be fine for use in many low-level contexts, but we may need to
+// rethink this decision if we hit a problem with it calling
+// down into malloc() etc.
+
+#ifndef BASE_RAW_PRINTER_H_
+#define BASE_RAW_PRINTER_H_
+
+#include "config.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class RawPrinter {
+ public:
+ // REQUIRES: "length > 0"
+ // Will printf any data added to this into "buf[0,length-1]" and
+ // will arrange to always keep buf[] null-terminated.
+ RawPrinter(char* buf, int length);
+
+ // Return the number of bytes that have been appended to the string
+ // so far. Does not count any bytes that were dropped due to overflow.
+ int length() const { return (ptr_ - base_); }
+
+ // Return the number of bytes that can be added to this.
+ int space_left() const { return (limit_ - ptr_); }
+
+ // Format the supplied arguments according to the "format" string
+ // and append to this. Will silently truncate the output if it does
+ // not fit.
+ void Printf(const char* format, ...)
+#ifdef HAVE___ATTRIBUTE__
+ __attribute__ ((__format__ (__printf__, 2, 3)))
+#endif
+;
+
+ private:
+ // We can write into [ptr_ .. limit_-1].
+ // *limit_ is also writable, but reserved for a terminating \0
+ // in case we overflow.
+ //
+ // Invariants: *ptr_ == \0
+ // Invariants: *limit_ == \0
+ char* base_; // Initial pointer
+ char* ptr_; // Where should we write next
+ char* limit_; // One past last non-\0 char we can write
+
+ DISALLOW_COPY_AND_ASSIGN(RawPrinter);
+};
+
+}
+
+#endif // BASE_RAW_PRINTER_H_
diff --git a/src/sampler.cc b/src/sampler.cc
new file mode 100755
index 0000000..dda225c
--- /dev/null
+++ b/src/sampler.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// All Rights Reserved.
+//
+// Author: Daniel Ford
+
+#include "sampler.h"
+
+#include <algorithm> // For min()
+#include <cmath>
+
+using std::min;
+
+// Twice the approximate gap between sampling actions.
+// I.e., we take one sample approximately once every
+// tcmalloc_sample_parameter bytes of allocation
+// i.e. about once every 512KB.
+#ifdef NO_TCMALLOC_SAMPLES
+DEFINE_int64(tcmalloc_sample_parameter, 0,
+ "Unused: code is compiled with NO_TCMALLOC_SAMPLES");
+#else
+DEFINE_int64(tcmalloc_sample_parameter,
+ EnvToInt64("TCMALLOC_SAMPLE_PARAMETER", 1<<19),
+ "The approximate gap in bytes between sampling actions."
+ "This must be between 1 and 1<<58.");
+// Note: there are other places in this file where the number 19 occurs.
+#endif
+
+namespace tcmalloc {
+
+// Statics for Sampler
+double Sampler::log_table_[1<<kFastlogNumBits];
+
+// Populate the lookup table for FastLog2
+// The approximates the log2 curve with a step function
+// Steps have height equal to log2 of the mid-point of the step
+void Sampler::PopulateFastLog2Table() {
+ for (int i = 0; i < (1<<kFastlogNumBits); i++) {
+ log_table_[i] = (log(1.0 + static_cast<double>(i+0.5)/(1<<kFastlogNumBits))
+ / log(2.0));
+ }
+}
+
+int Sampler::GetSamplePeriod() {
+ return FLAGS_tcmalloc_sample_parameter;
+}
+
+// Run this before using your sampler
+void Sampler::Init(uint32_t seed) {
+ // Initialize PRNG
+ if (seed != 0) {
+ rnd_ = seed;
+ } else {
+ rnd_ = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(this));
+ if (rnd_ == 0) {
+ rnd_ = 1;
+ }
+ }
+ // Step it forward 20 times for good measure
+ for (int i = 0; i < 20; i++) {
+ rnd_ = NextRandom(rnd_);
+ }
+ // Initialize counter
+ bytes_until_sample_ = PickNextSamplingPoint();
+}
+
+// Initialize the Statics for the Sampler class
+void Sampler::InitStatics() {
+ PopulateFastLog2Table();
+}
+
+// Generates a geometric variable with the specified mean (512K by default).
+// This is done by generating a random number between 0 and 1 and applying
+// the inverse cumulative distribution function for an exponential.
+// Specifically: Let m be the inverse of the sample period, then
+// p = 1 - exp(mx)
+// q = exp(mx)
+// log_e(q) = mx
+// log_e(q)/m = x
+// log_2(q) / (log_e(2) / m) = x
+// The value (log_e(2) / m) is precomputed
+// and may also be approximated for large sampler periods by
+// 1.0 / log2(1.0-1.0/(sample_period_));
+// In the code, q is actually in the range 1 to 2**26, hence the -26
+size_t Sampler::PickNextSamplingPoint() {
+ double sample_scaling = - log(2.0) * FLAGS_tcmalloc_sample_parameter;
+ rnd_ = NextRandom(rnd_);
+ // Take the top 26 bits as the random number
+ // (This plus the 1<<26 sampling bound give a max step possible of
+ // 1209424308 bytes.)
+ const uint64_t prng_mod_power = 48; // Number of bits in prng
+ // The uint32_t cast is to prevent a (hard-to-reproduce) NAN
+ // under piii debug for some binaries.
+ double q = static_cast<uint32_t>(rnd_ >> (prng_mod_power - 26)) + 1.0;
+ // Put the computed p-value through the CDF of a geometric
+ // For faster performance (save ~1/20th exec time), replace
+ // min(FastLog2(q) - 26,0) by (Fastlog2(q) - 26.000705)
+ // The value 26.000705 is used rather than 26 to compensate
+ // for inaccuracies in FastLog2 which otherwise result in a
+ // negative answer.
+ return static_cast<size_t>(min(0.0, (FastLog2(q) - 26)) * sample_scaling + 1);
+}
+
+} // namespace tcmalloc
diff --git a/src/sampler.h b/src/sampler.h
new file mode 100755
index 0000000..f39791d
--- /dev/null
+++ b/src/sampler.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// All Rights Reserved.
+//
+// Author: Daniel Ford
+
+#ifndef TCMALLOC_SAMPLER_H_
+#define TCMALLOC_SAMPLER_H_
+
+#include "config.h"
+#include "common.h"
+#include "static_vars.h"
+
+namespace tcmalloc {
+
+//-------------------------------------------------------------------
+// Sampler to decide when to create a sample trace for an allocation
+// Not thread safe: Each thread should have it's own sampler object.
+// Caller must use external synchronization if used
+// from multiple threads.
+//
+// With 512K average sample step (the default):
+// the probability of sampling a 4K allocation is about 0.00778
+// the probability of sampling a 1MB allocation is about 0.865
+// the probability of sampling a 1GB allocation is about 1.00000
+// In general, the probablity of sampling is an allocation of size X
+// given a flag value of Y (default 1M) is:
+// 1 - e^(-X/Y)
+//
+// With 128K average sample step:
+// the probability of sampling a 1MB allocation is about 0.99966
+// the probability of sampling a 1GB allocation is about 1.0
+// (about 1 - 2**(-26))
+// With 1M average sample step:
+// the probability of sampling a 4K allocation is about 0.00390
+// the probability of sampling a 1MB allocation is about 0.632
+// the probability of sampling a 1GB allocation is about 1.0
+//
+// The sampler works by representing memory as a long stream from
+// which allocations are taken. Some of the bytes in this stream are
+// marked and if an allocation includes a marked byte then it is
+// sampled. Bytes are marked according to a Poisson point process
+// with each byte being marked independently with probability
+// p = 1/tcmalloc_sample_parameter. This makes the probability
+// of sampling an allocation of X bytes equal to the CDF of
+// a geometric with mean tcmalloc_sample_parameter. (ie. the
+// probability that at least one byte in the range is marked). This
+// is accurately given by the CDF of the corresponding exponential
+// distribution : 1 - e^(X/tcmalloc_sample_parameter_)
+// Independence of the byte marking ensures independence of
+// the sampling of each allocation.
+//
+// This scheme is implemented by noting that, starting from any
+// fixed place, the number of bytes until the next marked byte
+// is geometrically distributed. This number is recorded as
+// bytes_until_sample_. Every allocation subtracts from this
+// number until it is less than 0. When this happens the current
+// allocation is sampled.
+//
+// When an allocation occurs, bytes_until_sample_ is reset to
+// a new independtly sampled geometric number of bytes. The
+// memoryless property of the point process means that this may
+// be taken as the number of bytes after the end of the current
+// allocation until the next marked byte. This ensures that
+// very large allocations which would intersect many marked bytes
+// only result in a single call to PickNextSamplingPoint.
+//-------------------------------------------------------------------
+
+class PERFTOOLS_DLL_DECL Sampler {
+ public:
+ // Initialize this sampler.
+ // Passing a seed of 0 gives a non-deterministic
+ // seed value given by casting the object ("this")
+ void Init(uint32_t seed);
+ void Cleanup();
+
+ // Record allocation of "k" bytes. Return true iff allocation
+ // should be sampled
+ bool SampleAllocation(size_t k);
+
+ // Generate a geometric with mean 512K (or FLAG_tcmalloc_sample_parameter)
+ size_t PickNextSamplingPoint();
+
+ // Initialize the statics for the Sampler class
+ static void InitStatics();
+
+ // Returns the current sample period
+ int GetSamplePeriod();
+
+ // The following are public for the purposes of testing
+ static uint64_t NextRandom(uint64_t rnd_); // Returns the next prng value
+ static double FastLog2(const double & d); // Computes Log2(x) quickly
+ static void PopulateFastLog2Table(); // Populate the lookup table
+
+ private:
+ size_t bytes_until_sample_; // Bytes until we sample next
+ uint64_t rnd_; // Cheap random number generator
+
+ // Statics for the fast log
+ // Note that this code may not depend on anything in //util
+ // hence the duplication of functionality here
+ static const int kFastlogNumBits = 10;
+ static const int kFastlogMask = (1 << kFastlogNumBits) - 1;
+ static double log_table_[1<<kFastlogNumBits]; // Constant
+};
+
+inline bool Sampler::SampleAllocation(size_t k) {
+ if (bytes_until_sample_ < k) {
+ bytes_until_sample_ = PickNextSamplingPoint();
+ return true;
+ } else {
+ bytes_until_sample_ -= k;
+ return false;
+ }
+}
+
+// Inline functions which are public for testing purposes
+
+// Returns the next prng value.
+// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48
+// This is the lrand64 generator.
+inline uint64_t Sampler::NextRandom(uint64_t rnd) {
+ const uint64_t prng_mult = 0x5DEECE66DLL;
+ const uint64_t prng_add = 0xB;
+ const uint64_t prng_mod_power = 48;
+ const uint64_t prng_mod_mask =
+ ~((~static_cast<uint64_t>(0)) << prng_mod_power);
+ return (prng_mult * rnd + prng_add) & prng_mod_mask;
+}
+
+// Adapted from //util/math/fastmath.[h|cc] by Noam Shazeer
+// This mimics the VeryFastLog2 code in those files
+inline double Sampler::FastLog2(const double & d) {
+ assert(d>0);
+ assert(sizeof(d) == sizeof(uint64_t));
+ uint64_t x;
+ memcpy(&x, &d, sizeof(x)); // we depend on the compiler inlining this
+ const uint32_t x_high = x >> 32;
+ const uint32_t y = x_high >> (20 - kFastlogNumBits) & kFastlogMask;
+ const int32_t exponent = ((x_high >> 20) & 0x7FF) - 1023;
+ return exponent + log_table_[y];
+}
+
+} // namespace tcmalloc
+
+#endif // TCMALLOC_SAMPLER_H_
diff --git a/src/span.cc b/src/span.cc
index 6be9900..72d36fe 100644
--- a/src/span.cc
+++ b/src/span.cc
@@ -89,7 +89,7 @@ int DLL_Length(const Span* list) {
return result;
}
-#if 0 // This isn't used.
+#if 0 // This isn't used. If that changes, rewrite to use TCMalloc_Printer.
void DLL_Print(const char* label, const Span* list) {
MESSAGE("%-10s %p:", label, list);
for (const Span* s = list->next; s != list; s = s->next) {
diff --git a/src/stack_trace_table.cc b/src/stack_trace_table.cc
new file mode 100644
index 0000000..68e5d7b
--- /dev/null
+++ b/src/stack_trace_table.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Andrew Fikes
+
+#include "config.h"
+#include "base/spinlock.h"
+#include "common.h"
+#include "static_vars.h"
+#include "stack_trace_table.h"
+
+namespace tcmalloc {
+
+bool StackTraceTable::Bucket::KeyEqual(uintptr_t h,
+ const StackTrace& t) const {
+ const bool eq = (this->hash == h && this->trace.depth == t.depth);
+ for (int i = 0; eq && i < t.depth; ++i) {
+ if (this->trace.stack[i] != t.stack[i]) {
+ return false;
+ }
+ }
+ return eq;
+}
+
+StackTraceTable::StackTraceTable()
+ : error_(false),
+ depth_total_(0),
+ bucket_total_(0),
+ table_(new Bucket*[kHashTableSize]()) {
+ memset(table_, 0, kHashTableSize * sizeof(Bucket*));
+}
+
+StackTraceTable::~StackTraceTable() {
+ delete[] table_;
+}
+
+void StackTraceTable::AddTrace(const StackTrace& t) {
+ if (error_) {
+ return;
+ }
+
+ // Hash function borrowed from base/heap-profile-table.cc
+ uintptr_t h = 0;
+ for (int i = 0; i < t.depth; ++i) {
+ h += reinterpret_cast<uintptr_t>(t.stack[i]);
+ h += h << 10;
+ h ^= h >> 6;
+ }
+ h += h << 3;
+ h ^= h >> 11;
+
+ const int idx = h % kHashTableSize;
+
+ Bucket* b = table_[idx];
+ while (b != NULL && !b->KeyEqual(h, t)) {
+ b = b->next;
+ }
+ if (b != NULL) {
+ b->count++;
+ b->trace.size += t.size; // keep cumulative size
+ } else {
+ depth_total_ += t.depth;
+ bucket_total_++;
+ b = Static::bucket_allocator()->New();
+ if (b == NULL) {
+ MESSAGE("tcmalloc: could not allocate bucket", sizeof(*b));
+ error_ = true;
+ } else {
+ b->hash = h;
+ b->trace = t;
+ b->count = 1;
+ b->next = table_[idx];
+ table_[idx] = b;
+ }
+ }
+}
+
+void** StackTraceTable::ReadStackTracesAndClear() {
+ if (error_) {
+ return NULL;
+ }
+
+ // Allocate output array
+ const int out_len = bucket_total_ * 3 + depth_total_ + 1;
+ void** out = new void*[out_len];
+ if (out == NULL) {
+ MESSAGE("tcmalloc: allocation failed for stack traces\n",
+ out_len * sizeof(*out));
+ return NULL;
+ }
+
+ // Fill output array
+ int idx = 0;
+ for (int i = 0; i < kHashTableSize; ++i) {
+ Bucket* b = table_[i];
+ while (b != NULL) {
+ out[idx++] = reinterpret_cast<void*>(static_cast<uintptr_t>(b->count));
+ out[idx++] = reinterpret_cast<void*>(b->trace.size); // cumulative size
+ out[idx++] = reinterpret_cast<void*>(b->trace.depth);
+ for (int d = 0; d < b->trace.depth; ++d) {
+ out[idx++] = b->trace.stack[d];
+ }
+ b = b->next;
+ }
+ }
+ out[idx++] = static_cast<uintptr_t>(0);
+ ASSERT(idx == out_len);
+
+ // Clear state
+ error_ = false;
+ depth_total_ = 0;
+ bucket_total_ = 0;
+ SpinLockHolder h(Static::pageheap_lock());
+ for (int i = 0; i < kHashTableSize; ++i) {
+ Bucket* b = table_[i];
+ while (b != NULL) {
+ Bucket* next = b->next;
+ Static::bucket_allocator()->Delete(b);
+ b = next;
+ }
+ table_[i] = NULL;
+ }
+
+ return out;
+}
+
+} // namespace tcmalloc
diff --git a/src/stack_trace_table.h b/src/stack_trace_table.h
new file mode 100644
index 0000000..d2b798e
--- /dev/null
+++ b/src/stack_trace_table.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Andrew Fikes
+//
+// Utility class for coalescing sampled stack traces. Not thread-safe.
+
+#ifndef TCMALLOC_STACK_TRACE_TABLE_H_
+#define TCMALLOC_STACK_TRACE_TABLE_H_
+
+#include "config.h"
+#include "common.h"
+
+namespace tcmalloc {
+
+class PERFTOOLS_DLL_DECL StackTraceTable {
+ public:
+ // REQUIRES: L < pageheap_lock
+ StackTraceTable();
+ ~StackTraceTable();
+
+ // Adds stack trace "t" to table.
+ //
+ // REQUIRES: L >= pageheap_lock
+ void AddTrace(const StackTrace& t);
+
+ // Returns stack traces formatted per MallocExtension guidelines.
+ // May return NULL on error. Clears state before returning.
+ //
+ // REQUIRES: L < pageheap_lock
+ void** ReadStackTracesAndClear();
+
+ // Exposed for PageHeapAllocator
+ struct Bucket {
+ // Key
+ uintptr_t hash;
+ StackTrace trace;
+
+ // Payload
+ int count;
+ Bucket* next;
+
+ bool KeyEqual(uintptr_t h, const StackTrace& t) const;
+ };
+
+ // For testing
+ int depth_total() const { return depth_total_; }
+ int bucket_total() const { return bucket_total_; }
+
+ private:
+ static const int kHashTableSize = 1 << 14; // => table_ is 128k
+
+ bool error_;
+ int depth_total_;
+ int bucket_total_;
+ Bucket** table_;
+};
+
+} // namespace tcmalloc
+
+#endif // TCMALLOC_STACK_TRACE_TABLE_H_
diff --git a/src/stacktrace.cc b/src/stacktrace.cc
index 136b965..a9a41f3 100644
--- a/src/stacktrace.cc
+++ b/src/stacktrace.cc
@@ -53,48 +53,19 @@
// Some code may do that.
#include "config.h"
+#include <google/stacktrace.h>
+#include "stacktrace_config.h"
-// First, the i386 case.
-#if defined(__i386__) && __GNUC__ >= 2
-# if !defined(NO_FRAME_POINTER)
-# include "stacktrace_x86-inl.h"
-# else
-# include "stacktrace_generic-inl.h"
-# endif
-
-// Now, the x86_64 case.
-#elif defined(__x86_64__) && __GNUC__ >= 2
-# if !defined(NO_FRAME_POINTER)
-# include "stacktrace_x86-inl.h"
-# elif defined(HAVE_LIBUNWIND_H) // a proxy for having libunwind installed
-# define UNW_LOCAL_ONLY
-# include "stacktrace_libunwind-inl.h"
-# elif 0
- // This is the unwinder used by gdb, which can call malloc (see above).
- // We keep this code around, so we can test cases where libunwind
- // doesn't work, but there's no way to enable it except for manually
- // editing this file (by replacing this "elif 0" with "elif 1", e.g.).
-# include "stacktrace_x86_64-inl.h"
-# elif defined(__linux)
-# error Cannnot calculate stack trace: need either libunwind or frame-pointers (see INSTALL file)
-# else
-# error Cannnot calculate stack trace: need libunwind (see INSTALL file)
-# endif
-
-// The PowerPC case
-#elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
-# if !defined(NO_FRAME_POINTER)
-# include "stacktrace_powerpc-inl.h"
-# else
-# include "stacktrace_generic-inl.h"
-# endif
-
-// The Windows case -- probably cygwin and mingw will use one of the
-// x86-includes above, but if not, we can fall back to windows intrinsics.
-#elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__)
-# include "stacktrace_win32-inl.h"
-
-// OK, those are all the processors we know how to deal with.
+#if defined(STACKTRACE_INL_HEADER)
+# include STACKTRACE_INL_HEADER
+#elif 0
+// This is for the benefit of code analysis tools that may have
+// trouble with the computed #include above.
+# include "base/stacktrace_x86-inl.h"
+# include "base/stacktrace_libunwind-inl.h"
+# include "base/stacktrace_generic-inl.h"
+# include "base/stacktrace_powerpc-inl.h"
+# include "base/stacktrace_win32-inl.h"
#else
# error Cannot calculate stack trace: will need to write for your environment
#endif
diff --git a/src/stacktrace_config.h b/src/stacktrace_config.h
new file mode 100644
index 0000000..3bd0fb3
--- /dev/null
+++ b/src/stacktrace_config.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Paul Pluzhnikov
+//
+// Figure out which unwinder to use on a given platform.
+//
+// Defines STACKTRACE_INL_HEADER to the *-inl.h containing
+// actual unwinder implementation.
+//
+// Defines STACKTRACE_SKIP_CONTEXT_ROUTINES if a separate
+// GetStack{Trace,Frames}WithContext should not be provided.
+//
+// This header is "private" to stacktrace.cc and
+// stacktrace_with_context.cc.
+//
+// DO NOT include it into any other files.
+
+#ifndef BASE_STACKTRACE_CONFIG_H_
+#define BASE_STACKTRACE_CONFIG_H_
+
+// First, the i386 case.
+#if defined(__i386__) && __GNUC__ >= 2
+# if !defined(NO_FRAME_POINTER)
+# define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h"
+# define STACKTRACE_SKIP_CONTEXT_ROUTINES 1
+# else
+# define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h"
+# endif
+
+// Now, the x86_64 case.
+#elif defined(__x86_64__) && __GNUC__ >= 2
+# if !defined(NO_FRAME_POINTER)
+# define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h"
+# define STACKTRACE_SKIP_CONTEXT_ROUTINES 1
+# elif defined(HAVE_LIBUNWIND_H) // a proxy for having libunwind installed
+# define STACKTRACE_INL_HEADER "stacktrace_libunwind-inl.h"
+# elif defined(__linux)
+# error Cannnot calculate stack trace: need either libunwind or frame-pointers (see INSTALL file)
+# else
+# error Cannnot calculate stack trace: need libunwind (see INSTALL file)
+# endif
+
+// The PowerPC case
+#elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
+# if !defined(NO_FRAME_POINTER)
+# define STACKTRACE_INL_HEADER "stacktrace_powerpc-inl.h"
+# else
+# define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h"
+# endif
+
+// The Windows case -- probably cygwin and mingw will use one of the
+// x86-includes above, but if not, we can fall back to windows intrinsics.
+#elif defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__)
+# define STACKTRACE_INL_HEADER "stacktrace_win32-inl.h"
+
+#endif // all the cases
+#endif // BASE_STACKTRACE_CONFIG_H_
diff --git a/src/stacktrace_libunwind-inl.h b/src/stacktrace_libunwind-inl.h
index a75e0de..176faff 100644
--- a/src/stacktrace_libunwind-inl.h
+++ b/src/stacktrace_libunwind-inl.h
@@ -32,6 +32,9 @@
//
// Produce stack trace using libunwind
+// We only need local unwinder.
+#define UNW_LOCAL_ONLY
+
extern "C" {
#include <assert.h>
#include <string.h> // for memset()
diff --git a/src/stacktrace_win32-inl.h b/src/stacktrace_win32-inl.h
index f969458..a717714 100644
--- a/src/stacktrace_win32-inl.h
+++ b/src/stacktrace_win32-inl.h
@@ -50,6 +50,7 @@
// http://code.google.com/p/google-perftools/issues/detail?id=83
#include <windows.h> // for GetProcAddress and GetModuleHandle
+#include <assert.h>
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
IN ULONG frames_to_skip,
@@ -71,3 +72,11 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth,
result, 0);
}
+
+int GetStackFrames(void** /* pcs */,
+ int* /* sizes */,
+ int /* max_depth */,
+ int /* skip_count */) {
+ assert(0 == "Not yet implemented");
+ return 0;
+}
diff --git a/src/stacktrace_with_context.cc b/src/stacktrace_with_context.cc
new file mode 100644
index 0000000..f9fc28f
--- /dev/null
+++ b/src/stacktrace_with_context.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Paul Pluzhnikov
+//
+// This code logically belongs in stacktrace.cc, but
+// it is moved into (this) separate file in order to
+// prevent inlining of routines defined here.
+//
+// Inlining causes skip_count to be incorrect, and there
+// is no portable way to prevent it.
+//
+// Eventually LTO (link-time optimization) and/or LLVM
+// may inline this code anyway. Let's hope they respect
+// ATTRIBUTE_NOINLINE.
+
+#include "config.h"
+#include <google/stacktrace.h>
+#include "stacktrace_config.h"
+#include "base/basictypes.h"
+
+#if !defined(STACKTRACE_SKIP_CONTEXT_ROUTINES)
+ATTRIBUTE_NOINLINE
+int GetStackFramesWithContext(void** pcs, int* sizes, int max_depth,
+ int skip_count, const void * /* uc */) {
+ return GetStackFrames(pcs, sizes, max_depth, skip_count + 1);
+}
+
+ATTRIBUTE_NOINLINE
+int GetStackTraceWithContext(void** result, int max_depth,
+ int skip_count, const void * /* uc */) {
+ return GetStackTrace(result, max_depth, skip_count + 1);
+}
+#endif
diff --git a/src/stacktrace_x86-inl.h b/src/stacktrace_x86-inl.h
index e088168..902806d 100644
--- a/src/stacktrace_x86-inl.h
+++ b/src/stacktrace_x86-inl.h
@@ -31,10 +31,22 @@
// Author: Sanjay Ghemawat
//
// Produce stack trace
+//
+// NOTE: there is code duplication between
+// GetStackTrace, GetStackTraceWithContext, GetStackFrames and
+// GetStackFramesWithContext. If you update one, update them all.
+//
+// There is no easy way to avoid this, because inlining
+// iterferes with skip_count, and there is no portable
+// way to turn inlining off, or force it always on.
#include "config.h"
#include <stdlib.h> // for NULL
+#include <assert.h>
+#if HAVE_UCONTEXT_H
+#include <ucontext.h> // for ucontext_t
+#endif
#ifdef HAVE_STDINT_H
#include <stdint.h> // for uintptr_t
#endif
@@ -43,18 +55,171 @@
#endif
#ifdef HAVE_MMAP
#include <sys/mman.h> // for msync
+#include "base/vdso_support.h"
#endif
#include "google/stacktrace.h"
+#if defined(__linux__) && defined(__i386__) && defined(__ELF__) && defined(HAVE_MMAP)
+// Count "push %reg" instructions in VDSO __kernel_vsyscall(),
+// preceeding "syscall" or "sysenter".
+// If __kernel_vsyscall uses frame pointer, answer 0.
+//
+// kMaxBytes tells how many instruction bytes of __kernel_vsyscall
+// to analyze before giving up. Up to kMaxBytes+1 bytes of
+// instructions could be accessed.
+//
+// Here are known __kernel_vsyscall instruction sequences:
+//
+// SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S).
+// Used on Intel.
+// 0xffffe400 <__kernel_vsyscall+0>: push %ecx
+// 0xffffe401 <__kernel_vsyscall+1>: push %edx
+// 0xffffe402 <__kernel_vsyscall+2>: push %ebp
+// 0xffffe403 <__kernel_vsyscall+3>: mov %esp,%ebp
+// 0xffffe405 <__kernel_vsyscall+5>: sysenter
+//
+// SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S).
+// Used on AMD.
+// 0xffffe400 <__kernel_vsyscall+0>: push %ebp
+// 0xffffe401 <__kernel_vsyscall+1>: mov %ecx,%ebp
+// 0xffffe403 <__kernel_vsyscall+3>: syscall
+//
+// i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S)
+// 0xffffe400 <__kernel_vsyscall+0>: int $0x80
+// 0xffffe401 <__kernel_vsyscall+1>: ret
+//
+static const int kMaxBytes = 10;
+
+// We use assert()s instead of DCHECK()s -- this is too low level
+// for DCHECK().
+
+static int CountPushInstructions(const unsigned char *const addr) {
+ int result = 0;
+ for (int i = 0; i < kMaxBytes; ++i) {
+ if (addr[i] == 0x89) {
+ // "mov reg,reg"
+ if (addr[i + 1] == 0xE5) {
+ // Found "mov %esp,%ebp".
+ return 0;
+ }
+ ++i; // Skip register encoding byte.
+ } else if (addr[i] == 0x0F &&
+ (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) {
+ // Found "sysenter" or "syscall".
+ return result;
+ } else if ((addr[i] & 0xF0) == 0x50) {
+ // Found "push %reg".
+ ++result;
+ } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) {
+ // Found "int $0x80"
+ assert(result == 0);
+ return 0;
+ } else {
+ // Unexpected instruction.
+ assert(0 == "unexpected instruction in __kernel_vsyscall");
+ return 0;
+ }
+ }
+ // Unexpected: didn't find SYSENTER or SYSCALL in
+ // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval.
+ assert(0 == "did not find SYSENTER or SYSCALL in __kernel_vsyscall");
+ return 0;
+}
+#endif
+
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return NULL if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
-template<bool STRICT_UNWINDING>
-static void **NextStackFrame(void **old_sp) {
+template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
+static void **NextStackFrame(void **old_sp, const void *uc) {
void **new_sp = (void **) *old_sp;
+#if defined(__linux__) && defined(__i386__) && defined(HAVE_VDSO_SUPPORT)
+ if (WITH_CONTEXT && uc != NULL) {
+ // How many "push %reg" instructions are there at __kernel_vsyscall?
+ // This is constant for a given kernel and processor, so compute
+ // it only once.
+ static int num_push_instructions = -1; // Sentinel: not computed yet.
+ // Initialize with sentinel value: __kernel_rt_sigreturn can not possibly
+ // be there.
+ static const unsigned char *kernel_rt_sigreturn_address = NULL;
+ static const unsigned char *kernel_vsyscall_address = NULL;
+ if (num_push_instructions == -1) {
+ base::VDSOSupport vdso;
+ if (vdso.IsPresent()) {
+ base::VDSOSupport::SymbolInfo rt_sigreturn_symbol_info;
+ base::VDSOSupport::SymbolInfo vsyscall_symbol_info;
+ if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5",
+ STT_FUNC, &rt_sigreturn_symbol_info) ||
+ !vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5",
+ STT_FUNC, &vsyscall_symbol_info) ||
+ rt_sigreturn_symbol_info.address == NULL ||
+ vsyscall_symbol_info.address == NULL) {
+ // Unexpected: 32-bit VDSO is present, yet one of the expected
+ // symbols is missing or NULL.
+ assert(0 == "VDSO is present, but doesn't have expected symbols");
+ num_push_instructions = 0;
+ } else {
+ kernel_rt_sigreturn_address =
+ reinterpret_cast<const unsigned char *>(
+ rt_sigreturn_symbol_info.address);
+ kernel_vsyscall_address =
+ reinterpret_cast<const unsigned char *>(
+ vsyscall_symbol_info.address);
+ num_push_instructions =
+ CountPushInstructions(kernel_vsyscall_address);
+ }
+ } else {
+ num_push_instructions = 0;
+ }
+ }
+ if (num_push_instructions != 0 && kernel_rt_sigreturn_address != NULL &&
+ old_sp[1] == kernel_rt_sigreturn_address) {
+ const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
+ // This kernel does not use frame pointer in its VDSO code,
+ // and so %ebp is not suitable for unwinding.
+ const void **const reg_ebp =
+ reinterpret_cast<const void **>(ucv->uc_mcontext.gregs[REG_EBP]);
+ const unsigned char *const reg_eip =
+ reinterpret_cast<unsigned char *>(ucv->uc_mcontext.gregs[REG_EIP]);
+ if (new_sp == reg_ebp &&
+ kernel_vsyscall_address <= reg_eip &&
+ reg_eip - kernel_vsyscall_address < kMaxBytes) {
+ // We "stepped up" to __kernel_vsyscall, but %ebp is not usable.
+ // Restore from 'ucv' instead.
+ void **const reg_esp =
+ reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_ESP]);
+ // Check that alleged %esp is not NULL and is reasonably aligned.
+ if (reg_esp &&
+ ((uintptr_t)reg_esp & (sizeof(reg_esp) - 1)) == 0) {
+ // Check that alleged %esp is actually readable. This is to prevent
+ // "double fault" in case we hit the first fault due to e.g. stack
+ // corruption.
+ //
+ // page_size is linker-initalized to avoid async-unsafe locking
+ // that GCC would otherwise insert (__cxa_guard_acquire etc).
+ static int page_size;
+ if (page_size == 0) {
+ // First time through.
+ page_size = getpagesize();
+ }
+ void *const reg_esp_aligned =
+ reinterpret_cast<void *>(
+ (uintptr_t)(reg_esp + num_push_instructions - 1) &
+ ~(page_size - 1));
+ if (msync(reg_esp_aligned, page_size, MS_ASYNC) == 0) {
+ // Alleged %esp is readable, use it for further unwinding.
+ new_sp = reinterpret_cast<void **>(
+ reg_esp[num_push_instructions - 1]);
+ }
+ }
+ }
+ }
+ }
+#endif
+
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
if (STRICT_UNWINDING) {
@@ -94,7 +259,32 @@ static void **NextStackFrame(void **old_sp) {
return new_sp;
}
-// If you change this function, also change GetStackFrames below.
+// If you change this function, see NOTE at the top of file.
+// Same as above, but with signal ucontext_t pointer.
+int GetStackTraceWithContext(void** result,
+ int max_depth,
+ int skip_count,
+ const void *uc) {
+ void **sp = reinterpret_cast<void**>(__builtin_frame_address(0));
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ if (*(sp+1) == reinterpret_cast<void *>(0)) {
+ // In 64-bit code, we often see a frame that
+ // points to itself and has a return address of 0.
+ break;
+ }
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ result[n++] = *(sp+1);
+ }
+ // Use strict unwinding rules.
+ sp = NextStackFrame<true, true>(sp, uc);
+ }
+ return n;
+}
+
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
@@ -130,7 +320,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
int n = 0;
while (sp && n < max_depth) {
- if (*(sp+1) == (void *)0) {
+ if (*(sp+1) == reinterpret_cast<void *>(0)) {
// In 64-bit code, we often see a frame that
// points to itself and has a return address of 0.
break;
@@ -141,12 +331,12 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
result[n++] = *(sp+1);
}
// Use strict unwinding rules.
- sp = NextStackFrame<true>(sp);
+ sp = NextStackFrame<true, false>(sp, NULL);
}
return n;
}
-// If you change this function, also change GetStackTrace above:
+// If you change this function, see NOTE at the top of file.
//
// This GetStackFrames routine shares a lot of code with GetStackTrace
// above. This code could have been refactored into a common routine,
@@ -207,7 +397,46 @@ int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
int n = 0;
while (sp && n < max_depth) {
- if (*(sp+1) == (void *)0) {
+ if (*(sp+1) == reinterpret_cast<void *>(0)) {
+ // In 64-bit code, we often see a frame that
+ // points to itself and has a return address of 0.
+ break;
+ }
+ // The GetStackFrames routine is called when we are in some
+ // informational context (the failure signal handler for example).
+ // Use the non-strict unwinding rules to produce a stack trace
+ // that is as complete as possible (even if it contains a few bogus
+ // entries in some rare cases).
+ void **next_sp = NextStackFrame<false, false>(sp, NULL);
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ pcs[n] = *(sp+1);
+ if (next_sp > sp) {
+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
+ n++;
+ }
+ sp = next_sp;
+ }
+ return n;
+}
+
+// If you change this function, see NOTE at the top of file.
+// Same as above, but with signal ucontext_t pointer.
+int GetStackFramesWithContext(void** pcs,
+ int* sizes,
+ int max_depth,
+ int skip_count,
+ const void *uc) {
+ void **sp = reinterpret_cast<void**>(__builtin_frame_address(0));
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ if (*(sp+1) == reinterpret_cast<void *>(0)) {
// In 64-bit code, we often see a frame that
// points to itself and has a return address of 0.
break;
@@ -217,7 +446,7 @@ int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
// Use the non-strict unwinding rules to produce a stack trace
// that is as complete as possible (even if it contains a few bogus
// entries in some rare cases).
- void **next_sp = NextStackFrame<false>(sp);
+ void **next_sp = NextStackFrame<false, true>(sp, uc);
if (skip_count > 0) {
skip_count--;
} else {
diff --git a/src/stacktrace_x86_64-inl.h b/src/stacktrace_x86_64-inl.h
index 41ec5c5..767ef9b 100644
--- a/src/stacktrace_x86_64-inl.h
+++ b/src/stacktrace_x86_64-inl.h
@@ -35,6 +35,7 @@
extern "C" {
#include <stdlib.h> // for NULL
#include <unwind.h> // ABI defined unwinder
+#include <string.h> // for memset
}
#include "google/stacktrace.h"
diff --git a/src/static_vars.cc b/src/static_vars.cc
index 9ab1afa..18d5146 100644
--- a/src/static_vars.cc
+++ b/src/static_vars.cc
@@ -31,6 +31,7 @@
// Author: Ken Ashcraft <opensource@google.com>
#include "static_vars.h"
+#include "sampler.h" // for the init function
namespace tcmalloc {
@@ -40,6 +41,7 @@ CentralFreeListPadded Static::central_cache_[kNumClasses];
PageHeapAllocator<Span> Static::span_allocator_;
PageHeapAllocator<StackTrace> Static::stacktrace_allocator_;
Span Static::sampled_objects_;
+PageHeapAllocator<StackTraceTable::Bucket> Static::bucket_allocator_;
StackTrace* Static::growth_stacks_ = NULL;
char Static::pageheap_memory_[sizeof(PageHeap)];
@@ -49,6 +51,7 @@ void Static::InitStaticVars() {
span_allocator_.New(); // Reduce cache conflicts
span_allocator_.New(); // Reduce cache conflicts
stacktrace_allocator_.Init();
+ bucket_allocator_.Init();
// Do a bit of sanitizing: make sure central_cache is aligned properly
CHECK_CONDITION((sizeof(central_cache_[0]) % 64) == 0);
for (int i = 0; i < kNumClasses; ++i) {
@@ -56,6 +59,7 @@ void Static::InitStaticVars() {
}
new ((void*)pageheap_memory_) PageHeap;
DLL_Init(&sampled_objects_);
+ Sampler::InitStatics();
}
} // namespace tcmalloc
diff --git a/src/static_vars.h b/src/static_vars.h
index f3a6e92..31fc414 100644
--- a/src/static_vars.h
+++ b/src/static_vars.h
@@ -42,6 +42,7 @@
#include "page_heap.h"
#include "page_heap_allocator.h"
#include "span.h"
+#include "stack_trace_table.h"
namespace tcmalloc {
@@ -77,8 +78,11 @@ class Static {
static StackTrace* growth_stacks() { return growth_stacks_; }
static void set_growth_stacks(StackTrace* s) { growth_stacks_ = s; }
- // Stack traces kept for sampled allocations.
+ // State kept for sampled allocations (/pprof/heap support)
static Span* sampled_objects() { return &sampled_objects_; }
+ static PageHeapAllocator<StackTraceTable::Bucket>* bucket_allocator() {
+ return &bucket_allocator_;
+ }
private:
static SpinLock pageheap_lock_;
@@ -93,6 +97,7 @@ class Static {
static PageHeapAllocator<Span> span_allocator_;
static PageHeapAllocator<StackTrace> stacktrace_allocator_;
static Span sampled_objects_;
+ static PageHeapAllocator<StackTraceTable::Bucket> bucket_allocator_;
// Linked list of stack traces recorded every time we allocated memory
// from the system. Useful for finding allocation sites that cause
diff --git a/src/system-alloc.cc b/src/system-alloc.cc
index 0645735..ac32e9e 100644
--- a/src/system-alloc.cc
+++ b/src/system-alloc.cc
@@ -97,6 +97,9 @@ DEFINE_int32(malloc_devmem_limit,
EnvToInt("TCMALLOC_DEVMEM_LIMIT", 0),
"Physical memory limit location in MB for /dev/mem allocation."
" Setting this to 0 means no limit.");
+DEFINE_bool(malloc_skip_sbrk,
+ EnvToBool("TCMALLOC_SKIP_SBRK", false),
+ "Whether sbrk can be used to obtain memory.");
DEFINE_bool(malloc_skip_mmap,
EnvToBool("TCMALLOC_SKIP_MMAP", false),
"Whether mmap can be used to obtain memory.");
@@ -147,6 +150,16 @@ bool RegisterSystemAllocator(SysAllocator *a, int priority) {
void* SbrkSysAllocator::Alloc(size_t size, size_t *actual_size,
size_t alignment) {
+ // Check if we should use sbrk allocation.
+ // FLAGS_malloc_skip_sbrk starts out as false (its uninitialized
+ // state) and eventually gets initialized to the specified value. Note
+ // that this code runs for a while before the flags are initialized.
+ // That means that even if this flag is set to true, some (initial)
+ // memory will be allocated with sbrk before the flag takes effect.
+ if (FLAGS_malloc_skip_sbrk) {
+ return NULL;
+ }
+
// sbrk will release memory if passed a negative number, so we do
// a strict check here
if (static_cast<ptrdiff_t>(size + alignment) < 0) return NULL;
diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc
index 5d8b225..ca88b91 100644
--- a/src/tcmalloc.cc
+++ b/src/tcmalloc.cc
@@ -173,6 +173,31 @@ DEFINE_int64(tcmalloc_large_alloc_report_threshold,
"is very large and therefore you should see no extra "
"logging unless the flag is overridden.");
+// These routines are called by free(), realloc(), etc. if the pointer is
+// invalid. This is a cheap (source-editing required) kind of exception
+// handling for these routines.
+namespace {
+void InvalidFree(void* ptr) {
+ CRASH("Attempt to free invalid pointer: %p\n", ptr);
+}
+
+void* InvalidRealloc(void* old_ptr, size_t new_size) {
+ CRASH("Attempt to realloc invalid pointer: %p (realloc to %" PRIuS ")\n",
+ old_ptr, new_size);
+ return NULL;
+}
+
+size_t InvalidGetSizeForRealloc(void* old_ptr) {
+ CRASH("Attempt to realloc invalid pointer: %p\n", old_ptr);
+ return 0;
+}
+
+size_t InvalidGetAllocatedSize(void* ptr) {
+ CRASH("Attempt to get the size of an invalid pointer: %p\n", ptr);
+ return 0;
+}
+} // unnamed namespace
+
// Extract interesting stats
struct TCMallocStats {
uint64_t system_bytes; // Bytes alloced from system
@@ -281,50 +306,6 @@ static void PrintStats(int level) {
delete[] buffer;
}
-static void** DumpStackTraces() {
- // Count how much space we need
- int needed_slots = 0;
- {
- SpinLockHolder h(Static::pageheap_lock());
- Span* sampled = Static::sampled_objects();
- for (Span* s = sampled->next; s != sampled; s = s->next) {
- StackTrace* stack = reinterpret_cast<StackTrace*>(s->objects);
- needed_slots += 3 + stack->depth;
- }
- needed_slots += 100; // Slop in case sample grows
- needed_slots += needed_slots/8; // An extra 12.5% slop
- }
-
- void** result = new void*[needed_slots];
- if (result == NULL) {
- MESSAGE("tcmalloc: could not allocate %d slots for stack traces\n",
- needed_slots);
- return NULL;
- }
-
- SpinLockHolder h(Static::pageheap_lock());
- int used_slots = 0;
- Span* sampled = Static::sampled_objects();
- for (Span* s = sampled->next; s != sampled; s = s->next) {
- ASSERT(used_slots < needed_slots); // Need to leave room for terminator
- StackTrace* stack = reinterpret_cast<StackTrace*>(s->objects);
- if (used_slots + 3 + stack->depth >= needed_slots) {
- // No more room
- break;
- }
-
- result[used_slots+0] = reinterpret_cast<void*>(static_cast<uintptr_t>(1));
- result[used_slots+1] = reinterpret_cast<void*>(stack->size);
- result[used_slots+2] = reinterpret_cast<void*>(stack->depth);
- for (int d = 0; d < stack->depth; d++) {
- result[used_slots+3+d] = stack->stack[d];
- }
- used_slots += 3 + stack->depth;
- }
- result[used_slots] = reinterpret_cast<void*>(static_cast<uintptr_t>(0));
- return result;
-}
-
static void** DumpHeapGrowthStackTraces() {
// Count how much space we need
int needed_slots = 0;
@@ -342,8 +323,8 @@ static void** DumpHeapGrowthStackTraces() {
void** result = new void*[needed_slots];
if (result == NULL) {
- MESSAGE("tcmalloc: could not allocate %d slots for stack traces\n",
- needed_slots);
+ MESSAGE("tcmalloc: allocation failed for stack trace slots",
+ needed_slots * sizeof(*result));
return NULL;
}
@@ -386,8 +367,17 @@ class TCMallocImplementation : public MallocExtension {
}
}
- virtual void** ReadStackTraces() {
- return DumpStackTraces();
+ virtual void** ReadStackTraces(int* sample_period) {
+ tcmalloc::StackTraceTable table;
+ {
+ SpinLockHolder h(Static::pageheap_lock());
+ Span* sampled = Static::sampled_objects();
+ for (Span* s = sampled->next; s != sampled; s = s->next) {
+ table.AddTrace(*reinterpret_cast<StackTrace*>(s->objects));
+ }
+ }
+ *sample_period = ThreadCache::GetCache()->GetSamplePeriod();
+ return table.ReadStackTracesAndClear(); // grabs and releases pageheap_lock
}
virtual void** ReadHeapGrowthStackTraces() {
@@ -467,6 +457,20 @@ class TCMallocImplementation : public MallocExtension {
virtual double GetMemoryReleaseRate() {
return FLAGS_tcmalloc_release_rate;
}
+ virtual size_t GetEstimatedAllocatedSize(size_t size) {
+ if (size <= kMaxSize) {
+ const size_t cl = Static::sizemap()->SizeClass(size);
+ const size_t alloc_size = Static::sizemap()->ByteSizeForClass(cl);
+ return alloc_size;
+ } else {
+ return tcmalloc::pages(size) << kPageShift;
+ }
+ }
+
+ // This just calls GetSizeWithCallback, but because that's in an
+ // unnamed namespace, we need to move the definition below it in the
+ // file.
+ virtual size_t GetAllocatedSize(void* ptr);
};
// The constructor allocates an object to ensure that initialization
@@ -584,19 +588,7 @@ static void ReportLargeAlloc(Length num_pages, void* result) {
write(STDERR_FILENO, buffer, strlen(buffer));
}
-// These routines are called by free() and realloc() if the pointer is
-// invalid. This is a cheap (source-editing required) kind of exception
-// handling for these routines.
namespace {
-void InvalidFree(void* ptr) {
- CRASH("Attempt to free invalid pointer: %p\n", ptr);
-}
-
-void* InvalidRealloc(void* old_ptr, size_t new_size) {
- CRASH("Attempt to realloc invalid pointer: %p (realloc to %" PRIuS ")\n",
- old_ptr, new_size);
- return NULL;
-}
// Helper for do_malloc().
inline void* do_malloc_pages(Length num_pages) {
@@ -714,33 +706,35 @@ inline void do_free(void* ptr) {
return do_free_with_callback(ptr, &InvalidFree);
}
+inline size_t GetSizeWithCallback(void* ptr,
+ size_t (*invalid_getsize_fn)(void*)) {
+ if (ptr == NULL)
+ return 0;
+ const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
+ size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
+ if (cl != 0) {
+ return Static::sizemap()->ByteSizeForClass(cl);
+ } else {
+ Span *span = Static::pageheap()->GetDescriptor(p);
+ if (span == NULL) { // means we do now own this memory
+ return (*invalid_getsize_fn)(ptr);
+ } else if (span->sizeclass != 0) {
+ Static::pageheap()->CacheSizeClass(p, span->sizeclass);
+ return Static::sizemap()->ByteSizeForClass(span->sizeclass);
+ } else {
+ return span->length << kPageShift;
+ }
+ }
+}
+
// This lets you call back to a given function pointer if ptr is invalid.
// It is used primarily by windows code which wants a specialized callback.
inline void* do_realloc_with_callback(void* old_ptr, size_t new_size,
void* (*invalid_realloc_fn)(void*,
size_t)) {
// Get the size of the old entry
- const PageID p = reinterpret_cast<uintptr_t>(old_ptr) >> kPageShift;
- size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
- Span *span = NULL;
- size_t old_size;
- if (cl == 0) {
- span = Static::pageheap()->GetDescriptor(p);
- if (!span) {
- // span can be NULL because the pointer passed in is invalid
- // (not something returned by malloc or friends), or because the
- // pointer was allocated with some other allocator besides tcmalloc.
- return InvalidRealloc(old_ptr, new_size);
- }
- cl = span->sizeclass;
- Static::pageheap()->CacheSizeClass(p, cl);
- }
- if (cl != 0) {
- old_size = Static::sizemap()->ByteSizeForClass(cl);
- } else {
- ASSERT(span != NULL);
- old_size = span->length << kPageShift;
- }
+ const size_t old_size = GetSizeWithCallback(old_ptr,
+ &InvalidGetSizeForRealloc);
// Reallocate if the new size is larger than the old size,
// or if the new size is significantly smaller than the old size.
@@ -936,6 +930,11 @@ inline void* cpp_alloc(size_t size, bool nothrow) {
} // end unnamed namespace
+// As promised, the definition of this function, declared above.
+size_t TCMallocImplementation::GetAllocatedSize(void* ptr) {
+ return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize);
+}
+
//-------------------------------------------------------------------
// Exported routines
//-------------------------------------------------------------------
diff --git a/src/tests/heap-checker-death_unittest.sh b/src/tests/heap-checker-death_unittest.sh
index e6ec597..e2e73a5 100755
--- a/src/tests/heap-checker-death_unittest.sh
+++ b/src/tests/heap-checker-death_unittest.sh
@@ -95,7 +95,7 @@ Test() {
fi
# If we get here, we failed. Now we just need to report why
echo "FAIL"
- if [ $actual_ec == 255 ]; then # 255 == SIGTERM due to $ALARM
+ if [ $actual_ec -eq 255 ]; then # 255 == SIGTERM due to $ALARM
echo "Test was taking unexpectedly long time to run and so we aborted it."
echo "Try the test case manually or raise the timeout from $timeout"
echo "to distinguish test slowness from a real problem."
@@ -156,7 +156,7 @@ Test 20 1 "Exiting .* because of .* leaks$" "" \
HEAP_CHECKER_TEST_TEST_LOOP_LEAK=1 HEAP_CHECKER_TEST_NO_THREADS=1 || exit 9
# Test that we produce a reasonable textual leak report.
-Test 60 1 "DoAllocHidden heap-checker_unittest[.]cc:" "" \
+Test 60 1 "DoAllocHidden" "" \
HEAP_CHECKER_TEST_TEST_LEAK=1 HEAP_CHECK_TEST_NO_THREADS=1 \
|| exit 10
diff --git a/src/tests/heap-checker_unittest.cc b/src/tests/heap-checker_unittest.cc
index db8e38f..55b6a21 100644
--- a/src/tests/heap-checker_unittest.cc
+++ b/src/tests/heap-checker_unittest.cc
@@ -79,8 +79,6 @@
#include <malloc.h>
#endif
-#include <netinet/in.h> // inet_ntoa
-#include <arpa/inet.h> // inet_ntoa
#ifdef HAVE_EXECINFO_H
#include <execinfo.h> // backtrace
#endif
@@ -479,7 +477,9 @@ static void TestHeapLeakCheckerDeathInverse() {
LogHidden("Leaking", foo);
DeAllocHidden(&bar);
Pause();
- VerifyLeaks(&check, SAME_HEAP, -150 * static_cast<int64>(sizeof(int)), 0);
+ VerifyLeaks(&check, SAME_HEAP,
+ 100 * static_cast<int64>(sizeof(int)),
+ 1);
DeAllocHidden(&foo);
}
@@ -511,7 +511,9 @@ static void TestHeapLeakCheckerDeathCountLess() {
DeAllocHidden(&bar1);
DeAllocHidden(&bar2);
Pause();
- VerifyLeaks(&check, SAME_HEAP, 0, -1);
+ VerifyLeaks(&check, SAME_HEAP,
+ 100 * sizeof(int),
+ 1);
DeAllocHidden(&foo);
}
@@ -530,7 +532,9 @@ static void TestHeapLeakCheckerDeathCountMore() {
LogHidden("Leaking", bar2);
DeAllocHidden(&foo);
Pause();
- VerifyLeaks(&check, SAME_HEAP, 0, 1);
+ VerifyLeaks(&check, SAME_HEAP,
+ 100 * sizeof(int),
+ 2);
DeAllocHidden(&bar1);
DeAllocHidden(&bar2);
}
@@ -557,8 +561,8 @@ static void TestHeapLeakChecker() {
}
}
-// no false positives from pprof
-static void TestHeapLeakCheckerPProf() {
+// no false positives
+static void TestHeapLeakCheckerNoFalsePositives() {
{ HeapLeakChecker check("trivial_p");
int foo = 5;
int* p = &foo;
@@ -579,9 +583,9 @@ static void TestHeapLeakCheckerPProf() {
}
}
-// trick heap change: same total # of bytes and objects, but
-// different individual object sizes
-static void TestHeapLeakCheckerTrick() {
+// test that we detect leaks when we have same total # of bytes and
+// objects, but different individual object sizes
+static void TestLeakButTotalsMatch() {
void* bar1 = AllocHidden(240 * sizeof(int));
Use(&bar1);
void* bar2 = AllocHidden(160 * sizeof(int));
@@ -599,16 +603,10 @@ static void TestHeapLeakCheckerTrick() {
DeAllocHidden(&bar1);
DeAllocHidden(&bar2);
Pause();
- if (can_create_leaks_reliably) {
- WipeStack(); // to help with can_create_leaks_reliably
- // this might still fail occasionally, but it should be very rare:
- CHECK(check.BriefSameHeap());
- } else {
- // we expect it to usually misbehave, so we silence it:
- WARN_IF(RUN_SILENT(check, BriefSameHeap) != true,
- "Tricky leaks unexpectedly found: "
- "Some liveness flood must be too optimistic");
- }
+
+ // foo1 and foo2 leaked
+ VerifyLeaks(&check, NO_LEAKS, (280+120)*sizeof(int), 2);
+
DeAllocHidden(&foo1);
DeAllocHidden(&foo2);
}
@@ -644,14 +642,6 @@ static void TransLeaks() {
AllocHidden(1 * sizeof(char));
}
-// have leaks but range-disable them
-void RangeDisabledLeaks() {
- void* start_address = HeapLeakChecker::GetDisableChecksStart();
- AllocHidden(3 * sizeof(int));
- TransLeaks();
- HeapLeakChecker::DisableChecksToHereFrom(start_address);
-}
-
// range-based disabling using Disabler
static void ScopedDisabledLeaks() {
HeapLeakChecker::Disabler disabler;
@@ -662,7 +652,6 @@ static void ScopedDisabledLeaks() {
// have different disabled leaks
static void* RunDisabledLeaks(void* a) {
- RangeDisabledLeaks();
ScopedDisabledLeaks();
return a;
}
@@ -815,9 +804,6 @@ static void TestLibCAllocate() {
}
strerror(errno);
- struct in_addr addr;
- addr.s_addr = INADDR_ANY;
- inet_ntoa(addr);
const time_t now = time(NULL);
ctime(&now);
#ifdef HAVE_EXECINFO_H
@@ -938,107 +924,6 @@ static void RunHeapBusyThreads() {
Pause();
}
-// NOTE: For NamedDisabledLeaks, NamedTwoDisabledLeaks
-// and NamedThreeDisabledLeaks for the name-based disabling to work in opt mode
-// we need to undo the tail-recursion optimization effect
-// of -foptimize-sibling-calls that is enabled by -O2 in gcc 3.* and 4.*
-// so that for the leaking calls we can find the stack frame
-// that resolves to a Named*DisabledLeaks function.
-// We do this by adding a fake last statement to these functions
-// so that tail-recursion optimization is done with it.
-
-// have leaks that we disable via our function name in MODULE_INITIALIZER
-static void NamedDisabledLeaks() {
- AllocHidden(5 * sizeof(float));
- TransLeaks();
- sleep(0); // undo -foptimize-sibling-calls
-}
-
-// to trick complier into preventing inlining
-static void (*named_disabled_leaks)() = &NamedDisabledLeaks;
-
-// have leaks that we disable via our function name ourselves
-void NamedTwoDisabledLeaks() {
- static bool first = true;
- if (first) {
- HeapLeakChecker::DisableChecksIn("NamedTwoDisabledLeaks");
- first = false;
- }
- AllocHidden(5 * sizeof(double));
- TransLeaks();
- sleep(0); // undo -foptimize-sibling-calls
-}
-
-// to trick complier into preventing inlining
-static void (*named_two_disabled_leaks)() = &NamedTwoDisabledLeaks;
-
-// have leaks that we disable via our function name in our caller
-static void NamedThreeDisabledLeaks() {
- AllocHidden(5 * sizeof(float));
- TransLeaks();
- sleep(0); // undo -foptimize-sibling-calls
-}
-
-// to trick complier into preventing inlining
-static void (*named_three_disabled_leaks)() = &NamedThreeDisabledLeaks;
-
-static bool range_disable_named = false;
-
-// have leaks that we disable via function names
-void* RunNamedDisabledLeaks(void* a) {
- // We get the address unconditionally here to fool gcc 4.1.0 in opt mode:
- // else it reorders the binary code so that our return address bracketing
- // does not work here.
- void* start_address = HeapLeakChecker::GetDisableChecksStart();
-
- named_disabled_leaks();
- named_two_disabled_leaks();
- named_three_disabled_leaks();
-
- // TODO(maxim): do not need this if we make pprof work in automated test runs
- if (range_disable_named) {
- HeapLeakChecker::DisableChecksToHereFrom(start_address);
- }
- sleep(0); // undo -foptimize-sibling-calls
- return a;
-}
-
-// have leaks inside of threads that we disable via function names
-static void ThreadNamedDisabledLeaks() {
- if (FLAGS_no_threads) return;
- pthread_t tid;
- pthread_attr_t attr;
- CHECK_EQ(pthread_attr_init(&attr), 0);
- CHECK_EQ(pthread_create(&tid, &attr, RunNamedDisabledLeaks, NULL), 0);
- void* res;
- CHECK_EQ(pthread_join(tid, &res), 0);
-}
-
-// test leak disabling via function names
-void TestHeapLeakCheckerNamedDisabling() {
- HeapLeakChecker::DisableChecksIn("NamedThreeDisabledLeaks");
-
- HeapLeakChecker check("named_disabling");
-
- RunNamedDisabledLeaks(NULL);
- RunNamedDisabledLeaks(NULL);
- ThreadNamedDisabledLeaks();
- RunNamedDisabledLeaks(NULL);
- ThreadNamedDisabledLeaks();
- ThreadNamedDisabledLeaks();
-
- Pause();
-
- if (!FLAGS_maybe_stripped) {
- CHECK_EQ(check.SameHeap(), true);
- // pprof checking should allow it
- } else {
- WARN_IF(check.SameHeap() != true,
- "named_disabling leaks are caught; "
- "we must be using a stripped binary");
- }
-}
-
// ========================================================================= //
// This code section is to test that objects that are reachable from global
@@ -1493,7 +1378,7 @@ int main(int argc, char** argv) {
TestHeapLeakChecker();
Pause();
- TestHeapLeakCheckerTrick();
+ TestLeakButTotalsMatch();
Pause();
TestHeapLeakCheckerDeathSimple();
@@ -1514,7 +1399,7 @@ int main(int argc, char** argv) {
CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good
- TestHeapLeakCheckerPProf();
+ TestHeapLeakCheckerNoFalsePositives();
Pause();
TestHeapLeakCheckerDisabling();
@@ -1548,9 +1433,6 @@ int main(int argc, char** argv) {
CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good
- void* start_address = HeapLeakChecker::GetDisableChecksStart();
-
- TestHeapLeakCheckerNamedDisabling();
Pause();
if (!FLAGS_maybe_stripped) {
@@ -1560,13 +1442,6 @@ int main(int argc, char** argv) {
"overall leaks are caught; we must be using a stripped binary");
}
- // TODO(maxim): do not need these if we make pprof work in automated test runs
- HeapLeakChecker::DisableChecksToHereFrom(start_address);
- // This will also disable (w/o relying on pprof anymore)
- // all leaks that earlier occured inside of ThreadNamedDisabledLeaks:
- range_disable_named = true;
- ThreadNamedDisabledLeaks();
-
CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good
return Pass();
diff --git a/src/tests/heap-profiler_unittest.sh b/src/tests/heap-profiler_unittest.sh
index 04bf7cc..a728aa9 100755
--- a/src/tests/heap-profiler_unittest.sh
+++ b/src/tests/heap-profiler_unittest.sh
@@ -59,8 +59,8 @@ TEST_TMPDIR=/tmp/heap_profile_info
# It's meaningful to the profiler, so make sure we know its state
unset HEAPPROFILE
-rm -rf $TEST_TMPDIR
-mkdir $TEST_TMPDIR || exit 2
+rm -rf "$TEST_TMPDIR"
+mkdir "$TEST_TMPDIR" || exit 2
num_failures=0
@@ -69,7 +69,7 @@ num_failures=0
# name, verify that the function name takes up at least 90% of the
# allocated memory. The function name is actually specified first.
VerifyMemFunction() {
- function=$1
+ function="$1"
shift
# get program name. Note we have to unset HEAPPROFILE so running
@@ -79,21 +79,33 @@ VerifyMemFunction() {
if [ $# = 2 ]; then
[ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
[ -f "$2" ] || { echo "Profile not found: $2"; exit 1; }
- $PPROF --base="$1" $exec "$2" >$TEST_TMPDIR/output.pprof 2>&1
+ $PPROF --base="$1" $exec "$2" >"$TEST_TMPDIR/output.pprof" 2>&1
else
[ -f "$1" ] || { echo "Profile not found: $1"; exit 1; }
- $PPROF $exec "$1" >$TEST_TMPDIR/output.pprof 2>&1
+ $PPROF $exec "$1" >"$TEST_TMPDIR/output.pprof" 2>&1
fi
- cat $TEST_TMPDIR/output.pprof \
+ cat "$TEST_TMPDIR/output.pprof" \
| tr -d % | awk '$6 ~ /^'$function'$/ && $2 > 90 {exit 1;}'
if [ $? != 1 ]; then
echo
echo "--- Test failed for $function: didn't account for 90% of executable memory"
echo "--- Program output:"
- cat $TEST_TMPDIR/output
+ cat "$TEST_TMPDIR/output"
echo "--- pprof output:"
- cat $TEST_TMPDIR/output.pprof
+ cat "$TEST_TMPDIR/output.pprof"
+ echo "---"
+ num_failures=`expr $num_failures + 1`
+ fi
+}
+
+VerifyOutputContains() {
+ text="$1"
+
+ if ! grep "$text" "$TEST_TMPDIR/output" >/dev/null 2>&1; then
+ echo "--- Test failed: output does not contain '$text'"
+ echo "--- Program output:"
+ cat "$TEST_TMPDIR/output"
echo "---"
num_failures=`expr $num_failures + 1`
fi
@@ -101,20 +113,28 @@ VerifyMemFunction() {
HEAPPROFILE="$TEST_TMPDIR/test"
HEAP_PROFILE_INUSE_INTERVAL="10240" # need this to be 10Kb
+HEAP_PROFILE_ALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
+HEAP_PROFILE_DEALLOCATION_INTERVAL="$HEAP_PROFILE_INUSE_INTERVAL"
export HEAPPROFILE
export HEAP_PROFILE_INUSE_INTERVAL
+export HEAP_PROFILE_ALLOCATION_INTERVAL
+export HEAP_PROFILE_DEALLOCATION_INTERVAL
# We make the unittest run a child process, to test that the child
# process doesn't try to write a heap profile as well and step on the
# parent's toes. If it does, we expect the parent-test to fail.
$HEAP_PROFILER 1 >$TEST_TMPDIR/output 2>&1 # run program, with 1 child proc
-VerifyMemFunction Allocate2 $HEAPPROFILE.0723.heap
-VerifyMemFunction Allocate $HEAPPROFILE.0700.heap $HEAPPROFILE.0760.heap
+VerifyMemFunction Allocate2 "$HEAPPROFILE.1329.heap"
+VerifyMemFunction Allocate "$HEAPPROFILE.1448.heap" "$HEAPPROFILE.1548.heap"
# Check the child process got to emit its own profile as well.
-VerifyMemFunction Allocate2 ${HEAPPROFILE}_*.0723.heap
-VerifyMemFunction Allocate ${HEAPPROFILE}_*.0700.heap ${HEAPPROFILE}_*.0760.heap
+VerifyMemFunction Allocate2 "$HEAPPROFILE"_*.1329.heap
+VerifyMemFunction Allocate "$HEAPPROFILE"_*.1448.heap "$HEAPPROFILE"_*.1548.heap
+
+# Make sure we logged both about allocating and deallocating memory
+VerifyOutputContains "62 MB allocated"
+VerifyOutputContains "62 MB freed"
rm -rf $TMPDIR # clean up
diff --git a/src/tests/malloc_extension_test.cc b/src/tests/malloc_extension_test.cc
new file mode 100644
index 0000000..7254fe5
--- /dev/null
+++ b/src/tests/malloc_extension_test.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Craig Silverstein
+//
+// Simple test of malloc_extension. Includes test of C shims.
+
+#include "config_for_unittests.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include "base/logging.h"
+#include <google/malloc_extension.h>
+#include <google/malloc_extension_c.h>
+
+int main(int argc, char** argv) {
+ void* a = malloc(1000);
+
+ size_t cxx_bytes_used, c_bytes_used;
+ CHECK(MallocExtension::instance()->GetNumericProperty(
+ "generic.current_allocated_bytes", &cxx_bytes_used));
+ CHECK(MallocExtension_GetNumericProperty(
+ "generic.current_allocated_bytes", &c_bytes_used));
+ CHECK_GT(cxx_bytes_used, 1000);
+ CHECK_EQ(cxx_bytes_used, c_bytes_used);
+
+ CHECK(MallocExtension::instance()->VerifyAllMemory());
+ CHECK(MallocExtension_VerifyAllMemory());
+
+ CHECK_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
+ // This is just a sanity check. If we allocated too much, tcmalloc is broken
+ CHECK_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
+ CHECK_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000), 1000);
+
+ // Check the c-shim version too.
+ CHECK_GE(MallocExtension_GetAllocatedSize(a), 1000);
+ CHECK_LE(MallocExtension_GetAllocatedSize(a), 5000);
+ CHECK_GE(MallocExtension_GetEstimatedAllocatedSize(1000), 1000);
+
+ free(a);
+
+ printf("DONE\n");
+ return 0;
+}
diff --git a/src/tests/pagemap_unittest.cc b/src/tests/pagemap_unittest.cc
new file mode 100644
index 0000000..902b8dd
--- /dev/null
+++ b/src/tests/pagemap_unittest.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2003, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Sanjay Ghemawat
+
+#include "config_for_unittests.h"
+#include <stdio.h>
+#include <stdlib.h>
+#if defined HAVE_STDINT_H
+#include <stdint.h> // to get intptr_t
+#elif defined HAVE_INTTYPES_H
+#include <inttypes.h> // another place intptr_t might be defined
+#endif
+#include <sys/types.h>
+#include <vector>
+#include "base/logging.h"
+#include "pagemap.h"
+
+using std::vector;
+
+static void Permute(vector<intptr_t>* elements) {
+ if (elements->empty())
+ return;
+ const size_t num_elements = elements->size();
+ for (size_t i = num_elements - 1; i > 0; --i) {
+ const size_t newpos = rand() % (i + 1);
+ const intptr_t tmp = (*elements)[i]; // swap
+ (*elements)[i] = (*elements)[newpos];
+ (*elements)[newpos] = tmp;
+ }
+}
+
+// Note: we leak memory every time a map is constructed, so do not
+// create too many maps.
+
+// Test specified map type
+template <class Type>
+void TestMap(int limit, bool limit_is_below_the_overflow_boundary) {
+ { // Test sequential ensure/assignment
+ Type map(malloc);
+ for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
+ map.Ensure(i, 1);
+ map.set(i, (void*)(i+1));
+ CHECK_EQ(map.get(i), (void*)(i+1));
+ }
+ for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
+ CHECK_EQ(map.get(i), (void*)(i+1));
+ }
+ }
+
+ { // Test bulk Ensure
+ Type map(malloc);
+ map.Ensure(0, limit);
+ for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
+ map.set(i, (void*)(i+1));
+ CHECK_EQ(map.get(i), (void*)(i+1));
+ }
+ for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
+ CHECK_EQ(map.get(i), (void*)(i+1));
+ }
+ }
+
+ // Test that we correctly notice overflow
+ {
+ Type map(malloc);
+ CHECK_EQ(map.Ensure(limit, limit+1), limit_is_below_the_overflow_boundary);
+ }
+
+ { // Test randomized accesses
+ srand(301); // srand isn't great, but it's portable
+ vector<intptr_t> elements;
+ for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) elements.push_back(i);
+ Permute(&elements);
+
+ Type map(malloc);
+ for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
+ map.Ensure(elements[i], 1);
+ map.set(elements[i], (void*)(elements[i]+1));
+ CHECK_EQ(map.get(elements[i]), (void*)(elements[i]+1));
+ }
+ for (intptr_t i = 0; i < static_cast<intptr_t>(limit); i++) {
+ CHECK_EQ(map.get(i), (void*)(i+1));
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+ TestMap< TCMalloc_PageMap1<10> > (100, true);
+ TestMap< TCMalloc_PageMap1<10> > (1 << 10, false);
+ TestMap< TCMalloc_PageMap2<20> > (100, true);
+ TestMap< TCMalloc_PageMap2<20> > (1 << 20, false);
+ TestMap< TCMalloc_PageMap3<20> > (100, true);
+ TestMap< TCMalloc_PageMap3<20> > (1 << 20, false);
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/src/tests/raw_printer_test.cc b/src/tests/raw_printer_test.cc
new file mode 100644
index 0000000..3138b50
--- /dev/null
+++ b/src/tests/raw_printer_test.cc
@@ -0,0 +1,60 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+// Author: sanjay@google.com (Sanjay Ghemawat)
+
+#include "raw_printer.h"
+#include <stdio.h>
+#include <string>
+#include "base/logging.h"
+
+using std::string;
+
+#define TEST(a, b) void TEST_##a##_##b()
+#define RUN_TEST(a, b) TEST_##a##_##b()
+
+TEST(RawPrinter, Empty) {
+ char buffer[1];
+ base::RawPrinter printer(buffer, arraysize(buffer));
+ CHECK_EQ(0, printer.length());
+ CHECK_EQ(string(""), buffer);
+ CHECK_EQ(0, printer.space_left());
+ printer.Printf("foo");
+ CHECK_EQ(string(""), string(buffer));
+ CHECK_EQ(0, printer.length());
+ CHECK_EQ(0, printer.space_left());
+}
+
+TEST(RawPrinter, PartiallyFilled) {
+ char buffer[100];
+ base::RawPrinter printer(buffer, arraysize(buffer));
+ printer.Printf("%s %s", "hello", "world");
+ CHECK_EQ(string("hello world"), string(buffer));
+ CHECK_EQ(11, printer.length());
+ CHECK_LT(0, printer.space_left());
+}
+
+TEST(RawPrinter, Truncated) {
+ char buffer[3];
+ base::RawPrinter printer(buffer, arraysize(buffer));
+ printer.Printf("%d", 12345678);
+ CHECK_EQ(string("12"), string(buffer));
+ CHECK_EQ(2, printer.length());
+ CHECK_EQ(0, printer.space_left());
+}
+
+TEST(RawPrinter, ExactlyFilled) {
+ char buffer[12];
+ base::RawPrinter printer(buffer, arraysize(buffer));
+ printer.Printf("%s %s", "hello", "world");
+ CHECK_EQ(string("hello world"), string(buffer));
+ CHECK_EQ(11, printer.length());
+ CHECK_EQ(0, printer.space_left());
+}
+
+int main(int argc, char **argv) {
+ RUN_TEST(RawPrinter, Empty);
+ RUN_TEST(RawPrinter, PartiallyFilled);
+ RUN_TEST(RawPrinter, Truncated);
+ RUN_TEST(RawPrinter, ExactlyFilled);
+ printf("PASS\n");
+ return 0; // 0 means success
+}
diff --git a/src/tests/realloc_unittest.cc b/src/tests/realloc_unittest.cc
new file mode 100644
index 0000000..20edb50
--- /dev/null
+++ b/src/tests/realloc_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2004, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Sanjay Ghemawat
+//
+// Test realloc() functionality
+
+#include "config_for_unittests.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm> // for min()
+#include "base/logging.h"
+
+using std::min;
+
+// Fill a buffer of the specified size with a predetermined pattern
+static void Fill(unsigned char* buffer, int n) {
+ for (int i = 0; i < n; i++) {
+ buffer[i] = (i & 0xff);
+ }
+}
+
+// Check that the specified buffer has the predetermined pattern
+// generated by Fill()
+static bool Valid(unsigned char* buffer, int n) {
+ for (int i = 0; i < n; i++) {
+ if (buffer[i] != (i & 0xff)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Return the next interesting size/delta to check. Returns -1 if no more.
+static int NextSize(int size) {
+ if (size < 100) {
+ return size+1;
+ } else if (size < 100000) {
+ // Find next power of two
+ int power = 1;
+ while (power < size) {
+ power <<= 1;
+ }
+
+ // Yield (power-1, power, power+1)
+ if (size < power-1) {
+ return power-1;
+ } else if (size == power-1) {
+ return power;
+ } else {
+ assert(size == power);
+ return power+1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+int main(int argc, char** argv) {
+ for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+ for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+ unsigned char* src = (unsigned char*) malloc(src_size);
+ Fill(src, src_size);
+ unsigned char* dst = (unsigned char*) realloc(src, dst_size);
+ CHECK(Valid(dst, min(src_size, dst_size)));
+ Fill(dst, dst_size);
+ CHECK(Valid(dst, dst_size));
+ if (dst != NULL) free(dst);
+ }
+ }
+
+ // Now make sure realloc works correctly even when we overflow the
+ // packed cache, so some entries are evicted from the cache.
+ // The cache has 2^12 entries, keyed by page number.
+ const int kNumEntries = 1 << 14;
+ int** p = (int**)malloc(sizeof(*p) * kNumEntries);
+ int sum = 0;
+ for (int i = 0; i < kNumEntries; i++) {
+ p[i] = (int*)malloc(8192); // no page size is likely to be bigger
+ p[i][1000] = i; // use memory deep in the heart of p
+ }
+ for (int i = 0; i < kNumEntries; i++) {
+ p[i] = (int*)realloc(p[i], 9000);
+ }
+ for (int i = 0; i < kNumEntries; i++) {
+ sum += p[i][1000];
+ free(p[i]);
+ }
+ CHECK_EQ(kNumEntries/2 * (kNumEntries - 1), sum); // assume kNE is even
+ free(p);
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/src/tests/sampler_test.cc b/src/tests/sampler_test.cc
new file mode 100755
index 0000000..2d5824e
--- /dev/null
+++ b/src/tests/sampler_test.cc
@@ -0,0 +1,653 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// All Rights Reserved.
+//
+// Author: Daniel Ford
+//
+// Checks basic properties of the sampler
+
+#include "config_for_unittests.h"
+#include <stdlib.h> // defines posix_memalign
+#include <stdio.h> // for the printf at the end
+#if defined HAVE_STDINT_H
+#include <stdint.h> // to get uintptr_t
+#elif defined HAVE_INTTYPES_H
+#include <inttypes.h> // another place uintptr_t might be defined
+#endif
+#include <sys/types.h>
+#include <iostream>
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <cmath>
+#include "base/logging.h"
+#include "base/commandlineflags.h"
+#include "sampler.h" // The Sampler class being tested
+
+using std::sort;
+using std::min;
+using std::max;
+using std::vector;
+using std::abs;
+
+vector<void (*)()> g_testlist; // the tests to run
+
+#define TEST(a, b) \
+ struct Test_##a##_##b { \
+ Test_##a##_##b() { g_testlist.push_back(&Run); } \
+ static void Run(); \
+ }; \
+ static Test_##a##_##b g_test_##a##_##b; \
+ void Test_##a##_##b::Run()
+
+
+static int RUN_ALL_TESTS() {
+ vector<void (*)()>::const_iterator it;
+ for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
+ (*it)(); // The test will error-exit if there's a problem.
+ }
+ fprintf(stderr, "\nPassed %d tests\n\nPASS\n", (int)g_testlist.size());
+ return 0;
+}
+
+#undef LOG // defined in base/logging.h
+// Ideally, we'd put the newline at the end, but this hack puts the
+// newline at the end of the previous log message, which is good enough :-)
+#define LOG(level) std::cerr << "\n"
+
+static std::string StringPrintf(const char* format, ...) {
+ char buf[256]; // should be big enough for all logging
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+ return buf;
+}
+
+namespace {
+template<typename T> class scoped_array {
+ public:
+ scoped_array(T* p) : p_(p) { }
+ ~scoped_array() { delete[] p_; }
+ const T* get() const { return p_; }
+ T* get() { return p_; }
+ T& operator[](int i) { return p_[i]; }
+ private:
+ T* p_;
+};
+}
+
+// Note that these tests are stochastic.
+// This mean that the chance of correct code passing the test is,
+// in the case of 5 standard deviations:
+// kSigmas=5: ~99.99994267%
+// in the case of 4 standard deviations:
+// kSigmas=4: ~99.993666%
+static const double kSigmas = 4;
+static const size_t kSamplingInterval = 512*1024;
+
+// Tests that GetSamplePeriod returns the expected value
+// which is 1<<19
+TEST(Sampler, TestGetSamplePeriod) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ uint64_t sample_period;
+ sample_period = sampler.GetSamplePeriod();
+ CHECK_GT(sample_period, 0);
+}
+
+// Tests of the quality of the random numbers generated
+// This uses the Anderson Darling test for uniformity.
+// See "Evaluating the Anderson-Darling Distribution" by Marsaglia
+// for details.
+
+// Short cut version of ADinf(z), z>0 (from Marsaglia)
+// This returns the p-value for Anderson Darling statistic in
+// the limit as n-> infinity. For finite n, apply the error fix below.
+double AndersonDarlingInf(double z) {
+ if (z < 2) {
+ return exp(-1.2337141 / z) / sqrt(z) * (2.00012 + (0.247105 -
+ (0.0649821 - (0.0347962 - (0.011672 - 0.00168691
+ * z) * z) * z) * z) * z);
+ }
+ return exp( - exp(1.0776 - (2.30695 - (0.43424 - (0.082433 -
+ (0.008056 - 0.0003146 * z) * z) * z) * z) * z));
+}
+
+// Corrects the approximation error in AndersonDarlingInf for small values of n
+// Add this to AndersonDarlingInf to get a better approximation
+// (from Marsaglia)
+double AndersonDarlingErrFix(int n, double x) {
+ if (x > 0.8) {
+ return (-130.2137 + (745.2337 - (1705.091 - (1950.646 -
+ (1116.360 - 255.7844 * x) * x) * x) * x) * x) / n;
+ }
+ double cutoff = 0.01265 + 0.1757 / n;
+ double t;
+ if (x < cutoff) {
+ t = x / cutoff;
+ t = sqrt(t) * (1 - t) * (49 * t - 102);
+ return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n;
+ } else {
+ t = (x - cutoff) / (0.8 - cutoff);
+ t = -0.00022633 + (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864
+ * t) * t) * t) * t) * t;
+ return t * (0.04213 + 0.01365 / n) / n;
+ }
+}
+
+// Returns the AndersonDarling p-value given n and the value of the statistic
+double AndersonDarlingPValue(int n, double z) {
+ double ad = AndersonDarlingInf(z);
+ double errfix = AndersonDarlingErrFix(n, ad);
+ return ad + errfix;
+}
+
+double AndersonDarlingStatistic(int n, double* random_sample) {
+ double ad_sum = 0;
+ for (int i = 0; i < n; i++) {
+ ad_sum += (2*i + 1) * log(random_sample[i] * (1 - random_sample[n-1-i]));
+ }
+ double ad_statistic = - n - 1/static_cast<double>(n) * ad_sum;
+ return ad_statistic;
+}
+
+// Tests if the array of doubles is uniformly distributed.
+// Returns the p-value of the Anderson Darling Statistic
+// for the given set of sorted random doubles
+// See "Evaluating the Anderson-Darling Distribution" by
+// Marsaglia and Marsaglia for details.
+double AndersonDarlingTest(int n, double* random_sample) {
+ double ad_statistic = AndersonDarlingStatistic(n, random_sample);
+ LOG(INFO) << StringPrintf("AD stat = %f, n=%d\n", ad_statistic, n);
+ double p = AndersonDarlingPValue(n, ad_statistic);
+ return p;
+}
+
+// Test the AD Test. The value of the statistic should go to zero as n->infty
+// Not run as part of regular tests
+void ADTestTest(int n) {
+ scoped_array<double> random_sample(new double[n]);
+ for (int i = 0; i < n; i++) {
+ random_sample[i] = (i+0.01)/n;
+ }
+ sort(random_sample.get(), random_sample.get() + n);
+ double ad_stat = AndersonDarlingStatistic(n, random_sample.get());
+ LOG(INFO) << StringPrintf("Testing the AD test. n=%d, ad_stat = %f",
+ n, ad_stat);
+}
+
+// Print the CDF of the distribution of the Anderson-Darling Statistic
+// Used for checking the Anderson-Darling Test
+// Not run as part of regular tests
+void ADCDF() {
+ for (int i = 1; i < 40; i++) {
+ double x = i/10.0;
+ LOG(INFO) << "x= " << x << " adpv= "
+ << AndersonDarlingPValue(100, x) << ", "
+ << AndersonDarlingPValue(1000, x);
+ }
+}
+
+// Testing that NextRandom generates uniform
+// random numbers.
+// Applies the Anderson-Darling test for uniformity
+void TestNextRandom(int n) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ uint64_t x = 1;
+ // This assumes that the prng returns 48 bit numbers
+ uint64_t max_prng_value = static_cast<uint64_t>(1)<<48;
+ // Initialize
+ for (int i = 1; i <= 20; i++) { // 20 mimics sampler.Init()
+ x = sampler.NextRandom(x);
+ }
+ scoped_array<uint64_t> int_random_sample(new uint64_t[n]);
+ // Collect samples
+ for (int i = 0; i < n; i++) {
+ int_random_sample[i] = x;
+ x = sampler.NextRandom(x);
+ }
+ // First sort them...
+ sort(int_random_sample.get(), int_random_sample.get() + n);
+ scoped_array<double> random_sample(new double[n]);
+ // Convert them to uniform randoms (in the range [0,1])
+ for (int i = 0; i < n; i++) {
+ random_sample[i] = static_cast<double>(int_random_sample[i])/max_prng_value;
+ }
+ // Now compute the Anderson-Darling statistic
+ double ad_pvalue = AndersonDarlingTest(n, random_sample.get());
+ LOG(INFO) << StringPrintf("pvalue for AndersonDarlingTest "
+ "with n= %d is p= %f\n", n, ad_pvalue);
+ CHECK_GT(min(ad_pvalue, 1 - ad_pvalue), 0.0001);
+ // << StringPrintf("prng is not uniform, %d\n", n);
+}
+
+
+TEST(Sampler, TestNextRandom_MultipleValues) {
+ TestNextRandom(10); // Check short-range correlation
+ TestNextRandom(100);
+ TestNextRandom(1000);
+ TestNextRandom(10000); // Make sure there's no systematic error
+}
+
+// Tests that PickNextSamplePeriod generates
+// geometrically distributed random numbers.
+// First converts to uniforms then applied the
+// Anderson-Darling test for uniformity.
+void TestPickNextSample(int n) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ scoped_array<uint64_t> int_random_sample(new uint64_t[n]);
+ int sample_period = sampler.GetSamplePeriod();
+ int ones_count = 0;
+ for (int i = 0; i < n; i++) {
+ int_random_sample[i] = sampler.PickNextSamplingPoint();
+ CHECK_GE(int_random_sample[i], 1);
+ if (int_random_sample[i] == 1) {
+ ones_count += 1;
+ }
+ CHECK_LT(ones_count, 4); // << " out of " << i << " samples.";
+ }
+ // First sort them...
+ sort(int_random_sample.get(), int_random_sample.get() + n);
+ scoped_array<double> random_sample(new double[n]);
+ // Convert them to uniform random numbers
+ // by applying the geometric CDF
+ for (int i = 0; i < n; i++) {
+ random_sample[i] = 1 - exp(-static_cast<double>(int_random_sample[i])
+ / sample_period);
+ }
+ // Now compute the Anderson-Darling statistic
+ double geom_ad_pvalue = AndersonDarlingTest(n, random_sample.get());
+ LOG(INFO) << StringPrintf("pvalue for geometric AndersonDarlingTest "
+ "with n= %d is p= %f\n", n, geom_ad_pvalue);
+ CHECK_GT(min(geom_ad_pvalue, 1 - geom_ad_pvalue), 0.0001);
+ // << "PickNextSamplingPoint does not produce good "
+ // "geometric/exponential random numbers\n";
+}
+
+TEST(Sampler, TestPickNextSample_MultipleValues) {
+ TestPickNextSample(10); // Make sure the first few are good (enough)
+ TestPickNextSample(100);
+ TestPickNextSample(1000);
+ TestPickNextSample(10000); // Make sure there's no systematic error
+}
+
+
+// This is superceeded by the Anderson-Darling Test
+// and it not run now.
+// Tests how fast nearby values are spread out with LRand64
+// The purpose of this code is to determine how many
+// steps to apply to the seed during initialization
+void TestLRand64Spread() {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ uint64_t current_value;
+ printf("Testing LRand64 Spread\n");
+ for (int i = 1; i < 10; i++) {
+ printf("%d ", i);
+ current_value = i;
+ for (int j = 1; j < 100; j++) {
+ current_value = sampler.NextRandom(current_value);
+ }
+ LOG(INFO) << current_value;
+ }
+}
+
+
+// Test for Fastlog2 code
+// We care about the percentage error because we're using this
+// for choosing step sizes, so "close" is relative to the size of
+// the step we would get if we used the built-in log function
+TEST(Sampler, FastLog2) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ double max_ratio_error = 0;
+ for (double d = -1021.9; d < 1; d+= 0.13124235) {
+ double e = pow(2.0, d);
+ double truelog = log(e) / log(2.0); // log_2(e)
+ double fastlog = sampler.FastLog2(e);
+ max_ratio_error = max(max_ratio_error,
+ max(truelog/fastlog-1, fastlog/truelog-1));
+ CHECK_LE(max_ratio_error, 0.01);
+ // << StringPrintf("d = %f, e=%f, truelog = %f, fastlog= %f\n",
+ // d, e, truelog, fastlog);
+ }
+ LOG(INFO) << StringPrintf("Fastlog2: max_ratio_error = %f\n",
+ max_ratio_error);
+}
+
+// Futher tests
+
+bool CheckMean(size_t mean, int num_samples) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ size_t total = 0;
+ for (int i = 0; i < num_samples; i++) {
+ total += sampler.PickNextSamplingPoint();
+ }
+ double empirical_mean = total / static_cast<double>(num_samples);
+ double expected_sd = mean / pow(num_samples * 1.0, 0.5);
+ return(abs(mean-empirical_mean) < expected_sd * kSigmas);
+}
+
+// Prints a sequence so you can look at the distribution
+void OutputSequence(int sequence_length) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ size_t next_step;
+ for (int i = 0; i< sequence_length; i++) {
+ next_step = sampler.PickNextSamplingPoint();
+ LOG(INFO) << next_step;
+ }
+}
+
+
+double StandardDeviationsErrorInSample(
+ int total_samples, int picked_samples,
+ int alloc_size, int sampling_interval) {
+ double p = 1 - exp(-(static_cast<double>(alloc_size) / sampling_interval));
+ double expected_samples = total_samples * p;
+ double sd = pow(p*(1-p)*total_samples, 0.5);
+ return((picked_samples - expected_samples) / sd);
+}
+
+TEST(Sampler, LargeAndSmallAllocs_CombinedTest) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ int counter_big = 0;
+ int counter_small = 0;
+ int size_big = 129*8*1024+1;
+ int size_small = 1024*8;
+ int num_iters = 128*4*8;
+ // Allocate in mixed chunks
+ for (int i = 0; i < num_iters; i++) {
+ if (sampler.SampleAllocation(size_big)) {
+ counter_big += 1;
+ }
+ for (int i = 0; i < 129; i++) {
+ if (sampler.SampleAllocation(size_small)) {
+ counter_small += 1;
+ }
+ }
+ }
+ // Now test that there are the right number of each
+ double large_allocs_sds =
+ StandardDeviationsErrorInSample(num_iters, counter_big,
+ size_big, kSamplingInterval);
+ double small_allocs_sds =
+ StandardDeviationsErrorInSample(num_iters*129, counter_small,
+ size_small, kSamplingInterval);
+ LOG(INFO) << StringPrintf("large_allocs_sds = %f\n", large_allocs_sds);
+ LOG(INFO) << StringPrintf("small_allocs_sds = %f\n", small_allocs_sds);
+ CHECK_LE(abs(large_allocs_sds), kSigmas);
+ CHECK_LE(abs(small_allocs_sds), kSigmas);
+}
+
+// Tests whether the mean is about right over 1000 samples
+TEST(Sampler, IsMeanRight) {
+ CHECK(CheckMean(kSamplingInterval, 1000));
+}
+
+// This flag is for the OldSampler class to use
+const int64 FLAGS_mock_tcmalloc_sample_parameter = 1<<19;
+
+// A cut down and slightly refactored version of the old Sampler
+class OldSampler {
+ public:
+ void Init(uint32_t seed);
+ void Cleanup() {}
+
+ // Record allocation of "k" bytes. Return true iff allocation
+ // should be sampled
+ bool SampleAllocation(size_t k);
+
+ // Generate a geometric with mean 1M (or FLAG value)
+ void PickNextSample(size_t k);
+
+ // Initialize the statics for the Sample class
+ static void InitStatics() {
+ sample_period = 1048583;
+ }
+ size_t bytes_until_sample_;
+
+ private:
+ uint32_t rnd_; // Cheap random number generator
+ static uint64_t sample_period;
+ // Should be a prime just above a power of 2:
+ // 2, 5, 11, 17, 37, 67, 131, 257,
+ // 521, 1031, 2053, 4099, 8209, 16411,
+ // 32771, 65537, 131101, 262147, 524309, 1048583,
+ // 2097169, 4194319, 8388617, 16777259, 33554467
+};
+
+// Statics for OldSampler
+uint64_t OldSampler::sample_period;
+
+void OldSampler::Init(uint32_t seed) {
+ // Initialize PRNG -- run it for a bit to get to good values
+ if (seed != 0) {
+ rnd_ = seed;
+ } else {
+ rnd_ = 12345;
+ }
+ bytes_until_sample_ = 0;
+ for (int i = 0; i < 100; i++) {
+ PickNextSample(sample_period * 2);
+ }
+};
+
+// A cut-down version of the old PickNextSampleRoutine
+void OldSampler::PickNextSample(size_t k) {
+ // Copied from "base/synchronization.cc" (written by Mike Burrows)
+ // Make next "random" number
+ // x^32+x^22+x^2+x^1+1 is a primitive polynomial for random numbers
+ static const uint32_t kPoly = (1 << 22) | (1 << 2) | (1 << 1) | (1 << 0);
+ uint32_t r = rnd_;
+ rnd_ = (r << 1) ^ ((static_cast<int32_t>(r) >> 31) & kPoly);
+
+ // Next point is "rnd_ % (sample_period)". I.e., average
+ // increment is "sample_period/2".
+ const int flag_value = FLAGS_mock_tcmalloc_sample_parameter;
+ static int last_flag_value = -1;
+
+ if (flag_value != last_flag_value) {
+ // There should be a spinlock here, but this code is
+ // for benchmarking only.
+ sample_period = 1048583;
+ last_flag_value = flag_value;
+ }
+
+ bytes_until_sample_ += rnd_ % sample_period;
+
+ if (k > (static_cast<size_t>(-1) >> 2)) {
+ // If the user has asked for a huge allocation then it is possible
+ // for the code below to loop infinitely. Just return (note that
+ // this throws off the sampling accuracy somewhat, but a user who
+ // is allocating more than 1G of memory at a time can live with a
+ // minor inaccuracy in profiling of small allocations, and also
+ // would rather not wait for the loop below to terminate).
+ return;
+ }
+
+ while (bytes_until_sample_ < k) {
+ // Increase bytes_until_sample_ by enough average sampling periods
+ // (sample_period >> 1) to allow us to sample past the current
+ // allocation.
+ bytes_until_sample_ += (sample_period >> 1);
+ }
+
+ bytes_until_sample_ -= k;
+}
+
+inline bool OldSampler::SampleAllocation(size_t k) {
+ if (bytes_until_sample_ < k) {
+ PickNextSample(k);
+ return true;
+ } else {
+ bytes_until_sample_ -= k;
+ return false;
+ }
+}
+
+// This checks that the stated maximum value for the
+// tcmalloc_sample_parameter flag never overflows bytes_until_sample_
+TEST(Sampler, bytes_until_sample_Overflow_Underflow) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ uint64_t one = 1;
+ // sample_parameter = 0; // To test the edge case
+ uint64_t sample_parameter_array[4] = {0, 1, one<<19, one<<58};
+ for (int i = 0; i < 4; i++) {
+ uint64_t sample_parameter = sample_parameter_array[i];
+ LOG(INFO) << "sample_parameter = " << sample_parameter;
+ double sample_scaling = - log(2.0) * sample_parameter;
+ // Take the top 26 bits as the random number
+ // (This plus the 1<<26 sampling bound give a max step possible of
+ // 1209424308 bytes.)
+ const uint64_t prng_mod_power = 48; // Number of bits in prng
+
+ // First, check the largest_prng value
+ uint64_t largest_prng_value = (static_cast<uint64_t>(1)<<48) - 1;
+ double q = (largest_prng_value >> (prng_mod_power - 26)) + 1.0;
+ LOG(INFO) << StringPrintf("q = %f\n", q);
+ LOG(INFO) << StringPrintf("FastLog2(q) = %f\n", sampler.FastLog2(q));
+ LOG(INFO) << StringPrintf("log2(q) = %f\n", log(q)/log(2.0));
+ // Replace min(sampler.FastLog2(q) - 26, 0.0) with
+ // (sampler.FastLog2(q) - 26.000705) when using that optimization
+ uint64_t smallest_sample_step
+ = static_cast<uint64_t>(min(sampler.FastLog2(q) - 26, 0.0)
+ * sample_scaling + 1);
+ LOG(INFO) << "Smallest sample step is " << smallest_sample_step;
+ uint64_t cutoff = static_cast<uint64_t>(10)
+ * (sample_parameter/(one<<24) + 1);
+ LOG(INFO) << "Acceptable value is < " << cutoff;
+ // This checks that the answer is "small" and positive
+ CHECK_LE(smallest_sample_step, cutoff);
+
+ // Next, check with the smallest prng value
+ uint64_t smallest_prng_value = 0;
+ q = (smallest_prng_value >> (prng_mod_power - 26)) + 1.0;
+ LOG(INFO) << StringPrintf("q = %f\n", q);
+ // Replace min(sampler.FastLog2(q) - 26, 0.0) with
+ // (sampler.FastLog2(q) - 26.000705) when using that optimization
+ uint64_t largest_sample_step
+ = static_cast<uint64_t>(min(sampler.FastLog2(q) - 26, 0.0)
+ * sample_scaling + 1);
+ LOG(INFO) << "Largest sample step is " << largest_sample_step;
+ CHECK_LE(largest_sample_step, one<<63);
+ CHECK_GE(largest_sample_step, smallest_sample_step);
+ }
+}
+
+
+// Test that NextRand is in the right range. Unfortunately, this is a
+// stochastic test which could miss problems.
+TEST(Sampler, NextRand_range) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ uint64_t one = 1;
+ // The next number should be (one << 48) - 1
+ uint64_t max_value = (one << 48) - 1;
+ uint64_t x = (one << 55);
+ int n = 22; // 27;
+ LOG(INFO) << "Running sampler.NextRandom 1<<" << n << " times";
+ for (int i = 1; i <= (1<<n); i++) { // 20 mimics sampler.Init()
+ x = sampler.NextRandom(x);
+ CHECK_LE(x, max_value);
+ }
+}
+
+// Tests certain arithmetic operations to make sure they compute what we
+// expect them too (for testing across different platforms)
+TEST(Sampler, arithmetic_1) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ uint64_t rnd; // our 48 bit random number, which we don't trust
+ const uint64_t prng_mod_power = 48;
+ uint64_t one = 1;
+ rnd = one;
+ uint64_t max_value = (one << 48) - 1;
+ for (int i = 1; i <= (1>>27); i++) { // 20 mimics sampler.Init()
+ rnd = sampler.NextRandom(rnd);
+ CHECK_LE(rnd, max_value);
+ double q = (rnd >> (prng_mod_power - 26)) + 1.0;
+ CHECK_GE(q, 0); // << rnd << " " << prng_mod_power;
+ }
+ // Test some potentially out of bounds value for rnd
+ for (int i = 1; i <= 66; i++) {
+ rnd = one << i;
+ double q = (rnd >> (prng_mod_power - 26)) + 1.0;
+ LOG(INFO) << "rnd = " << rnd << " i=" << i << " q=" << q;
+ CHECK_GE(q, 0);
+ // << " rnd=" << rnd << " i=" << i << " prng_mod_power" << prng_mod_power;
+ }
+}
+
+void test_arithmetic(uint64_t rnd) {
+ const uint64_t prng_mod_power = 48; // Number of bits in prng
+ uint64_t shifted_rnd = rnd >> (prng_mod_power - 26);
+ CHECK_GE(shifted_rnd, 0);
+ CHECK_LT(shifted_rnd, (1<<26));
+ LOG(INFO) << shifted_rnd;
+ LOG(INFO) << static_cast<double>(shifted_rnd);
+ CHECK_GE(static_cast<double>(static_cast<uint32_t>(shifted_rnd)), 0);
+ // << " rnd=" << rnd << " srnd=" << shifted_rnd;
+ CHECK_GE(static_cast<double>(shifted_rnd), 0);
+ // << " rnd=" << rnd << " srnd=" << shifted_rnd;
+ double q = static_cast<double>(shifted_rnd) + 1.0;
+ CHECK_GT(q, 0);
+}
+
+// Tests certain arithmetic operations to make sure they compute what we
+// expect them too (for testing across different platforms)
+// know bad values under with -c dbg --cpu piii for _some_ binaries:
+// rnd=227453640600554
+// shifted_rnd=54229173
+// (hard to reproduce)
+TEST(Sampler, arithmetic_2) {
+ uint64_t rnd = 227453640600554LL;
+ test_arithmetic(rnd);
+}
+
+
+// It's not really a test, but it's good to know
+TEST(Sample, size_of_class) {
+ tcmalloc::Sampler sampler;
+ sampler.Init(1);
+ LOG(INFO) << "Size of Sampler class is: " << sizeof(tcmalloc::Sampler);
+ LOG(INFO) << "Size of Sampler object is: " << sizeof(sampler);
+}
+
+int main(int argc, char **argv) {
+ return RUN_ALL_TESTS();
+}
diff --git a/src/tests/sampling_test.cc b/src/tests/sampling_test.cc
index d75815f..6845574 100644
--- a/src/tests/sampling_test.cc
+++ b/src/tests/sampling_test.cc
@@ -64,7 +64,7 @@ int main(int argc, char** argv) {
fprintf(stderr, "USAGE: %s <base of output files>\n", argv[0]);
exit(1);
}
- for (int i = 0; i < 10000; i++) {
+ for (int i = 0; i < 9000; i++) {
AllocateAllocate();
}
diff --git a/src/tests/sampling_test.sh b/src/tests/sampling_test.sh
index 22c2fad..9e45f67 100755
--- a/src/tests/sampling_test.sh
+++ b/src/tests/sampling_test.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Copyright (c) 2008, Google Inc.
# All rights reserved.
@@ -65,21 +65,21 @@ die() {
rm -rf "$OUTDIR" || die "Unable to delete $OUTDIR"
mkdir "$OUTDIR" || die "Unable to create $OUTDIR"
-# This puts the output into out.heap and out.growth.
-# It allocates 10^8 bytes of memory, which is 95M. However,
-# because we sample, the estimate may be a bit low. I've seen
-# from about 88.5M to 91.5M estimates.
+# This puts the output into out.heap and out.growth. It allocates
+# 9*10^7 bytes of memory, which is 85M. Because we sample, the
+# estimate may be a bit high or a bit low: we accept anything from
+# 70M to 99M.
"$SAMPLING_TEST" "$OUTDIR/out"
echo -n "Testing heap output..."
"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap" \
- | grep '^ *[8-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
+ | grep '^ *[7-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|| die `"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap"`
echo "OK"
echo -n "Testing growth output..."
"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth" \
- | grep '^ *[8-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
+ | grep '^ *[7-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|| die `"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth"`
echo "OK"
diff --git a/src/tests/stack_trace_table_test.cc b/src/tests/stack_trace_table_test.cc
new file mode 100644
index 0000000..61f9e64
--- /dev/null
+++ b/src/tests/stack_trace_table_test.cc
@@ -0,0 +1,97 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+// Author: fikes@google.com (Andrew Fikes)
+
+#include "config_for_unittests.h"
+#include <stdio.h> // for puts()
+#include "stack_trace_table.h"
+#include "base/logging.h"
+#include "base/spinlock.h"
+#include "static_vars.h"
+
+#undef ARRAYSIZE // may be defined on, eg, windows
+#define ARRAYSIZE(a) ( sizeof(a) / sizeof(*(a)) )
+
+static void CheckTracesAndReset(tcmalloc::StackTraceTable* table,
+ const uintptr_t* expected, int len) {
+ void** entries = table->ReadStackTracesAndClear();
+ for (int i = 0; i < len; ++i) {
+ CHECK_EQ(reinterpret_cast<uintptr_t>(entries[i]), expected[i]);
+ }
+ delete[] entries;
+}
+
+static void AddTrace(tcmalloc::StackTraceTable* table,
+ const tcmalloc::StackTrace& t) {
+ // Normally we'd need this lock, but since the test is single-threaded
+ // we don't. I comment it out on windows because the DLL-decl thing
+ // is really annoying in this case.
+#ifndef _MSC_VER
+ SpinLockHolder h(tcmalloc::Static::pageheap_lock());
+#endif
+ table->AddTrace(t);
+}
+
+int main(int argc, char **argv) {
+ tcmalloc::StackTraceTable table;
+
+ // Empty table
+ CHECK_EQ(table.depth_total(), 0);
+ CHECK_EQ(table.bucket_total(), 0);
+ static const uintptr_t k1[] = {0};
+ CheckTracesAndReset(&table, k1, ARRAYSIZE(k1));
+
+ tcmalloc::StackTrace t1;
+ t1.size = static_cast<uintptr_t>(1024);
+ t1.depth = static_cast<uintptr_t>(2);
+ t1.stack[0] = reinterpret_cast<void*>(1);
+ t1.stack[1] = reinterpret_cast<void*>(2);
+
+
+ tcmalloc::StackTrace t2;
+ t2.size = static_cast<uintptr_t>(512);
+ t2.depth = static_cast<uintptr_t>(2);
+ t2.stack[0] = reinterpret_cast<void*>(2);
+ t2.stack[1] = reinterpret_cast<void*>(1);
+
+ // Table w/ just t1
+ AddTrace(&table, t1);
+ CHECK_EQ(table.depth_total(), 2);
+ CHECK_EQ(table.bucket_total(), 1);
+ static const uintptr_t k2[] = {1, 1024, 2, 1, 2, 0};
+ CheckTracesAndReset(&table, k2, ARRAYSIZE(k2));
+
+ // Table w/ t1, t2
+ AddTrace(&table, t1);
+ AddTrace(&table, t2);
+ CHECK_EQ(table.depth_total(), 4);
+ CHECK_EQ(table.bucket_total(), 2);
+ static const uintptr_t k3[] = {1, 1024, 2, 1, 2, 1, 512, 2, 2, 1, 0};
+ CheckTracesAndReset(&table, k3, ARRAYSIZE(k3));
+
+ // Table w/ 2 x t1, 1 x t2
+ AddTrace(&table, t1);
+ AddTrace(&table, t2);
+ AddTrace(&table, t1);
+ CHECK_EQ(table.depth_total(), 4);
+ CHECK_EQ(table.bucket_total(), 2);
+ static const uintptr_t k4[] = {2, 2048, 2, 1, 2, 1, 512, 2, 2, 1, 0};
+ CheckTracesAndReset(&table, k4, ARRAYSIZE(k4));
+
+ // Same stack as t1, but w/ different size
+ tcmalloc::StackTrace t3;
+ t3.size = static_cast<uintptr_t>(2);
+ t3.depth = static_cast<uintptr_t>(2);
+ t3.stack[0] = reinterpret_cast<void*>(1);
+ t3.stack[1] = reinterpret_cast<void*>(2);
+
+ // Table w/ t1, t3
+ AddTrace(&table, t1);
+ AddTrace(&table, t3);
+ CHECK_EQ(table.depth_total(), 2);
+ CHECK_EQ(table.bucket_total(), 1);
+ static const uintptr_t k5[] = {2, 1026, 2, 1, 2, 0};
+ CheckTracesAndReset(&table, k5, ARRAYSIZE(k5));
+
+ puts("PASS");
+ return 0;
+}
diff --git a/src/tests/tcmalloc_unittest.cc b/src/tests/tcmalloc_unittest.cc
index 7840178..1fdd300 100644
--- a/src/tests/tcmalloc_unittest.cc
+++ b/src/tests/tcmalloc_unittest.cc
@@ -71,6 +71,9 @@
#ifdef HAVE_MMAP
#include <sys/mman.h> // for testing mmap hooks
#endif
+#ifdef HAVE_MALLOC_H
+#include <malloc.h> // defines pvalloc/etc on cygwin
+#endif
#include <assert.h>
#include <vector>
#include <string>
@@ -79,16 +82,19 @@
#include "base/simple_mutex.h"
#include "google/malloc_hook.h"
#include "google/malloc_extension.h"
+#include "thread_cache.h"
#include "tests/testutil.h"
// Windows doesn't define pvalloc and a few other obsolete unix
// functions; nor does it define posix_memalign (which is not obsolete).
-#ifdef _WIN32
+#if defined(_MSC_VER) || defined(__MINGW32__)
# define cfree free // don't bother to try to test these obsolete fns
# define valloc malloc
# define pvalloc malloc
# ifdef PERFTOOLS_NO_ALIGNED_MALLOC
# define _aligned_malloc(size, alignment) malloc(size)
+# else
+# include <malloc.h> // for _aligned_malloc
# endif
# define memalign(alignment, size) _aligned_malloc(size, alignment)
// Assume if we fail, it's because of out-of-memory.
@@ -109,6 +115,8 @@
using std::vector;
using std::string;
+namespace testing {
+
static const int FLAGS_numtests = 50000;
static const int FLAGS_log_every_n_tests = 50000; // log exactly once
@@ -710,7 +718,21 @@ static void TestMallocAlignment() {
}
}
-int main(int argc, char** argv) {
+static void TestHugeThreadCache() {
+ fprintf(LOGSTREAM, "==== Testing huge thread cache\n");
+ // More than 2^16 to cause integer overflow of 16 bit counters.
+ static const int kNum = 70000;
+ char** array = new char*[kNum];
+ for (int i = 0; i < kNum; ++i) {
+ array[i] = new char[10];
+ }
+ for (int i = 0; i < kNum; ++i) {
+ delete[] array[i];
+ }
+ delete[] array;
+}
+
+static int RunAllTests(int argc, char** argv) {
// Optional argv[1] is the seed
AllocatorState rnd(argc > 1 ? atoi(argv[1]) : 100);
@@ -949,6 +971,17 @@ int main(int argc, char** argv) {
free(large_object);
}
- fprintf(LOGSTREAM, "PASS\n");
+ TestHugeThreadCache();
+
return 0;
}
+
+}
+
+using testing::RunAllTests;
+
+int main(int argc, char** argv) {
+ RunAllTests(argc, argv);
+
+ fprintf(LOGSTREAM, "PASS\n");
+}
diff --git a/src/thread_cache.cc b/src/thread_cache.cc
index ba23a0d..d2b0c4f 100644
--- a/src/thread_cache.cc
+++ b/src/thread_cache.cc
@@ -30,47 +30,45 @@
// ---
// Author: Ken Ashcraft <opensource@google.com>
+#include "config.h"
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#include <algorithm> // for min and max
#include "thread_cache.h"
#include "maybe_threads.h"
-// Twice the approximate gap between sampling actions.
-// I.e., we take one sample approximately once every
-// tcmalloc_sample_parameter/2
-// bytes of allocation, i.e., ~ once every 128KB.
-// Must be a prime number.
-#ifdef NO_TCMALLOC_SAMPLES
-DEFINE_int64(tcmalloc_sample_parameter, 0,
- "Unused: code is compiled with NO_TCMALLOC_SAMPLES");
-static size_t sample_period = 0;
-#else
-DEFINE_int64(tcmalloc_sample_parameter,
- EnvToInt("TCMALLOC_SAMPLE_PARAMETER", 262147),
- "Twice the approximate gap between sampling actions."
- " Must be a prime number. Otherwise will be rounded up to a "
- " larger prime number");
-static size_t sample_period = EnvToInt("TCMALLOC_SAMPLE_PARAMETER", 262147);
-#endif
-// Protects sample_period above
-static SpinLock sample_period_lock(SpinLock::LINKER_INITIALIZED);
+using std::min;
+using std::max;
-namespace tcmalloc {
+DEFINE_bool(tcmalloc_use_dynamic_thread_cache_sizes,
+ EnvToBool("TCMALLOC_USE_DYNAMIC_THREAD_CACHE_SIZES", true),
+ "When false, active threads will equally share "
+ "FLAGS_tcmalloc_max_total_thread_cache_bytes and the freelists "
+ "within each thread cache will have a max length of "
+ "256. When on, active threads will compete for allocation of "
+ "FLAGS_tcmalloc_max_total_thread_cache_bytes, and the max length "
+ "of each freelist will change based on the usage pattern.");
+
+DEFINE_int64(tcmalloc_max_total_thread_cache_bytes,
+ EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES", 16<<20),
+ "Bound on the total amount of bytes allocated to "
+ "thread caches. This bound is not strict, so it is possible "
+ "for the cache to go over this bound in certain circumstances. ");
-/* The smallest prime > 2^n */
-static unsigned int primes_list[] = {
- // Small values might cause high rates of sampling
- // and hence commented out.
- // 2, 5, 11, 17, 37, 67, 131, 257,
- // 521, 1031, 2053, 4099, 8209, 16411,
- 32771, 65537, 131101, 262147, 524309, 1048583,
- 2097169, 4194319, 8388617, 16777259, 33554467 };
+namespace tcmalloc {
static bool phinited = false;
+volatile bool ThreadCache::use_dynamic_cache_size_ =
+ FLAGS_tcmalloc_use_dynamic_thread_cache_sizes;
volatile size_t ThreadCache::per_thread_cache_size_ = kMaxThreadCacheSize;
size_t ThreadCache::overall_thread_cache_size_ = kDefaultOverallThreadCacheSize;
+ssize_t ThreadCache::unclaimed_cache_space_ = kDefaultOverallThreadCacheSize;
PageHeapAllocator<ThreadCache> threadcache_allocator;
ThreadCache* ThreadCache::thread_heaps_ = NULL;
int ThreadCache::thread_heap_count_ = 0;
+ThreadCache* ThreadCache::next_memory_steal_ = NULL;
#ifdef HAVE_TLS
__thread ThreadCache* ThreadCache::threadlocal_heap_
# ifdef HAVE___ATTRIBUTE__
@@ -114,6 +112,23 @@ bool kernel_supports_tls = false; // be conservative
void ThreadCache::Init(pthread_t tid) {
size_ = 0;
+
+ if (use_dynamic_cache_size_) {
+ max_size_ = 0;
+ IncreaseCacheLimitLocked();
+ if (max_size_ == 0) {
+ // There isn't enough memory to go around. Just give the minimum to
+ // this thread.
+ max_size_ = kMinThreadCacheSize;
+
+ // Take unclaimed_cache_space_ negative.
+ unclaimed_cache_space_ -= kMinThreadCacheSize;
+ ASSERT(unclaimed_cache_space_ < 0);
+ }
+ } else {
+ max_size_ = per_thread_cache_size_;
+ }
+
next_ = NULL;
prev_ = NULL;
tid_ = tid;
@@ -122,12 +137,9 @@ void ThreadCache::Init(pthread_t tid) {
list_[cl].Init();
}
- // Initialize RNG -- run it for a bit to get to good values
- bytes_until_sample_ = 0;
- rnd_ = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(this));
- for (int i = 0; i < 100; i++) {
- PickNextSample(FLAGS_tcmalloc_sample_parameter * 2);
- }
+ uint32_t sampler_seed;
+ memcpy(&sampler_seed, &tid, sizeof(sampler_seed));
+ sampler_.Init(sampler_seed);
}
void ThreadCache::Cleanup() {
@@ -142,21 +154,76 @@ void ThreadCache::Cleanup() {
// Remove some objects of class "cl" from central cache and add to thread heap.
// On success, return the first object for immediate use; otherwise return NULL.
void* ThreadCache::FetchFromCentralCache(size_t cl, size_t byte_size) {
+ FreeList* list = &list_[cl];
+ ASSERT(list->empty());
+ const int batch_size = Static::sizemap()->num_objects_to_move(cl);
+
+ // If !use_dynamic_cache_size_, batch_size should always be less than
+ // max_length() (which will be kMaxFreeListLength).
+ const int num_to_move = min<int>(list->max_length(), batch_size);
void *start, *end;
int fetch_count = Static::central_cache()[cl].RemoveRange(
- &start, &end,
- Static::sizemap()->num_objects_to_move(cl));
+ &start, &end, num_to_move);
+
ASSERT((start == NULL) == (fetch_count == 0));
if (--fetch_count >= 0) {
size_ += byte_size * fetch_count;
- list_[cl].PushRange(fetch_count, SLL_Next(start), end);
+ list->PushRange(fetch_count, SLL_Next(start), end);
+ }
+
+ if (use_dynamic_cache_size_) {
+ // Increase max length slowly up to batch_size. After that,
+ // increase by batch_size in one shot so that the length is a
+ // multiple of batch_size.
+ if (list->max_length() < batch_size) {
+ list->set_max_length(list->max_length() + 1);
+ } else {
+ // Don't let the list get too long. In 32 bit builds, the length
+ // is represented by a 16 bit int, so we need to watch out for
+ // integer overflow.
+ int new_length = min<int>(list->max_length() + batch_size,
+ kMaxDynamicFreeListLength);
+ // The list's max_length must always be a multiple of batch_size,
+ // and kMaxDynamicFreeListLength is not necessarily a multiple
+ // of batch_size.
+ new_length -= new_length % batch_size;
+ ASSERT(new_length % batch_size == 0);
+ list->set_max_length(new_length);
+ }
}
return start;
}
+void ThreadCache::ListTooLong(FreeList* list, size_t cl) {
+ const int batch_size = Static::sizemap()->num_objects_to_move(cl);
+ ReleaseToCentralCache(list, cl, batch_size);
+
+ if (!use_dynamic_cache_size_) {
+ return;
+ }
+
+ // If the list is too long, we need to transfer some number of
+ // objects to the central cache. Ideally, we would transfer
+ // num_objects_to_move, so the code below tries to make max_length
+ // converge on num_objects_to_move.
+
+ if (list->max_length() < batch_size) {
+ // Slow start the max_length so we don't overreserve.
+ list->set_max_length(list->max_length() + 1);
+ } else if (list->max_length() > batch_size) {
+ // If we consistently go over max_length, shrink max_length. If we don't
+ // shrink it, some amount of memory will always stay in this freelist.
+ list->set_length_overages(list->length_overages() + 1);
+ if (list->length_overages() > kMaxOverages) {
+ ASSERT(list->max_length() > batch_size);
+ list->set_max_length(list->max_length() - batch_size);
+ list->set_length_overages(0);
+ }
+ }
+}
+
// Remove some objects of class "cl" from thread heap and add to central cache
-size_t ThreadCache::ReleaseToCentralCache(FreeList* src,
- size_t cl, int N) {
+void ThreadCache::ReleaseToCentralCache(FreeList* src, size_t cl, int N) {
ASSERT(src == &list_[cl]);
if (N > src->length()) N = src->length();
size_t delta_bytes = N * Static::sizemap()->ByteSizeForClass(cl);
@@ -173,7 +240,7 @@ size_t ThreadCache::ReleaseToCentralCache(FreeList* src,
void *tail, *head;
src->PopRange(N, &head, &tail);
Static::central_cache()[cl].InsertRange(head, tail, N);
- return size_ -= delta_bytes;
+ size_ -= delta_bytes;
}
// Release idle memory to the central cache
@@ -185,67 +252,77 @@ void ThreadCache::Scavenge() {
// may not release much memory, but if so we will call scavenge again
// pretty soon and the low-water marks will be high on that call.
//int64 start = CycleClock::Now();
-
for (int cl = 0; cl < kNumClasses; cl++) {
FreeList* list = &list_[cl];
const int lowmark = list->lowwatermark();
if (lowmark > 0) {
const int drop = (lowmark > 1) ? lowmark/2 : 1;
ReleaseToCentralCache(list, cl, drop);
+
+ if (use_dynamic_cache_size_) {
+ // Shrink the max length if it isn't used. Only shrink down to
+ // batch_size -- if the thread was active enough to get the max_length
+ // above batch_size, it will likely be that active again. If
+ // max_length shinks below batch_size, the thread will have to
+ // go through the slow-start behavior again. The slow-start is useful
+ // mainly for threads that stay relatively idle for their entire
+ // lifetime.
+ const int batch_size = Static::sizemap()->num_objects_to_move(cl);
+ if (list->max_length() > batch_size) {
+ list->set_max_length(
+ max<int>(list->max_length() - batch_size, batch_size));
+ }
+ }
}
list->clear_lowwatermark();
}
- //int64 finish = CycleClock::Now();
- //CycleTimer ct;
- //MESSAGE("GC: %.0f ns\n", ct.CyclesToUsec(finish-start)*1000.0);
-}
-
-void ThreadCache::PickNextSample(size_t k) {
- // Copied from "base/synchronization.cc" (written by Mike Burrows)
- // Make next "random" number
- // x^32+x^22+x^2+x^1+1 is a primitive polynomial for random numbers
- static const uint32_t kPoly = (1 << 22) | (1 << 2) | (1 << 1) | (1 << 0);
- uint32_t r = rnd_;
- rnd_ = (r << 1) ^ ((static_cast<int32_t>(r) >> 31) & kPoly);
-
- // Next point is "rnd_ % (sample_period)". I.e., average
- // increment is "sample_period/2".
- const int flag_value = FLAGS_tcmalloc_sample_parameter;
- static int last_flag_value = -1;
-
- if (flag_value != last_flag_value) {
- SpinLockHolder h(&sample_period_lock);
- int i;
- for (i = 0; i < (sizeof(primes_list)/sizeof(primes_list[0]) - 1); i++) {
- if (primes_list[i] >= flag_value) {
- break;
- }
- }
- sample_period = primes_list[i];
- last_flag_value = flag_value;
+ if (use_dynamic_cache_size_) {
+ IncreaseCacheLimit();
}
- bytes_until_sample_ += rnd_ % sample_period;
+// int64 finish = CycleClock::Now();
+// CycleTimer ct;
+// MESSAGE("GC: %.0f ns\n", ct.CyclesToUsec(finish-start)*1000.0);
+}
+
+void ThreadCache::IncreaseCacheLimit() {
+ SpinLockHolder h(Static::pageheap_lock());
+ IncreaseCacheLimitLocked();
+}
- if (k > (static_cast<size_t>(-1) >> 2)) {
- // If the user has asked for a huge allocation then it is possible
- // for the code below to loop infinitely. Just return (note that
- // this throws off the sampling accuracy somewhat, but a user who
- // is allocating more than 1G of memory at a time can live with a
- // minor inaccuracy in profiling of small allocations, and also
- // would rather not wait for the loop below to terminate).
+void ThreadCache::IncreaseCacheLimitLocked() {
+ if (unclaimed_cache_space_ > 0) {
+ // Possibly make unclaimed_cache_space_ negative.
+ unclaimed_cache_space_ -= kStealAmount;
+ max_size_ += kStealAmount;
return;
}
+ // Don't hold pageheap_lock too long. Try to steal from 10 other
+ // threads before giving up. The i < 10 condition also prevents an
+ // infinite loop in case none of the existing thread heaps are
+ // suitable places to steal from.
+ for (int i = 0; i < 10;
+ ++i, next_memory_steal_ = next_memory_steal_->next_) {
+ // Reached the end of the linked list. Start at the beginning.
+ if (next_memory_steal_ == NULL) {
+ ASSERT(thread_heaps_ != NULL);
+ next_memory_steal_ = thread_heaps_;
+ }
+ if (next_memory_steal_ == this ||
+ next_memory_steal_->max_size_ <= kMinThreadCacheSize) {
+ continue;
+ }
+ next_memory_steal_->max_size_ -= kStealAmount;
+ max_size_ += kStealAmount;
- while (bytes_until_sample_ < k) {
- // Increase bytes_until_sample_ by enough average sampling periods
- // (sample_period >> 1) to allow us to sample past the current
- // allocation.
- bytes_until_sample_ += (sample_period >> 1);
+ next_memory_steal_ = next_memory_steal_->next_;
+ return;
}
+}
- bytes_until_sample_ -= k;
+int ThreadCache::GetSamplePeriod() {
+ return sampler_.GetSamplePeriod();
}
void ThreadCache::InitModule() {
@@ -322,6 +399,27 @@ ThreadCache* ThreadCache::CreateCacheIfNecessary() {
return heap;
}
+ThreadCache* ThreadCache::NewHeap(pthread_t tid) {
+ // Create the heap and add it to the linked list
+ ThreadCache *heap = threadcache_allocator.New();
+ heap->Init(tid);
+ heap->next_ = thread_heaps_;
+ heap->prev_ = NULL;
+ if (thread_heaps_ != NULL) {
+ thread_heaps_->prev_ = heap;
+ } else {
+ // This is the only thread heap at the momment.
+ ASSERT(next_memory_steal_ == NULL);
+ next_memory_steal_ = heap;
+ }
+ thread_heaps_ = heap;
+ thread_heap_count_++;
+ if (!use_dynamic_cache_size_) {
+ RecomputePerThreadCacheSize();
+ }
+ return heap;
+}
+
void ThreadCache::BecomeIdle() {
if (!tsd_inited_) return; // No caches yet
ThreadCache* heap = GetThreadHeap();
@@ -367,12 +465,19 @@ void ThreadCache::DeleteCache(ThreadCache* heap) {
if (heap->prev_ != NULL) heap->prev_->next_ = heap->next_;
if (thread_heaps_ == heap) thread_heaps_ = heap->next_;
thread_heap_count_--;
- RecomputeThreadCacheSize();
+
+ if (next_memory_steal_ == heap) next_memory_steal_ = heap->next_;
+ if (next_memory_steal_ == NULL) next_memory_steal_ = thread_heaps_;
+ unclaimed_cache_space_ += heap->max_size_;
+
+ if (!use_dynamic_cache_size_) {
+ RecomputePerThreadCacheSize();
+ }
threadcache_allocator.Delete(heap);
}
-void ThreadCache::RecomputeThreadCacheSize() {
+void ThreadCache::RecomputePerThreadCacheSize() {
// Divide available space across threads
int n = thread_heap_count_ > 0 ? thread_heap_count_ : 1;
size_t space = overall_thread_cache_size_ / n;
@@ -381,17 +486,42 @@ void ThreadCache::RecomputeThreadCacheSize() {
if (space < kMinThreadCacheSize) space = kMinThreadCacheSize;
if (space > kMaxThreadCacheSize) space = kMaxThreadCacheSize;
+ double ratio = space / max<double>(1, per_thread_cache_size_);
+ size_t claimed = 0;
+ for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) {
+ // Don't circumvent the slow-start growth of max_size_ by increasing
+ // the total cache size.
+ if (!use_dynamic_cache_size_ || ratio < 1.0) {
+ h->max_size_ = static_cast<size_t>(h->max_size_ * ratio);
+ }
+ claimed += h->max_size_;
+ }
+ unclaimed_cache_space_ = overall_thread_cache_size_ - claimed;
per_thread_cache_size_ = space;
//MESSAGE("Threads %d => cache size %8d\n", n, int(space));
}
-void ThreadCache::Print() const {
+void ThreadCache::Print(TCMalloc_Printer* out) const {
for (int cl = 0; cl < kNumClasses; ++cl) {
- MESSAGE(" %5" PRIuS " : %4" PRIuS " len; %4d lo\n",
- Static::sizemap()->ByteSizeForClass(cl),
- list_[cl].length(),
- list_[cl].lowwatermark());
+ out->printf(" %5" PRIuS " : %4" PRIuS " len; %4d lo; %4"PRIuS
+ " max; %4"PRIuS" overages;\n",
+ Static::sizemap()->ByteSizeForClass(cl),
+ list_[cl].length(),
+ list_[cl].lowwatermark(),
+ list_[cl].max_length(),
+ list_[cl].length_overages());
+ }
+}
+
+void ThreadCache::PrintThreads(TCMalloc_Printer* out) {
+ size_t actual_limit = 0;
+ for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) {
+ h->Print(out);
+ actual_limit += h->max_size_;
}
+ out->printf("ThreadCache overall: %"PRIuS ", unclaimed: %"PRIuS
+ ", actual: %"PRIuS"\n",
+ overall_thread_cache_size_, unclaimed_cache_space_, actual_limit);
}
void ThreadCache::GetThreadStats(uint64_t* total_bytes, uint64_t* class_count) {
@@ -409,9 +539,13 @@ void ThreadCache::set_overall_thread_cache_size(size_t new_size) {
// Clip the value to a reasonable range
if (new_size < kMinThreadCacheSize) new_size = kMinThreadCacheSize;
if (new_size > (1<<30)) new_size = (1<<30); // Limit to 1GB
-
overall_thread_cache_size_ = new_size;
- ThreadCache::RecomputeThreadCacheSize();
+
+ RecomputePerThreadCacheSize();
+}
+
+void ThreadCache::set_use_dynamic_thread_cache_size(bool use_dynamic) {
+ use_dynamic_cache_size_ = use_dynamic;
}
} // namespace tcmalloc
diff --git a/src/thread_cache.h b/src/thread_cache.h
index 3d4dd7e..608fe33 100644
--- a/src/thread_cache.h
+++ b/src/thread_cache.h
@@ -34,10 +34,14 @@
#define TCMALLOC_THREAD_CACHE_H_
#include "config.h"
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
#include "common.h"
#include "linked_list.h"
#include "maybe_threads.h"
#include "page_heap_allocator.h"
+#include "sampler.h"
#include "static_vars.h"
namespace tcmalloc {
@@ -59,6 +63,9 @@ inline bool KernelSupportsTLS() {
class ThreadCache {
public:
+ // Default bound on the total amount of thread caches.
+ static const size_t kDefaultOverallThreadCacheSize = 16 << 20;
+
// All ThreadCache objects are kept in a linked list (for stats collection)
ThreadCache* next_;
ThreadCache* prev_;
@@ -76,24 +83,21 @@ class ThreadCache {
void Deallocate(void* ptr, size_t size_class);
void Scavenge();
- void Print() const;
+ void Print(TCMalloc_Printer* out) const;
+
+ int GetSamplePeriod();
// Record allocation of "k" bytes. Return true iff allocation
// should be sampled
bool SampleAllocation(size_t k);
- // Pick next sampling point
- void PickNextSample(size_t k);
-
static void InitModule();
static void InitTSD();
static ThreadCache* GetThreadHeap();
static ThreadCache* GetCache();
static ThreadCache* GetCacheIfPresent();
static ThreadCache* CreateCacheIfNecessary();
- static void DeleteCache(ThreadCache* heap);
static void BecomeIdle();
- static void RecomputeThreadCacheSize();
// Return the number of thread heaps in use.
static inline int HeapsInUse();
@@ -102,9 +106,13 @@ class ThreadCache {
// class_count must be an array of size kNumClasses. Writes the number of
// items on the corresponding freelist. class_count may be NULL.
// The storage of both parameters must be zero intialized.
- // Requires Static::pageheap_lock is held.
+ // REQUIRES: Static::pageheap_lock is held.
static void GetThreadStats(uint64_t* total_bytes, uint64_t* class_count);
+ // Write debugging statistics to 'out'.
+ // REQUIRES: Static::pageheap_lock is held.
+ static void PrintThreads(TCMalloc_Printer* out);
+
// Sets the total thread cache size to new_size, recomputing the
// individual thread cache sizes as necessary.
// REQUIRES: Static::pageheap lock is held.
@@ -113,6 +121,15 @@ class ThreadCache {
return overall_thread_cache_size_;
}
+ // Turn on/off dynamic sizing of the thread caches and the freelists
+ // within those thread caches. When off, threads will equally share
+ // the overall_thread_cache_size() and the freelists will have a
+ // max_length() of kMaxFreeListLength. When on, threads will compete
+ // for allocation of overall_thread_cache_size() and the max_length()
+ // of each freelist will change based on the usage pattern.
+ // REQUIRES: Static::pageheap lock is held.
+ static void set_use_dynamic_thread_cache_size(bool use_dynamic);
+
private:
class FreeList {
private:
@@ -120,13 +137,19 @@ class ThreadCache {
#ifdef _LP64
// On 64-bit hardware, manipulating 16-bit values may be slightly slow.
- // Since it won't cost any space, let's make these fields 32 bits each.
- uint32_t length_; // Current length
- uint32_t lowater_; // Low water mark for list length
+ uint32_t length_; // Current length.
+ uint32_t lowater_; // Low water mark for list length.
+ uint32_t max_length_; // Dynamic max list length based on usage.
+ // Tracks the number of times a deallocation has caused
+ // length_ > max_length_. After the kMaxOverages'th time, max_length_
+ // shrinks and length_overages_ is reset to zero.
+ uint32_t length_overages_;
#else
// If we aren't using 64-bit pointers then pack these into less space.
uint16_t length_;
uint16_t lowater_;
+ uint16_t max_length_;
+ uint16_t length_overages_;
#endif
public:
@@ -134,6 +157,8 @@ class ThreadCache {
list_ = NULL;
length_ = 0;
lowater_ = 0;
+ max_length_ = 1;
+ length_overages_ = 0;
}
// Return current length of list
@@ -141,6 +166,32 @@ class ThreadCache {
return length_;
}
+ // Return the maximum length of the list.
+ size_t max_length() const {
+ if (use_dynamic_cache_size_) {
+ return max_length_;
+ } else {
+ return kMaxFreeListLength;
+ }
+ }
+
+ // Set the maximum length of the list. If 'new_max' > length(), the
+ // client is responsible for removing objects from the list.
+ void set_max_length(size_t new_max) {
+ if (use_dynamic_cache_size_) {
+ max_length_ = new_max;
+ }
+ }
+
+ // Return the number of times that length() has gone over max_length().
+ size_t length_overages() const {
+ return length_overages_;
+ }
+
+ void set_length_overages(size_t new_count) {
+ length_overages_ = new_count;
+ }
+
// Is list empty?
bool empty() const {
return list_ == NULL;
@@ -175,19 +226,36 @@ class ThreadCache {
}
};
- // Default bound on the total amount of thread caches
- static const size_t kDefaultOverallThreadCacheSize = 16 << 20;
+ // The number of bytes one ThreadCache will steal from another when
+ // the first ThreadCache is forced to Scavenge(), delaying the
+ // next call to Scavenge for this thread.
+ static const size_t kStealAmount = 1 << 16;
// Lower and upper bounds on the per-thread cache sizes
- static const size_t kMinThreadCacheSize = kMaxSize * 2;
+ static const size_t kMinThreadCacheSize = kMaxSize * 2; //kStealAmount;
static const size_t kMaxThreadCacheSize = 2 << 20;
+ // The number of times that a deallocation can cause a freelist to
+ // go over its max_length() before shrinking max_length().
+ static const int kMaxOverages = 3;
+
// Gets and returns an object from the central cache, and, if possible,
// also adds some objects of that size class to this thread cache.
void* FetchFromCentralCache(size_t cl, size_t byte_size);
- // Releases N items from this thread cache. Returns size_.
- size_t ReleaseToCentralCache(FreeList* src, size_t cl, int N);
+ // Releases some number of items from src. Adjusts the list's max_length
+ // to eventually converge on num_objects_to_move(cl).
+ void ListTooLong(FreeList* src, size_t cl);
+
+ // Releases N items from this thread cache.
+ void ReleaseToCentralCache(FreeList* src, size_t cl, int N);
+
+ // Increase max_size_ by reducing unclaimed_cache_space_ or by
+ // reducing the max_size_ of some other thread. In both cases,
+ // the delta is kStealAmount.
+ void IncreaseCacheLimit();
+ // Same as above but requires Static::pageheap_lock() is held.
+ void IncreaseCacheLimitLocked();
// If TLS is available, we also store a copy of the per-thread object
// in a __thread variable since __thread variables are faster to read
@@ -221,34 +289,53 @@ class ThreadCache {
static ThreadCache* thread_heaps_;
static int thread_heap_count_;
+ // A pointer to one of the objects in thread_heaps_. Represents
+ // the next ThreadCache from which a thread over its max_size_ should
+ // steal memory limit. Round-robin through all of the objects in
+ // thread_heaps_. Protected by Static::pageheap_lock.
+ static ThreadCache* next_memory_steal_;
+
// Overall thread cache size. Protected by Static::pageheap_lock.
static size_t overall_thread_cache_size_;
// Global per-thread cache size. Writes are protected by
// Static::pageheap_lock. Reads are done without any locking, which should be
// fine as long as size_t can be written atomically and we don't place
- // invariants between this variable and other pieces of state.
+ // invariants between this variable and other pieces of state. See
+ // use_dynamic_cache_size_ below.
static volatile size_t per_thread_cache_size_;
+ // If true, threads use a dynamic max_size_ and dynamic freelist lengths.
+ // If false, threads each get a max_size_ equal to per_thread_cache_size_,
+ // and the freelist lengths are statically sized.
+ static volatile bool use_dynamic_cache_size_;
+
+ // Represents overall_thread_cache_size_ minus the sum of max_size_
+ // across all ThreadCaches. Protected by Static::pageheap_lock.
+ static ssize_t unclaimed_cache_space_;
+
// Warning: the offset of list_ affects performance. On general
// principles, we don't like list_[x] to span multiple L1 cache
// lines. However, merely placing list_ at offset 0 here seems to
// cause cache conflicts.
- // We sample allocations, biased by the size of the allocation
- size_t bytes_until_sample_; // Bytes until we sample next
- uint32_t rnd_; // Cheap random number generator
-
size_t size_; // Combined size of data
+ size_t max_size_; // size_ > max_size_ --> Scavenge()
pthread_t tid_; // Which thread owns it
FreeList list_[kNumClasses]; // Array indexed by size-class
bool in_setspecific_; // In call to pthread_setspecific?
// Allocate a new heap. REQUIRES: Static::pageheap_lock is held.
- static inline ThreadCache* NewHeap(pthread_t tid);
+ static ThreadCache* NewHeap(pthread_t tid);
// Use only as pthread thread-specific destructor function.
static void DestroyThreadCache(void* ptr);
+
+ static void DeleteCache(ThreadCache* heap);
+ static void RecomputePerThreadCacheSize();
+
+ // We sample allocations, biased by the size of the allocation
+ Sampler sampler_; // A sampler
};
// Allocator for thread heaps
@@ -262,13 +349,7 @@ inline int ThreadCache::HeapsInUse() {
}
inline bool ThreadCache::SampleAllocation(size_t k) {
- if (bytes_until_sample_ < k) {
- PickNextSample(k);
- return true;
- } else {
- bytes_until_sample_ -= k;
- return false;
- }
+ return sampler_.SampleAllocation(k);
}
inline void* ThreadCache::Allocate(size_t size) {
@@ -285,38 +366,23 @@ inline void* ThreadCache::Allocate(size_t size) {
inline void ThreadCache::Deallocate(void* ptr, size_t cl) {
FreeList* list = &list_[cl];
- ssize_t list_headroom =
- static_cast<ssize_t>(kMaxFreeListLength - 1) - list->length();
size_ += Static::sizemap()->ByteSizeForClass(cl);
- size_t cache_size = size_;
- ssize_t size_headroom = per_thread_cache_size_ - cache_size - 1;
+ ssize_t size_headroom = max_size_ - size_ - 1;
list->Push(ptr);
+ ssize_t list_headroom =
+ static_cast<ssize_t>(list->max_length()) - list->length();
// There are two relatively uncommon things that require further work.
// In the common case we're done, and in that case we need a single branch
// because of the bitwise-or trick that follows.
if ((list_headroom | size_headroom) < 0) {
if (list_headroom < 0) {
- cache_size = ReleaseToCentralCache(
- list, cl, Static::sizemap()->num_objects_to_move(cl));
+ ListTooLong(list, cl);
}
- if (cache_size >= per_thread_cache_size_) Scavenge();
+ if (size_ >= max_size_) Scavenge();
}
}
-inline ThreadCache* ThreadCache::NewHeap(pthread_t tid) {
- // Create the heap and add it to the linked list
- ThreadCache *heap = threadcache_allocator.New();
- heap->Init(tid);
- heap->next_ = thread_heaps_;
- heap->prev_ = NULL;
- if (thread_heaps_ != NULL) thread_heaps_->prev_ = heap;
- thread_heaps_ = heap;
- thread_heap_count_++;
- RecomputeThreadCacheSize();
- return heap;
-}
-
inline ThreadCache* ThreadCache::GetThreadHeap() {
#ifdef HAVE_TLS
// __thread is faster, but only when the kernel supports it
diff --git a/src/windows/addr2line-pdb.c b/src/windows/addr2line-pdb.c
index 97b614b..5384731 100644
--- a/src/windows/addr2line-pdb.c
+++ b/src/windows/addr2line-pdb.c
@@ -45,6 +45,7 @@
#include <windows.h>
#include <dbghelp.h>
+
#define SEARCH_CAP (1024*1024)
#define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
diff --git a/src/windows/config.h b/src/windows/config.h
index d42da35..6be561e 100644
--- a/src/windows/config.h
+++ b/src/windows/config.h
@@ -54,6 +54,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
+/* Define to 1 if the system has the type `Elf32_Versym'. */
+#undef HAVE_ELF32_VERSYM
+
/* Define to 1 if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
@@ -132,6 +135,9 @@
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
@@ -141,6 +147,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
/* Define to 1 if compiler supports __thread */
#define HAVE_TLS 1
@@ -153,6 +162,9 @@
/* Define to 1 if you have the <unwind.h> header file. */
#undef HAVE_UNWIND_H
+/* Define to 1 if you have the <windows.h> header file. */
+#define HAVE_WINDOWS_H 1
+
/* define if your compiler has __attribute__ */
#undef HAVE___ATTRIBUTE__
diff --git a/src/windows/patch_functions.cc b/src/windows/patch_functions.cc
index b44b935..d73c064 100644
--- a/src/windows/patch_functions.cc
+++ b/src/windows/patch_functions.cc
@@ -1,32 +1,66 @@
-/* Copyright (c) 2007, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+// Author: Craig Silversteion
+//
+// The main purpose of this file is to patch the libc allocation
+// routines (malloc and friends, but also _msize and other
+// windows-specific libc-style routines). However, we also patch
+// windows routines to do accounting. We do better at the former than
+// the latter. Here are some comments from Paul Pluzhnikov about what
+// it might take to do a really good job patching windows routines to
+// keep track of memory usage:
+//
+// "You should intercept at least the following:
+// HeapCreate HeapDestroy HeapAlloc HeapReAlloc HeapFree
+// RtlCreateHeap RtlDestroyHeap RtlAllocateHeap RtlFreeHeap
+// malloc calloc realloc free
+// malloc_dbg calloc_dbg realloc_dbg free_dbg
+// Some of these call the other ones (but not always), sometimes
+// recursively (i.e. HeapCreate may call HeapAlloc on a different
+// heap, IIRC)."
+//
+// Since Paul didn't mention VirtualAllocEx, he may not have even been
+// considering all the mmap-like functions that windows has (or he may
+// just be ignoring it because he's seen we already patch it). Of the
+// above, we do not patch the *_dbg functions, and of the windows
+// functions, we only patch HeapAlloc and HeapFree.
+//
+// The *_dbg functions come into play with /MDd, /MTd, and /MLd,
+// probably. It may be ok to just turn off tcmalloc in those cases --
+// if the user wants the windows debug malloc, they probably don't
+// want tcmalloc! We should also test with all of /MD, /MT, and /ML,
+// which we're not currently doing.
+
+// TODO(csilvers): try to do better here? Paul does conclude:
+// "Keeping track of all of this was a nightmare."
#ifndef _WIN32
# error You should only be including windows/patch_functions.cc in a windows environment!
diff --git a/src/windows/port.h b/src/windows/port.h
index 6d14699..e5b9b5f 100644
--- a/src/windows/port.h
+++ b/src/windows/port.h
@@ -88,6 +88,8 @@ typedef intptr_t ssize_t;
#endif
// ----------------------------------- THREADS
+
+#ifndef HAVE_PTHREAD // not true for MSVC, but may be true for MSYS
typedef DWORD pthread_t;
typedef DWORD pthread_key_t;
typedef LONG pthread_once_t;
@@ -107,6 +109,7 @@ extern pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); // in port.cc
#define perftools_pthread_once(once, init) do { \
if (InterlockedCompareExchange(once, 1, 0) == 0) (init)(); \
} while (0)
+#endif // HAVE_PTHREAD
// __declspec(thread) isn't usable in a dll opened via LoadLibrary().
// But it doesn't work to LoadLibrary() us anyway, because of all the
@@ -173,6 +176,8 @@ extern PERFTOOLS_DLL_DECL void RunManyInThreadWithId(void (*fn)(int), int count,
// ----------------------------------- MMAP and other memory allocation
+
+#ifndef HAVE_MMAP // not true for MSVC, but may be true for msys
#define MAP_FAILED 0
#define MREMAP_FIXED 2 // the value in linux, though it doesn't really matter
// These, when combined with the mmap invariants below, yield the proper action
@@ -190,6 +195,7 @@ extern PERFTOOLS_DLL_DECL void RunManyInThreadWithId(void (*fn)(int), int count,
: NULL )
#define munmap(start, length) (VirtualFree(start, 0, MEM_RELEASE) ? 0 : -1)
+#endif // HAVE_MMAP
// We could maybe use VirtualAlloc for sbrk as well, but no need
#define sbrk(increment) ( (void*)-1 ) // sbrk returns -1 on failure
@@ -212,8 +218,10 @@ extern PERFTOOLS_DLL_DECL int safe_vsnprintf(char *str, size_t size,
#define SCNd64 "I64d"
#define PRIu64 "I64u"
#ifdef _WIN64
+# define PRIuPTR "llu"
# define PRIxPTR "llx"
#else
+# define PRIuPTR "lu"
# define PRIxPTR "lx"
#endif
diff --git a/vsprojects/addr2line-pdb/addr2line-pdb.vcproj b/vsprojects/addr2line-pdb/addr2line-pdb.vcproj
index 55d0984..c5ae27b 100755
--- a/vsprojects/addr2line-pdb/addr2line-pdb.vcproj
+++ b/vsprojects/addr2line-pdb/addr2line-pdb.vcproj
@@ -12,8 +12,8 @@
<Configurations>
<Configuration
Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2">
<Tool
@@ -61,8 +61,8 @@
</Configuration>
<Configuration
Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2">
<Tool
diff --git a/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj b/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
index 5059557..f6af7da 100755
--- a/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
+++ b/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
@@ -353,6 +353,23 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\..\src\sampler.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\..\src\windows\patch_functions.cc">
<FileConfiguration
Name="Debug|Win32">
@@ -421,6 +438,23 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\..\src\raw_printer.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\..\src\span.cc">
<FileConfiguration
Name="Debug|Win32">
@@ -455,6 +489,40 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\..\src\stacktrace_with_context.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\stack_trace_table.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\..\src\static_vars.cc">
<FileConfiguration
Name="Debug|Win32">
@@ -601,15 +669,27 @@
RelativePath="..\..\src\google\profiler.h">
</File>
<File
+ RelativePath="..\..\src\raw_printer.h">
+ </File>
+ <File
+ RelativePath="..\..\src\sampler.h">
+ </File>
+ <File
RelativePath="..\..\src\span.h">
</File>
<File
RelativePath="..\..\src\google\stacktrace.h">
</File>
<File
+ RelativePath="..\..\src\stacktrace_config.h">
+ </File>
+ <File
RelativePath="..\..\src\stacktrace_win32-inl.h.h">
</File>
<File
+ RelativePath="..\..\src\stack_trace_table.h">
+ </File>
+ <File
RelativePath="..\..\src\static_vars.h">
</File>
<File
diff --git a/vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj b/vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj
index 563a91b..f51b9f0 100755
--- a/vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj
+++ b/vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj
@@ -231,6 +231,23 @@
RuntimeLibrary="2"/>
</FileConfiguration>
</File>
+ <File
+ RelativePath="..\..\src\stacktrace_with_context.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
</Filter>
<Filter
Name="Header Files"
@@ -275,6 +292,9 @@
<File
RelativePath="..\..\src\google\stacktrace.h">
</File>
+ <File
+ RelativePath="..\..\src\google\stacktrace_config.h">
+ </File>
</Filter>
</Files>
<Globals>
diff --git a/vsprojects/malloc_extension_test/malloc_extension_test.vcproj b/vsprojects/malloc_extension_test/malloc_extension_test.vcproj
new file mode 100755
index 0000000..378d686
--- /dev/null
+++ b/vsprojects/malloc_extension_test/malloc_extension_test.vcproj
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="malloc_extension_test"
+ ProjectGUID="{3765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/malloc_extension_test.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/malloc_extension_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/malloc_extension_test.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{3FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\..\src\tests\malloc_extension_test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{33995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\..\src\google\malloc_extension.h">
+ </File>
+ <File
+ RelativePath="..\..\src\google\malloc_extension_c.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\config.h">
+ </File>
+ <File
+ RelativePath="..\..\src\config_for_unittests.h">
+ </File>
+ <File
+ RelativePath="..\..\src\base\logging.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\port.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/nm-pdb/nm-pdb.vcproj b/vsprojects/nm-pdb/nm-pdb.vcproj
index a79e26b..e922297 100755
--- a/vsprojects/nm-pdb/nm-pdb.vcproj
+++ b/vsprojects/nm-pdb/nm-pdb.vcproj
@@ -12,8 +12,8 @@
<Configurations>
<Configuration
Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2">
<Tool
@@ -61,8 +61,8 @@
</Configuration>
<Configuration
Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2">
<Tool
diff --git a/vsprojects/pagemap_unittest/pagemap_unittest.vcproj b/vsprojects/pagemap_unittest/pagemap_unittest.vcproj
new file mode 100755
index 0000000..bed83f1
--- /dev/null
+++ b/vsprojects/pagemap_unittest/pagemap_unittest.vcproj
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="pagemap_unittest"
+ ProjectGUID="{9765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/pagemap_unittest.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/pagemap_unittest.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/pagemap_unittest.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{9FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\..\src\tests\pagemap_unittest.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\..\src\pagemap.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\config.h">
+ </File>
+ <File
+ RelativePath="..\..\src\config_for_unittests.h">
+ </File>
+ <File
+ RelativePath="..\..\src\base\logging.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\port.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/realloc_unittest/realloc_unittest.vcproj b/vsprojects/realloc_unittest/realloc_unittest.vcproj
new file mode 100755
index 0000000..bfeb500
--- /dev/null
+++ b/vsprojects/realloc_unittest/realloc_unittest.vcproj
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="realloc_unittest"
+ ProjectGUID="{4765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/realloc_unittest.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/realloc_unittest.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/realloc_unittest.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\..\src\tests\realloc_unittest.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{43995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\..\src\windows\config.h">
+ </File>
+ <File
+ RelativePath="..\..\src\config_for_unittests.h">
+ </File>
+ <File
+ RelativePath="..\..\src\base\logging.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\port.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/sampler_test/sampler_test.vcproj b/vsprojects/sampler_test/sampler_test.vcproj
new file mode 100755
index 0000000..ffbe7b4
--- /dev/null
+++ b/vsprojects/sampler_test/sampler_test.vcproj
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="sampler_test"
+ ProjectGUID="{B765198D-5305-4AB0-9A21-A0CD8201EB2A}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/sampler_test.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/sampler_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/sampler_test.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{BFC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\..\src\tests\sampler_test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{B3995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\..\src\base\commandlineflags.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\config.h">
+ </File>
+ <File
+ RelativePath="..\..\src\config_for_unittests.h">
+ </File>
+ <File
+ RelativePath="..\..\src\base\logging.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\port.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj b/vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj
new file mode 100755
index 0000000..2805bdb
--- /dev/null
+++ b/vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="stack_trace_table_test"
+ ProjectGUID="{A4754725-DE0D-4214-8979-324247AAD78E}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/stack_trace_table_test.exe"
+ LinkIncremental="2"
+ ForceSymbolReferences="__tcmalloc"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/stack_trace_table_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/stack_trace_table_test.exe"
+ LinkIncremental="1"
+ ForceSymbolReferences="__tcmalloc"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{AFC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\..\src\tests\stack_trace_table_test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{A3995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\..\src\windows\config.h">
+ </File>
+ <File
+ RelativePath="..\..\src\config_for_unittests.h">
+ </File>
+ <File
+ RelativePath="..\..\src\windows\port.h">
+ </File>
+ <File
+ RelativePath="..\..\src\stack_trace_table.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vsprojects/tmu-static/tmu-static.vcproj b/vsprojects/tmu-static/tmu-static.vcproj
index d4d1856..5ff9419 100755
--- a/vsprojects/tmu-static/tmu-static.vcproj
+++ b/vsprojects/tmu-static/tmu-static.vcproj
@@ -379,6 +379,25 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\..\src\sampler.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D PERFTOOLS_DLL_DECL="
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D PERFTOOLS_DLL_DECL="
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\..\src\windows\patch_functions.cc">
<FileConfiguration
Name="Debug|Win32">
@@ -455,6 +474,25 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\..\src\raw_printer.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D PERFTOOLS_DLL_DECL="
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D PERFTOOLS_DLL_DECL="
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\..\src\span.cc">
<FileConfiguration
Name="Debug|Win32">
@@ -491,6 +529,42 @@
</FileConfiguration>
</File>
<File
+ RelativePath="..\..\src\stacktrace_with_context.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D PERFTOOLS_DLL_DECL="
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/D PERFTOOLS_DLL_DECL="
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\src\stack_trace_table.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\src\windows; ..\..\src"
+ RuntimeLibrary="2"/>
+ </FileConfiguration>
+ </File>
+ <File
RelativePath="..\..\src\static_vars.cc">
<FileConfiguration
Name="Debug|Win32">
@@ -690,9 +764,21 @@
RelativePath="..\..\src\google\stacktrace.h">
</File>
<File
+ RelativePath="..\..\src\google\stacktrace_config.h">
+ </File>
+ <File
RelativePath="..\..\src\stacktrace_win32-inl.h.h">
</File>
<File
+ RelativePath="..\..\src\raw_printer.h">
+ </File>
+ <File
+ RelativePath="..\..\src\sampler.h">
+ </File>
+ <File
+ RelativePath="..\..\src\stack_trace_table.h">
+ </File>
+ <File
RelativePath="..\..\src\static_vars.h">
</File>
<File