diff options
93 files changed, 8581 insertions, 2363 deletions
@@ -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) @@ -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} @@ -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. @@ -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]) @@ -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 >= ~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 (> 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++; @@ -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
|