diff options
-rw-r--r-- | ChangeLog | 51 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | NEWS | 33 | ||||
-rw-r--r-- | README | 2 | ||||
-rwxr-xr-x | configure | 137 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | m4/acx_pthread.m4 | 34 | ||||
-rw-r--r-- | packages/deb/changelog | 6 | ||||
-rw-r--r-- | src/base/cycleclock.h | 39 | ||||
-rw-r--r-- | src/base/dynamic_annotations.c | 1 | ||||
-rw-r--r-- | src/base/logging.h | 1 | ||||
-rw-r--r-- | src/base/stl_allocator.h | 1 | ||||
-rw-r--r-- | src/base/vdso_support.cc | 1 | ||||
-rw-r--r-- | src/debugallocation.cc | 26 | ||||
-rw-r--r-- | src/heap-checker.cc | 62 | ||||
-rw-r--r-- | src/page_heap.cc | 20 | ||||
-rw-r--r-- | src/page_heap.h | 2 | ||||
-rwxr-xr-x | src/pprof | 59 | ||||
-rw-r--r-- | src/symbolize.h | 1 | ||||
-rw-r--r-- | src/system-alloc.cc | 1 | ||||
-rw-r--r-- | src/tests/debugallocation_test.cc | 18 | ||||
-rwxr-xr-x | src/tests/debugallocation_test.sh | 33 | ||||
-rw-r--r-- | src/tests/malloc_extension_test.cc | 24 | ||||
-rw-r--r-- | src/windows/port.h | 5 |
25 files changed, 390 insertions, 181 deletions
@@ -1,4 +1,53 @@ -Thu Aug 5 12:48:03 PDT 2010 +Fri Feb 04 15:54:31 2011 Google Inc. <opensource@google.com> + + * google-perftools: version 1.7 release + * Reduce page map key size under x86_64 by 4.4MB (rus) + * Remove a flaky malloc-extension test (fdabek) + * Improve the performance of PageHeap::New (ond..., csilvers) + * Improve sampling_test with no-inline additions/etc (fdabek) + * 16-byte align debug allocs (jyasskin) + * Change FillProcSelfMaps to detect out-of-buffer-space (csilvers) + * Document the need for sampling to use GetHeapSample (csilvers) + * Try to read TSC frequency from tsc_freq_khs (adurbin) + * Do better at figuring out if tests are running under gdb (ppluzhnikov) + * Improve spinlock contention performance (ruemmler) + * Better internal-function list for pprof's /contention (ruemmler) + * Speed up GoogleOnce (m3b) + * Limit number of incoming/outgoing edges in pprof (sanjay) + * Add pprof --evince to go along with --gv (csilvers) + * Document the various ways to get heap-profiling information (csilvers) + * Separate out synchronization profiling routines (ruemmler) + * Improve malloc-stats output to be more understandable (csilvers) + * Add support for census profiler in pporf (nabeelmian) + * Document how pprof's /symbol must support GET requests (csilvers) + * Improve acx_pthread.m4 (ssuomi, liujisi) + * Speed up pprof's ExtractSymbols (csilvers) + * Ignore some known-leaky (java) libraries in the heap checker (davidyu) + * Make kHideMask use all 64 bits in tests (ppluzhnikov) + * Clean up pprof input-file handling (csilvers) + * BUGFIX: Don't crash if __environ is NULL (csilvers) + * BUGFIX: Fix totally broken debugallocation tests (csilvers) + * BUGFIX: Fix up fake_VDSO handling for unittest (ppluzhnikov) + * BUGFIX: Suppress all large allocs when report threshold is 0 (lexie) + * BUGFIX: mmap2 on i386 takes an off_t, not off64_t (csilvers) + * PORTING: Add missing PERFTOOLS_DLL_DECL (csilvers) + * PORTING: Add stddef.h to make newer gcc's happy (csilvers) + * PORTING: Document some tricks for working under OS X (csilvers) + * PORTING: Don't try to check valgrind for windows (csilvers) + * PORTING: Make array-size a var to compile under clang (chandlerc) + * PORTING: No longer hook _aligned_malloc and _aligned_free (csilvers) + * PORTING: Quiet some gcc warnings (csilvers) + * PORTING: Replace %PRIxPTR with %p to be more portable (csilvers) + * PORTING: Support systems that capitalize /proc weirdly (sanek) + * PORTING: Treat arm3 the same as arm5t in cycletimer (csilvers) + * PORTING: Update windows logging to not allocate memory (csilvers) + * PORTING: avoid double-patching newer windows DLLs (roger.orr) + * PORTING: get dynamic_annotations.c to work on windows (csilvers) + * Add pkg-config .pc files for the 5 libraries we produce (csilvers) + * Added proper libtool versioning, so this lib will be 0.1.0 (csilvers) + * Moved from autoconf 2.64 to 2.65 + +Thu Aug 5 12:48:03 PDT 2010 Google Inc. <opensource@google.com> * google-perftools: version 1.6 release * Add tc_malloc_usable_size for compatibility with glibc (csilvers) diff --git a/Makefile.am b/Makefile.am index 2ac1445..e18e9ae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -729,7 +729,7 @@ noinst_PROGRAMS += debugallocation_test debugallocation_test_SOURCES = src/tests/debugallocation_test.cc debugallocation_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) debugallocation_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) -debugallocation_test_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) +debugallocation_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) endif WITH_DEBUGALLOC diff --git a/Makefile.in b/Makefile.in index 2a929c6..693230b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -790,7 +790,7 @@ am__debugallocation_test_SOURCES_DIST = \ @WITH_DEBUGALLOC_TRUE@am_debugallocation_test_OBJECTS = debugallocation_test-debugallocation_test.$(OBJEXT) debugallocation_test_OBJECTS = $(am_debugallocation_test_OBJECTS) @WITH_DEBUGALLOC_TRUE@debugallocation_test_DEPENDENCIES = \ -@WITH_DEBUGALLOC_TRUE@ libtcmalloc_minimal_debug.la \ +@WITH_DEBUGALLOC_TRUE@ libtcmalloc_debug.la \ @WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1) am__debugallocation_test_sh_SOURCES_DIST = \ src/tests/debugallocation_test.sh @@ -2135,7 +2135,7 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS) @WITH_DEBUGALLOC_TRUE@debugallocation_test_SOURCES = src/tests/debugallocation_test.cc @WITH_DEBUGALLOC_TRUE@debugallocation_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) @WITH_DEBUGALLOC_TRUE@debugallocation_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS) -@WITH_DEBUGALLOC_TRUE@debugallocation_test_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS) +@WITH_DEBUGALLOC_TRUE@debugallocation_test_LDADD = libtcmalloc_debug.la $(PTHREAD_LIBS) ### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker) @@ -1,3 +1,35 @@ +== 04 February 2011 == + +I've just released perftools 1.7 + +I apologize for the delay since the last release; so many great new +patches and bugfixes kept coming in (and are still coming in; I also +apologize to those folks who have to slip until the next release). I +picked this arbitrary time to make a cut. + +Among the many new features in this release is a multi-megabyte +reduction in the amount of tcmalloc overhead uder x86_64, improved +performance in the case of contention, and many many bugfixes, +especially architecture-specific bugfixes. See the +[http://google-perftools.googlecode.com/svn/tags/perftools-1.7/ChangeLog ChangeLog] +for full details. + +One architecture-specific change of note is added comments in the +[http://google-perftools.googlecode.com/svn/tags/perftools-1.7/README README] +for using tcmalloc under OS X. I'm trying to get my head around the +exact behavior of the OS X linker, and hope to have more improvements +for the next release, but I hope these notes help folks who have been +having trouble with tcmalloc on OS X. + +*Windows users*: I've heard reports that some unittests fail on +Windows when compiled with MSVC 10 in Release mode. All tests pass in +Debug mode. I've not heard of any problems with earlier versions of +MSVC. I don't know if this is a problem with the runtime patching (so +the static patching discussed in README_windows.txt will still work), +a problem with perftools more generally, or a bug in MSVC 10. Anyone +with windows expertise that can debug this, I'd be glad to hear from! + + === 5 August 2010 === I've just released perftools 1.6 @@ -37,6 +69,7 @@ mimic the windows function of the same name. Full details are in the [http://google-perftools.googlecode.com/svn/tags/perftools-1.5/ChangeLog ChangeLog]. + === 11 September 2009 === I've just released perftools 1.4 @@ -276,4 +276,4 @@ new threads, or is otherwise likely to cause a call to pthread_mutex_lock! --- -22 May 2009 +11 January 2011 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for google-perftools 1.6. +# Generated by GNU Autoconf 2.65 for google-perftools 1.7. # # Report bugs to <opensource@google.com>. # @@ -701,8 +701,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='google-perftools' PACKAGE_TARNAME='google-perftools' -PACKAGE_VERSION='1.6' -PACKAGE_STRING='google-perftools 1.6' +PACKAGE_VERSION='1.7' +PACKAGE_STRING='google-perftools 1.7' PACKAGE_BUGREPORT='opensource@google.com' PACKAGE_URL='' @@ -1468,7 +1468,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.6 to adapt to many kinds of systems. +\`configure' configures google-perftools 1.7 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1539,7 +1539,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of google-perftools 1.6:";; + short | recursive ) echo "Configuration of google-perftools 1.7:";; esac cat <<\_ACEOF @@ -1649,7 +1649,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -google-perftools configure 1.6 +google-perftools configure 1.7 generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. @@ -2234,7 +2234,7 @@ cat >config.log <<_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.6, which was +It was created by google-perftools $as_me 1.7, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -2584,8 +2584,10 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -TCMALLOC_SO_VERSION=0:1:0 -PROFILER_SO_VERSION=0:1:0 +# Update this value for every release! (A:B:C will map to foo.so.(A-C).C.B) +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +TCMALLOC_SO_VERSION=1:0:1 +PROFILER_SO_VERSION=1:0:1 @@ -2977,7 +2979,7 @@ fi # Define the identity of the package. PACKAGE='google-perftools' - VERSION='1.6' + VERSION='1.7' cat >>confdefs.h <<_ACEOF @@ -5579,13 +5581,13 @@ if test "${lt_cv_nm_interface+set}" = set; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:5582: $ac_compile\"" >&5) + (eval echo "\"\$as_me:5584: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:5585: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:5587: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:5588: output\"" >&5) + (eval echo "\"\$as_me:5590: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -6791,7 +6793,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 6794 "configure"' > conftest.$ac_ext + echo '#line 6796 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -8664,11 +8666,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:8667: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8669: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:8671: \$? = $ac_status" >&5 + echo "$as_me:8673: \$? = $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. @@ -9003,11 +9005,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:9006: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9008: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:9010: \$? = $ac_status" >&5 + echo "$as_me:9012: \$? = $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. @@ -9108,11 +9110,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:9111: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9113: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:9115: \$? = $ac_status" >&5 + echo "$as_me:9117: \$? = $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 @@ -9163,11 +9165,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:9166: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9168: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:9170: \$? = $ac_status" >&5 + echo "$as_me:9172: \$? = $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 @@ -11547,7 +11549,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11550 "configure" +#line 11552 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11643,7 +11645,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11646 "configure" +#line 11648 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -13599,11 +13601,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:13602: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13604: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:13606: \$? = $ac_status" >&5 + echo "$as_me:13608: \$? = $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. @@ -13698,11 +13700,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:13701: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13703: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:13705: \$? = $ac_status" >&5 + echo "$as_me:13707: \$? = $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 @@ -13750,11 +13752,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:13753: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13755: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:13757: \$? = $ac_status" >&5 + echo "$as_me:13759: \$? = $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 @@ -16628,6 +16630,77 @@ $as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shar acx_pthread_ok=no fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether what we have so far is sufficient with -nostdlib" >&5 +$as_echo_n "checking whether what we have so far is sufficient with -nostdlib... " >&6; } + CFLAGS="-nostdlib $CFLAGS" + # we need c with nostdlib + LIBS="$LIBS -lc" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <pthread.h> +int +main () +{ +pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + done=yes +else + done=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + if test "x$done" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + if test x"$done" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lpthread saves the day" >&5 +$as_echo_n "checking whether -lpthread saves the day... " >&6; } + LIBS="-lpthread $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <pthread.h> +int +main () +{ +pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + done=yes +else + done=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + if test "x$done" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Impossible to determine how to use pthreads with shared libraries and -nostdlib" >&5 +$as_echo "$as_me: WARNING: Impossible to determine how to use pthreads with shared libraries and -nostdlib" >&2;} + fi + fi + CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" @@ -17498,7 +17571,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by google-perftools $as_me 1.6, which was +This file was extended by google-perftools $as_me 1.7, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -17564,7 +17637,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -google-perftools config.status 1.6 +google-perftools config.status 1.7 configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index b74cda8..43ae558 100644 --- a/configure.ac +++ b/configure.ac @@ -4,9 +4,11 @@ # make sure we're interpreted by some minimal autoconf AC_PREREQ(2.57) -AC_INIT(google-perftools, 1.6, opensource@google.com) -TCMALLOC_SO_VERSION=0:1:0 -PROFILER_SO_VERSION=0:1:0 +AC_INIT(google-perftools, 1.7, opensource@google.com) +# Update this value for every release! (A:B:C will map to foo.so.(A-C).C.B) +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +TCMALLOC_SO_VERSION=1:0:1 +PROFILER_SO_VERSION=1:0:1 AC_SUBST(TCMALLOC_SO_VERSION) AC_SUBST(PROFILER_SO_VERSION) diff --git a/m4/acx_pthread.m4 b/m4/acx_pthread.m4 index 2cf20de..89d42c7 100644 --- a/m4/acx_pthread.m4 +++ b/m4/acx_pthread.m4 @@ -340,6 +340,40 @@ if test "x$acx_pthread_ok" = xyes; then acx_pthread_ok=no fi + AC_MSG_CHECKING([whether what we have so far is sufficient with -nostdlib]) + CFLAGS="-nostdlib $CFLAGS" + # we need c with nostdlib + LIBS="$LIBS -lc" + AC_TRY_LINK([#include <pthread.h>], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes],[done=no]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + if test x"$done" = xno; then + AC_MSG_CHECKING([whether -lpthread saves the day]) + LIBS="-lpthread $LIBS" + AC_TRY_LINK([#include <pthread.h>], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [done=yes],[done=no]) + + if test "x$done" = xyes; then + AC_MSG_RESULT([yes]) + PTHREAD_LIBS="$PTHREAD_LIBS -lpthread" + else + AC_MSG_RESULT([no]) + AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries and -nostdlib]) + fi + fi + CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" diff --git a/packages/deb/changelog b/packages/deb/changelog index 579ebf0..e9fd548 100644 --- a/packages/deb/changelog +++ b/packages/deb/changelog @@ -1,3 +1,9 @@ +google-perftools (1.7-1) unstable; urgency=low + + * New upstream release. + + -- Google Inc. <opensource@google.com> Fri, 04 Feb 2011 15:54:31 -0800 + google-perftools (1.6-1) unstable; urgency=low * New upstream release. diff --git a/src/base/cycleclock.h b/src/base/cycleclock.h index b114170..02cddf3 100644 --- a/src/base/cycleclock.h +++ b/src/base/cycleclock.h @@ -47,29 +47,29 @@ #include "base/basictypes.h" // make sure we get the def for int64 #if defined(__MACH__) && defined(__APPLE__) -#include <mach/mach_time.h> -#elif defined(__ARM_ARCH_5T__) -#include <sys/time.h> +# include <mach/mach_time.h> +#elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_3__) +# include <sys/time.h> #endif // NOTE: only i386 and x86_64 have been well tested. // PPC, sparc, alpha, and ia64 are based on // http://peter.kuscsik.com/wordpress/?p=14 -// with modifications by m3b. cf +// with modifications by m3b. See also // https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h struct CycleClock { // This should return the number of cycles since power-on. Thread-safe. static inline int64 Now() { #if defined(__MACH__) && defined(__APPLE__) - // this goes at the top because we need ALL Macs, regardless - // of architecture, to return the number of "mach time units" - // that have passes since startup. See sysinfo.cc where - // InitializeSystemInfo() sets the supposed cpu clock frequency of macs - // to the number of mach time units per second, not actual + // this goes at the top because we need ALL Macs, regardless of + // architecture, to return the number of "mach time units" that + // have passed since startup. See sysinfo.cc where + // InitializeSystemInfo() sets the supposed cpu clock frequency of + // macs to the number of mach time units per second, not actual // CPU clock frequency (which can change in the face of CPU - // frequency scaling). also note that when the Mac sleeps, - // this counter pauses; it does not continue counting, nor resets - // to zero. + // frequency scaling). Also note that when the Mac sleeps, this + // counter pauses; it does not continue counting, nor does it + // reset to zero. return mach_absolute_time(); #elif defined(__i386__) int64 ret; @@ -88,10 +88,6 @@ struct CycleClock { tbl &= -static_cast<int64>(tbu0 == tbu1); // high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage) return (tbu1 << 32) | tbl; -#elif defined(__ARM_ARCH_5T__) - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast<uint64>(tv.tv_sec) * 1000000 + tv.tv_usec; #elif defined(__sparc__) int64 tick; asm(".byte 0x83, 0x41, 0x00, 0x00"); @@ -103,6 +99,17 @@ struct CycleClock { return itc; #elif defined(_MSC_VER) && defined(_M_IX86) _asm rdtsc + +// If none of the above cases trigger, we use a solution based on +// a system call (gettimeofday or similar). We do these in order +// from fastest to slowest. We do not have an '#else' catch-all +// case here that just calls gettimeofday(); that system call is +// slow, and this function is expected to be fast, so we don't want +// to use it without an explicit decision that it's the only way. +#elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_3__) + struct timeval tv; + gettimeofday(&tv, NULL); + return static_cast<uint64>(tv.tv_sec) * 1000000 + tv.tv_usec; #else // We could define __alpha here as well, but it only has a 32-bit // timer (good for like 4 seconds), which isn't very useful. diff --git a/src/base/dynamic_annotations.c b/src/base/dynamic_annotations.c index 0746540..1005f90 100644 --- a/src/base/dynamic_annotations.c +++ b/src/base/dynamic_annotations.c @@ -35,6 +35,7 @@ # error "This file should be built as pure C to avoid name mangling" #endif +#include "config.h" #include <stdlib.h> #include <string.h> diff --git a/src/base/logging.h b/src/base/logging.h index fe25acf..5c3e546 100644 --- a/src/base/logging.h +++ b/src/base/logging.h @@ -233,6 +233,7 @@ inline void LOG_IF(int lvl, bool cond, const char* pat, ...) { // Like other "raw" routines, these functions are best effort, and // thus don't return error codes (except RawOpenForWriting()). #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) +#define NOMINMAX // @#!$& windows #include <windows.h> typedef HANDLE RawFD; const RawFD kIllegalRawFD = INVALID_HANDLE_VALUE; diff --git a/src/base/stl_allocator.h b/src/base/stl_allocator.h index 7b0b8ca..d9d2983 100644 --- a/src/base/stl_allocator.h +++ b/src/base/stl_allocator.h @@ -37,6 +37,7 @@ #include <config.h> +#include <stddef.h> // for ptrdiff_t #include <limits> #include "base/basictypes.h" diff --git a/src/base/vdso_support.cc b/src/base/vdso_support.cc index 4543fab..09288a5 100644 --- a/src/base/vdso_support.cc +++ b/src/base/vdso_support.cc @@ -40,6 +40,7 @@ #ifdef HAVE_VDSO_SUPPORT // defined in vdso_support.h #include <fcntl.h> +#include <stddef.h> // for ptrdiff_t #include "base/atomicops.h" // for MemoryBarrier #include "base/linux_syscall_support.h" diff --git a/src/debugallocation.cc b/src/debugallocation.cc index c83ba5a..d149ec4 100644 --- a/src/debugallocation.cc +++ b/src/debugallocation.cc @@ -668,24 +668,24 @@ class MallocBlock { reinterpret_cast<void*>( PRINTABLE_PTHREAD(queue_entry.deleter_threadid))); - SymbolTable symbolization_table; - const int num_symbols = queue_entry.num_deleter_pcs; // short alias name - for (int i = 0; i < num_symbols; i++) { + // We don't want to allocate or deallocate memory here, so we use + // placement-new. It's ok that we don't destroy this, since we're + // just going to error-exit below anyway. Union is for alignment. + union { void* alignment; char buf[sizeof(SymbolTable)]; } tablebuf; + SymbolTable* symbolization_table = new (tablebuf.buf) SymbolTable; + for (int i = 0; i < queue_entry.num_deleter_pcs; i++) { // Symbolizes the previous address of pc because pc may be in the // next function. This may happen when the function ends with // a call to a function annotated noreturn (e.g. CHECK). - char* pc = - reinterpret_cast<char*>(queue_entry.deleter_pcs[i]) - 1; - symbolization_table.Add(pc); + char *pc = reinterpret_cast<char*>(queue_entry.deleter_pcs[i]); + symbolization_table->Add(pc - 1); } if (FLAGS_symbolize_stacktrace) - symbolization_table.Symbolize(); - for (int i = 0; i < num_symbols; i++) { - char *pc = - reinterpret_cast<char*>(queue_entry.deleter_pcs[i]) - 1; - TracePrintf(STDERR_FILENO, " @ %"PRIxPTR" %s\n", - reinterpret_cast<uintptr_t>(pc), - symbolization_table.GetSymbol(pc)); + symbolization_table->Symbolize(); + for (int i = 0; i < queue_entry.num_deleter_pcs; i++) { + char *pc = reinterpret_cast<char*>(queue_entry.deleter_pcs[i]); + TracePrintf(STDERR_FILENO, " @ %p %s\n", + pc, symbolization_table->GetSymbol(pc - 1)); } } else { RAW_LOG(ERROR, diff --git a/src/heap-checker.cc b/src/heap-checker.cc index 3f042ea..bfb1cd3 100644 --- a/src/heap-checker.cc +++ b/src/heap-checker.cc @@ -109,11 +109,7 @@ using std::char_traits; // If current process is being ptrace()d, 'TracerPid' in /proc/self/status // will be non-zero. static bool IsDebuggerAttached(void) { // only works under linux, probably - // Since we could be called from FailureSignalHandler, avoid stdio - // which could have been corrupted. - // Limit stack usage as well. Currently, TracerPid is at max offset 76 - // (depending on length of argv[0]) into /proc/self/status. - char buf[100]; + char buf[256]; // TracerPid comes relatively earlier in status output int fd = open("/proc/self/status", O_RDONLY); if (fd == -1) { return false; // Can't tell for sure. @@ -189,12 +185,6 @@ DEFINE_bool(heap_check_test_pointer_alignment, // use 1 if any alignment is ok. // heap_check_test_pointer_alignment flag guides if we try the value of 1. // The larger it can be, the lesser is the chance of missing real leaks. -// -// sizeof(void)* is correct. However gold (the new linker) has a bug where it -// sometimes places global pointers on 4-byte boundaries, even when pointers -// are 8 bytes long. While we are fixing the linker, degrade to 4-byte -// alignment on all targets. http://b/1226481 -// static const size_t kPointerSourceAlignment = sizeof(void*); DEFINE_int32(heap_check_pointer_source_alignment, EnvToInt("HEAP_CHECK_POINTER_SOURCE_ALIGNMENT", @@ -1874,9 +1864,6 @@ void HeapCleaner::RunHeapCleanups() { if (!FLAGS_heap_check_after_destructors) DoMainHeapCheck(); } -// defined below -static int GetCommandLineFrom(const char* file, char* cmdline, int size); - static bool internal_init_start_has_run = false; // Called exactly once, before main() (but hopefully just before). @@ -2242,53 +2229,6 @@ void HeapLeakChecker::TurnItselfOffLocked() { RAW_CHECK(!heap_checker_on, ""); } -// Read in the command line from 'file' into 'cmdline' and return the size read -// 'size' is the space available in 'cmdline'. -// We need this because we don't yet have argv/argc. -// CAVEAT: 'file' (some /proc/*/cmdline) usually contains the command line -// already truncated (to 4K on Linux). -// Arguments in cmdline will be '\0'-terminated, -// the first one will be the binary's name. -static int GetCommandLineFrom(const char* file, char* cmdline, int size) { - // This routine is only used to check if we're running under gdb, so - // it's ok if this #if fails and the routine is a no-op. - // - // This function is called before memory allocation hooks are set up - // so we must not have any memory allocations in it. We use syscall - // versions of open/read/close here because we don't trust the non-syscall - // versions: they might 'accidentally' cause a memory allocation. - // Here's a real-life problem scenario we had: - // 1) A program LD_PRELOADed a library called list_file_used.a - // 2) list_file_used intercepted open/read/close and called dlsym() - // 3) dlsym() called pthread_setspecific() which called malloc(). - // This malloced memory is 'hidden' from the heap-checker. By - // definition, this thread-local data is live, and everything it points - // to is live (not a memory leak) as well. But because this memory - // was hidden from the heap-checker, everything it points to was - // taken to be orphaned, and therefore, a memory leak. -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__MINGW32__) - // Use a win32 call to get the command line. - const char* command_line = ::GetCommandLine(); - strncpy(cmdline, command_line, size); - cmdline[size - 1] = '\0'; - return strlen(cmdline); -#elif defined(HAVE_SYS_SYSCALL_H) - int fd = syscall(SYS_open, file, O_RDONLY); - int result = 0; - if (fd >= 0) { - ssize_t r; - while ((r = syscall(SYS_read, fd, cmdline + result, size)) > 0) { - result += r; - size -= r; - } - syscall(SYS_close, fd); - } - return result; -#else - return 0; -#endif -} - extern bool heap_leak_checker_bcad_variable; // in heap-checker-bcad.cc static bool has_called_before_constructors = false; diff --git a/src/page_heap.cc b/src/page_heap.cc index c92e16b..2e02444 100644 --- a/src/page_heap.cc +++ b/src/page_heap.cc @@ -61,7 +61,7 @@ PageHeap::PageHeap() } } -Span* PageHeap::New(Length n) { +Span* PageHeap::SearchFreeAndLargeLists(Length n) { ASSERT(Check()); ASSERT(n > 0); @@ -79,19 +79,25 @@ Span* PageHeap::New(Length n) { ASSERT(ll->next->location == Span::ON_RETURNED_FREELIST); return Carve(ll->next, n); } - // Still no luck, so keep looking in larger classes. } + // No luck in free lists, our last chance is in a larger class. + return AllocLarge(n); // May be NULL +} - Span* result = AllocLarge(n); - if (result != NULL) return result; +Span* PageHeap::New(Length n) { + ASSERT(Check()); + ASSERT(n > 0); + + Span* result = SearchFreeAndLargeLists(n); + if (result != NULL) + return result; - // Grow the heap and try again + // Grow the heap and try again. if (!GrowHeap(n)) { ASSERT(Check()); return NULL; } - - return AllocLarge(n); + return SearchFreeAndLargeLists(n); } Span* PageHeap::AllocLarge(Length n) { diff --git a/src/page_heap.h b/src/page_heap.h index 545bdda..50ecb36 100644 --- a/src/page_heap.h +++ b/src/page_heap.h @@ -215,6 +215,8 @@ class PERFTOOLS_DLL_DECL PageHeap { // Statistics on system, free, and unmapped bytes Stats stats_; + Span* SearchFreeAndLargeLists(Length n); + bool GrowHeap(Length n); // REQUIRES: span->length >= n @@ -72,7 +72,7 @@ use strict; use warnings; use Getopt::Long; -my $PPROF_VERSION = "1.5"; +my $PPROF_VERSION = "1.7"; # These are the object tools we use which can come from a # user-specified location using --tools, from the PPROF_TOOLS @@ -211,6 +211,7 @@ Call-graph Options: --nodecount=<n> Show at most so many nodes [default=80] --nodefraction=<f> Hide nodes below <f>*total [default=.005] --edgefraction=<f> Hide edges below <f>*total [default=.001] + --maxdegree=<n> Max incoming/outgoing edges per node [default=8] --focus=<regexp> Focus on nodes matching <regexp> --ignore=<regexp> Ignore nodes matching <regexp> --scale=<n> Set GV scaling [default=0] @@ -319,6 +320,7 @@ sub Init() { $main::opt_nodecount = 80; $main::opt_nodefraction = 0.005; $main::opt_edgefraction = 0.001; + $main::opt_maxdegree = 8; $main::opt_focus = ''; $main::opt_ignore = ''; $main::opt_scale = 0; @@ -388,6 +390,7 @@ sub Init() { "nodecount=i" => \$main::opt_nodecount, "nodefraction=f" => \$main::opt_nodefraction, "edgefraction=f" => \$main::opt_edgefraction, + "maxdegree=i" => \$main::opt_maxdegree, "focus=s" => \$main::opt_focus, "ignore=s" => \$main::opt_ignore, "scale=i" => \$main::opt_scale, @@ -1814,12 +1817,38 @@ sub PrintDot { } } - # Print edges - foreach my $e (keys(%edge)) { + # Print edges (process in order of decreasing counts) + my %indegree = (); # Number of incoming edges added per node so far + my %outdegree = (); # Number of outgoing edges added per node so far + foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) { my @x = split(/\001/, $e); $n = $edge{$e}; - if (abs($n) > $edgelimit) { + # Initialize degree of kept incoming and outgoing edges if necessary + my $src = $x[0]; + my $dst = $x[1]; + if (!exists($outdegree{$src})) { $outdegree{$src} = 0; } + if (!exists($indegree{$dst})) { $indegree{$dst} = 0; } + + my $keep; + if ($indegree{$dst} == 0) { + # Keep edge if needed for reachability + $keep = 1; + } elsif (abs($n) <= $edgelimit) { + # Drop if we are below --edgefraction + $keep = 0; + } elsif ($outdegree{$src} >= $main::opt_maxdegree || + $indegree{$dst} >= $main::opt_maxdegree) { + # Keep limited number of in/out edges per node + $keep = 0; + } else { + $keep = 1; + } + + if ($keep) { + $outdegree{$src}++; + $indegree{$dst}++; + # Compute line width based on edge count my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0); if ($fraction > 1) { $fraction = 1; } @@ -2157,6 +2186,19 @@ function handleMouseUp(evt) { EOF } +# Return a small number that identifies the argument. +# Multiple calls with the same argument will return the same number. +# Calls with different arguments will return different numbers. +sub ShortIdFor { + my $key = shift; + my $id = $main::uniqueid{$key}; + if (!defined($id)) { + $id = keys(%main::uniqueid) + 1; + $main::uniqueid{$key} = $id; + } + return $id; +} + # Translate a stack of addresses into a stack of symbols sub TranslateStack { my $symbols = shift; @@ -2194,6 +2236,15 @@ sub TranslateStack { if ($j > 2) { $func = "$func (inline)"; } + + # Do not merge nodes corresponding to Callback::Run since that + # causes confusing cycles in dot display. Instead, we synthesize + # a unique name for this frame per caller. + if ($func =~ m/Callback.*::Run$/) { + my $caller = ($i > 0) ? $addrs[$i-1] : 0; + $func = "Run#" . ShortIdFor($caller); + } + if ($main::opt_addresses) { push(@result, "$a $func $fileline"); } elsif ($main::opt_lines) { diff --git a/src/symbolize.h b/src/symbolize.h index 1ab4ed6..12c976b 100644 --- a/src/symbolize.h +++ b/src/symbolize.h @@ -37,6 +37,7 @@ #ifdef HAVE_STDINT_H #include <stdint.h> // for uintptr_t #endif +#include <stddef.h> // for NULL #include <map> using std::map; diff --git a/src/system-alloc.cc b/src/system-alloc.cc index e589469..f28fa22 100644 --- a/src/system-alloc.cc +++ b/src/system-alloc.cc @@ -31,6 +31,7 @@ // Author: Sanjay Ghemawat #include <config.h> +#include <stddef.h> // for NULL #if defined HAVE_STDINT_H #include <stdint.h> #elif defined HAVE_INTTYPES_H diff --git a/src/tests/debugallocation_test.cc b/src/tests/debugallocation_test.cc index f10e2dc..dd5af13 100644 --- a/src/tests/debugallocation_test.cc +++ b/src/tests/debugallocation_test.cc @@ -213,6 +213,17 @@ TEST(DebugAllocationTest, DanglingWriteAtExitTest) { *x = old_x_value; // restore x so that the test can exit successfully. } +TEST(DebugAllocationTest, StackTraceWithDanglingWriteAtExitTest) { + int *x = new int; + delete x; + int old_x_value = *x; + *x = 1; + // verify that we also get a stack trace when we have a dangling write. + // The " @ " is part of the stack trace output. + IF_DEBUG_EXPECT_DEATH(exit(0), " @ .* main"); + *x = old_x_value; // restore x so that the test can exit successfully. +} + static size_t CurrentlyAllocatedBytes() { size_t value; CHECK(MallocExtension::instance()->GetNumericProperty( @@ -264,16 +275,11 @@ TEST(DebugAllocationTest, HugeAlloc) { // compiler as too large for the allocation. size_t kTooBig = ~static_cast<size_t>(0); void* a = NULL; - char* b = NULL; #ifndef NDEBUG a = malloc(kTooBig); EXPECT_EQ(NULL, a); - b = NULL; - IF_DEBUG_EXPECT_DEATH(b = new char[kTooBig], - "Unable to allocate.*new\\[\\] failed\\."); - EXPECT_EQ(NULL, b); // kAlsoTooBig is small enough not to get caught by debugallocation's check, // but will still fall through to tcmalloc's check. This must also be @@ -282,8 +288,6 @@ TEST(DebugAllocationTest, HugeAlloc) { a = malloc(kAlsoTooBig); EXPECT_EQ(NULL, a); - IF_DEBUG_EXPECT_DEATH(b = new char[kAlsoTooBig], "Unable to allocate.*new failed"); - EXPECT_EQ(NULL, b); #endif } diff --git a/src/tests/debugallocation_test.sh b/src/tests/debugallocation_test.sh index 2568d54..5d9bd8b 100755 --- a/src/tests/debugallocation_test.sh +++ b/src/tests/debugallocation_test.sh @@ -52,21 +52,38 @@ num_failures=0 # Increments num_failures if the death test does not succeed. OneDeathTest() { "$DEBUGALLOCATION_TEST" "$1" 2>&1 | { - read regex_line - regex=`expr "$regex_line" : "Expected regex:\(.*\)"` - test -z "$regex" && echo "done" # no regex line, not a death-case - grep "$regex" >/dev/null 2>&1 # pass the rest of the lines through grep - } || num_failures=`expr $num_failures + 1` + regex_line='dummy' + # Normally the regex_line is the first line of output, but not + # always (if tcmalloc itself does any logging to stderr). + while test -n "$regex_line"; do + read regex_line + regex=`expr "$regex_line" : "Expected regex:\(.*\)"` + test -n "$regex" && break # found the regex line + done + test -z "$regex" && echo "done" || grep "$regex" 2>&1 + } } death_test_num=0 # which death test to run -while test -z `OneDeathTest "$death_test_num"`; do - echo "Done with death test $death_test_num" +while /bin/true; do + echo -n "Running death test $death_test_num..." + output="`OneDeathTest $death_test_num`" + case $output in + # Empty string means grep didn't find anything. + "") echo "FAILED"; num_failures=`expr $num_failures + 1`;; + "done"*) echo "done with death tests"; break;; + # Any other string means grep found something, like it ought to. + *) echo "OK";; + esac death_test_num=`expr $death_test_num + 1` done # Test the non-death parts of the test too -if ! "$DEBUGALLOCATION_TEST"; then +echo -n "Running non-death tests..." +if "$DEBUGALLOCATION_TEST"; then + echo "OK" +else + echo "FAILED" num_failures=`expr $num_failures + 1` fi diff --git a/src/tests/malloc_extension_test.cc b/src/tests/malloc_extension_test.cc index 60f4919..0bd85ad 100644 --- a/src/tests/malloc_extension_test.cc +++ b/src/tests/malloc_extension_test.cc @@ -72,30 +72,6 @@ int main(int argc, char** argv) { ASSERT_LE(MallocExtension_GetAllocatedSize(a), 5000); ASSERT_GE(MallocExtension_GetEstimatedAllocatedSize(1000), 1000); - // test invariant: size of freelist = heap_size - allocated_bytes - free(malloc(32000)); - size_t heap_size = 0; - size_t allocated = 0; - ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty( - "generic.current_allocated_bytes", &allocated)); - ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty( - "generic.heap_size", &heap_size)); - vector<MallocExtension::FreeListInfo> info; - MallocExtension::instance()->GetFreeListSizes(&info); - - ASSERT_GE(info.size(), 0); - int64 free_bytes = 0; - for (vector<MallocExtension::FreeListInfo>::const_iterator it = info.begin(); - it != info.end(); - ++it) { - free_bytes += it->total_bytes_free; - } - - // don't expect an exact equality since the calls to query the heap - // themselves free and allocate memory - size_t error = abs((heap_size - allocated) - free_bytes); - ASSERT_LT(error, 0.15 * heap_size); - free(a); printf("DONE\n"); diff --git a/src/windows/port.h b/src/windows/port.h index 81a68e6..ff6b714 100644 --- a/src/windows/port.h +++ b/src/windows/port.h @@ -277,7 +277,10 @@ enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 }; #define O_RDONLY _O_RDONLY #endif -extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); +#ifdef __cplusplus +extern "C" +#endif +PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); // ----------------------------------- SYSTEM/PROCESS typedef int pid_t; |