mirror of
https://github.com/gperftools/gperftools
synced 2025-02-22 07:06:50 +00:00
* Suppress all large allocs when report threshold==0
* Clarified meaning of various malloc stats * Change from ATTRIBUTED_DEPRECATED to comments * Make array-size a var to compile under clang * Reduce page map key size under x86_64 by 4.4MB * Added full qualification to MemoryBarrier * Support systems that capitalize /proc weirdly * Avoid gcc warning: exporting type in unnamed ns * Add some dynamic annotations for gcc attributes * Add support for census profiler in pprof * Speed up pprof's ExtractSymbols * Speed up GoogleOnce * Add pkg-config (.pc) files * Detect when __environ exists but is NULL * Improve spinlock contention performance * Add GetFreeListSizes * Improve sampling_test, eg by adding no-inline * Relax malloc_extension test-check for big pages * Add proper library version number information * Update from autoconf 2.64 to 2.65 * Better document how to write a server that works with pprof * Change FillProcSelfMaps to better handle out-of-space * No longer hook _aligned_malloc/free in windows * Handle function-forwarding in DLLs when patching (in windows) * Update .vcproj files that had wrong .cc files in them (!) * get rid of unnecessary 'size < 0' * fix comments a bit in sysinfo.cc * another go at improving malloc-stats output * fix comment typo in profiler.cc * Add a few more thread annotations * Try to read TSC frequency from 'tsc_freq_khz' * Fix annotalysis/TSAN incompatibility * Add pprof --evince to go along with --gv * Document need for sampling to use GetHeapSample * Fix flakiness in malloc_extension_test * Separate out synchronization profiling routines git-svn-id: http://gperftools.googlecode.com/svn/trunk@99 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
This commit is contained in:
parent
682ff7da12
commit
3014cf142e
63
Makefile.am
63
Makefile.am
@ -194,6 +194,7 @@ libwindows_la_SOURCES = $(WINDOWS_INCLUDES) \
|
||||
libwindows_la_LIBADD = -lPsapi
|
||||
|
||||
SPINLOCK_INCLUDES = src/base/spinlock.h \
|
||||
src/base/spinlock_internal.h \
|
||||
src/base/spinlock_win32-inl.h \
|
||||
src/base/spinlock_linux-inl.h \
|
||||
src/base/spinlock_posix-inl.h \
|
||||
@ -203,6 +204,7 @@ SPINLOCK_INCLUDES = src/base/spinlock.h \
|
||||
src/base/atomicops-internals-x86.h
|
||||
noinst_LTLIBRARIES += libspinlock.la
|
||||
libspinlock_la_SOURCES = src/base/spinlock.cc \
|
||||
src/base/spinlock_internal.cc \
|
||||
$(SPINLOCK_INCLUDES)
|
||||
|
||||
LIBSPINLOCK = libwindows.la libspinlock.la libsysinfo.la liblogging.la
|
||||
@ -219,6 +221,7 @@ SYSTEM_ALLOC_CC =
|
||||
else !MINGW
|
||||
# spinlock is the only code that uses atomicops.
|
||||
SPINLOCK_INCLUDES = src/base/spinlock.h \
|
||||
src/base/spinlock_internal.h \
|
||||
src/base/atomicops.h \
|
||||
src/base/atomicops-internals-macosx.h \
|
||||
src/base/atomicops-internals-linuxppc.h \
|
||||
@ -227,6 +230,7 @@ SPINLOCK_INCLUDES = src/base/spinlock.h \
|
||||
|
||||
noinst_LTLIBRARIES += libspinlock.la
|
||||
libspinlock_la_SOURCES = src/base/spinlock.cc \
|
||||
src/base/spinlock_internal.cc \
|
||||
src/base/atomicops-internals-x86.cc \
|
||||
$(SPINLOCK_INCLUDES)
|
||||
libspinlock_la_LIBADD = $(NANOSLEEP_LIBS)
|
||||
@ -407,7 +411,8 @@ WINDOWS_PROJECTS += vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
|
||||
libtcmalloc_minimal_la_SOURCES = $(TCMALLOC_CC) $(TCMALLOC_MINIMAL_INCLUDES)
|
||||
libtcmalloc_minimal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \
|
||||
$(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
|
||||
libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
# -version-info gets passed to libtool
|
||||
libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@
|
||||
libtcmalloc_minimal_la_LIBADD = libtcmalloc_minimal_internal.la $(PTHREAD_LIBS)
|
||||
|
||||
# For windows, we're playing around with trying to do some stacktrace
|
||||
@ -675,7 +680,9 @@ libtcmalloc_minimal_debug_la_SOURCES = src/debugallocation.cc \
|
||||
$(TCMALLOC_MINIMAL_INCLUDES)
|
||||
libtcmalloc_minimal_debug_la_CXXFLAGS = $(libtcmalloc_minimal_la_CXXFLAGS) \
|
||||
-DTCMALLOC_FOR_DEBUGALLOCATION
|
||||
libtcmalloc_minimal_debug_la_LDFLAGS = $(libtcmalloc_minimal_la_LDFLAGS)
|
||||
# version_info gets passed to libtool
|
||||
libtcmalloc_minimal_debug_la_LDFLAGS = $(libtcmalloc_minimal_la_LDFLAGS) \
|
||||
-version-info @TCMALLOC_SO_VERSION@
|
||||
libtcmalloc_minimal_debug_la_LIBADD = $(libtcmalloc_minimal_la_LIBADD)
|
||||
|
||||
LIBS_TO_WEAKEN += libtcmalloc_minimal_debug.la
|
||||
@ -770,7 +777,7 @@ libtcmalloc_internal_la_LIBADD = libstacktrace.la $(PTHREAD_LIBS)
|
||||
lib_LTLIBRARIES += libtcmalloc.la
|
||||
libtcmalloc_la_SOURCES = $(TCMALLOC_CC) $(TCMALLOC_INCLUDES)
|
||||
libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
|
||||
libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@
|
||||
libtcmalloc_la_LIBADD = libtcmalloc_internal.la $(PTHREAD_LIBS)
|
||||
|
||||
if WITH_HEAP_CHECKER
|
||||
@ -973,7 +980,8 @@ libtcmalloc_debug_la_SOURCES = src/debugallocation.cc $(HEAP_CHECKER_SOURCES) \
|
||||
$(TCMALLOC_INCLUDES)
|
||||
libtcmalloc_debug_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) \
|
||||
-DTCMALLOC_FOR_DEBUGALLOCATION
|
||||
libtcmalloc_debug_la_LDFLAGS = $(libtcmalloc_la_LDFLAGS)
|
||||
libtcmalloc_debug_la_LDFLAGS = $(libtcmalloc_la_LDFLAGS) \
|
||||
-version-info @TCMALLOC_SO_VERSION@
|
||||
libtcmalloc_debug_la_LIBADD = $(libtcmalloc_la_LIBADD)
|
||||
|
||||
LIBS_TO_WEAKEN += libtcmalloc_debug.la
|
||||
@ -1083,7 +1091,8 @@ libprofiler_la_SOURCES = src/profiler.cc \
|
||||
libprofiler_la_LIBADD = libstacktrace.la
|
||||
# We have to include ProfileData for profiledata_unittest
|
||||
CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStartWithOptions|ProfilerStop|ProfilerFlush|ProfilerEnable|ProfilerDisable|ProfilingIsEnabledForAllThreads|ProfilerRegisterThread|ProfilerGetCurrentState|ProfilerState|ProfileData|ProfileHandler)'
|
||||
libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS)
|
||||
libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS) \
|
||||
-version-info @PROFILER_SO_VERSION@
|
||||
|
||||
# See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this.
|
||||
# Basically it's to work around systems where --rpath doesn't work right.
|
||||
@ -1172,8 +1181,11 @@ if WITH_CPU_PROFILER
|
||||
lib_LTLIBRARIES += libtcmalloc_and_profiler.la
|
||||
libtcmalloc_and_profiler_la_SOURCES = $(libtcmalloc_la_SOURCES) $(libprofiler_la_SOURCES)
|
||||
libtcmalloc_and_profiler_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) $(libprofiler_la_CXXFLAGS)
|
||||
# Since this library is meant to be used as a .a, I don't worry as much
|
||||
# about .so versioning. I just give the libtcmalloc version number.
|
||||
# TODO(csilvers): use -export-symbols-regex?
|
||||
libtcmalloc_and_profiler_la_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
libtcmalloc_and_profiler_la_LDFLAGS = $(PTHREAD_CFLAGS) \
|
||||
-version-info @TCMALLOC_SO_VERSION@
|
||||
# We don't include libprofiler_la_LIBADD here because all it adds is
|
||||
# libstacktrace.la, which we already get via libtcmalloc. Trying to
|
||||
# specify it twice causes link-time duplicate-definition errors. :-(
|
||||
@ -1210,6 +1222,45 @@ rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec
|
||||
deb: dist-gzip packages/deb.sh packages/deb/*
|
||||
@cd packages && ./deb.sh ${PACKAGE} ${VERSION}
|
||||
|
||||
# http://linux.die.net/man/1/pkg-config, http://pkg-config.freedesktop.org/wiki
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libtcmalloc.pc libtcmalloc_minimal.pc \
|
||||
libtcmalloc_debug.pc libtcmalloc_minimal_debug.pc \
|
||||
libprofiler.pc
|
||||
CLEANFILES = $(pkgconfig_DATA)
|
||||
|
||||
# I get the description and URL lines from the rpm spec. I use sed to
|
||||
# try to rewrite exec_prefix, libdir, and includedir in terms of
|
||||
# prefix, if possible.
|
||||
libtcmalloc.pc: Makefile packages/rpm/rpm.spec
|
||||
echo 'prefix=$(prefix)' > "$@".tmp
|
||||
echo 'exec_prefix='`echo '$(exec_prefix)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp
|
||||
echo 'libdir='`echo '$(libdir)' | sed 's@^$(exec_prefix)@$${exec_prefix}@'` >> "$@".tmp
|
||||
echo 'includedir='`echo '$(includedir)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp
|
||||
echo '' >> "$@".tmp
|
||||
echo 'Name: $(PACKAGE)' >> "$@".tmp
|
||||
echo 'Version: $(VERSION)' >> "$@".tmp
|
||||
-grep '^Summary:' packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp
|
||||
-grep '^URL: ' packages/rpm/rpm.spec >> "$@".tmp
|
||||
echo 'Requires:' >> "$@".tmp
|
||||
echo 'Libs: -L$${libdir} -ltcmalloc' >> "$@".tmp
|
||||
echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp
|
||||
echo 'Cflags: -I$${includedir}' >> "$@".tmp
|
||||
mv -f "$@".tmp "$@"
|
||||
|
||||
# The other versions are mostly the same.
|
||||
libtcmalloc_minimal.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal/ > "$@"
|
||||
|
||||
libtcmalloc_debug.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_debug/ > "$@"
|
||||
|
||||
libtcmalloc_minimal_debug.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal_debug/ > "$@"
|
||||
|
||||
libprofiler.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-lprofiler/ > "$@"
|
||||
|
||||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
|
184
Makefile.in
184
Makefile.in
@ -264,7 +264,9 @@ 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 \
|
||||
$(top_srcdir)/m4/install_prefix.m4 $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/m4/namespaces.m4 \
|
||||
$(top_srcdir)/m4/pc_from_ucontext.m4 \
|
||||
$(top_srcdir)/m4/program_invocation_name.m4 \
|
||||
@ -284,7 +286,8 @@ am__vpath_adj = case $$p in \
|
||||
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
|
||||
"$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
|
||||
"$(DESTDIR)$(docdir)" "$(DESTDIR)$(googleincludedir)" \
|
||||
"$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" \
|
||||
"$(DESTDIR)$(googleincludedir)" \
|
||||
"$(DESTDIR)$(googleincludedir)"
|
||||
libLTLIBRARIES_INSTALL = $(INSTALL)
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
|
||||
@ -300,8 +303,8 @@ am__libprofiler_la_SOURCES_DIST = src/profiler.cc \
|
||||
src/profile-handler.h src/getpc.h src/base/basictypes.h \
|
||||
src/base/commandlineflags.h src/base/googleinit.h \
|
||||
src/base/logging.h src/base/simple_mutex.h src/base/sysinfo.h \
|
||||
src/base/spinlock.h src/base/atomicops.h \
|
||||
src/base/atomicops-internals-macosx.h \
|
||||
src/base/spinlock.h src/base/spinlock_internal.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 \
|
||||
@ -321,16 +324,20 @@ libprofiler_la_OBJECTS = $(am_libprofiler_la_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
@MINGW_FALSE@libspinlock_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
|
||||
am__libspinlock_la_SOURCES_DIST = src/base/spinlock.cc \
|
||||
src/base/spinlock_internal.cc \
|
||||
src/base/atomicops-internals-x86.cc src/base/spinlock.h \
|
||||
src/base/atomicops.h src/base/atomicops-internals-macosx.h \
|
||||
src/base/spinlock_internal.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/base/spinlock_win32-inl.h src/base/spinlock_linux-inl.h \
|
||||
src/base/spinlock_posix-inl.h
|
||||
@MINGW_FALSE@am_libspinlock_la_OBJECTS = spinlock.lo \
|
||||
@MINGW_FALSE@ atomicops-internals-x86.lo $(am__objects_1)
|
||||
@MINGW_TRUE@am_libspinlock_la_OBJECTS = spinlock.lo $(am__objects_1)
|
||||
@MINGW_FALSE@ spinlock_internal.lo atomicops-internals-x86.lo \
|
||||
@MINGW_FALSE@ $(am__objects_1)
|
||||
@MINGW_TRUE@am_libspinlock_la_OBJECTS = spinlock.lo \
|
||||
@MINGW_TRUE@ spinlock_internal.lo $(am__objects_1)
|
||||
libspinlock_la_OBJECTS = $(am_libspinlock_la_OBJECTS)
|
||||
@MINGW_FALSE@am_libspinlock_la_rpath =
|
||||
@MINGW_TRUE@am_libspinlock_la_rpath =
|
||||
@ -363,7 +370,8 @@ libsysinfo_la_OBJECTS = $(am_libsysinfo_la_OBJECTS)
|
||||
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/spinlock_internal.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 \
|
||||
@ -413,7 +421,8 @@ libtcmalloc_la_OBJECTS = $(am_libtcmalloc_la_OBJECTS)
|
||||
am__libtcmalloc_and_profiler_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/spinlock_internal.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 \
|
||||
@ -466,7 +475,8 @@ am__libtcmalloc_debug_la_SOURCES_DIST = src/debugallocation.cc \
|
||||
src/heap-checker.cc src/heap-checker-bcad.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/spinlock_internal.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 \
|
||||
@ -509,7 +519,8 @@ am__libtcmalloc_internal_la_SOURCES_DIST = src/common.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/spinlock_internal.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 \
|
||||
@ -568,7 +579,8 @@ libtcmalloc_minimal_la_DEPENDENCIES = libtcmalloc_minimal_internal.la \
|
||||
am__libtcmalloc_minimal_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/spinlock_internal.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 \
|
||||
@ -594,7 +606,8 @@ am__DEPENDENCIES_4 = libtcmalloc_minimal_internal.la \
|
||||
am__libtcmalloc_minimal_debug_la_SOURCES_DIST = \
|
||||
src/debugallocation.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/spinlock_internal.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 \
|
||||
@ -625,7 +638,8 @@ am__libtcmalloc_minimal_internal_la_SOURCES_DIST = src/common.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/spinlock_internal.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 \
|
||||
@ -860,7 +874,8 @@ am__low_level_alloc_unittest_SOURCES_DIST = \
|
||||
src/tests/low_level_alloc_unittest.cc \
|
||||
src/base/low_level_alloc.h src/base/basictypes.h \
|
||||
src/google/malloc_hook.h src/google/malloc_hook_c.h \
|
||||
src/malloc_hook-inl.h src/base/spinlock.h src/base/atomicops.h \
|
||||
src/malloc_hook-inl.h src/base/spinlock.h \
|
||||
src/base/spinlock_internal.h src/base/atomicops.h \
|
||||
src/base/atomicops-internals-macosx.h \
|
||||
src/base/atomicops-internals-linuxppc.h \
|
||||
src/base/atomicops-internals-x86-msvc.h \
|
||||
@ -1374,7 +1389,8 @@ am__dist_doc_DATA_DIST = AUTHORS COPYING ChangeLog INSTALL NEWS README \
|
||||
doc/pprof-test.gif doc/pprof-vsnprintf-big.gif \
|
||||
doc/pprof-vsnprintf.gif
|
||||
dist_docDATA_INSTALL = $(INSTALL_DATA)
|
||||
DATA = $(dist_doc_DATA)
|
||||
pkgconfigDATA_INSTALL = $(INSTALL_DATA)
|
||||
DATA = $(dist_doc_DATA) $(pkgconfig_DATA)
|
||||
am__googleinclude_HEADERS_DIST = src/google/stacktrace.h \
|
||||
src/google/malloc_hook.h src/google/malloc_hook_c.h \
|
||||
src/google/malloc_extension.h src/google/malloc_extension_c.h \
|
||||
@ -1419,7 +1435,7 @@ CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
ECHO = @ECHO@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
@ -1429,8 +1445,7 @@ ENABLE_FRAME_POINTERS_TRUE = @ENABLE_FRAME_POINTERS_TRUE@
|
||||
ENABLE_STATIC_FALSE = @ENABLE_STATIC_FALSE@
|
||||
ENABLE_STATIC_TRUE = @ENABLE_STATIC_TRUE@
|
||||
EXEEXT = @EXEEXT@
|
||||
F77 = @F77@
|
||||
FFLAGS = @FFLAGS@
|
||||
FGREP = @FGREP@
|
||||
GCC_FALSE = @GCC_FALSE@
|
||||
GCC_TRUE = @GCC_TRUE@
|
||||
GREP = @GREP@
|
||||
@ -1440,21 +1455,27 @@ INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBSTDCXX_LA_LINKER_FLAG = @LIBSTDCXX_LA_LINKER_FLAG@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBTOOL_DEPS = @LIBTOOL_DEPS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MINGW_FALSE = @MINGW_FALSE@
|
||||
MINGW_TRUE = @MINGW_TRUE@
|
||||
NANOSLEEP_LIBS = @NANOSLEEP_LIBS@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJCOPY = @OBJCOPY@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
@ -1463,6 +1484,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PROFILER_SO_VERSION = @PROFILER_SO_VERSION@
|
||||
PTHREAD_CC = @PTHREAD_CC@
|
||||
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
|
||||
PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||
@ -1471,6 +1493,7 @@ SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
TCMALLOC_SO_VERSION = @TCMALLOC_SO_VERSION@
|
||||
TC_VERSION_MAJOR = @TC_VERSION_MAJOR@
|
||||
TC_VERSION_MINOR = @TC_VERSION_MINOR@
|
||||
TC_VERSION_PATCH = @TC_VERSION_PATCH@
|
||||
@ -1494,7 +1517,7 @@ X86_64_AND_NO_FP_BY_DEFAULT_FALSE = @X86_64_AND_NO_FP_BY_DEFAULT_FALSE@
|
||||
X86_64_AND_NO_FP_BY_DEFAULT_TRUE = @X86_64_AND_NO_FP_BY_DEFAULT_TRUE@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_F77 = @ac_ct_F77@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
ac_cv_have_struct_mallinfo = @ac_cv_have_struct_mallinfo@
|
||||
acx_pthread_config = @acx_pthread_config@
|
||||
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
|
||||
@ -1530,6 +1553,7 @@ libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
lt_ECHO = @lt_ECHO@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
@ -1761,6 +1785,7 @@ libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) $(am__append_7)
|
||||
@MINGW_TRUE@libwindows_la_LIBADD = -lPsapi
|
||||
# spinlock is the only code that uses atomicops.
|
||||
@MINGW_FALSE@SPINLOCK_INCLUDES = src/base/spinlock.h \
|
||||
@MINGW_FALSE@ src/base/spinlock_internal.h \
|
||||
@MINGW_FALSE@ src/base/atomicops.h \
|
||||
@MINGW_FALSE@ src/base/atomicops-internals-macosx.h \
|
||||
@MINGW_FALSE@ src/base/atomicops-internals-linuxppc.h \
|
||||
@ -1768,6 +1793,7 @@ libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) $(am__append_7)
|
||||
@MINGW_FALSE@ src/base/atomicops-internals-x86.h
|
||||
|
||||
@MINGW_TRUE@SPINLOCK_INCLUDES = src/base/spinlock.h \
|
||||
@MINGW_TRUE@ src/base/spinlock_internal.h \
|
||||
@MINGW_TRUE@ src/base/spinlock_win32-inl.h \
|
||||
@MINGW_TRUE@ src/base/spinlock_linux-inl.h \
|
||||
@MINGW_TRUE@ src/base/spinlock_posix-inl.h \
|
||||
@ -1777,10 +1803,12 @@ libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) $(am__append_7)
|
||||
@MINGW_TRUE@ src/base/atomicops-internals-x86.h
|
||||
|
||||
@MINGW_FALSE@libspinlock_la_SOURCES = src/base/spinlock.cc \
|
||||
@MINGW_FALSE@ src/base/spinlock_internal.cc \
|
||||
@MINGW_FALSE@ src/base/atomicops-internals-x86.cc \
|
||||
@MINGW_FALSE@ $(SPINLOCK_INCLUDES)
|
||||
|
||||
@MINGW_TRUE@libspinlock_la_SOURCES = src/base/spinlock.cc \
|
||||
@MINGW_TRUE@ src/base/spinlock_internal.cc \
|
||||
@MINGW_TRUE@ $(SPINLOCK_INCLUDES)
|
||||
|
||||
# spinlock also needs NumCPUs, from libsysinfo, which in turn needs liblogging
|
||||
@ -1928,7 +1956,8 @@ libtcmalloc_minimal_la_SOURCES = $(TCMALLOC_CC) $(TCMALLOC_MINIMAL_INCLUDES)
|
||||
libtcmalloc_minimal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \
|
||||
$(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
|
||||
|
||||
libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
# -version-info gets passed to libtool
|
||||
libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@
|
||||
libtcmalloc_minimal_la_LIBADD = libtcmalloc_minimal_internal.la $(PTHREAD_LIBS)
|
||||
@MINGW_FALSE@LIBTCMALLOC_MINIMAL = libtcmalloc_minimal.la
|
||||
|
||||
@ -2057,7 +2086,10 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
|
||||
@WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_CXXFLAGS = $(libtcmalloc_minimal_la_CXXFLAGS) \
|
||||
@WITH_DEBUGALLOC_TRUE@ -DTCMALLOC_FOR_DEBUGALLOCATION
|
||||
|
||||
@WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_LDFLAGS = $(libtcmalloc_minimal_la_LDFLAGS)
|
||||
# version_info gets passed to libtool
|
||||
@WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_LDFLAGS = $(libtcmalloc_minimal_la_LDFLAGS) \
|
||||
@WITH_DEBUGALLOC_TRUE@ -version-info @TCMALLOC_SO_VERSION@
|
||||
|
||||
@WITH_DEBUGALLOC_TRUE@libtcmalloc_minimal_debug_la_LIBADD = $(libtcmalloc_minimal_la_LIBADD)
|
||||
@WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_SOURCES = $(tcmalloc_minimal_unittest_SOURCES)
|
||||
@WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_CXXFLAGS = $(tcmalloc_minimal_unittest_CXXFLAGS) \
|
||||
@ -2127,7 +2159,7 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
|
||||
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(PTHREAD_CFLAGS) -DNDEBUG \
|
||||
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) \
|
||||
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_32)
|
||||
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@
|
||||
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LIBADD = libtcmalloc_internal.la $(PTHREAD_LIBS)
|
||||
@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@HEAP_CHECKER_SOURCES =
|
||||
|
||||
@ -2241,7 +2273,9 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) \
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ -DTCMALLOC_FOR_DEBUGALLOCATION
|
||||
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_LDFLAGS = $(libtcmalloc_la_LDFLAGS)
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_LDFLAGS = $(libtcmalloc_la_LDFLAGS) \
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ -version-info @TCMALLOC_SO_VERSION@
|
||||
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_debug_la_LIBADD = $(libtcmalloc_la_LIBADD)
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_SOURCES = $(tcmalloc_unittest_SOURCES)
|
||||
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_CXXFLAGS = $(tcmalloc_unittest_CXXFLAGS) \
|
||||
@ -2302,7 +2336,9 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
|
||||
@WITH_CPU_PROFILER_TRUE@libprofiler_la_LIBADD = libstacktrace.la
|
||||
# We have to include ProfileData for profiledata_unittest
|
||||
@WITH_CPU_PROFILER_TRUE@CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStartWithOptions|ProfilerStop|ProfilerFlush|ProfilerEnable|ProfilerDisable|ProfilingIsEnabledForAllThreads|ProfilerRegisterThread|ProfilerGetCurrentState|ProfilerState|ProfileData|ProfileHandler)'
|
||||
@WITH_CPU_PROFILER_TRUE@libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS)
|
||||
@WITH_CPU_PROFILER_TRUE@libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS) \
|
||||
@WITH_CPU_PROFILER_TRUE@ -version-info @PROFILER_SO_VERSION@
|
||||
|
||||
|
||||
# See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this.
|
||||
# Basically it's to work around systems where --rpath doesn't work right.
|
||||
@ -2351,8 +2387,12 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
|
||||
@WITH_CPU_PROFILER_TRUE@profiler4_unittest_DEPENDENCIES = $(LIBPROFILER)
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_SOURCES = $(libtcmalloc_la_SOURCES) $(libprofiler_la_SOURCES)
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_CXXFLAGS = $(libtcmalloc_la_CXXFLAGS) $(libprofiler_la_CXXFLAGS)
|
||||
# Since this library is meant to be used as a .a, I don't worry as much
|
||||
# about .so versioning. I just give the libtcmalloc version number.
|
||||
# TODO(csilvers): use -export-symbols-regex?
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_LDFLAGS = $(PTHREAD_CFLAGS) \
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ -version-info @TCMALLOC_SO_VERSION@
|
||||
|
||||
# We don't include libprofiler_la_LIBADD here because all it adds is
|
||||
# libstacktrace.la, which we already get via libtcmalloc. Trying to
|
||||
# specify it twice causes link-time duplicate-definition errors. :-(
|
||||
@ -2361,6 +2401,14 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_CXXFLAGS = $(tcmalloc_both_unittest_CXXFLAGS)
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_LDFLAGS)
|
||||
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_LDADD = libtcmalloc_and_profiler.la
|
||||
|
||||
# http://linux.die.net/man/1/pkg-config, http://pkg-config.freedesktop.org/wiki
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libtcmalloc.pc libtcmalloc_minimal.pc \
|
||||
libtcmalloc_debug.pc libtcmalloc_minimal_debug.pc \
|
||||
libprofiler.pc
|
||||
|
||||
CLEANFILES = $(pkgconfig_DATA)
|
||||
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
|
||||
$(SCRIPTS) libtool \
|
||||
src/windows/get_mangled_names.cc src/windows/override_functions.cc \
|
||||
@ -2829,6 +2877,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sampling_debug_test-sampling_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)/spinlock_internal.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@
|
||||
@ -2958,6 +3007,13 @@ spinlock.lo: src/base/spinlock.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 spinlock.lo `test -f 'src/base/spinlock.cc' || echo '$(srcdir)/'`src/base/spinlock.cc
|
||||
|
||||
spinlock_internal.lo: src/base/spinlock_internal.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT spinlock_internal.lo -MD -MP -MF "$(DEPDIR)/spinlock_internal.Tpo" -c -o spinlock_internal.lo `test -f 'src/base/spinlock_internal.cc' || echo '$(srcdir)/'`src/base/spinlock_internal.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/spinlock_internal.Tpo" "$(DEPDIR)/spinlock_internal.Plo"; else rm -f "$(DEPDIR)/spinlock_internal.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/spinlock_internal.cc' object='spinlock_internal.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 spinlock_internal.lo `test -f 'src/base/spinlock_internal.cc' || echo '$(srcdir)/'`src/base/spinlock_internal.cc
|
||||
|
||||
atomicops-internals-x86.lo: src/base/atomicops-internals-x86.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT atomicops-internals-x86.lo -MD -MP -MF "$(DEPDIR)/atomicops-internals-x86.Tpo" -c -o atomicops-internals-x86.lo `test -f 'src/base/atomicops-internals-x86.cc' || echo '$(srcdir)/'`src/base/atomicops-internals-x86.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/atomicops-internals-x86.Tpo" "$(DEPDIR)/atomicops-internals-x86.Plo"; else rm -f "$(DEPDIR)/atomicops-internals-x86.Tpo"; exit 1; fi
|
||||
@ -4310,6 +4366,23 @@ uninstall-dist_docDATA:
|
||||
echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(docdir)/$$f"; \
|
||||
done
|
||||
install-pkgconfigDATA: $(pkgconfig_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(pkgconfigdir)" || $(mkdir_p) "$(DESTDIR)$(pkgconfigdir)"
|
||||
@list='$(pkgconfig_DATA)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(am__strip_dir) \
|
||||
echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
|
||||
$(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-pkgconfigDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(pkgconfig_DATA)'; for p in $$list; do \
|
||||
f=$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \
|
||||
done
|
||||
install-googleincludeHEADERS: $(googleinclude_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(googleincludedir)" || $(mkdir_p) "$(DESTDIR)$(googleincludedir)"
|
||||
@ -4606,7 +4679,7 @@ all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(MANS) $(DATA) \
|
||||
install-binPROGRAMS: install-libLTLIBRARIES
|
||||
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(googleincludedir)" "$(DESTDIR)$(googleincludedir)"; do \
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(googleincludedir)" "$(DESTDIR)$(googleincludedir)"; do \
|
||||
test -z "$$dir" || $(mkdir_p) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
@ -4626,6 +4699,7 @@ install-strip:
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
@ -4657,7 +4731,8 @@ info: info-am
|
||||
info-am:
|
||||
|
||||
install-data-am: install-dist_docDATA install-googleincludeHEADERS \
|
||||
install-man install-nodist_googleincludeHEADERS
|
||||
install-man install-nodist_googleincludeHEADERS \
|
||||
install-pkgconfigDATA
|
||||
|
||||
install-exec-am: install-binPROGRAMS install-binSCRIPTS \
|
||||
install-exec-local install-libLTLIBRARIES
|
||||
@ -4691,7 +4766,7 @@ ps-am:
|
||||
uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
|
||||
uninstall-dist_docDATA uninstall-googleincludeHEADERS \
|
||||
uninstall-info-am uninstall-libLTLIBRARIES uninstall-man \
|
||||
uninstall-nodist_googleincludeHEADERS
|
||||
uninstall-nodist_googleincludeHEADERS uninstall-pkgconfigDATA
|
||||
|
||||
uninstall-man: uninstall-man1
|
||||
|
||||
@ -4708,15 +4783,16 @@ uninstall-man: uninstall-man1
|
||||
install-exec-am install-exec-local \
|
||||
install-googleincludeHEADERS install-info install-info-am \
|
||||
install-libLTLIBRARIES install-man install-man1 \
|
||||
install-nodist_googleincludeHEADERS 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 \
|
||||
uninstall-nodist_googleincludeHEADERS
|
||||
install-nodist_googleincludeHEADERS install-pkgconfigDATA \
|
||||
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 uninstall-nodist_googleincludeHEADERS \
|
||||
uninstall-pkgconfigDATA
|
||||
|
||||
@ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@ # TODO(csilvers): check if -fomit-frame-pointer might be in $(CXXFLAGS),
|
||||
@ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@ # before setting this.
|
||||
@ -4778,6 +4854,38 @@ rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec
|
||||
deb: dist-gzip packages/deb.sh packages/deb/*
|
||||
@cd packages && ./deb.sh ${PACKAGE} ${VERSION}
|
||||
|
||||
# I get the description and URL lines from the rpm spec. I use sed to
|
||||
# try to rewrite exec_prefix, libdir, and includedir in terms of
|
||||
# prefix, if possible.
|
||||
libtcmalloc.pc: Makefile packages/rpm/rpm.spec
|
||||
echo 'prefix=$(prefix)' > "$@".tmp
|
||||
echo 'exec_prefix='`echo '$(exec_prefix)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp
|
||||
echo 'libdir='`echo '$(libdir)' | sed 's@^$(exec_prefix)@$${exec_prefix}@'` >> "$@".tmp
|
||||
echo 'includedir='`echo '$(includedir)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp
|
||||
echo '' >> "$@".tmp
|
||||
echo 'Name: $(PACKAGE)' >> "$@".tmp
|
||||
echo 'Version: $(VERSION)' >> "$@".tmp
|
||||
-grep '^Summary:' packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp
|
||||
-grep '^URL: ' packages/rpm/rpm.spec >> "$@".tmp
|
||||
echo 'Requires:' >> "$@".tmp
|
||||
echo 'Libs: -L$${libdir} -ltcmalloc' >> "$@".tmp
|
||||
echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp
|
||||
echo 'Cflags: -I$${includedir}' >> "$@".tmp
|
||||
mv -f "$@".tmp "$@"
|
||||
|
||||
# The other versions are mostly the same.
|
||||
libtcmalloc_minimal.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal/ > "$@"
|
||||
|
||||
libtcmalloc_debug.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_debug/ > "$@"
|
||||
|
||||
libtcmalloc_minimal_debug.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-ltcmalloc_minimal_debug/ > "$@"
|
||||
|
||||
libprofiler.pc: libtcmalloc.pc
|
||||
cat libtcmalloc.pc | sed s/-ltcmalloc/-lprofiler/ > "$@"
|
||||
|
||||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
|
6
NEWS
6
NEWS
@ -8,9 +8,9 @@ support for `malloc_usable_size()` as a glibc-compatible alias to
|
||||
experimental support for tcmalloc large pages, which may speed up
|
||||
tcmalloc at the cost of greater memory use. To use tcmalloc large
|
||||
pages, see the
|
||||
[http://google-perftools.googlecode.com/svn/tags/perftools-1.5/INSTALL
|
||||
[http://google-perftools.googlecode.com/svn/tags/perftools-1.6/INSTALL
|
||||
INSTALL file]; for all changes, see the
|
||||
[http://google-perftools.googlecode.com/svn/tags/perftools-1.5/ChangeLog
|
||||
[http://google-perftools.googlecode.com/svn/tags/perftools-1.6/ChangeLog
|
||||
ChangeLog].
|
||||
|
||||
OS X NOTE: improvements in the profiler unittest have turned up an OS
|
||||
@ -22,7 +22,7 @@ setitimer) in threaded programs, and has insight into this problem,
|
||||
please send mail to google-perftools@googlegroups.com.
|
||||
|
||||
To see if you're affected by this, look for profiling time that pprof
|
||||
attributes to ___semwait_signal. This is work being done in other
|
||||
attributes to `___semwait_signal`. This is work being done in other
|
||||
threads, that is being attributed to sleeping-time in the main thread.
|
||||
|
||||
|
||||
|
2
README
2
README
@ -37,7 +37,7 @@ As a quick-start, do the following after installing this package:
|
||||
|
||||
1) Link your executable with -ltcmalloc
|
||||
2) Run your executable with the HEAPPROFILE environment var set:
|
||||
$ HEAPROFILE=/tmp/heapprof <path/to/binary> [binary args]
|
||||
$ HEAPPROFILE=/tmp/heapprof <path/to/binary> [binary args]
|
||||
3) Run pprof to analyze the heap usage
|
||||
$ pprof <path/to/binary> /tmp/heapprof.0045.heap # run 'ls' to see options
|
||||
$ pprof --gv <path/to/binary> /tmp/heapprof.0045.heap
|
||||
|
6657
aclocal.m4
vendored
6657
aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
@ -5,9 +5,16 @@
|
||||
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_SUBST(TCMALLOC_SO_VERSION)
|
||||
AC_SUBST(PROFILER_SO_VERSION)
|
||||
|
||||
# The argument here is just something that should be in the current directory
|
||||
# (for sanity checking)
|
||||
AC_CONFIG_SRCDIR(README)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CANONICAL_HOST
|
||||
AM_INIT_AUTOMAKE([dist-zip])
|
||||
AM_CONFIG_HEADER(src/config.h)
|
||||
|
@ -58,13 +58,28 @@ get heap information. The actual url is controlled via the variable
|
||||
<code>HEAP_PAGE</code> in the <code>pprof</code> script, so you
|
||||
can change it if you'd like.</p>
|
||||
|
||||
<p>The server should respond by calling</p>
|
||||
<p>There are two ways to get this data. The first is to call</p>
|
||||
<pre>
|
||||
MallocExtension::instance()->GetHeapSample(&output);
|
||||
</pre>
|
||||
<p>and sending <code>output</code> back as an HTTP response to
|
||||
<code>pprof</code>. <code>MallocExtension</code> is defined in the
|
||||
header file <code>google/malloc_extension.h</code>.</p>
|
||||
<p>and have the server send <code>output</code> back as an HTTP
|
||||
response to <code>pprof</code>. <code>MallocExtension</code> is
|
||||
defined in the header file <code>google/malloc_extension.h</code>.</p>
|
||||
|
||||
<p>Note this will only only work if the binary is being run with
|
||||
sampling turned on (which is not the default). To do this, set the
|
||||
environment variable <code>TCMALLOC_SAMPLE_PARAMETER</code> to a
|
||||
positive value, such as 524288, before running.</p>
|
||||
|
||||
<p>The other way is to call <code>HeapProfileStart(filename)</code>
|
||||
(from <code>heap-profiler.h</code>), continue to do work, and then,
|
||||
some number of seconds later, call <code>GetHeapProfile()</code>
|
||||
(followed by <code>HeapProfilerStop()</code>). The server can send
|
||||
the output of <code>GetHeapProfile</code> back as the HTTP response to
|
||||
pprof. (Note you must <code>free()</code> this data after using it.)
|
||||
This is similar to how <A HREF="#profile">profile requests</A> are
|
||||
handled, below. This technique does not require the application to
|
||||
run with sampling turned on.</p>
|
||||
|
||||
<p>Here's an example of what the output should look like:</p>
|
||||
<pre>
|
||||
@ -84,7 +99,8 @@ heap profile: 14933: 791700132 [ 14933: 791700132] @ heap
|
||||
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>
|
||||
<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>
|
||||
|
||||
@ -111,7 +127,7 @@ heap profile: 741: 812122112 [ 741: 812122112] @ growth
|
||||
</pre>
|
||||
|
||||
|
||||
<h2> <code><b>/pprof/profile</b></code> </h2>
|
||||
<h2> <A NAME="profile"><code><b>/pprof/profile</b></code></A> </h2>
|
||||
|
||||
<p><code>pprof</code> asks for the url
|
||||
<code>/pprof/profile?seconds=XX</code> to get cpu-profiling
|
||||
@ -194,10 +210,21 @@ map from hex addresses to variable names. The actual url is
|
||||
controlled via the variable <code>SYMBOL_PAGE</code> in the
|
||||
<code>pprof</code> script, so you can change it if you'd like.</p>
|
||||
|
||||
<p>This is perhaps the hardest request to write code for, because
|
||||
it must accept POST requests. This means that after the HTTP headers,
|
||||
pprof will pass in a list of hex addresses connected by
|
||||
<code>+</code>, like so:</p>
|
||||
<p>When the server receives a GET request for
|
||||
<code>/pprof/symbol</code>, it should return a line formatted like
|
||||
so:</p>
|
||||
<pre>
|
||||
num_symbols: ###
|
||||
</pre>
|
||||
<p>where <code>###</code> is the number of symbols found in the
|
||||
binary. (For now, the only important distinction is whether the value
|
||||
is 0, which it is for executables that lack debug information, or
|
||||
not-0).</p>
|
||||
|
||||
<p>This is perhaps the hardest request to write code for, because in
|
||||
addition to the GET request for this url, the server must accept POST
|
||||
requests. This means that after the HTTP headers, pprof will pass in
|
||||
a list of hex addresses connected by <code>+</code>, like so:</p>
|
||||
<pre>
|
||||
curl -d '0x0824d061+0x0824d1cf' http://remote_host:80/pprof/symbol
|
||||
</pre>
|
||||
@ -216,10 +243,11 @@ stream, like so:</p>
|
||||
<p>The other reason this is the most difficult request to implement,
|
||||
is that the application will have to figure out for itself how to map
|
||||
from address to function name. One possibility is to run <code>nm -C
|
||||
-n <program name></code> to get the mappings, either statically
|
||||
(say at program-compile time), or dynamically, by having the
|
||||
application call out to <code>nm</code> for every
|
||||
<code>pprof/symbol</code> call (presumably with some caching!).</p>
|
||||
-n <program name></code> to get the mappings at
|
||||
program-compile-time. Another, at least on Linux, is to call out to
|
||||
addr2line for every <code>pprof/symbol</code> call, for instance
|
||||
<code>addr2line -Cfse /proc/<getpid>/exe 0x12345678 0x876543210</code>
|
||||
(presumably with some caching!)</p>
|
||||
|
||||
<p><code>pprof</code> itself does just this for local profiles (not
|
||||
ones that talk to remote servers); look at the subroutine
|
||||
|
7377
m4/libtool.m4
vendored
Normal file
7377
m4/libtool.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
368
m4/ltoptions.m4
vendored
Normal file
368
m4/ltoptions.m4
vendored
Normal file
@ -0,0 +1,368 @@
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltoptions.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
|
||||
|
||||
|
||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ------------------------------------------
|
||||
m4_define([_LT_MANGLE_OPTION],
|
||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ---------------------------------------
|
||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
|
||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
|
||||
# saved as a flag.
|
||||
m4_define([_LT_SET_OPTION],
|
||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
|
||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
[m4_warning([Unknown $1 option `$2'])])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
|
||||
# ------------------------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
m4_define([_LT_IF_OPTION],
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
|
||||
|
||||
|
||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
|
||||
# -------------------------------------------------------
|
||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
|
||||
# are set.
|
||||
m4_define([_LT_UNLESS_OPTIONS],
|
||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
|
||||
[m4_define([$0_found])])])[]dnl
|
||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
|
||||
])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
|
||||
# ----------------------------------------
|
||||
# OPTION-LIST is a space-separated list of Libtool options associated
|
||||
# with MACRO-NAME. If any OPTION has a matching handler declared with
|
||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
|
||||
# the unknown option and exit.
|
||||
m4_defun([_LT_SET_OPTIONS],
|
||||
[# Set options
|
||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[_LT_SET_OPTION([$1], _LT_Option)])
|
||||
|
||||
m4_if([$1],[LT_INIT],[
|
||||
dnl
|
||||
dnl Simply set some default values (i.e off) if boolean options were not
|
||||
dnl specified:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
|
||||
])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
|
||||
])
|
||||
dnl
|
||||
dnl If no reference was made to various pairs of opposing options, then
|
||||
dnl we run the default mode handler for the pair. For example, if neither
|
||||
dnl `shared' nor `disable-shared' was passed, we enable building of shared
|
||||
dnl archives by default:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
|
||||
[_LT_ENABLE_FAST_INSTALL])
|
||||
])
|
||||
])# _LT_SET_OPTIONS
|
||||
|
||||
|
||||
## --------------------------------- ##
|
||||
## Macros to handle LT_INIT options. ##
|
||||
## --------------------------------- ##
|
||||
|
||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
|
||||
# -----------------------------------------
|
||||
m4_define([_LT_MANGLE_DEFUN],
|
||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
|
||||
# -----------------------------------------------
|
||||
m4_define([LT_OPTION_DEFINE],
|
||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
|
||||
])# LT_OPTION_DEFINE
|
||||
|
||||
|
||||
# dlopen
|
||||
# ------
|
||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_DLOPEN],
|
||||
[_LT_SET_OPTION([LT_INIT], [dlopen])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the `dlopen' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
|
||||
|
||||
|
||||
# win32-dll
|
||||
# ---------
|
||||
# Declare package support for building win32 dll's.
|
||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
|
||||
[enable_win32_dll=yes
|
||||
|
||||
case $host in
|
||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
|
||||
AC_CHECK_TOOL(AS, as, false)
|
||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
||||
AC_CHECK_TOOL(OBJDUMP, objdump, false)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -z "$AS" && AS=as
|
||||
_LT_DECL([], [AS], [0], [Assembler program])dnl
|
||||
|
||||
test -z "$DLLTOOL" && DLLTOOL=dlltool
|
||||
_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
|
||||
|
||||
test -z "$OBJDUMP" && OBJDUMP=objdump
|
||||
_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
|
||||
])# win32-dll
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
|
||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
_LT_SET_OPTION([LT_INIT], [win32-dll])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the `win32-dll' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
|
||||
|
||||
|
||||
# _LT_ENABLE_SHARED([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-shared flag, and supports the `shared' and
|
||||
# `disable-shared' LT_INIT options.
|
||||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
|
||||
m4_define([_LT_ENABLE_SHARED],
|
||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([shared],
|
||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
|
||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_shared=yes ;;
|
||||
no) enable_shared=no ;;
|
||||
*)
|
||||
enable_shared=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
|
||||
for pkg in $enableval; do
|
||||
IFS="$lt_save_ifs"
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_shared=yes
|
||||
fi
|
||||
done
|
||||
IFS="$lt_save_ifs"
|
||||
;;
|
||||
esac],
|
||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
|
||||
|
||||
_LT_DECL([build_libtool_libs], [enable_shared], [0],
|
||||
[Whether or not to build shared libraries])
|
||||
])# _LT_ENABLE_SHARED
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-shared])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
|
||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_STATIC([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-static flag, and support the `static' and
|
||||
# `disable-static' LT_INIT options.
|
||||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
|
||||
m4_define([_LT_ENABLE_STATIC],
|
||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
|
||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_static=yes ;;
|
||||
no) enable_static=no ;;
|
||||
*)
|
||||
enable_static=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
|
||||
for pkg in $enableval; do
|
||||
IFS="$lt_save_ifs"
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_static=yes
|
||||
fi
|
||||
done
|
||||
IFS="$lt_save_ifs"
|
||||
;;
|
||||
esac],
|
||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
|
||||
|
||||
_LT_DECL([build_old_libs], [enable_static], [0],
|
||||
[Whether or not to build static libraries])
|
||||
])# _LT_ENABLE_STATIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-static])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
|
||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --enable-fast-install flag, and support the `fast-install'
|
||||
# and `disable-fast-install' LT_INIT options.
|
||||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
|
||||
m4_define([_LT_ENABLE_FAST_INSTALL],
|
||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([fast-install],
|
||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
|
||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_fast_install=yes ;;
|
||||
no) enable_fast_install=no ;;
|
||||
*)
|
||||
enable_fast_install=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
|
||||
for pkg in $enableval; do
|
||||
IFS="$lt_save_ifs"
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_fast_install=yes
|
||||
fi
|
||||
done
|
||||
IFS="$lt_save_ifs"
|
||||
;;
|
||||
esac],
|
||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
|
||||
|
||||
_LT_DECL([fast_install], [enable_fast_install], [0],
|
||||
[Whether or not to optimize for fast installation])dnl
|
||||
])# _LT_ENABLE_FAST_INSTALL
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
|
||||
|
||||
# Old names:
|
||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the `fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the `disable-fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
|
||||
|
||||
|
||||
# _LT_WITH_PIC([MODE])
|
||||
# --------------------
|
||||
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
|
||||
# LT_INIT options.
|
||||
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
|
||||
m4_define([_LT_WITH_PIC],
|
||||
[AC_ARG_WITH([pic],
|
||||
[AS_HELP_STRING([--with-pic],
|
||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
|
||||
[pic_mode="$withval"],
|
||||
[pic_mode=default])
|
||||
|
||||
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
|
||||
|
||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
|
||||
])# _LT_WITH_PIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
|
||||
|
||||
# Old name:
|
||||
AU_DEFUN([AC_LIBTOOL_PICMODE],
|
||||
[_LT_SET_OPTION([LT_INIT], [pic-only])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the `pic-only' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
|
||||
|
||||
## ----------------- ##
|
||||
## LTDL_INIT Options ##
|
||||
## ----------------- ##
|
||||
|
||||
m4_define([_LTDL_MODE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
|
||||
[m4_define([_LTDL_MODE], [nonrecursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
|
||||
[m4_define([_LTDL_MODE], [recursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
|
||||
[m4_define([_LTDL_MODE], [subproject])])
|
||||
|
||||
m4_define([_LTDL_TYPE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [installable],
|
||||
[m4_define([_LTDL_TYPE], [installable])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
|
||||
[m4_define([_LTDL_TYPE], [convenience])])
|
123
m4/ltsugar.m4
vendored
Normal file
123
m4/ltsugar.m4
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltsugar.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
|
||||
|
||||
|
||||
# lt_join(SEP, ARG1, [ARG2...])
|
||||
# -----------------------------
|
||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
|
||||
# associated separator.
|
||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
|
||||
# versions in m4sugar had bugs.
|
||||
m4_define([lt_join],
|
||||
[m4_if([$#], [1], [],
|
||||
[$#], [2], [[$2]],
|
||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
m4_define([_lt_join],
|
||||
[m4_if([$#$2], [2], [],
|
||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
|
||||
|
||||
# lt_car(LIST)
|
||||
# lt_cdr(LIST)
|
||||
# ------------
|
||||
# Manipulate m4 lists.
|
||||
# These macros are necessary as long as will still need to support
|
||||
# Autoconf-2.59 which quotes differently.
|
||||
m4_define([lt_car], [[$1]])
|
||||
m4_define([lt_cdr],
|
||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
|
||||
[$#], 1, [],
|
||||
[m4_dquote(m4_shift($@))])])
|
||||
m4_define([lt_unquote], $1)
|
||||
|
||||
|
||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
|
||||
# ------------------------------------------
|
||||
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
|
||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended
|
||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
|
||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
|
||||
# than defined and empty).
|
||||
#
|
||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier
|
||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
|
||||
m4_define([lt_append],
|
||||
[m4_define([$1],
|
||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
|
||||
|
||||
|
||||
|
||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
|
||||
# ----------------------------------------------------------
|
||||
# Produce a SEP delimited list of all paired combinations of elements of
|
||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
|
||||
# has the form PREFIXmINFIXSUFFIXn.
|
||||
# Needed until we can rely on m4_combine added in Autoconf 2.62.
|
||||
m4_define([lt_combine],
|
||||
[m4_if(m4_eval([$# > 3]), [1],
|
||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
|
||||
[[m4_foreach([_Lt_prefix], [$2],
|
||||
[m4_foreach([_Lt_suffix],
|
||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
|
||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
|
||||
|
||||
|
||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
|
||||
# -----------------------------------------------------------------------
|
||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
|
||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
|
||||
m4_define([lt_if_append_uniq],
|
||||
[m4_ifdef([$1],
|
||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
|
||||
[lt_append([$1], [$2], [$3])$4],
|
||||
[$5])],
|
||||
[lt_append([$1], [$2], [$3])$4])])
|
||||
|
||||
|
||||
# lt_dict_add(DICT, KEY, VALUE)
|
||||
# -----------------------------
|
||||
m4_define([lt_dict_add],
|
||||
[m4_define([$1($2)], [$3])])
|
||||
|
||||
|
||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
|
||||
# --------------------------------------------
|
||||
m4_define([lt_dict_add_subkey],
|
||||
[m4_define([$1($2:$3)], [$4])])
|
||||
|
||||
|
||||
# lt_dict_fetch(DICT, KEY, [SUBKEY])
|
||||
# ----------------------------------
|
||||
m4_define([lt_dict_fetch],
|
||||
[m4_ifval([$3],
|
||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
|
||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
|
||||
|
||||
|
||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
|
||||
# -----------------------------------------------------------------
|
||||
m4_define([lt_if_dict_fetch],
|
||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
|
||||
[$5],
|
||||
[$6])])
|
||||
|
||||
|
||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
|
||||
# --------------------------------------------------------------
|
||||
m4_define([lt_dict_filter],
|
||||
[m4_if([$5], [], [],
|
||||
[lt_join(m4_quote(m4_default([$4], [[, ]])),
|
||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
|
||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
|
||||
])
|
23
m4/ltversion.m4
vendored
Normal file
23
m4/ltversion.m4
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# Generated from ltversion.in.
|
||||
|
||||
# serial 3017 ltversion.m4
|
||||
# This file is part of GNU Libtool
|
||||
|
||||
m4_define([LT_PACKAGE_VERSION], [2.2.6b])
|
||||
m4_define([LT_PACKAGE_REVISION], [1.3017])
|
||||
|
||||
AC_DEFUN([LTVERSION_VERSION],
|
||||
[macro_version='2.2.6b'
|
||||
macro_revision='1.3017'
|
||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
||||
_LT_DECL(, macro_revision, 0)
|
||||
])
|
92
m4/lt~obsolete.m4
vendored
Normal file
92
m4/lt~obsolete.m4
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4 lt~obsolete.m4
|
||||
|
||||
# These exist entirely to fool aclocal when bootstrapping libtool.
|
||||
#
|
||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
|
||||
# which have later been changed to m4_define as they aren't part of the
|
||||
# exported API, or moved to Autoconf or Automake where they belong.
|
||||
#
|
||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
||||
# using a macro with the same name in our local m4/libtool.m4 it'll
|
||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
||||
# and doesn't know about Autoconf macros at all.)
|
||||
#
|
||||
# So we provide this file, which has a silly filename so it's always
|
||||
# included after everything else. This provides aclocal with the
|
||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
||||
# because those macros already exist, or will be overwritten later.
|
||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
||||
#
|
||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
||||
# Yes, that means every name once taken will need to remain here until
|
||||
# we give up compatibility with versions before 1.7, at which point
|
||||
# we need to keep only those names which we still refer to.
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
||||
|
||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
||||
m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
@ -1,3 +1,4 @@
|
||||
usr/lib
|
||||
usr/lib/pkgconfig
|
||||
usr/include
|
||||
usr/include/google
|
||||
|
@ -2,7 +2,9 @@ usr/include/google/*
|
||||
usr/lib/lib*.so
|
||||
usr/lib/lib*.a
|
||||
usr/lib/*.la
|
||||
usr/lib/pkgconfig/*.pc
|
||||
debian/tmp/usr/include/google/*
|
||||
debian/tmp/usr/lib/lib*.so
|
||||
debian/tmp/usr/lib/lib*.a
|
||||
debian/tmp/usr/lib/*.la
|
||||
debian/tmp/usr/lib/pkgconfig/*.pc
|
||||
|
@ -73,3 +73,4 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{_libdir}/*.a
|
||||
%{_libdir}/*.la
|
||||
%{_libdir}/*.so
|
||||
%{_libdir}/pkgconfig/*.pc
|
||||
|
234
src/base/atomicops-internals-arm-gcc.h
Normal file
234
src/base/atomicops-internals-arm-gcc.h
Normal file
@ -0,0 +1,234 @@
|
||||
/* Copyright (c) 2010, 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: Lei Zhang, Sasha Levitskiy
|
||||
*/
|
||||
|
||||
// This file is an internal atomic implementation, use base/atomicops.h instead.
|
||||
//
|
||||
// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "base/basictypes.h" // For COMPILE_ASSERT
|
||||
|
||||
typedef int32_t Atomic32;
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
typedef int64_t Atomic64;
|
||||
|
||||
// 0xffff0fc0 is the hard coded address of a function provided by
|
||||
// the kernel which implements an atomic compare-exchange. On older
|
||||
// ARM architecture revisions (pre-v6) this may be implemented using
|
||||
// a syscall. This address is stable, and in active use (hard coded)
|
||||
// by at least glibc-2.7 and the Android C library.
|
||||
// pLinuxKernelCmpxchg has both acquire and release barrier sematincs.
|
||||
typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
|
||||
Atomic32 new_value,
|
||||
volatile Atomic32* ptr);
|
||||
LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
|
||||
(LinuxKernelCmpxchgFunc) 0xffff0fc0;
|
||||
|
||||
typedef void (*LinuxKernelMemoryBarrierFunc)(void);
|
||||
LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
|
||||
(LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
|
||||
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value = *ptr;
|
||||
do {
|
||||
if (!pLinuxKernelCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr))) {
|
||||
return old_value;
|
||||
}
|
||||
prev_value = *ptr;
|
||||
} while (prev_value == old_value);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
do {
|
||||
old_value = *ptr;
|
||||
} while (pLinuxKernelCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr)));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
for (;;) {
|
||||
// Atomic exchange the old value with an incremented one.
|
||||
Atomic32 old_value = *ptr;
|
||||
Atomic32 new_value = old_value + increment;
|
||||
if (pLinuxKernelCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr)) == 0) {
|
||||
// The exchange took place as expected.
|
||||
return new_value;
|
||||
}
|
||||
// Otherwise, *ptr changed mid-loop and we need to retry.
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
pLinuxKernelMemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
|
||||
// 64-bit versions are not implemented yet.
|
||||
|
||||
inline void NotImplementedFatalError(const char *function_name) {
|
||||
fprintf(stderr, "64-bit %s() not implemented on this platform\n",
|
||||
function_name);
|
||||
abort();
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
NotImplementedFatalError("NoBarrier_CompareAndSwap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
NotImplementedFatalError("NoBarrier_AtomicExchange");
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
NotImplementedFatalError("NoBarrier_AtomicIncrement");
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
NotImplementedFatalError("Barrier_AtomicIncrement");
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
NotImplementedFatalError("NoBarrier_Store");
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
NoBarrier_AtomicExchange(ptr, value);
|
||||
// acts as a barrier in this implementation
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
NotImplementedFatalError("Release_Store");
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
NotImplementedFatalError("NoBarrier_Load");
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value = NoBarrier_Load(ptr);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return NoBarrier_Load(ptr);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
@ -109,7 +109,7 @@ const int64 kint64min = ( ((( int64) kint32min) << 32) | 0 );
|
||||
// Also allow for printing of a pthread_t.
|
||||
#define GPRIuPTHREAD "lu"
|
||||
#define GPRIxPTHREAD "lx"
|
||||
#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__APPLE__)
|
||||
#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast<uintptr_t>(pthreadt)
|
||||
#else
|
||||
#define PRINTABLE_PTHREAD(pthreadt) pthreadt
|
||||
|
@ -370,6 +370,41 @@
|
||||
|
||||
#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
|
||||
|
||||
/* Macro definitions for GCC attributes that allow static thread safety
|
||||
analysis to recognize and use some of the dynamic annotations as
|
||||
escape hatches.
|
||||
TODO(lcwu): remove the check for __SUPPORT_DYN_ANNOTATION__ once the
|
||||
default crosstool/GCC supports these GCC attributes. */
|
||||
|
||||
#define ANNOTALYSIS_STATIC_INLINE
|
||||
#define ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY ;
|
||||
|
||||
#if defined(__GNUC__) && defined(__SUPPORT_TS_ANNOTATION__) \
|
||||
&& (!defined(SWIG)) && defined(__SUPPORT_DYN_ANNOTATION__)
|
||||
|
||||
#if DYNAMIC_ANNOTATIONS_ENABLED == 0
|
||||
#define ANNOTALYSIS_ONLY 1
|
||||
#undef ANNOTALYSIS_STATIC_INLINE
|
||||
#define ANNOTALYSIS_STATIC_INLINE static inline
|
||||
#undef ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY
|
||||
#define ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY {}
|
||||
#endif
|
||||
#define ANNOTALYSIS_IGNORE_READS_BEGIN __attribute__ ((ignore_reads_begin))
|
||||
#define ANNOTALYSIS_IGNORE_READS_END __attribute__ ((ignore_reads_end))
|
||||
#define ANNOTALYSIS_IGNORE_WRITES_BEGIN __attribute__ ((ignore_writes_begin))
|
||||
#define ANNOTALYSIS_IGNORE_WRITES_END __attribute__ ((ignore_writes_end))
|
||||
#define ANNOTALYSIS_UNPROTECTED_READ __attribute__ ((unprotected_read))
|
||||
|
||||
#else
|
||||
|
||||
#define ANNOTALYSIS_IGNORE_READS_BEGIN
|
||||
#define ANNOTALYSIS_IGNORE_READS_END
|
||||
#define ANNOTALYSIS_IGNORE_WRITES_BEGIN
|
||||
#define ANNOTALYSIS_IGNORE_WRITES_END
|
||||
#define ANNOTALYSIS_UNPROTECTED_READ
|
||||
|
||||
#endif
|
||||
|
||||
/* Use the macros above rather than using these functions directly. */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -431,10 +466,18 @@ void AnnotateTraceMemory(const char *file, int line,
|
||||
const volatile void *arg);
|
||||
void AnnotateThreadName(const char *file, int line,
|
||||
const char *name);
|
||||
void AnnotateIgnoreReadsBegin(const char *file, int line);
|
||||
void AnnotateIgnoreReadsEnd(const char *file, int line);
|
||||
void AnnotateIgnoreWritesBegin(const char *file, int line);
|
||||
void AnnotateIgnoreWritesEnd(const char *file, int line);
|
||||
ANNOTALYSIS_STATIC_INLINE
|
||||
void AnnotateIgnoreReadsBegin(const char *file, int line)
|
||||
ANNOTALYSIS_IGNORE_READS_BEGIN ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY
|
||||
ANNOTALYSIS_STATIC_INLINE
|
||||
void AnnotateIgnoreReadsEnd(const char *file, int line)
|
||||
ANNOTALYSIS_IGNORE_READS_END ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY
|
||||
ANNOTALYSIS_STATIC_INLINE
|
||||
void AnnotateIgnoreWritesBegin(const char *file, int line)
|
||||
ANNOTALYSIS_IGNORE_WRITES_BEGIN ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY
|
||||
ANNOTALYSIS_STATIC_INLINE
|
||||
void AnnotateIgnoreWritesEnd(const char *file, int line)
|
||||
ANNOTALYSIS_IGNORE_WRITES_END ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY
|
||||
void AnnotateEnableRaceDetection(const char *file, int line, int enable);
|
||||
void AnnotateNoOp(const char *file, int line,
|
||||
const volatile void *arg);
|
||||
@ -485,7 +528,8 @@ double ValgrindSlowdown(void);
|
||||
one can use
|
||||
... = ANNOTATE_UNPROTECTED_READ(x); */
|
||||
template <class T>
|
||||
inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) {
|
||||
inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x)
|
||||
ANNOTALYSIS_UNPROTECTED_READ {
|
||||
ANNOTATE_IGNORE_READS_BEGIN();
|
||||
T res = x;
|
||||
ANNOTATE_IGNORE_READS_END();
|
||||
@ -511,4 +555,67 @@ double ValgrindSlowdown(void);
|
||||
|
||||
#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
|
||||
|
||||
/* Annotalysis, a GCC based static analyzer, is able to understand and use
|
||||
some of the dynamic annotations defined in this file. However, dynamic
|
||||
annotations are usually disabled in the opt mode (to avoid additional
|
||||
runtime overheads) while Annotalysis only works in the opt mode.
|
||||
In order for Annotalysis to use these dynamic annotations when they
|
||||
are disabled, we re-define these annotations here. Note that unlike the
|
||||
original macro definitions above, these macros are expanded to calls to
|
||||
static inline functions so that the compiler will be able to remove the
|
||||
calls after the analysis. */
|
||||
|
||||
#ifdef ANNOTALYSIS_ONLY
|
||||
|
||||
#undef ANNOTALYSIS_ONLY
|
||||
|
||||
/* Undefine and re-define the macros that the static analyzer understands. */
|
||||
#undef ANNOTATE_IGNORE_READS_BEGIN
|
||||
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
||||
AnnotateIgnoreReadsBegin(__FILE__, __LINE__)
|
||||
|
||||
#undef ANNOTATE_IGNORE_READS_END
|
||||
#define ANNOTATE_IGNORE_READS_END() \
|
||||
AnnotateIgnoreReadsEnd(__FILE__, __LINE__)
|
||||
|
||||
#undef ANNOTATE_IGNORE_WRITES_BEGIN
|
||||
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||
AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
||||
|
||||
#undef ANNOTATE_IGNORE_WRITES_END
|
||||
#define ANNOTATE_IGNORE_WRITES_END() \
|
||||
AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
||||
|
||||
#undef ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
|
||||
do { \
|
||||
ANNOTATE_IGNORE_READS_BEGIN(); \
|
||||
ANNOTATE_IGNORE_WRITES_BEGIN(); \
|
||||
}while(0) \
|
||||
|
||||
#undef ANNOTATE_IGNORE_READS_AND_WRITES_END
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
|
||||
do { \
|
||||
ANNOTATE_IGNORE_WRITES_END(); \
|
||||
ANNOTATE_IGNORE_READS_END(); \
|
||||
}while(0) \
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#undef ANNOTATE_UNPROTECTED_READ
|
||||
template <class T>
|
||||
inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x)
|
||||
__attribute__ ((unprotected_read)) {
|
||||
ANNOTATE_IGNORE_READS_BEGIN();
|
||||
T res = x;
|
||||
ANNOTATE_IGNORE_READS_END();
|
||||
return res;
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ANNOTALYSIS_ONLY */
|
||||
|
||||
/* Undefine the macros intended only in this file. */
|
||||
#undef ANNOTALYSIS_STATIC_INLINE
|
||||
#undef ANNOTALYSIS_SEMICOLON_OR_EMPTY_BODY
|
||||
|
||||
#endif /* BASE_DYNAMIC_ANNOTATIONS_H_ */
|
||||
|
@ -49,10 +49,13 @@
|
||||
|
||||
// On some systems (like freebsd), we can't call write() at all in a
|
||||
// global constructor, perhaps because errno hasn't been set up.
|
||||
// (In windows, we can't call it because it might call malloc.)
|
||||
// Calling the write syscall is safer (it doesn't set errno), so we
|
||||
// prefer that. Note we don't care about errno for logging: we just
|
||||
// do logging on a best-effort basis.
|
||||
#ifdef HAVE_SYS_SYSCALL_H
|
||||
#if defined(_MSC_VER)
|
||||
#define WRITE_TO_STDERR(buf, len) WriteToStderr(buf, len); // in port.cc
|
||||
#elif defined(HAVE_SYS_SYSCALL_H)
|
||||
#include <sys/syscall.h>
|
||||
#define WRITE_TO_STDERR(buf, len) syscall(SYS_write, STDERR_FILENO, buf, len)
|
||||
#else
|
||||
|
@ -59,7 +59,9 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
static const int kMaxLevel = 30;
|
||||
|
||||
namespace {
|
||||
// We put this class-only struct in a namespace to avoid polluting the
|
||||
// global namespace with this struct name (thus risking an ODR violation).
|
||||
namespace low_level_alloc_internal {
|
||||
// This struct describes one allocated block, or one free block.
|
||||
struct AllocList {
|
||||
struct Header {
|
||||
@ -79,6 +81,8 @@ namespace {
|
||||
// LLA_SkiplistLevels()
|
||||
};
|
||||
}
|
||||
using low_level_alloc_internal::AllocList;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// A trivial skiplist implementation. This is used to keep the freelist
|
||||
|
@ -32,47 +32,28 @@
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <time.h> /* For nanosleep() */
|
||||
#ifdef HAVE_SCHED_H
|
||||
#include <sched.h> /* For sched_yield() */
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* For read() */
|
||||
#endif
|
||||
#include <fcntl.h> /* for open(), O_RDONLY */
|
||||
#include <string.h> /* for strncmp */
|
||||
#include <errno.h>
|
||||
#include "base/spinlock.h"
|
||||
#include "base/synchronization_profiling.h"
|
||||
#include "base/spinlock_internal.h"
|
||||
#include "base/cycleclock.h"
|
||||
#include "base/sysinfo.h" /* for NumCPUs() */
|
||||
|
||||
// We can do contention-profiling of SpinLocks, but the code is in
|
||||
// mutex.cc, which is not always linked in with spinlock. Hence we
|
||||
// provide this weak definition, which is used if mutex.cc isn't linked in.
|
||||
ATTRIBUTE_WEAK extern void SubmitSpinLockProfileData(const void *, int64);
|
||||
void SubmitSpinLockProfileData(const void *, int64) {}
|
||||
// NOTE on the Lock-state values:
|
||||
//
|
||||
// kSpinLockFree represents the unlocked state
|
||||
// kSpinLockHeld represents the locked state with no waiters
|
||||
//
|
||||
// Values greater than kSpinLockHeld represent the locked state with waiters,
|
||||
// where the value is the time the current lock holder had to
|
||||
// wait before obtaining the lock. The kSpinLockSleeper state is a special
|
||||
// "locked with waiters" state that indicates that a sleeper needs to
|
||||
// be woken, but the thread that just released the lock didn't wait.
|
||||
|
||||
static int adaptive_spin_count = 0;
|
||||
|
||||
const base::LinkerInitialized SpinLock::LINKER_INITIALIZED =
|
||||
base::LINKER_INITIALIZED;
|
||||
|
||||
// The OS-specific header included below must provide two calls:
|
||||
// Wait until *w becomes zero, atomically set it to 1 and return.
|
||||
// static void SpinLockWait(volatile Atomic32 *w);
|
||||
//
|
||||
// Hint that a thread waiting in SpinLockWait() could now make progress. May
|
||||
// do nothing. This call may not read or write *w; it must use only the
|
||||
// address.
|
||||
// static void SpinLockWake(volatile Atomic32 *w);
|
||||
#if defined(_WIN32)
|
||||
#include "base/spinlock_win32-inl.h"
|
||||
#elif defined(__linux__)
|
||||
#include "base/spinlock_linux-inl.h"
|
||||
#else
|
||||
#include "base/spinlock_posix-inl.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
struct SpinLock_InitHelper {
|
||||
SpinLock_InitHelper() {
|
||||
@ -91,36 +72,111 @@ static SpinLock_InitHelper init_helper;
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
// Monitor the lock to see if its value changes within some time period
|
||||
// (adaptive_spin_count loop iterations). A timestamp indicating
|
||||
// when the thread initially started waiting for the lock is passed in via
|
||||
// the initial_wait_timestamp value. The total wait time in cycles for the
|
||||
// lock is returned in the wait_cycles parameter. The last value read
|
||||
// from the lock is returned from the method.
|
||||
Atomic32 SpinLock::SpinLoop(int64 initial_wait_timestamp,
|
||||
Atomic32* wait_cycles) {
|
||||
int c = adaptive_spin_count;
|
||||
while (base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree && --c > 0) {
|
||||
}
|
||||
Atomic32 spin_loop_wait_cycles = CalculateWaitCycles(initial_wait_timestamp);
|
||||
Atomic32 lock_value =
|
||||
base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
|
||||
spin_loop_wait_cycles);
|
||||
*wait_cycles = spin_loop_wait_cycles;
|
||||
return lock_value;
|
||||
}
|
||||
|
||||
void SpinLock::SlowLock() {
|
||||
int c = adaptive_spin_count;
|
||||
// The lock was not obtained initially, so this thread needs to wait for
|
||||
// it. Record the current timestamp in the local variable wait_start_time
|
||||
// so the total wait time can be stored in the lockword once this thread
|
||||
// obtains the lock.
|
||||
int64 wait_start_time = CycleClock::Now();
|
||||
Atomic32 wait_cycles;
|
||||
Atomic32 lock_value = SpinLoop(wait_start_time, &wait_cycles);
|
||||
|
||||
// Spin a few times in the hope that the lock holder releases the lock
|
||||
while ((c > 0) && (lockword_ != 0)) {
|
||||
c--;
|
||||
int lock_wait_call_count = 0;
|
||||
while (lock_value != kSpinLockFree) {
|
||||
// If the lock is currently held, but not marked as having a sleeper, mark
|
||||
// it as having a sleeper.
|
||||
if (lock_value == kSpinLockHeld) {
|
||||
// Here, just "mark" that the thread is going to sleep. Don't store the
|
||||
// lock wait time in the lock as that will cause the current lock
|
||||
// owner to think it experienced contention.
|
||||
lock_value = base::subtle::Acquire_CompareAndSwap(&lockword_,
|
||||
kSpinLockHeld,
|
||||
kSpinLockSleeper);
|
||||
if (lock_value == kSpinLockHeld) {
|
||||
// Successfully transitioned to kSpinLockSleeper. Pass
|
||||
// kSpinLockSleeper to the SpinLockWait routine to properly indicate
|
||||
// the last lock_value observed.
|
||||
lock_value = kSpinLockSleeper;
|
||||
} else if (lock_value == kSpinLockFree) {
|
||||
// Lock is free again, so try and aquire it before sleeping. The
|
||||
// new lock state will be the number of cycles this thread waited if
|
||||
// this thread obtains the lock.
|
||||
lock_value = base::subtle::Acquire_CompareAndSwap(&lockword_,
|
||||
kSpinLockFree,
|
||||
wait_cycles);
|
||||
continue; // skip the delay at the end of the loop
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for an OS specific delay.
|
||||
base::internal::SpinLockDelay(&lockword_, lock_value,
|
||||
++lock_wait_call_count);
|
||||
// Spin again after returning from the wait routine to give this thread
|
||||
// some chance of obtaining the lock.
|
||||
lock_value = SpinLoop(wait_start_time, &wait_cycles);
|
||||
}
|
||||
|
||||
if (lockword_ == 1) {
|
||||
int32 now = (CycleClock::Now() >> PROFILE_TIMESTAMP_SHIFT);
|
||||
// Don't loose the lock: make absolutely sure "now" is not zero
|
||||
now |= 1;
|
||||
// Atomically replace the value of lockword_ with "now" if
|
||||
// lockword_ is 1, thereby remembering the first timestamp to
|
||||
// be recorded.
|
||||
base::subtle::NoBarrier_CompareAndSwap(&lockword_, 1, now);
|
||||
// base::subtle::NoBarrier_CompareAndSwap() returns:
|
||||
// 0: the lock is/was available; nothing stored
|
||||
// 1: our timestamp was stored
|
||||
// > 1: an older timestamp is already in lockword_; nothing stored
|
||||
}
|
||||
|
||||
SpinLockWait(&lockword_); // wait until lock acquired; OS specific
|
||||
}
|
||||
|
||||
void SpinLock::SlowUnlock(int64 wait_timestamp) {
|
||||
SpinLockWake(&lockword_); // wake waiter if necessary; OS specific
|
||||
// The wait time for contentionz lock profiling must fit into 32 bits.
|
||||
// However, the lower 32-bits of the cycle counter wrap around too quickly
|
||||
// with high frequency processors, so a right-shift by 7 is performed to
|
||||
// quickly divide the cycles by 128. Using these 32 bits, reduces the
|
||||
// granularity of time measurement to 128 cycles, and loses track
|
||||
// of wait time for waits greater than 109 seconds on a 5 GHz machine
|
||||
// [(2^32 cycles/5 Ghz)*128 = 109.95 seconds]. Waits this long should be
|
||||
// very rare and the reduced granularity should not be an issue given
|
||||
// processors in the Google fleet operate at a minimum of one billion
|
||||
// cycles/sec.
|
||||
enum { PROFILE_TIMESTAMP_SHIFT = 7 };
|
||||
|
||||
// Collect contentionz profile info. Subtract one from wait_timestamp as
|
||||
// antidote to "now |= 1;" in SlowLock().
|
||||
SubmitSpinLockProfileData(this, wait_timestamp - 1);
|
||||
void SpinLock::SlowUnlock(uint64 wait_cycles) {
|
||||
base::internal::SpinLockWake(&lockword_, false); // wake waiter if necessary
|
||||
|
||||
// Collect contentionz profile info, expanding the wait_cycles back out to
|
||||
// the full value. If wait_cycles is <= kSpinLockSleeper, then no wait
|
||||
// was actually performed, so don't record the wait time. Note, that the
|
||||
// CalculateWaitCycles method adds in kSpinLockSleeper cycles
|
||||
// unconditionally to guarantee the wait time is not kSpinLockFree or
|
||||
// kSpinLockHeld. The adding in of these small number of cycles may
|
||||
// overestimate the contention by a slight amount 50% of the time. However,
|
||||
// if this code tried to correct for that addition by subtracting out the
|
||||
// kSpinLockSleeper amount that would underestimate the contention slightly
|
||||
// 50% of the time. Both ways get the wrong answer, so the code
|
||||
// overestimates to be more conservative. Overestimating also makes the code
|
||||
// a little simpler.
|
||||
//
|
||||
if (wait_cycles > kSpinLockSleeper) {
|
||||
base::SubmitSpinLockProfileData(this,
|
||||
wait_cycles << PROFILE_TIMESTAMP_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
inline int32 SpinLock::CalculateWaitCycles(int64 wait_start_time) {
|
||||
int32 wait_cycles = ((CycleClock::Now() - wait_start_time) >>
|
||||
PROFILE_TIMESTAMP_SHIFT);
|
||||
// The number of cycles waiting for the lock is used as both the
|
||||
// wait_cycles and lock value, so it can't be kSpinLockFree or
|
||||
// kSpinLockHeld. Make sure the value returned is at least
|
||||
// kSpinLockSleeper.
|
||||
wait_cycles |= kSpinLockSleeper;
|
||||
return wait_cycles;
|
||||
}
|
||||
|
@ -44,14 +44,14 @@
|
||||
#define BASE_SPINLOCK_H_
|
||||
|
||||
#include <config.h>
|
||||
#include "base/basictypes.h"
|
||||
#include "base/atomicops.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/dynamic_annotations.h"
|
||||
#include "base/thread_annotations.h"
|
||||
|
||||
class LOCKABLE SpinLock {
|
||||
public:
|
||||
SpinLock() : lockword_(0) { }
|
||||
SpinLock() : lockword_(kSpinLockFree) { }
|
||||
|
||||
// Special constructor for use with static SpinLock objects. E.g.,
|
||||
//
|
||||
@ -70,18 +70,21 @@ class LOCKABLE SpinLock {
|
||||
// TODO(csilvers): uncomment the annotation when we figure out how to
|
||||
// support this macro with 0 args (see thread_annotations.h)
|
||||
inline void Lock() /*EXCLUSIVE_LOCK_FUNCTION()*/ {
|
||||
if (Acquire_CompareAndSwap(&lockword_, 0, 1) != 0) {
|
||||
if (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
|
||||
kSpinLockHeld) != kSpinLockFree) {
|
||||
SlowLock();
|
||||
}
|
||||
ANNOTATE_RWLOCK_ACQUIRED(this, 1);
|
||||
}
|
||||
|
||||
// Acquire this SpinLock and return true if the acquisition can be
|
||||
// done without blocking, else return false. If this SpinLock is
|
||||
// free at the time of the call, TryLock will return true with high
|
||||
// probability.
|
||||
// Try to acquire this SpinLock without blocking and return true if the
|
||||
// acquisition was successful. If the lock was not acquired, false is
|
||||
// returned. If this SpinLock is free at the time of the call, TryLock
|
||||
// will return true with high probability.
|
||||
inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
|
||||
bool res = (Acquire_CompareAndSwap(&lockword_, 0, 1) == 0);
|
||||
bool res =
|
||||
(base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree,
|
||||
kSpinLockHeld) == kSpinLockFree);
|
||||
if (res) {
|
||||
ANNOTATE_RWLOCK_ACQUIRED(this, 1);
|
||||
}
|
||||
@ -92,47 +95,37 @@ class LOCKABLE SpinLock {
|
||||
// TODO(csilvers): uncomment the annotation when we figure out how to
|
||||
// support this macro with 0 args (see thread_annotations.h)
|
||||
inline void Unlock() /*UNLOCK_FUNCTION()*/ {
|
||||
// This is defined in mutex.cc.
|
||||
extern void SubmitSpinLockProfileData(const void *, int64);
|
||||
|
||||
int64 wait_timestamp = static_cast<uint32>(lockword_);
|
||||
uint64 wait_cycles =
|
||||
static_cast<uint64>(base::subtle::NoBarrier_Load(&lockword_));
|
||||
ANNOTATE_RWLOCK_RELEASED(this, 1);
|
||||
Release_Store(&lockword_, 0);
|
||||
if (wait_timestamp != 1) {
|
||||
base::subtle::Release_Store(&lockword_, kSpinLockFree);
|
||||
if (wait_cycles != kSpinLockHeld) {
|
||||
// Collect contentionz profile info, and speed the wakeup of any waiter.
|
||||
// The lockword_ value indicates when the waiter started waiting.
|
||||
SlowUnlock(wait_timestamp);
|
||||
// The wait_cycles value indicates how long this thread spent waiting
|
||||
// for the lock.
|
||||
SlowUnlock(wait_cycles);
|
||||
}
|
||||
}
|
||||
|
||||
// Report if we think the lock can be held by this thread.
|
||||
// When the lock is truly held by the invoking thread
|
||||
// we will always return true.
|
||||
// Indended to be used as CHECK(lock.IsHeld());
|
||||
// Determine if the lock is held. When the lock is held by the invoking
|
||||
// thread, true will always be returned. Intended to be used as
|
||||
// CHECK(lock.IsHeld()).
|
||||
inline bool IsHeld() const {
|
||||
return lockword_ != 0;
|
||||
return base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree;
|
||||
}
|
||||
|
||||
// The timestamp for contention lock profiling must fit into 31 bits.
|
||||
// as lockword_ is 32 bits and we loose an additional low-order bit due
|
||||
// to the statement "now |= 1" in SlowLock().
|
||||
// To select 31 bits from the 64-bit cycle counter, we shift right by
|
||||
// PROFILE_TIMESTAMP_SHIFT = 7.
|
||||
// Using these 31 bits, we reduce granularity of time measurement to
|
||||
// 256 cycles, and will loose track of wait time for waits greater than
|
||||
// 109 seconds on a 5 GHz machine, longer for faster clock cycles.
|
||||
// Waits this long should be very rare.
|
||||
enum { PROFILE_TIMESTAMP_SHIFT = 7 };
|
||||
|
||||
static const base::LinkerInitialized LINKER_INITIALIZED; // backwards compat
|
||||
private:
|
||||
// Lock-state: 0 means unlocked; 1 means locked with no waiters; values
|
||||
// greater than 1 indicate locked with waiters, where the value is the time
|
||||
// the first waiter started waiting and is used for contention profiling.
|
||||
enum { kSpinLockFree = 0 };
|
||||
enum { kSpinLockHeld = 1 };
|
||||
enum { kSpinLockSleeper = 2 };
|
||||
|
||||
volatile Atomic32 lockword_;
|
||||
|
||||
void SlowLock();
|
||||
void SlowUnlock(int64 wait_timestamp);
|
||||
void SlowUnlock(uint64 wait_cycles);
|
||||
Atomic32 SpinLoop(int64 initial_wait_timestamp, Atomic32* wait_cycles);
|
||||
inline int32 CalculateWaitCycles(int64 wait_start_time);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SpinLock);
|
||||
};
|
||||
|
77
src/base/spinlock_internal.cc
Normal file
77
src/base/spinlock_internal.cc
Normal file
@ -0,0 +1,77 @@
|
||||
/* Copyright (c) 2010, 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.
|
||||
*/
|
||||
|
||||
// The OS-specific header included below must provide two calls:
|
||||
// base::internal::SpinLockDelay() and base::internal::SpinLockWake().
|
||||
// See spinlock_internal.h for the spec of SpinLockWake().
|
||||
|
||||
// void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop)
|
||||
// SpinLockDelay() generates an apprproate spin delay on iteration "loop" of a
|
||||
// spin loop on location *w, whose previously observed value was "value".
|
||||
// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
|
||||
// or may wait for a delay that can be truncated by a call to SpinlockWake(w).
|
||||
// In all cases, it must return in bounded time even if SpinlockWake() is not
|
||||
// called.
|
||||
|
||||
#include "base/spinlock_internal.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "base/spinlock_win32-inl.h"
|
||||
#elif defined(__linux__)
|
||||
#include "base/spinlock_linux-inl.h"
|
||||
#else
|
||||
#include "base/spinlock_posix-inl.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// See spinlock_internal.h for spec.
|
||||
int32 SpinLockWait(volatile Atomic32 *w, int n,
|
||||
const SpinLockWaitTransition trans[]) {
|
||||
int32 v;
|
||||
bool done = false;
|
||||
for (int loop = 0; !done; loop++) {
|
||||
v = base::subtle::Acquire_Load(w);
|
||||
int i;
|
||||
for (i = 0; i != n && v != trans[i].from; i++) {
|
||||
}
|
||||
if (i == n) {
|
||||
SpinLockDelay(w, v, loop); // no matching transition
|
||||
} else if (trans[i].to == v || // null transition
|
||||
base::subtle::Acquire_CompareAndSwap(w, v, trans[i].to) == v) {
|
||||
done = trans[i].done;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
64
src/base/spinlock_internal.h
Normal file
64
src/base/spinlock_internal.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* Copyright (c) 2010, 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.
|
||||
*
|
||||
* ---
|
||||
* This file is an internal part spinlock.cc and once.cc
|
||||
* It may not be used directly by code outside of //base.
|
||||
*/
|
||||
|
||||
#ifndef BASE_SPINLOCK_INTERNAL_H_
|
||||
#define BASE_SPINLOCK_INTERNAL_H_
|
||||
|
||||
#include <config.h>
|
||||
#include "base/basictypes.h"
|
||||
#include "base/atomicops.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// SpinLockWait() waits until it can perform one of several transitions from
|
||||
// "from" to "to". It returns when it performs a transition where done==true.
|
||||
struct SpinLockWaitTransition {
|
||||
int32 from;
|
||||
int32 to;
|
||||
bool done;
|
||||
};
|
||||
|
||||
// Wait until *w can transition from trans[i].from to trans[i].to for some i
|
||||
// satisfying 0<=i<n && trans[i].done, atomically make the transition,
|
||||
// then return the old value of *w. Make any other atomic tranistions
|
||||
// where !trans[i].done, but continue waiting.
|
||||
int32 SpinLockWait(volatile Atomic32 *w, int n,
|
||||
const SpinLockWaitTransition trans[]);
|
||||
void SpinLockWake(volatile Atomic32 *w, bool all);
|
||||
void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
#endif
|
@ -28,11 +28,12 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* This file is a Linux-specific part of spinlock.cc
|
||||
* This file is a Linux-specific part of spinlock_internal.cc
|
||||
*/
|
||||
|
||||
#include <sched.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include "base/linux_syscall_support.h"
|
||||
|
||||
#define FUTEX_WAIT 0
|
||||
@ -48,7 +49,7 @@ static struct InitModule {
|
||||
int x = 0;
|
||||
// futexes are ints, so we can use them only when
|
||||
// that's the same size as the lockword_ in SpinLock.
|
||||
have_futex = (sizeof (Atomic32) == sizeof (int) &&
|
||||
have_futex = (sizeof (Atomic32) == sizeof (int) &&
|
||||
sys_futex(&x, FUTEX_WAKE, 1, 0) >= 0);
|
||||
if (have_futex &&
|
||||
sys_futex(&x, FUTEX_WAKE | futex_private_flag, 1, 0) < 0) {
|
||||
@ -56,36 +57,41 @@ static struct InitModule {
|
||||
}
|
||||
}
|
||||
} init_module;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
static void SpinLockWait(volatile Atomic32 *w) {
|
||||
int save_errno = errno;
|
||||
struct timespec tm;
|
||||
tm.tv_sec = 0;
|
||||
if (have_futex) {
|
||||
int value;
|
||||
tm.tv_nsec = 1000000; // 1ms; really we're trying to sleep for one kernel
|
||||
// clock tick
|
||||
while ((value = base::subtle::Acquire_CompareAndSwap(w, 0, 1)) != 0) {
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) {
|
||||
if (loop != 0) {
|
||||
int save_errno = errno;
|
||||
struct timespec tm;
|
||||
tm.tv_sec = 0;
|
||||
if (have_futex) {
|
||||
tm.tv_nsec = 1000000; // 1ms; really we're trying to sleep for one
|
||||
// kernel clock tick
|
||||
} else {
|
||||
tm.tv_nsec = 2000001; // above 2ms so linux 2.4 doesn't spin
|
||||
}
|
||||
if (have_futex) {
|
||||
sys_futex(reinterpret_cast<int *>(const_cast<Atomic32 *>(w)),
|
||||
FUTEX_WAIT | futex_private_flag,
|
||||
value, reinterpret_cast<struct kernel_timespec *>(&tm));
|
||||
}
|
||||
} else {
|
||||
tm.tv_nsec = 2000001; // above 2ms so linux 2.4 doesn't spin
|
||||
if (base::subtle::NoBarrier_Load(w) != 0) {
|
||||
sched_yield();
|
||||
}
|
||||
while (base::subtle::Acquire_CompareAndSwap(w, 0, 1) != 0) {
|
||||
FUTEX_WAIT | futex_private_flag,
|
||||
value, reinterpret_cast<struct kernel_timespec *>(&tm));
|
||||
} else {
|
||||
nanosleep(&tm, NULL);
|
||||
}
|
||||
errno = save_errno;
|
||||
}
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
static void SpinLockWake(volatile Atomic32 *w) {
|
||||
void SpinLockWake(volatile Atomic32 *w, bool all) {
|
||||
if (have_futex) {
|
||||
sys_futex(reinterpret_cast<int *>(const_cast<Atomic32 *>(w)),
|
||||
FUTEX_WAKE | futex_private_flag, 1, 0);
|
||||
FUTEX_WAKE | futex_private_flag, all? INT_MAX : 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
@ -28,25 +28,35 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* This file is a Posix-specific part of spinlock.cc
|
||||
* This file is a Posix-specific part of spinlock_internal.cc
|
||||
*/
|
||||
|
||||
#include <sched.h>
|
||||
#include <time.h>
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_SCHED_H
|
||||
#include <sched.h> /* For sched_yield() */
|
||||
#endif
|
||||
#include <time.h> /* For nanosleep() */
|
||||
|
||||
static void SpinLockWait(volatile Atomic32 *w) {
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) {
|
||||
int save_errno = errno;
|
||||
struct timespec tm;
|
||||
tm.tv_sec = 0;
|
||||
tm.tv_nsec = 1000000;
|
||||
if (base::subtle::NoBarrier_Load(w) != 0) {
|
||||
if (loop == 0) {
|
||||
} else if (loop == 1) {
|
||||
sched_yield();
|
||||
}
|
||||
while (base::subtle::Acquire_CompareAndSwap(w, 0, 1) != 0) {
|
||||
} else {
|
||||
struct timespec tm;
|
||||
tm.tv_sec = 0;
|
||||
tm.tv_nsec = 1000000;
|
||||
nanosleep(&tm, NULL);
|
||||
}
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
static void SpinLockWake(volatile Atomic32 *w) {
|
||||
void SpinLockWake(volatile Atomic32 *w, bool all) {
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
@ -28,20 +28,26 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* This file is a Win32-specific part of spinlock.cc
|
||||
* This file is a Win32-specific part of spinlock_internal.cc
|
||||
*/
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static void SpinLockWait(volatile Atomic32 *w) {
|
||||
if (base::subtle::NoBarrier_Load(w) != 0) {
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) {
|
||||
if (loop == 0) {
|
||||
} else if (loop == 1) {
|
||||
Sleep(0);
|
||||
}
|
||||
while (base::subtle::Acquire_CompareAndSwap(w, 0, 1) != 0) {
|
||||
} else {
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void SpinLockWake(volatile Atomic32 *w) {
|
||||
void SpinLockWake(volatile Atomic32 *w, bool all) {
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
50
src/base/synchronization_profiling.h
Normal file
50
src/base/synchronization_profiling.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* Copyright (c) 2010, 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: Chris Ruemmler
|
||||
*/
|
||||
|
||||
#ifndef BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_
|
||||
#define BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// We can do contention-profiling of SpinLocks, but the code is in
|
||||
// mutex.cc, which is not always linked in with spinlock. Hence we
|
||||
// provide a weak definition, which are used if mutex.cc isn't linked in.
|
||||
|
||||
// Submit the number of cycles the spinlock spent contending.
|
||||
ATTRIBUTE_WEAK extern void SubmitSpinLockProfileData(const void *, int64);
|
||||
extern void SubmitSpinLockProfileData(const void *contendedlock,
|
||||
int64 wait_cycles) {}
|
||||
}
|
||||
#endif // BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_
|
@ -111,20 +111,23 @@
|
||||
// 8K), so it's not an ideal solution.
|
||||
const char* GetenvBeforeMain(const char* name) {
|
||||
#if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h
|
||||
const int namelen = strlen(name);
|
||||
for (char** p = __environ; *p; p++) {
|
||||
if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match
|
||||
return *p + namelen+1; // point after =
|
||||
if (__environ) { // can exist but be NULL, if statically linked
|
||||
const int namelen = strlen(name);
|
||||
for (char** p = __environ; *p; p++) {
|
||||
if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match
|
||||
return *p + namelen+1; // point after =
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
#elif defined(PLATFORM_WINDOWS)
|
||||
#endif
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
// TODO(mbelshe) - repeated calls to this function will overwrite the
|
||||
// contents of the static buffer.
|
||||
static char envbuf[1024]; // enough to hold any envvar we care about
|
||||
if (!GetEnvironmentVariableA(name, envbuf, sizeof(envbuf)-1))
|
||||
static char envvar_buf[1024]; // enough to hold any envvar we care about
|
||||
if (!GetEnvironmentVariableA(name, envvar_buf, sizeof(envvar_buf)-1))
|
||||
return NULL;
|
||||
return envbuf;
|
||||
#else
|
||||
return envvar_buf;
|
||||
#endif
|
||||
// static is ok because this function should only be called before
|
||||
// main(), when we're single-threaded.
|
||||
static char envbuf[16<<10];
|
||||
@ -152,7 +155,6 @@ const char* GetenvBeforeMain(const char* name) {
|
||||
p = endp + 1;
|
||||
}
|
||||
return NULL; // env var never found
|
||||
#endif
|
||||
}
|
||||
|
||||
// This takes as an argument an environment-variable name (like
|
||||
@ -229,6 +231,26 @@ static int64 EstimateCyclesPerSecond(const int estimate_time_ms) {
|
||||
return guess;
|
||||
}
|
||||
|
||||
// Helper function for reading an int from a file. Returns true if successful
|
||||
// and the memory location pointed to by value is set to the value read.
|
||||
static bool ReadIntFromFile(const char *file, int *value) {
|
||||
bool ret = false;
|
||||
int fd = open(file, O_RDONLY);
|
||||
if (fd != -1) {
|
||||
char line[1024];
|
||||
char* err;
|
||||
memset(line, '\0', sizeof(line));
|
||||
read(fd, line, sizeof(line) - 1);
|
||||
const int temp_value = strtol(line, &err, 10);
|
||||
if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
|
||||
*value = temp_value;
|
||||
ret = true;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// WARNING: logging calls back to InitializeSystemInfo() so it must
|
||||
// not invoke any logging code. Also, InitializeSystemInfo() can be
|
||||
// called before main() -- in fact it *must* be since already_called
|
||||
@ -254,26 +276,31 @@ static void InitializeSystemInfo() {
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
|
||||
char line[1024];
|
||||
char* err;
|
||||
int freq;
|
||||
|
||||
// If the kernel is exporting the tsc frequency use that. There are issues
|
||||
// where cpuinfo_max_freq cannot be relied on because the BIOS may be
|
||||
// exporintg an invalid p-state (on x86) or p-states may be used to put the
|
||||
// processor in a new mode (turbo mode). Essentially, those frequencies
|
||||
// cannot always be relied upon. The same reasons apply to /proc/cpuinfo as
|
||||
// well.
|
||||
if (!saw_mhz &&
|
||||
ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) {
|
||||
// The value is in kHz (as the file name suggests). For example, on a
|
||||
// 2GHz warpstation, the file contains the value "2000000".
|
||||
cpuinfo_cycles_per_second = freq * 1000.0;
|
||||
saw_mhz = true;
|
||||
}
|
||||
|
||||
// If CPU scaling is in effect, we want to use the *maximum* frequency,
|
||||
// not whatever CPU speed some random processor happens to be using now.
|
||||
if (!saw_mhz) {
|
||||
const char* pname0 =
|
||||
"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
|
||||
int fd0 = open(pname0, O_RDONLY);
|
||||
if (fd0 != -1) {
|
||||
memset(line, '\0', sizeof(line));
|
||||
read(fd0, line, sizeof(line));
|
||||
const int max_freq = strtol(line, &err, 10);
|
||||
if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
|
||||
// The value is in kHz. For example, on a 2GHz machine, the file
|
||||
// contains the value "2000000". Historically this file contained no
|
||||
// newline, but at some point the kernel started appending a newline.
|
||||
cpuinfo_cycles_per_second = max_freq * 1000.0;
|
||||
saw_mhz = true;
|
||||
}
|
||||
close(fd0);
|
||||
}
|
||||
if (!saw_mhz &&
|
||||
ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
|
||||
&freq)) {
|
||||
// The value is in kHz. For example, on a 2GHz machine, the file
|
||||
// contains the value "2000000".
|
||||
cpuinfo_cycles_per_second = freq * 1000.0;
|
||||
saw_mhz = true;
|
||||
}
|
||||
|
||||
// Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq.
|
||||
@ -311,20 +338,20 @@ static void InitializeSystemInfo() {
|
||||
if (newline != NULL)
|
||||
*newline = '\0';
|
||||
|
||||
if (!saw_mhz && strncmp(line, "cpu MHz", sizeof("cpu MHz")-1) == 0) {
|
||||
if (!saw_mhz && strncasecmp(line, "cpu MHz", sizeof("cpu MHz")-1) == 0) {
|
||||
const char* freqstr = strchr(line, ':');
|
||||
if (freqstr) {
|
||||
cpuinfo_cycles_per_second = strtod(freqstr+1, &err) * 1000000.0;
|
||||
if (freqstr[1] != '\0' && *err == '\0')
|
||||
saw_mhz = true;
|
||||
}
|
||||
} else if (strncmp(line, "bogomips", sizeof("bogomips")-1) == 0) {
|
||||
} else if (strncasecmp(line, "bogomips", sizeof("bogomips")-1) == 0) {
|
||||
const char* freqstr = strchr(line, ':');
|
||||
if (freqstr)
|
||||
bogo_clock = strtod(freqstr+1, &err) * 1000000.0;
|
||||
if (freqstr == NULL || freqstr[1] == '\0' || *err != '\0')
|
||||
bogo_clock = 1.0;
|
||||
} else if (strncmp(line, "processor", sizeof("processor")-1) == 0) {
|
||||
} else if (strncasecmp(line, "processor", sizeof("processor")-1) == 0) {
|
||||
num_cpus++; // count up every time we see an "processor :" entry
|
||||
}
|
||||
} while (chars_read > 0);
|
||||
@ -888,9 +915,10 @@ namespace tcmalloc {
|
||||
|
||||
// Helper to add the list of mapped shared libraries to a profile.
|
||||
// Fill formatted "/proc/self/maps" contents into buffer 'buf' of size 'size'
|
||||
// and return the actual size occupied in 'buf'.
|
||||
// and return the actual size occupied in 'buf'. We fill wrote_all to true
|
||||
// if we successfully wrote all proc lines to buf, false else.
|
||||
// We do not provision for 0-terminating 'buf'.
|
||||
int FillProcSelfMaps(char buf[], int size) {
|
||||
int FillProcSelfMaps(char buf[], int size, bool* wrote_all) {
|
||||
ProcMapsIterator::Buffer iterbuf;
|
||||
ProcMapsIterator it(0, &iterbuf); // 0 means "current pid"
|
||||
|
||||
@ -898,10 +926,17 @@ int FillProcSelfMaps(char buf[], int size) {
|
||||
int64 inode;
|
||||
char *flags, *filename;
|
||||
int bytes_written = 0;
|
||||
*wrote_all = true;
|
||||
while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) {
|
||||
bytes_written += it.FormatLine(buf + bytes_written, size - bytes_written,
|
||||
start, end, flags, offset, inode, filename,
|
||||
0);
|
||||
const int line_length = it.FormatLine(buf + bytes_written,
|
||||
size - bytes_written,
|
||||
start, end, flags, offset,
|
||||
inode, filename, 0);
|
||||
if (line_length == 0)
|
||||
*wrote_all = false; // failed to write this line out
|
||||
else
|
||||
bytes_written += line_length;
|
||||
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ class ProcMapsIterator {
|
||||
// Helper routines
|
||||
|
||||
namespace tcmalloc {
|
||||
int FillProcSelfMaps(char buf[], int size);
|
||||
int FillProcSelfMaps(char buf[], int size, bool* wrote_all);
|
||||
void DumpProcSelfMaps(RawFD fd);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,9 @@
|
||||
#define BASE_THREAD_ANNOTATIONS_H_
|
||||
|
||||
|
||||
#if defined(__GNUC__) && defined(__SUPPORT_TS_ANNOTATION__) && (!defined(SWIG))
|
||||
#if defined(__GNUC__) \
|
||||
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) \
|
||||
&& defined(__SUPPORT_TS_ANNOTATION__) && (!defined(SWIG))
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
|
@ -395,7 +395,7 @@ const void *VDSOSupport::Init() {
|
||||
}
|
||||
// Subtle: this code runs outside of any locks; prevent compiler
|
||||
// from assigning to getcpu_fn_ more than once.
|
||||
MemoryBarrier();
|
||||
base::subtle::MemoryBarrier();
|
||||
getcpu_fn_ = fn;
|
||||
return vdso_base_;
|
||||
}
|
||||
|
13
src/common.h
13
src/common.h
@ -77,6 +77,8 @@ static const size_t kPageSize = 1 << kPageShift;
|
||||
static const size_t kMaxSize = 8u * kPageSize;
|
||||
static const size_t kAlignment = 8;
|
||||
static const size_t kLargeSizeClass = 0;
|
||||
// For all span-lengths < kMaxPages we keep an exact-size list.
|
||||
static const size_t kMaxPages = 1 << (20 - kPageShift);
|
||||
|
||||
// Default bound on the total amount of thread caches.
|
||||
static const size_t kDefaultOverallThreadCacheSize = 8u * kMaxThreadCacheSize;
|
||||
@ -102,6 +104,17 @@ static const int kMaxDynamicFreeListLength = 8192;
|
||||
|
||||
static const Length kMaxValidPages = (~static_cast<Length>(0)) >> kPageShift;
|
||||
|
||||
#ifdef __x86_64__
|
||||
// All current and planned x86_64 processors only look at the lower 48 bits
|
||||
// in virtual to physical address translation. The top 16 are thus unused.
|
||||
// TODO(rus): Under what operating systems can we increase it safely to 17?
|
||||
// This lets us use smaller page maps. On first allocation, a 36-bit page map
|
||||
// uses only 96 KB instead of the 4.5 MB used by a 52-bit page map.
|
||||
static const int kAddressBits = 48;
|
||||
#else
|
||||
static const int kAddressBits = 8 * sizeof(void*);
|
||||
#endif
|
||||
|
||||
namespace tcmalloc {
|
||||
|
||||
// Convert byte size into pages. This won't overflow, but may return
|
||||
|
@ -119,6 +119,9 @@
|
||||
/* Define to 1 if the system has the type `struct mallinfo'. */
|
||||
#undef HAVE_STRUCT_MALLINFO
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
||||
#undef HAVE_SYS_PRCTL_H
|
||||
|
||||
@ -173,6 +176,10 @@
|
||||
/* Define to 1 if int32_t is equivalent to intptr_t */
|
||||
#undef INT32_EQUALS_INTPTR
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#undef NO_MINUS_C_MINUS_O
|
||||
|
||||
|
@ -497,7 +497,7 @@ class MallocBlock {
|
||||
// practical effect is that allocations are limited to 4Gb or so, even if
|
||||
// the address space could take more.
|
||||
static size_t max_size_t = ~0;
|
||||
if (size < 0 || size > max_size_t - sizeof(MallocBlock)) {
|
||||
if (size > max_size_t - sizeof(MallocBlock)) {
|
||||
RAW_LOG(ERROR, "Massive size passed to malloc: %"PRIuS"", size);
|
||||
return NULL;
|
||||
}
|
||||
@ -1356,6 +1356,20 @@ class DebugMallocImplementation : public ParentImplementation {
|
||||
virtual size_t GetEstimatedAllocatedSize(size_t size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
virtual void GetFreeListSizes(vector<MallocExtension::FreeListInfo>* v) {
|
||||
static const char* kDebugFreeQueue = "debug.free_queue";
|
||||
|
||||
ParentImplementation::GetFreeListSizes(v);
|
||||
|
||||
MallocExtension::FreeListInfo i;
|
||||
i.type = kDebugFreeQueue;
|
||||
i.min_object_size = 0;
|
||||
i.max_object_size = numeric_limits<size_t>::max();
|
||||
i.total_bytes_free = MallocBlock::FreeQueueSize();
|
||||
v->push_back(i);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static DebugMallocImplementation debug_malloc_implementation;
|
||||
|
@ -136,7 +136,7 @@ class PERFTOOLS_DLL_DECL HeapLeakChecker {
|
||||
bool NoLeaks() { return DoNoLeaks(DO_NOT_SYMBOLIZE); }
|
||||
|
||||
// These forms are obsolete; use NoLeaks() instead.
|
||||
// TODO(csilvers): mark with ATTRIBUTE_DEPRECATED.
|
||||
// TODO(csilvers): mark as DEPRECATED.
|
||||
bool QuickNoLeaks() { return NoLeaks(); }
|
||||
bool BriefNoLeaks() { return NoLeaks(); }
|
||||
bool SameHeap() { return NoLeaks(); }
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Annoying stuff for windows -- makes sure clients can import these functions
|
||||
#ifndef PERFTOOLS_DLL_DECL
|
||||
@ -102,12 +103,17 @@ class PERFTOOLS_DLL_DECL MallocExtension {
|
||||
// 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".
|
||||
// NOTE: by default, tcmalloc does not do any heap sampling, and this
|
||||
// function will always return an empty sample. To get useful
|
||||
// data from GetHeapSample, you must also set the environment
|
||||
// variable TCMALLOC_SAMPLE_PARAMETER to a value such as 524288.
|
||||
virtual void GetHeapSample(MallocExtensionWriter* writer);
|
||||
|
||||
// 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".
|
||||
// be passed to "pprof". (This does not depend on, or require,
|
||||
// TCMALLOC_SAMPLE_PARAMETER.)
|
||||
virtual void GetHeapGrowthStacks(MallocExtensionWriter* writer);
|
||||
|
||||
// Invokes func(arg, range) for every controlled memory
|
||||
@ -244,6 +250,45 @@ class PERFTOOLS_DLL_DECL MallocExtension {
|
||||
// malloc implementation during initialization.
|
||||
static void Register(MallocExtension* implementation);
|
||||
|
||||
// Returns detailed information about malloc's freelists. For each list,
|
||||
// return a FreeListInfo:
|
||||
struct FreeListInfo {
|
||||
size_t min_object_size;
|
||||
size_t max_object_size;
|
||||
size_t total_bytes_free;
|
||||
const char* type;
|
||||
};
|
||||
// Each item in the vector refers to a different freelist. The lists
|
||||
// are identified by the range of allocations that objects in the
|
||||
// list can satisfy ([min_object_size, max_object_size]) and the
|
||||
// type of freelist (see below). The current size of the list is
|
||||
// returned in total_bytes_free (which count against a processes
|
||||
// resident and virtual size).
|
||||
//
|
||||
// Currently supported types are:
|
||||
//
|
||||
// "tcmalloc.page{_unmapped}" - tcmalloc's page heap. An entry for each size
|
||||
// class in the page heap is returned. Bytes in "page_unmapped"
|
||||
// are no longer backed by physical memory and do not count against
|
||||
// the resident size of a process.
|
||||
//
|
||||
// "tcmalloc.large{_unmapped}" - tcmalloc's list of objects larger
|
||||
// than the largest page heap size class. Only one "large"
|
||||
// entry is returned. There is no upper-bound on the size
|
||||
// of objects in the large free list; this call returns
|
||||
// kint64max for max_object_size. Bytes in
|
||||
// "large_unmapped" are no longer backed by physical memory
|
||||
// and do not count against the resident size of a process.
|
||||
//
|
||||
// "tcmalloc.central" - tcmalloc's central free-list. One entry per
|
||||
// size-class is returned. Never unmapped.
|
||||
//
|
||||
// "debug.free_queue" - free objects queued by the debug allocator
|
||||
// and not returned to tcmalloc.
|
||||
//
|
||||
// "tcmalloc.thread" - tcmalloc's per-thread caches. Never unmapped.
|
||||
virtual void GetFreeListSizes(std::vector<FreeListInfo>* v);
|
||||
|
||||
protected:
|
||||
// Get a list of stack traces of sampled allocation points. Returns
|
||||
// a pointer to a "new[]-ed" result array, and stores the sample
|
||||
|
@ -342,7 +342,8 @@ int HeapProfileTable::FillOrderedProfile(char buf[], int size) const {
|
||||
// any gaps. Whew!
|
||||
int map_length = snprintf(buf, size, "%s", kProcSelfMapsHeader);
|
||||
if (map_length < 0 || map_length >= size) return 0;
|
||||
map_length += FillProcSelfMaps(buf + map_length, size - map_length);
|
||||
bool dummy; // "wrote_all" -- did /proc/self/maps fit in its entirety?
|
||||
map_length += FillProcSelfMaps(buf + map_length, size - map_length, &dummy);
|
||||
RAW_DCHECK(map_length <= size, "");
|
||||
char* const map_start = buf + size - map_length; // move to end
|
||||
memmove(map_start, buf, map_length);
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "maybe_threads.h"
|
||||
|
||||
using STL_NAMESPACE::string;
|
||||
using STL_NAMESPACE::vector;
|
||||
|
||||
static void DumpAddressMap(string* result) {
|
||||
*result += "\nMAPPED_LIBRARIES:\n";
|
||||
@ -59,9 +60,11 @@ static void DumpAddressMap(string* result) {
|
||||
const size_t old_resultlen = result->size();
|
||||
for (int amap_size = 10240; amap_size < 10000000; amap_size *= 2) {
|
||||
result->resize(old_resultlen + amap_size);
|
||||
bool wrote_all = false;
|
||||
const int bytes_written =
|
||||
tcmalloc::FillProcSelfMaps(&((*result)[old_resultlen]), amap_size);
|
||||
if (bytes_written < amap_size - 1) { // we fit!
|
||||
tcmalloc::FillProcSelfMaps(&((*result)[old_resultlen]), amap_size,
|
||||
&wrote_all);
|
||||
if (wrote_all) { // we fit!
|
||||
(*result)[old_resultlen + bytes_written] = '\0';
|
||||
result->resize(old_resultlen + bytes_written);
|
||||
return;
|
||||
@ -167,6 +170,11 @@ size_t MallocExtension::GetAllocatedSize(void* p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MallocExtension::GetFreeListSizes(
|
||||
vector<MallocExtension::FreeListInfo>* v) {
|
||||
v->clear();
|
||||
}
|
||||
|
||||
// The current malloc extension object.
|
||||
|
||||
static pthread_once_t module_init = PTHREAD_ONCE_INIT;
|
||||
|
@ -117,7 +117,6 @@
|
||||
|
||||
#include "memory_region_map.h"
|
||||
|
||||
#include "base/linux_syscall_support.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/low_level_alloc.h"
|
||||
#include "malloc_hook-inl.h"
|
||||
|
@ -338,6 +338,35 @@ static double PagesToMB(uint64_t pages) {
|
||||
return (pages << kPageShift) / 1048576.0;
|
||||
}
|
||||
|
||||
void PageHeap::GetClassSizes(int64 class_sizes_normal[kMaxPages],
|
||||
int64 class_sizes_returned[kMaxPages],
|
||||
int64* normal_pages_in_spans,
|
||||
int64* returned_pages_in_spans) {
|
||||
|
||||
for (int s = 0; s < kMaxPages; s++) {
|
||||
if (class_sizes_normal != NULL) {
|
||||
class_sizes_normal[s] = DLL_Length(&free_[s].normal);
|
||||
}
|
||||
if (class_sizes_returned != NULL) {
|
||||
class_sizes_returned[s] = DLL_Length(&free_[s].returned);
|
||||
}
|
||||
}
|
||||
|
||||
if (normal_pages_in_spans != NULL) {
|
||||
*normal_pages_in_spans = 0;
|
||||
for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) {
|
||||
*normal_pages_in_spans += s->length;;
|
||||
}
|
||||
}
|
||||
|
||||
if (returned_pages_in_spans != NULL) {
|
||||
*returned_pages_in_spans = 0;
|
||||
for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) {
|
||||
*returned_pages_in_spans += s->length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PageHeap::Dump(TCMalloc_Printer* out) {
|
||||
int nonempty_sizes = 0;
|
||||
for (int s = 0; s < kMaxPages; s++) {
|
||||
|
@ -140,6 +140,10 @@ class PERFTOOLS_DLL_DECL PageHeap {
|
||||
uint64_t unmapped_bytes; // Total bytes on returned freelists
|
||||
};
|
||||
inline Stats stats() const { return stats_; }
|
||||
void GetClassSizes(int64 class_sizes_normal[kMaxPages],
|
||||
int64 class_sizes_returned[kMaxPages],
|
||||
int64* normal_pages_in_spans,
|
||||
int64* returned_pages_in_spans);
|
||||
|
||||
bool Check();
|
||||
// Like Check() but does some more comprehensive checking.
|
||||
@ -176,11 +180,8 @@ class PERFTOOLS_DLL_DECL PageHeap {
|
||||
// should keep this value big because various incarnations of Linux
|
||||
// have small limits on the number of mmap() regions per
|
||||
// address-space.
|
||||
static const int kMinSystemAlloc = 1 << (20 - kPageShift);
|
||||
|
||||
// For all span-lengths < kMaxPages we keep an exact-size list.
|
||||
// REQUIRED: kMaxPages >= kMinSystemAlloc;
|
||||
static const size_t kMaxPages = kMinSystemAlloc;
|
||||
// REQUIRED: kMinSystemAlloc <= kMaxPages;
|
||||
static const int kMinSystemAlloc = kMaxPages;
|
||||
|
||||
// Never delay scavenging for more than the following number of
|
||||
// deallocated pages. With 4K pages, this comes to 4GB of
|
||||
@ -192,8 +193,8 @@ class PERFTOOLS_DLL_DECL PageHeap {
|
||||
static const int kDefaultReleaseDelay = 1 << 18;
|
||||
|
||||
// Pick the appropriate map and cache types based on pointer size
|
||||
typedef MapSelector<8*sizeof(uintptr_t)>::Type PageMap;
|
||||
typedef MapSelector<8*sizeof(uintptr_t)>::CacheType PageMapCache;
|
||||
typedef MapSelector<kAddressBits>::Type PageMap;
|
||||
typedef MapSelector<kAddressBits>::CacheType PageMapCache;
|
||||
PageMap pagemap_;
|
||||
mutable PageMapCache pagemap_cache_;
|
||||
|
||||
|
83
src/pprof
83
src/pprof
@ -89,6 +89,7 @@ my %obj_tool_map = (
|
||||
);
|
||||
my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local
|
||||
my $GV = "gv";
|
||||
my $EVINCE = "evince"; # could also be xpdf or perhaps acroread
|
||||
my $KCACHEGRIND = "kcachegrind";
|
||||
my $PS2PDF = "ps2pdf";
|
||||
# These are used for dynamic profiles
|
||||
@ -103,6 +104,7 @@ my $GROWTH_PAGE = "/pprof/growth";
|
||||
my $CONTENTION_PAGE = "/pprof/contention";
|
||||
my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter
|
||||
my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
|
||||
my $CENSUSPROFILE_PAGE = "/pprof/censusprofile"; # must support "?seconds=#"
|
||||
my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST
|
||||
my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
|
||||
|
||||
@ -110,7 +112,7 @@ my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
|
||||
# All the alternatives must begin with /.
|
||||
my $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" .
|
||||
"$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" .
|
||||
"$FILTEREDPROFILE_PAGE)";
|
||||
"$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)";
|
||||
|
||||
# default binary name
|
||||
my $UNKNOWN_BINARY = "(unknown)";
|
||||
@ -148,7 +150,7 @@ pprof [options] <profile>
|
||||
|
||||
The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
|
||||
$GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
|
||||
or /pprof/filteredprofile.
|
||||
$CENSUSPROFILE_PAGE, or /pprof/filteredprofile.
|
||||
For instance: "pprof http://myserver.com:80$HEAP_PAGE".
|
||||
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
|
||||
pprof --symbols <program>
|
||||
@ -180,6 +182,7 @@ Output type:
|
||||
--text Generate text report
|
||||
--callgrind Generate callgrind format to stdout
|
||||
--gv Generate Postscript and display
|
||||
--evince Generate PDF and display
|
||||
--web Generate SVG and display
|
||||
--list=<regexp> Generate source listing of matching routines
|
||||
--disasm=<regexp> Generate disassembly of matching routines
|
||||
@ -304,6 +307,7 @@ sub Init() {
|
||||
$main::opt_disasm = "";
|
||||
$main::opt_symbols = 0;
|
||||
$main::opt_gv = 0;
|
||||
$main::opt_evince = 0;
|
||||
$main::opt_web = 0;
|
||||
$main::opt_dot = 0;
|
||||
$main::opt_ps = 0;
|
||||
@ -372,6 +376,7 @@ sub Init() {
|
||||
"disasm=s" => \$main::opt_disasm,
|
||||
"symbols!" => \$main::opt_symbols,
|
||||
"gv!" => \$main::opt_gv,
|
||||
"evince!" => \$main::opt_evince,
|
||||
"web!" => \$main::opt_web,
|
||||
"dot!" => \$main::opt_dot,
|
||||
"ps!" => \$main::opt_ps,
|
||||
@ -452,6 +457,7 @@ sub Init() {
|
||||
($main::opt_disasm eq '' ? 0 : 1) +
|
||||
($main::opt_symbols == 0 ? 0 : 1) +
|
||||
$main::opt_gv +
|
||||
$main::opt_evince +
|
||||
$main::opt_web +
|
||||
$main::opt_dot +
|
||||
$main::opt_ps +
|
||||
@ -646,6 +652,8 @@ sub Main() {
|
||||
if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
|
||||
if ($main::opt_gv) {
|
||||
RunGV(TempName($main::next_tmpfile, "ps"), "");
|
||||
} elsif ($main::opt_evince) {
|
||||
RunEvince(TempName($main::next_tmpfile, "pdf"), "");
|
||||
} elsif ($main::opt_web) {
|
||||
my $tmp = TempName($main::next_tmpfile, "svg");
|
||||
RunWeb($tmp);
|
||||
@ -708,6 +716,12 @@ sub RunGV {
|
||||
}
|
||||
}
|
||||
|
||||
sub RunEvince {
|
||||
my $fname = shift;
|
||||
my $bg = shift; # "" or " &" if we should run in background
|
||||
system("$EVINCE " . $fname . $bg);
|
||||
}
|
||||
|
||||
sub RunWeb {
|
||||
my $fname = shift;
|
||||
print STDERR "Loading web page file:///$fname\n";
|
||||
@ -805,6 +819,7 @@ sub InteractiveCommand {
|
||||
$main::opt_disasm = 0;
|
||||
$main::opt_list = 0;
|
||||
$main::opt_gv = 0;
|
||||
$main::opt_evince = 0;
|
||||
$main::opt_cum = 0;
|
||||
|
||||
if (m/^\s*(text|top)(\d*)\s*(.*)/) {
|
||||
@ -878,11 +893,14 @@ sub InteractiveCommand {
|
||||
PrintDisassembly($libs, $flat, $cumulative, $routine, $total);
|
||||
return 1;
|
||||
}
|
||||
if (m/^\s*(gv|web)\s*(.*)/) {
|
||||
if (m/^\s*(gv|web|evince)\s*(.*)/) {
|
||||
$main::opt_gv = 0;
|
||||
$main::opt_evince = 0;
|
||||
$main::opt_web = 0;
|
||||
if ($1 eq "gv") {
|
||||
$main::opt_gv = 1;
|
||||
} elsif ($1 eq "evince") {
|
||||
$main::opt_evince = 1;
|
||||
} elsif ($1 eq "web") {
|
||||
$main::opt_web = 1;
|
||||
}
|
||||
@ -902,6 +920,8 @@ sub InteractiveCommand {
|
||||
if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
|
||||
if ($main::opt_gv) {
|
||||
RunGV(TempName($main::next_tmpfile, "ps"), " &");
|
||||
} elsif ($main::opt_evince) {
|
||||
RunEvince(TempName($main::next_tmpfile, "pdf"), " &");
|
||||
} elsif ($main::opt_web) {
|
||||
RunWeb(TempName($main::next_tmpfile, "svg"));
|
||||
}
|
||||
@ -1685,6 +1705,8 @@ sub PrintDot {
|
||||
my $output;
|
||||
if ($main::opt_gv) {
|
||||
$output = "| $DOT -Tps2 >" . TempName($main::next_tmpfile, "ps");
|
||||
} elsif ($main::opt_evince) {
|
||||
$output = "| $DOT -Tps2 | $PS2PDF - " . TempName($main::next_tmpfile, "pdf");
|
||||
} elsif ($main::opt_ps) {
|
||||
$output = "| $DOT -Tps2";
|
||||
} elsif ($main::opt_pdf) {
|
||||
@ -2955,7 +2977,7 @@ sub FetchDynamicProfile {
|
||||
|
||||
my $fetcher = AddFetchTimeout($URL_FETCHER, $fetch_timeout);
|
||||
my $cmd = "$fetcher '$url' > '$tmp_profile'";
|
||||
if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE/){
|
||||
if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE|$CENSUSPROFILE_PAGE/){
|
||||
print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n";
|
||||
if ($encourage_patience) {
|
||||
print STDERR "Be patient...\n";
|
||||
@ -3531,16 +3553,18 @@ sub ReadHeapProfile {
|
||||
# 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;
|
||||
if ($n1 != 0) {
|
||||
my $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
|
||||
my $scale_factor = 1/(1 - exp(-$ratio));
|
||||
$n1 *= $scale_factor;
|
||||
$s1 *= $scale_factor;
|
||||
}
|
||||
if ($n2 != 0) {
|
||||
my $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
|
||||
my $scale_factor = 1/(1 - exp(-$ratio));
|
||||
$n2 *= $scale_factor;
|
||||
$s2 *= $scale_factor;
|
||||
}
|
||||
} else {
|
||||
# Remote-heap version 1
|
||||
my $ratio;
|
||||
@ -4091,9 +4115,15 @@ sub ExtractSymbols {
|
||||
|
||||
my $symbols = {};
|
||||
|
||||
# Map each PC value to the containing library
|
||||
my %seen = ();
|
||||
foreach my $lib (@{$libs}) {
|
||||
# Map each PC value to the containing library. To make this faster,
|
||||
# we sort libraries by their starting pc value (highest first), and
|
||||
# advance through the libraries as we advance the pc. Sometimes the
|
||||
# addresses of libraries may overlap with the addresses of the main
|
||||
# binary, so to make sure the libraries 'win', we iterate over the
|
||||
# libraries in reverse order (which assumes the binary doesn't start
|
||||
# in the middle of a library, which seems a fair assumption).
|
||||
my @pcs = (sort { $a cmp $b } keys(%{$pcset})); # pcset is 0-extended strings
|
||||
foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) {
|
||||
my $libname = $lib->[0];
|
||||
my $start = $lib->[1];
|
||||
my $finish = $lib->[2];
|
||||
@ -4101,12 +4131,21 @@ sub ExtractSymbols {
|
||||
|
||||
# Get list of pcs that belong in this library.
|
||||
my $contained = [];
|
||||
foreach my $pc (keys(%{$pcset})) {
|
||||
if (!$seen{$pc} && ($pc ge $start) && ($pc le $finish)) {
|
||||
$seen{$pc} = 1;
|
||||
push(@{$contained}, $pc);
|
||||
}
|
||||
my ($start_pc_index, $finish_pc_index);
|
||||
# Find smallest finish_pc_index such that $finish < $pc[$finish_pc_index].
|
||||
for ($finish_pc_index = $#pcs + 1; $finish_pc_index > 0;
|
||||
$finish_pc_index--) {
|
||||
last if $pcs[$finish_pc_index - 1] le $finish;
|
||||
}
|
||||
# Find smallest start_pc_index such that $start <= $pc[$start_pc_index].
|
||||
for ($start_pc_index = $finish_pc_index; $start_pc_index > 0;
|
||||
$start_pc_index--) {
|
||||
last if $pcs[$start_pc_index - 1] lt $start;
|
||||
}
|
||||
# This keeps PC values higher than $pc[$finish_pc_index] in @pcs,
|
||||
# in case there are overlaps in libraries and the main binary.
|
||||
@{$contained} = splice(@pcs, $start_pc_index,
|
||||
$finish_pc_index - $start_pc_index);
|
||||
# Map to symbols
|
||||
MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols);
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class CpuProfiler {
|
||||
int (*filter_)(void*);
|
||||
void* filter_arg_;
|
||||
|
||||
// Opague token returned by the profile handler. To be used when calling
|
||||
// Opaque token returned by the profile handler. To be used when calling
|
||||
// ProfileHandlerUnregisterCallback.
|
||||
ProfileHandlerToken* prof_handler_token_;
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
#include "system-alloc.h"
|
||||
#include "internal_logging.h"
|
||||
#include "base/logging.h"
|
||||
@ -73,6 +74,24 @@ static const bool kDebugMode = false;
|
||||
static const bool kDebugMode = true;
|
||||
#endif
|
||||
|
||||
// Anonymous namespace to avoid name conflicts on "CheckAddressBits".
|
||||
namespace {
|
||||
|
||||
// Check that no bit is set at position ADDRESS_BITS or higher.
|
||||
template <int ADDRESS_BITS> bool CheckAddressBits(uintptr_t ptr) {
|
||||
return (ptr >> ADDRESS_BITS) == 0;
|
||||
}
|
||||
|
||||
// Specialize for the bit width of a pointer to avoid undefined shift.
|
||||
template <> bool CheckAddressBits<8 * sizeof(void*)>(uintptr_t ptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // Anonymous namespace to avoid name conflicts on "CheckAddressBits".
|
||||
|
||||
COMPILE_ASSERT(kAddressBits <= 8 * sizeof(void*),
|
||||
address_bits_larger_than_pointer_size);
|
||||
|
||||
// Structure for discovering alignment
|
||||
union MemoryAligner {
|
||||
void* p;
|
||||
@ -443,7 +462,16 @@ void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
|
||||
if (a == NULL) continue;
|
||||
if (a->usable_ && !a->failed_) {
|
||||
void* result = a->Alloc(size, actual_size, alignment);
|
||||
if (result != NULL) return result;
|
||||
if (result != NULL) {
|
||||
if (actual_size) {
|
||||
CheckAddressBits<kAddressBits>(
|
||||
reinterpret_cast<uintptr_t>(result) + *actual_size - 1);
|
||||
} else {
|
||||
CheckAddressBits<kAddressBits>(
|
||||
reinterpret_cast<uintptr_t>(result) + size - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
190
src/tcmalloc.cc
190
src/tcmalloc.cc
@ -110,6 +110,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <google/tcmalloc.h>
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/basictypes.h" // gets us PRIu64
|
||||
@ -136,7 +137,9 @@
|
||||
# define WIN32_DO_PATCHING 1
|
||||
#endif
|
||||
|
||||
using std::max;
|
||||
using STL_NAMESPACE::max;
|
||||
using STL_NAMESPACE::numeric_limits;
|
||||
using STL_NAMESPACE::vector;
|
||||
using tcmalloc::AlignmentForSize;
|
||||
using tcmalloc::PageHeap;
|
||||
using tcmalloc::PageHeapAllocator;
|
||||
@ -439,6 +442,52 @@ static void DumpStats(TCMalloc_Printer* out, int level) {
|
||||
|
||||
static const double MB = 1048576.0;
|
||||
|
||||
const uint64_t virtual_memory_used = (stats.pageheap.system_bytes
|
||||
+ stats.metadata_bytes);
|
||||
const uint64_t physical_memory_used = (virtual_memory_used
|
||||
- stats.pageheap.unmapped_bytes);
|
||||
const uint64_t bytes_in_use_by_app = (physical_memory_used
|
||||
- stats.metadata_bytes
|
||||
- stats.pageheap.free_bytes
|
||||
- stats.central_bytes
|
||||
- stats.transfer_bytes
|
||||
- stats.thread_bytes);
|
||||
|
||||
out->printf(
|
||||
"------------------------------------------------\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes in use by application\n"
|
||||
"MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in page heap freelist\n"
|
||||
"MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in central cache freelist\n"
|
||||
"MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in transfer cache freelist\n"
|
||||
"MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in thread cache freelists\n"
|
||||
"MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes in malloc metadata\n"
|
||||
"MALLOC: ------------\n"
|
||||
"MALLOC: = %12" PRIu64 " (%7.1f MB) Actual memory used (physical + swap)\n"
|
||||
"MALLOC: + %12" PRIu64 " (%7.1f MB) Bytes released to OS (aka unmapped)\n"
|
||||
"MALLOC: ------------\n"
|
||||
"MALLOC: = %12" PRIu64 " (%7.1f MB) Virtual address space used\n"
|
||||
"MALLOC:\n"
|
||||
"MALLOC: %12" PRIu64 " Spans in use\n"
|
||||
"MALLOC: %12" PRIu64 " Thread heaps in use\n"
|
||||
"MALLOC: %12" PRIu64 " Tcmalloc page size\n"
|
||||
"------------------------------------------------\n"
|
||||
"Call ReleaseFreeMemory() to release freelist memory to the OS"
|
||||
" (via madvise()).\n"
|
||||
"Bytes released to the OS take up virtual address space"
|
||||
" but no physical memory.\n",
|
||||
bytes_in_use_by_app, bytes_in_use_by_app / MB,
|
||||
stats.pageheap.free_bytes, stats.pageheap.free_bytes / MB,
|
||||
stats.central_bytes, stats.central_bytes / MB,
|
||||
stats.transfer_bytes, stats.transfer_bytes / MB,
|
||||
stats.thread_bytes, stats.thread_bytes / MB,
|
||||
stats.metadata_bytes, stats.metadata_bytes / MB,
|
||||
physical_memory_used, physical_memory_used / MB,
|
||||
stats.pageheap.unmapped_bytes, stats.pageheap.unmapped_bytes / MB,
|
||||
virtual_memory_used, virtual_memory_used / MB,
|
||||
uint64_t(Static::span_allocator()->inuse()),
|
||||
uint64_t(ThreadCache::HeapsInUse()),
|
||||
uint64_t(kPageSize));
|
||||
|
||||
if (level >= 2) {
|
||||
out->printf("------------------------------------------------\n");
|
||||
out->printf("Size class breakdown\n");
|
||||
@ -464,38 +513,6 @@ static void DumpStats(TCMalloc_Printer* out, int level) {
|
||||
out->printf("------------------------------------------------\n");
|
||||
DumpSystemAllocatorStats(out);
|
||||
}
|
||||
|
||||
const uint64_t bytes_in_use = stats.pageheap.system_bytes
|
||||
- stats.pageheap.free_bytes
|
||||
- stats.pageheap.unmapped_bytes
|
||||
- stats.central_bytes
|
||||
- stats.transfer_bytes
|
||||
- stats.thread_bytes;
|
||||
|
||||
out->printf("------------------------------------------------\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Heap size\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes in use by application\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in page heap\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes unmapped in page heap\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in central cache\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in transfer cache\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Bytes free in thread caches\n"
|
||||
"MALLOC: %12" PRIu64 " Spans in use\n"
|
||||
"MALLOC: %12" PRIu64 " Thread heaps in use\n"
|
||||
"MALLOC: %12" PRIu64 " (%7.1f MB) Metadata allocated\n"
|
||||
"MALLOC: %12" PRIu64 " Tcmalloc page size\n"
|
||||
"------------------------------------------------\n",
|
||||
stats.pageheap.system_bytes, stats.pageheap.system_bytes / MB,
|
||||
bytes_in_use, bytes_in_use / MB,
|
||||
stats.pageheap.free_bytes, stats.pageheap.free_bytes / MB,
|
||||
stats.pageheap.unmapped_bytes, stats.pageheap.unmapped_bytes / MB,
|
||||
stats.central_bytes, stats.central_bytes / MB,
|
||||
stats.transfer_bytes, stats.transfer_bytes / MB,
|
||||
stats.thread_bytes, stats.thread_bytes / MB,
|
||||
uint64_t(Static::span_allocator()->inuse()),
|
||||
uint64_t(ThreadCache::HeapsInUse()),
|
||||
stats.metadata_bytes, stats.metadata_bytes / MB,
|
||||
uint64_t(kPageSize));
|
||||
}
|
||||
|
||||
static void PrintStats(int level) {
|
||||
@ -609,6 +626,20 @@ class TCMallocImplementation : public MallocExtension {
|
||||
}
|
||||
}
|
||||
|
||||
// We may print an extra, tcmalloc-specific warning message here.
|
||||
virtual void GetHeapSample(MallocExtensionWriter* writer) {
|
||||
if (FLAGS_tcmalloc_sample_parameter == 0) {
|
||||
const char* const kWarningMsg =
|
||||
"#\n# WARNING: This heap profile does not have any data in it,\n"
|
||||
"# because the application was run with heap sampling turned off.\n"
|
||||
"# To get useful data from from GetHeapSample(), you must first\n"
|
||||
"# set the environment variable TCMALLOC_SAMPLE_PARAMETER to a\n"
|
||||
"# positive sampling period, such as 524288.\n#\n";
|
||||
writer->append(kWarningMsg, strlen(kWarningMsg));
|
||||
}
|
||||
MallocExtension::GetHeapSample(writer);
|
||||
}
|
||||
|
||||
virtual void** ReadStackTraces(int* sample_period) {
|
||||
tcmalloc::StackTraceTable table;
|
||||
{
|
||||
@ -753,6 +784,99 @@ class TCMallocImplementation : public MallocExtension {
|
||||
// unnamed namespace, we need to move the definition below it in the
|
||||
// file.
|
||||
virtual size_t GetAllocatedSize(void* ptr);
|
||||
|
||||
virtual void GetFreeListSizes(vector<MallocExtension::FreeListInfo>* v) {
|
||||
static const char* kCentralCacheType = "tcmalloc.central";
|
||||
static const char* kTransferCacheType = "tcmalloc.transfer";
|
||||
static const char* kThreadCacheType = "tcmalloc.thread";
|
||||
static const char* kPageHeapType = "tcmalloc.page";
|
||||
static const char* kPageHeapUnmappedType = "tcmalloc.page_unmapped";
|
||||
static const char* kLargeSpanType = "tcmalloc.large";
|
||||
static const char* kLargeUnmappedSpanType = "tcmalloc.large_unmapped";
|
||||
|
||||
v->clear();
|
||||
|
||||
// central class information
|
||||
int64 prev_class_size = 0;
|
||||
for (int cl = 1; cl < kNumClasses; ++cl) {
|
||||
size_t class_size = Static::sizemap()->ByteSizeForClass(cl);
|
||||
MallocExtension::FreeListInfo i;
|
||||
i.min_object_size = prev_class_size + 1;
|
||||
i.max_object_size = class_size;
|
||||
i.total_bytes_free =
|
||||
Static::central_cache()[cl].length() * class_size;
|
||||
i.type = kCentralCacheType;
|
||||
v->push_back(i);
|
||||
|
||||
// transfer cache
|
||||
i.total_bytes_free =
|
||||
Static::central_cache()[cl].tc_length() * class_size;
|
||||
i.type = kTransferCacheType;
|
||||
v->push_back(i);
|
||||
|
||||
prev_class_size = Static::sizemap()->ByteSizeForClass(cl);
|
||||
}
|
||||
|
||||
// Add stats from per-thread heaps
|
||||
uint64_t class_count[kNumClasses];
|
||||
memset(class_count, 0, sizeof(class_count));
|
||||
{
|
||||
SpinLockHolder h(Static::pageheap_lock());
|
||||
uint64_t thread_bytes = 0;
|
||||
ThreadCache::GetThreadStats(&thread_bytes, class_count);
|
||||
}
|
||||
|
||||
prev_class_size = 0;
|
||||
for (int cl = 1; cl < kNumClasses; ++cl) {
|
||||
MallocExtension::FreeListInfo i;
|
||||
i.min_object_size = prev_class_size + 1;
|
||||
i.max_object_size = Static::sizemap()->ByteSizeForClass(cl);
|
||||
i.total_bytes_free =
|
||||
class_count[cl] * Static::sizemap()->ByteSizeForClass(cl);
|
||||
i.type = kThreadCacheType;
|
||||
v->push_back(i);
|
||||
}
|
||||
|
||||
// append page heap info
|
||||
int64 page_count_normal[kMaxPages];
|
||||
int64 page_count_returned[kMaxPages];
|
||||
int64 span_count_normal;
|
||||
int64 span_count_returned;
|
||||
{
|
||||
SpinLockHolder h(Static::pageheap_lock());
|
||||
Static::pageheap()->GetClassSizes(page_count_normal,
|
||||
page_count_returned,
|
||||
&span_count_normal,
|
||||
&span_count_returned);
|
||||
}
|
||||
|
||||
// spans: mapped
|
||||
MallocExtension::FreeListInfo span_info;
|
||||
span_info.type = kLargeSpanType;
|
||||
span_info.max_object_size = (numeric_limits<size_t>::max)();
|
||||
span_info.min_object_size = kMaxPages << kPageShift;
|
||||
span_info.total_bytes_free = span_count_normal << kPageShift;
|
||||
v->push_back(span_info);
|
||||
|
||||
// spans: unmapped
|
||||
span_info.type = kLargeUnmappedSpanType;
|
||||
span_info.total_bytes_free = span_count_returned << kPageShift;
|
||||
v->push_back(span_info);
|
||||
|
||||
for (int s = 1; s < kMaxPages; s++) {
|
||||
MallocExtension::FreeListInfo i;
|
||||
i.max_object_size = (s << kPageShift);
|
||||
i.min_object_size = ((s - 1) << kPageShift);
|
||||
|
||||
i.type = kPageHeapType;
|
||||
i.total_bytes_free = (s << kPageShift) * page_count_normal[s];
|
||||
v->push_back(i);
|
||||
|
||||
i.type = kPageHeapUnmappedType;
|
||||
i.total_bytes_free = (s << kPageShift) * page_count_returned[s];
|
||||
v->push_back(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The constructor allocates an object to ensure that initialization
|
||||
|
@ -259,7 +259,10 @@ TEST(DebugAllocationTest, GetAllocatedSizeTest) {
|
||||
}
|
||||
|
||||
TEST(DebugAllocationTest, HugeAlloc) {
|
||||
const size_t kTooBig = ~static_cast<size_t>(0);
|
||||
// This must not be a const variable so it doesn't form an
|
||||
// integral-constant-expression which can be *statically* rejected by the
|
||||
// compiler as too large for the allocation.
|
||||
size_t kTooBig = ~static_cast<size_t>(0);
|
||||
void* a = NULL;
|
||||
char* b = NULL;
|
||||
|
||||
@ -273,8 +276,9 @@ TEST(DebugAllocationTest, HugeAlloc) {
|
||||
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.
|
||||
const size_t kAlsoTooBig = kTooBig - 1024;
|
||||
// but will still fall through to tcmalloc's check. This must also be
|
||||
// a non-const variable. See kTooBig for more details.
|
||||
size_t kAlsoTooBig = kTooBig - 1024;
|
||||
|
||||
a = malloc(kAlsoTooBig);
|
||||
EXPECT_EQ(NULL, a);
|
||||
|
@ -39,6 +39,8 @@
|
||||
#include <google/malloc_extension.h>
|
||||
#include <google/malloc_extension_c.h>
|
||||
|
||||
using STL_NAMESPACE::vector;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
void* a = malloc(1000);
|
||||
|
||||
@ -70,6 +72,30 @@ 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");
|
||||
|
@ -45,6 +45,8 @@
|
||||
|
||||
using std::string;
|
||||
|
||||
extern "C" void* AllocateAllocate() ATTRIBUTE_NOINLINE;
|
||||
|
||||
extern "C" void* AllocateAllocate() {
|
||||
// The VLOG's are mostly to discourage inlining
|
||||
VLOG(1, "Allocating some more");
|
||||
|
@ -81,13 +81,13 @@ mkdir "$OUTDIR" || die "Unable to create $OUTDIR"
|
||||
|
||||
echo "Testing heap output..."
|
||||
"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap" \
|
||||
| grep '^ *[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|
||||
| grep '[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|
||||
|| die "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.heap"
|
||||
echo "OK"
|
||||
|
||||
echo "Testing growth output..."
|
||||
"$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth" \
|
||||
| grep '^ *[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|
||||
| grep '[5-9][0-9]\.[0-9][ 0-9.%]*_*AllocateAllocate' >/dev/null \
|
||||
|| die "$PPROF" --text "$SAMPLING_TEST_BINARY" "$OUTDIR/out.growth"
|
||||
echo "OK"
|
||||
|
||||
|
@ -38,7 +38,9 @@
|
||||
#include <inttypes.h> // another place uintptr_t might be defined
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <algorithm>
|
||||
#include "base/logging.h"
|
||||
#include "common.h"
|
||||
#include "system-alloc.h"
|
||||
|
||||
class ArraySysAllocator : public SysAllocator {
|
||||
@ -98,6 +100,18 @@ static void TestBasicInvoked() {
|
||||
CHECK(a.invoked_);
|
||||
}
|
||||
|
||||
#if 0 // could port this to various OSs, but won't bother for now
|
||||
TEST(AddressBits, CpuVirtualBits) {
|
||||
// Check that kAddressBits is as least as large as either the number of bits
|
||||
// in a pointer or as the number of virtual bits handled by the processor.
|
||||
// To be effective this test must be run on each processor model.
|
||||
const int kPointerBits = 8 * sizeof(void*);
|
||||
const int kImplementedVirtualBits = NumImplementedVirtualBits();
|
||||
|
||||
CHECK_GE(kAddressBits, min(kImplementedVirtualBits, kPointerBits));
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
TestBasicInvoked();
|
||||
|
||||
|
@ -100,17 +100,12 @@
|
||||
# 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.
|
||||
// Note, this isn't a perfect analogue: we don't enforce constraints on "align"
|
||||
// I'd like to map posix_memalign to _aligned_malloc, but _aligned_malloc
|
||||
// must be paired with _aligned_free (not normal free), which is too
|
||||
// invasive a change to how we allocate memory here. So just bail
|
||||
# include <errno.h>
|
||||
# define posix_memalign(pptr, align, size) \
|
||||
((*(pptr)=_aligned_malloc(size, align)) ? 0 : ENOMEM)
|
||||
# define memalign(alignment, size) malloc(size)
|
||||
# define posix_memalign(pptr, align, size) ((*(pptr)=malloc(size)) ? 0 : ENOMEM)
|
||||
#endif
|
||||
|
||||
// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
|
||||
@ -1033,6 +1028,14 @@ static int RunAllTests(int argc, char** argv) {
|
||||
free(p1);
|
||||
VerifyDeleteHookWasCalled();
|
||||
|
||||
// Windows has _aligned_malloc. Let's test that that's captured too.
|
||||
#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(PERFTOOLS_NO_ALIGNED_MALLOC)
|
||||
p1 = _aligned_malloc(sizeof(p1) * 2, 64);
|
||||
VerifyNewHookWasCalled();
|
||||
_aligned_free(p1);
|
||||
VerifyDeleteHookWasCalled();
|
||||
#endif
|
||||
|
||||
p1 = valloc(60);
|
||||
VerifyNewHookWasCalled();
|
||||
free(p1);
|
||||
|
@ -92,7 +92,7 @@
|
||||
#undef HAVE_LINUX_PTRACE_H
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
@ -175,7 +175,7 @@ class LibcInfo {
|
||||
kNew, kNewArray, kDelete, kDeleteArray,
|
||||
kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow,
|
||||
// These are windows-only functions from malloc.h
|
||||
k_Msize, k_Expand, k_Aligned_malloc, k_Aligned_free,
|
||||
k_Msize, k_Expand,
|
||||
kNumFunctions
|
||||
};
|
||||
|
||||
@ -274,12 +274,12 @@ template<int> class LibcInfoWithPatchFunctions : public LibcInfo {
|
||||
const std::nothrow_t&) __THROW;
|
||||
static size_t Perftools__msize(void *ptr) __THROW;
|
||||
static void* Perftools__expand(void *ptr, size_t size) __THROW;
|
||||
static void* Perftools__aligned_malloc(size_t size, size_t alignment) __THROW;
|
||||
static void Perftools__aligned_free(void *ptr) __THROW;
|
||||
// malloc.h also defines these functions:
|
||||
// _aligned_malloc, _aligned_free,
|
||||
// _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc
|
||||
// _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea
|
||||
// But they seem pretty obscure, and I'm fine not overriding them for now.
|
||||
// It may be they all call into malloc/free anyway.
|
||||
};
|
||||
|
||||
// This is a subset of MODDULEENTRY32, that we need for patching.
|
||||
@ -300,10 +300,19 @@ struct ModuleEntryCopy {
|
||||
ModuleEntryCopy(const MODULEINFO& mi) {
|
||||
this->modBaseAddr = mi.lpBaseOfDll;
|
||||
this->modBaseSize = mi.SizeOfImage;
|
||||
for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++)
|
||||
rgProcAddresses[i] = (GenericFnPtr)::GetProcAddress(
|
||||
LPVOID modEndAddr = (char*)mi.lpBaseOfDll + mi.SizeOfImage;
|
||||
for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) {
|
||||
FARPROC target = ::GetProcAddress(
|
||||
reinterpret_cast<const HMODULE>(mi.lpBaseOfDll),
|
||||
LibcInfo::function_name(i));
|
||||
// Sometimes a DLL forwards a function to a function in another
|
||||
// DLL. We don't want to patch those forwarded functions --
|
||||
// they'll get patched when the other DLL is processed.
|
||||
if (target >= modBaseAddr && target < modEndAddr)
|
||||
rgProcAddresses[i] = (GenericFnPtr)target;
|
||||
else
|
||||
rgProcAddresses[i] = (GenericFnPtr)NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -390,7 +399,7 @@ const char* const LibcInfo::function_name_[] = {
|
||||
NULL, // kMangledNewArrayNothrow,
|
||||
NULL, // kMangledDeleteNothrow,
|
||||
NULL, // kMangledDeleteArrayNothrow,
|
||||
"_msize", "_expand", "_aligned_malloc", "_aligned_free",
|
||||
"_msize", "_expand",
|
||||
};
|
||||
|
||||
// For mingw, I can't patch the new/delete here, because the
|
||||
@ -421,14 +430,6 @@ const GenericFnPtr LibcInfo::static_fn_[] = {
|
||||
#endif
|
||||
(GenericFnPtr)&::_msize,
|
||||
(GenericFnPtr)&::_expand,
|
||||
#ifdef PERFTOOLS_NO_ALIGNED_MALLOC // for older versions of mingw
|
||||
// _aligned_malloc isn't always available in mingw, so don't try to patch.
|
||||
(GenericFnPtr)NULL,
|
||||
(GenericFnPtr)NULL,
|
||||
#else
|
||||
(GenericFnPtr)&::_aligned_malloc,
|
||||
(GenericFnPtr)&::_aligned_free,
|
||||
#endif
|
||||
};
|
||||
|
||||
template<int T> GenericFnPtr LibcInfoWithPatchFunctions<T>::origstub_fn_[] = {
|
||||
@ -451,8 +452,6 @@ const GenericFnPtr LibcInfoWithPatchFunctions<T>::perftools_fn_[] = {
|
||||
(GenericFnPtr)&Perftools_deletearray_nothrow,
|
||||
(GenericFnPtr)&Perftools__msize,
|
||||
(GenericFnPtr)&Perftools__expand,
|
||||
(GenericFnPtr)&Perftools__aligned_malloc,
|
||||
(GenericFnPtr)&Perftools__aligned_free,
|
||||
};
|
||||
|
||||
/*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = {
|
||||
@ -908,21 +907,6 @@ void* LibcInfoWithPatchFunctions<T>::Perftools__expand(void *ptr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<int T>
|
||||
void* LibcInfoWithPatchFunctions<T>::Perftools__aligned_malloc(size_t size,
|
||||
size_t alignment)
|
||||
__THROW {
|
||||
void* result = do_memalign_or_cpp_memalign(alignment, size);
|
||||
MallocHook::InvokeNewHook(result, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<int T>
|
||||
void LibcInfoWithPatchFunctions<T>::Perftools__aligned_free(void *ptr) __THROW {
|
||||
MallocHook::InvokeDeleteHook(ptr);
|
||||
do_free_with_callback(ptr, (void (*)(void*))origstub_fn_[k_Aligned_free]);
|
||||
}
|
||||
|
||||
LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
|
||||
DWORD_PTR dwBytes) {
|
||||
LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR))
|
||||
|
@ -83,6 +83,18 @@ extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We need to write to 'stderr' without having windows allocate memory.
|
||||
// The safest way is via a low-level call like WriteConsoleA(). But
|
||||
// even then we need to be sure to print in small bursts so as to not
|
||||
// require memory allocation.
|
||||
extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
|
||||
// Looks like windows allocates for writes of >80 bytes
|
||||
for (int i = 0; i < len; i += 80) {
|
||||
write(STDERR_FILENO, buf + i, std::min(80, len - i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Threads code
|
||||
|
||||
|
@ -277,6 +277,8 @@ 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);
|
||||
|
||||
// ----------------------------------- SYSTEM/PROCESS
|
||||
typedef int pid_t;
|
||||
#define getpid _getpid
|
||||
|
@ -195,6 +195,23 @@
|
||||
RuntimeLibrary="2"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.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\port.cc">
|
||||
<FileConfiguration
|
||||
@ -236,13 +253,37 @@
|
||||
RelativePath="..\..\src\base\logging.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
RelativePath="..\..\src\base\atomicops-internals-arm-gcc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-linuxppc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-macosx.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_linux-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_posix-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_win32-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\cycleclock.h">
|
||||
|
@ -554,6 +554,23 @@
|
||||
RuntimeLibrary="2"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.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\base\sysinfo.cc">
|
||||
<FileConfiguration
|
||||
@ -639,13 +656,37 @@
|
||||
RelativePath="..\..\src\base\low_level_alloc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
RelativePath="..\..\src\base\atomicops-internals-arm-gcc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-linuxppc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-macosx.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_linux-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_posix-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_win32-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\google\malloc_extension.h">
|
||||
|
@ -195,6 +195,23 @@
|
||||
RuntimeLibrary="2"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.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\tests\low_level_alloc_unittest.cc">
|
||||
<FileConfiguration
|
||||
@ -275,13 +292,37 @@
|
||||
RelativePath="..\..\src\base\commandlineflags.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
RelativePath="..\..\src\base\atomicops-internals-arm-gcc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-linuxppc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-macosx.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_linux-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_posix-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_win32-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\windows\config.h">
|
||||
|
@ -144,13 +144,37 @@
|
||||
RelativePath="..\..\src\base\logging.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
RelativePath="..\..\src\base\atomicops-internals-arm-gcc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-linuxppc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-macosx.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_linux-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_posix-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_win32-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\cycleclock.h">
|
||||
|
@ -598,6 +598,25 @@
|
||||
RuntimeLibrary="2"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.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\base\sysinfo.cc">
|
||||
<FileConfiguration
|
||||
@ -728,13 +747,37 @@
|
||||
RelativePath="..\..\src\base\low_level_alloc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
RelativePath="..\..\src\base\atomicops-internals-arm-gcc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-linuxppc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-macosx.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\atomicops-internals-x86-msvc.h">
|
||||
RelativePath="..\..\src\base\spinlock.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_internal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_linux-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_posix-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\base\spinlock_win32-inl.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\google\malloc_extension.h">
|
||||
|
Loading…
Reference in New Issue
Block a user