summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--INSTALL233
-rw-r--r--Makefile.am234
-rw-r--r--Makefile.in1217
-rwxr-xr-xconfigure260
-rw-r--r--configure.ac19
-rw-r--r--doc/cpuprofile-fileformat.html264
-rw-r--r--doc/cpuprofile.html4
-rw-r--r--packages/deb/changelog6
-rw-r--r--src/base/linux_syscall_support.h204
-rw-r--r--src/base/spinlock.cc22
-rw-r--r--src/base/sysinfo.cc22
-rw-r--r--src/config.h.in6
-rw-r--r--src/getpc.h4
-rw-r--r--src/google/heap-checker.h2
-rw-r--r--src/google/profiler.h21
-rw-r--r--src/google/stacktrace.h45
-rw-r--r--src/heap-checker.cc3
-rw-r--r--src/heap-profile-table.cc12
-rw-r--r--src/heap-profiler.cc31
-rw-r--r--src/malloc_hook.cc6
-rw-r--r--src/memfs_malloc.cc20
-rw-r--r--src/memory_region_map.cc8
-rw-r--r--src/packed-cache-inl.h4
-rwxr-xr-xsrc/pprof35
-rw-r--r--src/profiledata.cc312
-rw-r--r--src/profiledata.h162
-rw-r--r--src/profiler.cc548
-rw-r--r--src/stacktrace_generic-inl.h49
-rw-r--r--src/stacktrace_libunwind-inl.h70
-rw-r--r--src/stacktrace_powerpc-inl.h132
-rw-r--r--src/stacktrace_x86-inl.h110
-rw-r--r--src/stacktrace_x86_64-inl.h49
-rw-r--r--src/system-alloc.cc27
-rw-r--r--src/system-alloc.h10
-rw-r--r--src/tcmalloc.cc10
-rw-r--r--src/tests/addressmap_unittest.cc1
-rw-r--r--src/tests/heap-checker_unittest.cc1
-rw-r--r--src/tests/low_level_alloc_unittest.cc7
-rwxr-xr-xsrc/tests/maybe_threads_unittest.sh4
-rw-r--r--src/tests/profiledata_unittest.cc320
-rw-r--r--src/tests/system-alloc_unittest.cc4
-rw-r--r--src/tests/tcmalloc_unittest.cc2
-rw-r--r--src/tests/testutil.cc72
-rw-r--r--src/windows/config.h16
-rw-r--r--src/windows/mingw.h47
-rw-r--r--src/windows/mini_disassembler.h6
-rw-r--r--src/windows/patch_functions.cc162
-rw-r--r--src/windows/port.cc87
-rw-r--r--src/windows/port.h35
-rw-r--r--src/windows/preamble_patcher.h20
-rw-r--r--src/windows/preamble_patcher_with_stub.cc26
-rwxr-xr-xvsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj2
53 files changed, 3639 insertions, 1351 deletions
diff --git a/ChangeLog b/ChangeLog
index 0127ff1..871291f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Thu Nov 29 07:59:43 2007 Google Inc. <opensource@google.com>
+
+ * google-perftools: version 0.94 release
+ * PORTING: MinGW/Msys support -- runs same code as MSVC does (csilvers)
+ * PORTING: Add NumCPUs support for Mac OS X (csilvers)
+ * Work around a sscanf bug in glibc(?) (waldemar)
+ * Fix Windows MSVC bug triggered by thread deletion (csilvers)
+ * Fix bug that triggers in MSVC /O2: missing volatile (gpike)
+ * March-of-time support: quiet warnings/errors for gcc 4.2, OS X 10.5
+ * Modify pprof so it works without nm: useful for windows (csilvers)
+ * pprof: Support filtering for CPU profiles (cgd)
+ * Bugfix: have realloc report to hooks in all situations (maxim)
+ * Speed improvement: replace slow memcpy with std::copy (soren)
+ * Speed: better iterator efficiency in RecordRegionRemoval (soren)
+ * Speed: minor speed improvements via better bitfield alignment (gpike)
+ * Documentation: add documentation of binary profile output (cgd)
+
Fri Aug 17 12:32:56 2007 Google Inc. <opensource@google.com>
* google-perftools: version 0.93 release
diff --git a/INSTALL b/INSTALL
index 9d765c6..a42e74b 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,10 +1,7 @@
-Installation Instructions
-*************************
+Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
-Software Foundation, Inc.
-
-This file is free documentation; the Free Software Foundation gives
+ This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
@@ -15,7 +12,7 @@ Perftools-Specific Install Notes
The glibc built-in stack-unwinder on 64-bit systems has some problems
with the perftools libraries. (In particular, the cpu/heap profiler
-may be in the middle of malloc, holding some malloc-related locks, when
+may be in the middle of malloc, holding some malloc-related locks when
they invoke the stack unwinder. The built-in stack unwinder may call
malloc recursively, which may require the thread to acquire a lock it
already holds: deadlock.)
@@ -69,84 +66,53 @@ Perftools has been tested on the following systems:
Mac OS X 10.3.9 (Panther) (PowerPC)
Mac OS X 10.4.8 (Tiger) (PowerPC)
Mac OS X 10.4.8 (Tiger) (x86)
+ Mac OS X 10.5 (Leopard) (x86)
Solaris 10 (x86)
Windows XP, Visual Studio 2003 (VC++ 7) (x86)
Windows XP, Visual Studio 2005 (VC++ 8) (x86)
+ Windows XP, MinGW 5.1.3 (x86)
It works in its full generality on all the Linux systems tested, both
-x86 and x86_64 (though see 64-bit notes above). There's also
-preliminary support for ia64 architectures, though more remains to be
-done there.
-
-On other unix-based systems, most of perftools works. The basic
-memory-allocation library, tcmalloc_minimal, works on all systems.
-The cpu-profiler also works widely. The heap-profiler works on many
-systems, but ONLY FOR SINGLE-THREADED PROGRAMS. It also does not
-profile mmap calls, which the linux version of the code does. In both
-cases, this is because the necessary system munging -- to find all
-threads, to override the relevant syscalls -- has only been written
-for Linux.
-
-The last provided tool, the heap-checker, works only on Linux. This
-is again because the necessary system munging -- in this case, to find
-all the memory-mapped regions owned by a process -- has only been
-written for Linux. You can still safely try to use the heap-checker,
-it will just turn itself off and not do any leak-detection.
-
-In all cases -- including for Windows -- the basic code that replaces
-new/malloc works and is usable, by linking in either libtcmalloc or
-libtcmalloc_minimal.
+x86 and x86_64 (though see 64-bit notes above). Portions of perftools
+work on the other systems. The basic memory-allocation library,
+tcmalloc_minimal, works on all systems. The cpu-profiler also works
+fairly widely. However, the heap-profiler and heap-checker are not
+yet as widely supported.
+
+Note that tcmalloc_minimal is perfectly usable as a malloc/new
+replacement, so it is possible to use tcmalloc on all the systems
+above, by linking in libtcmalloc_minimal.
** FreeBSD:
- Everything should build successfully (creating
- libtcmalloc_minimal.so, libtcmalloc.so, and libprofile.so in the
- process):
+ The following binaries build and run successfully (creating
+ libtcmalloc_minimal.so and libprofile.so in the process):
% ./configure
- % make
- % make check # to run the tests
- % make install # to install the libraries
-
- Most of the unittests should pass. A few may fail:
-
- 1) frag_unittest tries to allocate 400M of memory, and if you have
- less virtual memory on your system, the test may fail with a
- bad_alloc exception.
-
- 2) profiler_unittest.sh sometimes fails in the "fork" test. This
- is because stray SIGPROF signals from the parent process are
- making their way into the child process. (This may be a kernel
- bug that only exists in older kernels.) The profiling code
- itself is working fine. This only affects programs that call
- fork(); for most programs, as long as the unittest makes it to
- the "fork" test, it indicates the cpu profiler is safe to use.
-
- 3) heap-checker-death_unittest.sh will fail because the
- heap-checker does not successfully run on FreeBSD. The
- leak-checker notices it cannot run and turns itself off; as a
- result, it does not die in the way the unittest is expecting,
- leading to test failure. (Likewise, while
- heap-checker_unittest.sh succeeds, it doesn't actually test
- anything, since heap-checking is never actually enabled during
- those tests.)
-
- As a result, you can safely link any or all of libtcmalloc_minimal,
- libtcmalloc, or libprofiler into your application. The following
- functionality is available:
-
- 1) malloc/new replacement: by linking in libtcmalloc or
- libtcmalloc_minimal.
- 2) heap-profiler: by linking in libtcmalloc and setting HEAPPROFILE.
- 3) cpu-profiler: by linking in libprofile and setting CPUPROFILE.
-
- The following functionality is not available; if you try to enable
- it, it will turn itself off:
-
- 1) heap-checker (automatic leak-detection): by linking in
- libtcmalloc and setting HEAPCHECK.
-
- See the README and documentation in the doc/ directory for more
- information on how to use these features.
+ % make tcmalloc_minimal_unittest tcmalloc_minimal_large_unittest \
+ addressmap_unittest atomicops_unittest frag_unittest \
+ low_level_alloc_unittest markidle_unittest memalign_unittest \
+ packed_cache_test stacktrace_unittest system_alloc_unittest \
+ thread_dealloc_unittest profiler_unittest.sh
+ % ./tcmalloc_minimal_unittest # to run this test
+ % [etc] # to run other tests
+
+ Two caveats: first, frag_unittest tries to allocate 400M of memory,
+ and if you have less virtual memory on your system, the test may
+ fail with a bad_alloc exception.
+
+ Second, profiler_unittest.sh sometimes fails in the "fork" test.
+ This is because stray SIGPROF signals from the parent process are
+ making their way into the child process. (This may be a kernel
+ bug that only exists in older kernels.) The profiling code itself
+ is working fine. This only affects programs that call fork(); for
+ most programs, the cpu profiler is entirely safe to use.
+
+ libtcmalloc.so does not successfully build, so neither do these
+ unittests that depend on it:
+ % make -k heap-profiler_unittest.sh heap-checker_unittest.sh \
+ heap-checker-death_unittest.sh maybe_threads_unittest.sh \
+ tcmalloc_unittest tcmalloc_both_unittest \
+ tcmalloc_large_unittest
I have not tested other *BSD systems, but they are probably similar.
@@ -157,11 +123,9 @@ libtcmalloc_minimal.
not work at all: it depends on a header file, OSAtomic.h, which is
new in 10.4.
- For the other three systems, all binaries and libraries build, and
- the set of unittests that pass are exactly the same as for FreeBSD.
- In particular, you can use the basic malloc/new replacements (by
- linking in libtcmalloc or libtcmalloc_minimal), the heap-profiler
- (by linking in libtcmalloc and setting HEAPPROFILE),
+ For the other three systems, the binaries and libraries that
+ successfully build are exactly the same as for FreeBSD. See that
+ section for a list of binaries and instructions on building them.
** Solaris 10 x86:
@@ -171,24 +135,16 @@ libtcmalloc_minimal.
src/solaris/libstdc++.la for more info), which we work around by
adding a custom LDFLAGS argument:
- % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin ./configure LDFLAGS="-Lsrc/solaris -lrt -lnsl"
- % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin make
-
- Again, all binaries and libraries successfully build. However,
- while libprofiler.so can be used to generate CPU profiles, pprof is
- not very successful at reading them -- necessary helper programs
- like nm don't seem to be installed by default on Solaris, or
- perhaps are only installed as part of the Sun C++ compiler package.
- Even more trouble exists trying to generate heap-profiles, because
- the Sun linker does not support __attribute__((section)). I've
- been unable to test this, but it might work correctly if you can
- get gcc to use the gnu linker (/usr/sfw/bin/gld) instead of sun's
- ld.
-
- The perftools code uses a lot of gcc-specific functionality,
- including attributes like section-naming and weak-linking, so it
- may be difficult to fully port this code to the Sun C++ compiler.
- The basic tcmalloc_minimal library may port well, however.
+ % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin ./configure LDFLAGS="-Lsrc/solaris -lrt"
+ % PATH=${PATH}:/usr/sfw/bin/:/usr/ccs/bin make [...]
+
+ Again, the binaries and libraries that successfully build are
+ exactly the same as for FreeBSD. (However, while libprofiler.so can
+ be used to generate profiles, pprof is not very successful at
+ reading them -- necessary helper programs like nm don't seem
+ to be installed by default on Solaris, or perhaps are only
+ installed as part of the Sun C++ compiler package.) See that
+ section for a list of binaries, and instructions on building them.
** Windows:
@@ -199,26 +155,18 @@ libtcmalloc_minimal.
the basic tcmalloc library functionality, overriding malloc and new
and such, is working fine, both with VC++ 7.1 (Visual Studio 2003)
and VC++ 8.0 (Visual Studio 2005). See README.windows for
- instructions on how to install on Windows.
-
-
-*** FURTHER OPTIONAL TESTING
+ instructions on how to install on Windows using Visual Studio.
- In addition to all the tests that tcmalloc performs with "make
- check", for your convenience we've included part a test suite that
- comes with ptmalloc, another malloc implementation. It is not
- enabled by default, because the tests do not compile on all systems.
- If you want to run these tests, you can try the following:
-
- % make ptmalloc_unittest1 ptmalloc_unittest2
- % ./ptmalloc_unittest1 # to run the test
- % ./ptmalloc_unittest2 # to run the test
+ This Windows functionality is also available using MinGW and Msys.
+ In this case, you can use the regular './configure && make'
+ process. 'make install' should also work. The Makefile will limit
+ itself to those libraries and binaries that work on windows.
Basic Installation
==================
-These are generic installation instructions.
+ These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
@@ -278,9 +226,9 @@ The simplest way to compile this package is:
Compilers and Options
=====================
-Some systems require unusual options for compilation or linking that the
-`configure' script does not know about. Run `./configure --help' for
-details on some of the pertinent environment variables.
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
@@ -293,7 +241,7 @@ is an example:
Compiling For Multiple Architectures
====================================
-You can compile the package for more than one kind of computer at the
+ You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
@@ -310,19 +258,19 @@ for another architecture.
Installation Names
==================
-By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc. You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX'.
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
+options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
@@ -333,7 +281,7 @@ option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
-Some packages pay attention to `--enable-FEATURE' options to
+ Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
@@ -348,11 +296,11 @@ you can use the `configure' options `--x-includes=DIR' and
Specifying the System Type
==========================
-There may be some features `configure' cannot figure out automatically,
-but needs to determine by the type of machine the package will run on.
-Usually, assuming the package is built to be run on the _same_
-architectures, `configure' can figure that out, but if it prints a
-message saying it cannot guess the machine type, give it the
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
@@ -367,7 +315,7 @@ where SYSTEM can have one of these forms:
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
+use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
@@ -378,9 +326,9 @@ eventually be run) with `--host=TYPE'.
Sharing Defaults
================
-If you want to set default values for `configure' scripts to share, you
-can create a site shell script called `config.site' that gives default
-values for variables like `CC', `cache_file', and `prefix'.
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
@@ -389,7 +337,7 @@ A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
-Variables not defined in a site shell script can be set in the
+ Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
@@ -397,18 +345,14 @@ them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script). Here is a another example:
-
- /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
-configuration-related scripts to be executed by `/bin/bash'.
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
`configure' Invocation
======================
-`configure' recognizes the following options to control how it operates.
+ `configure' recognizes the following options to control how it
+operates.
`--help'
`-h'
@@ -441,4 +385,3 @@ configuration-related scripts to be executed by `/bin/bash'.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
-
diff --git a/Makefile.am b/Makefile.am
index d351602..9dd93f1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -78,6 +78,41 @@ dist_doc_DATA += doc/index.html doc/designstyle.css
### ------- library routines, in src/base
+# This is a 'convenience library' -- it's not actually installed or anything
+LOGGING_INCLUDES = src/base/logging.h \
+ src/base/commandlineflags.h \
+ src/base/basictypes.h
+noinst_LTLIBRARIES += liblogging.la
+liblogging_la_SOURCES = src/base/logging.cc \
+ $(LOGGING_INCLUDES)
+
+# For MinGW, we use libwindows and not libspinlock. For every other
+# unix system, we use libspinlock and don't need libwindows. Luckily,
+# we need the windows.a library in exactly the same place we need
+# spinlock.a (pretty much everywhere), so we can use the same variable
+# name for each. In addition, there is a bunch of functionality in
+# libwindows that obsoletes the need for other files like
+# system_alloc.cc.
+if MINGW
+WINDOWS_INCLUDES = src/windows/port.h \
+ src/windows/mingw.h \
+ src/windows/mini_disassembler.h \
+ src/windows/mini_disassembler_types.h \
+ src/windows/preamble_patcher.h
+noinst_LTLIBRARIES += libwindows.la
+libwindows_la_SOURCES = $(WINDOWS_INCLUDES) \
+ src/windows/port.cc \
+ src/windows/ia32_modrm_map.cc \
+ src/windows/ia32_opcode_map.cc \
+ src/windows/mini_disassembler.cc \
+ src/windows/patch_functions.cc \
+ src/windows/preamble_patcher.cc \
+ src/windows/preamble_patcher_with_stub.cc
+LIBSPINLOCK = libwindows.la
+
+MAYBE_THREADS_CC =
+SYSTEM_ALLOC_CC =
+else
# spinlock is the only code that uses atomicops.
SPINLOCK_INCLUDES = src/base/spinlock.h \
src/base/atomicops.h \
@@ -85,18 +120,15 @@ SPINLOCK_INCLUDES = src/base/spinlock.h \
src/base/atomicops-internals-x86-msvc.h \
src/base/atomicops-internals-x86.h
-# This is a 'convenience library' -- it's not actually installed or anything
noinst_LTLIBRARIES += libspinlock.la
libspinlock_la_SOURCES = src/base/spinlock.cc \
src/base/atomicops-internals-x86.cc \
$(SPINLOCK_INCLUDES)
+LIBSPINLOCK = libspinlock.la
-LOGGING_INCLUDES = src/base/logging.h \
- src/base/commandlineflags.h \
- src/base/basictypes.h
-noinst_LTLIBRARIES += liblogging.la
-liblogging_la_SOURCES = src/base/logging.cc \
- $(LOGGING_INCLUDES)
+MAYBE_THREADS_CC = src/maybe_threads.cc
+SYSTEM_ALLOC_CC = src/system-alloc.cc
+endif
### Unittests
TESTS += low_level_alloc_unittest
@@ -110,8 +142,9 @@ low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \
src/malloc_hook.cc \
src/tests/low_level_alloc_unittest.cc \
$(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES)
-low_level_alloc_unittest_LDADD = libspinlock.la liblogging.la libstacktrace.la
+low_level_alloc_unittest_LDADD = $(LIBSPINLOCK) liblogging.la libstacktrace.la
+if !MINGW
TESTS += atomicops_unittest
ATOMICOPS_UNITTEST_INCLUDES = src/base/atomicops.h \
src/base/atomicops-internals-macosx.h \
@@ -120,7 +153,8 @@ ATOMICOPS_UNITTEST_INCLUDES = src/base/atomicops.h \
$(LOGGING_INCLUDES)
atomicops_unittest_SOURCES = src/tests/atomicops_unittest.cc \
$(ATOMICOPS_UNITTEST_INCLUDES)
-atomicops_unittest_LDADD = libspinlock.la liblogging.la
+atomicops_unittest_LDADD = $(LIBSPINLOCK) liblogging.la
+endif !MINGW
### ------- stack trace
@@ -141,11 +175,12 @@ libstacktrace_la_SOURCES = src/stacktrace.cc \
$(STACKTRACE_INCLUDES)
# TODO(csilvers): only add these two things when stacktrace.cc would
# #include "stacktrace_libunwind-inl.h"
-libstacktrace_la_LIBADD = $(UNWIND_LIBS) libspinlock.la
+libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK)
STACKTRACE_SYMBOLS = '(GetStackTrace)'
libstacktrace_la_LDFLAGS = -export-symbols-regex $(STACKTRACE_SYMBOLS)
### Unittests
+#if !MINGW
TESTS += stacktrace_unittest
STACKTRACE_UNITTEST_INLCUDES = src/config_for_unittests.h \
src/base/commandlineflags.h \
@@ -154,6 +189,7 @@ STACKTRACE_UNITTEST_INLCUDES = src/config_for_unittests.h \
stacktrace_unittest_SOURCES = src/tests/stacktrace_unittest.cc \
$(STACKTRACE_UNITTEST_INLCUDES)
stacktrace_unittest_LDADD = libstacktrace.la liblogging.la
+#endif !MINGW
### Documentation
dist_doc_DATA +=
@@ -164,12 +200,15 @@ dist_doc_DATA +=
bin_SCRIPTS = src/pprof
### Unittests
+
+if !MINGW
check_SCRIPTS = pprof_unittest
pprof_unittest: $(top_srcdir)/src/pprof
$(top_srcdir)/src/pprof -test
# Let unittests find pprof if they need to run it
TESTS_ENVIRONMENT += PPROF_PATH=$(top_srcdir)/src/pprof
+endif !MINGW
### Documentation
dist_man_MANS = doc/pprof.1
@@ -197,17 +236,17 @@ googleinclude_HEADERS += $(SG_TCMALLOC_MINIMAL_INCLUDES)
lib_LTLIBRARIES += libtcmalloc_minimal.la
WINDOWS_PROJECTS += vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
libtcmalloc_minimal_la_SOURCES = src/internal_logging.cc \
- src/system-alloc.cc \
+ $(SYSTEM_ALLOC_CC) \
src/memfs_malloc.cc \
src/tcmalloc.cc \
src/malloc_hook.cc \
src/malloc_extension.cc \
- src/maybe_threads.cc \
+ $(MAYBE_THREADS_CC) \
$(TCMALLOC_MINIMAL_INCLUDES)
libtcmalloc_minimal_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS)
libtcmalloc_minimal_la_LIBADD = $(PTHREAD_LIBS) \
- libstacktrace.la libspinlock.la liblogging.la
+ libstacktrace.la $(LIBSPINLOCK) liblogging.la
# Whenever we link in tcmalloc_minimal, we also need to link in
# libstacktrace.so (we also need libspinlock and liblogging, but those
@@ -233,23 +272,12 @@ LIBTCMALLOC_MINIMAL = libstacktrace.la libtcmalloc_minimal.la
## malloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
## src/malloc_hook.cc \
## src/malloc_extension.cc \
-## src/maybe_threads.cc \
+## $(MAYBE_THREADS_CC) \
## $(MALLOC_UNITTEST_INCLUDES)
## malloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
## malloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
## malloc_unittest_LDADD = $(PTHREAD_LIBS)
-TESTS += tcmalloc_unittest
-TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \
- src/google/malloc_extension.h
-tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
- src/tcmalloc.h \
- src/tests/testutil.h src/tests/testutil.cc \
- $(TCMALLOC_UNITTEST_INCLUDES)
-tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
-
TESTS += tcmalloc_minimal_unittest
WINDOWS_PROJECTS += vsprojects/tcmalloc_minimal_unittest/tcmalloc_minimal_unittest.vcproj
WINDOWS_PROJECTS += vsprojects/tcmalloc_minimal_unittest-static/tcmalloc_minimal_unittest-static.vcproj
@@ -261,23 +289,6 @@ tcmalloc_minimal_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
tcmalloc_minimal_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) \
liblogging.la $(PTHREAD_LIBS)
-# This makes sure it's safe to link in both tcmalloc and tcmalloc_minimal.
-# (One would never do this on purpose, but perhaps by accident...)
-TESTS += tcmalloc_both_unittest
-tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
- src/tests/testutil.h src/tests/testutil.cc \
- $(TCMALLOC_UNITTEST_INCLUDES)
-tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
- liblogging.la $(PTHREAD_LIBS)
-
-TESTS += tcmalloc_large_unittest
-tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
-tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
-
TESTS += tcmalloc_minimal_large_unittest
WINDOWS_PROJECTS += vsprojects/tcmalloc_minimal_large/tcmalloc_minimal_large_unittest.vcproj
tcmalloc_minimal_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
@@ -291,11 +302,24 @@ maybe_threads_unittest_sh_SOURCES = src/tests/maybe_threads_unittest.sh
noinst_SCRIPTS += $(maybe_threads_unittest_sh_SOURCES)
# This script preloads libtcmalloc, and calls two other binaries as well
maybe_threads_unittest.sh$(EXEEXT): $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) \
- $(LIBTCMALLOC) \
- low_level_alloc_unittest profiler1_unittest
+ $(LIBTCMALLOC_MINIMAL) \
+ low_level_alloc_unittest
rm -f $@
cp -p $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) $@
+# These all tests components of tcmalloc_minimal
+
+TESTS += addressmap_unittest
+WINDOWS_PROJECTS += vsprojects/addressmap_unittest/addressmap_unittest.vcproj
+ADDRESSMAP_UNITTEST_INCLUDES = src/addressmap-inl.h \
+ src/base/commandlineflags.h \
+ $(LOGGING_INCLUDES)
+addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc \
+ $(ADDRESSMAP_UNITTEST_INCLUDES)
+addressmap_unittest_CXXFLAGS = -g $(AM_CXXFLAGS)
+addressmap_unittest_LDADD = liblogging.la
+
+if !MINGW
TESTS += system_alloc_unittest
WINDOWS_PROJECTS += vsprojects/system_alloc_unittest/system_alloc_unittest.vcproj
system_alloc_unittest_SOURCES = src/config_for_unittests.h \
@@ -303,6 +327,7 @@ system_alloc_unittest_SOURCES = src/config_for_unittests.h \
system_alloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
system_alloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
system_alloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+endif !MINGW
TESTS += packed_cache_test
WINDOWS_PROJECTS += vsprojects/packed-cache_test/packed-cache_test.vcproj
@@ -310,29 +335,6 @@ packed_cache_test_SOURCES = src/tests/packed-cache_test.cc \
src/packed-cache-inl.h \
src/base/logging.h
-# performance/unittests originally from ptmalloc2
-# Commented out for now because they don't compile on all systems.
-# However, you can still make/run by hand like so:
-# make ptmalloc_unittest1 ptmalloc_unittest2
-# ./ptmalloc_unittest1; ./ptmalloc_unittest2
-##TESTS += ptmalloc_unittest1 ptmalloc_unittest2
-EXTRA_PROGRAMS = ptmalloc_unittest1 ptmalloc_unittest2
-PTMALLOC_UNITTEST_INCLUDES = src/tests/ptmalloc/t-test.h \
- src/tests/ptmalloc/thread-m.h \
- src/tests/ptmalloc/lran2.h \
- src/tests/ptmalloc/thread-st.h \
- src/tests/ptmalloc/malloc-machine.h
-ptmalloc_unittest1_SOURCES = src/tests/ptmalloc/t-test1.c \
- $(PTMALLOC_UNITTEST_INCLUDES)
-ptmalloc_unittest1_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
-ptmalloc_unittest1_LDFLAGS = $(PTHREAD_CFLAGS)
-ptmalloc_unittest1_LDADD = $(PTHREAD_LIBS)
-ptmalloc_unittest2_SOURCES = src/tests/ptmalloc/t-test2.c \
- $(PTMALLOC_UNITTEST_INCLUDES)
-ptmalloc_unittest2_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
-ptmalloc_unittest2_LDFLAGS = $(PTHREAD_CFLAGS)
-ptmalloc_unittest2_LDADD = $(PTHREAD_LIBS)
-
TESTS += frag_unittest
WINDOWS_PROJECTS += vsprojects/frag_unittest/frag_unittest.vcproj
frag_unittest_SOURCES = src/tests/frag_unittest.cc src/config_for_unittests.h
@@ -367,6 +369,29 @@ thread_dealloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
thread_dealloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+# performance/unittests originally from ptmalloc2
+# Commented out for now because they don't compile on all systems.
+# However, you can still make/run by hand like so:
+# make ptmalloc_unittest1 ptmalloc_unittest2
+# ./ptmalloc_unittest1; ./ptmalloc_unittest2
+##TESTS += ptmalloc_unittest1 ptmalloc_unittest2
+EXTRA_PROGRAMS = ptmalloc_unittest1 ptmalloc_unittest2
+PTMALLOC_UNITTEST_INCLUDES = src/tests/ptmalloc/t-test.h \
+ src/tests/ptmalloc/thread-m.h \
+ src/tests/ptmalloc/lran2.h \
+ src/tests/ptmalloc/thread-st.h \
+ src/tests/ptmalloc/malloc-machine.h
+ptmalloc_unittest1_SOURCES = src/tests/ptmalloc/t-test1.c \
+ $(PTMALLOC_UNITTEST_INCLUDES)
+ptmalloc_unittest1_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
+ptmalloc_unittest1_LDFLAGS = $(PTHREAD_CFLAGS)
+ptmalloc_unittest1_LDADD = $(PTHREAD_LIBS)
+ptmalloc_unittest2_SOURCES = src/tests/ptmalloc/t-test2.c \
+ $(PTMALLOC_UNITTEST_INCLUDES)
+ptmalloc_unittest2_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
+ptmalloc_unittest2_LDFLAGS = $(PTHREAD_CFLAGS)
+ptmalloc_unittest2_LDADD = $(PTHREAD_LIBS)
+
### Documentation
dist_doc_DATA += doc/tcmalloc.html \
doc/overview.gif \
@@ -407,6 +432,9 @@ dist_doc_DATA += doc/overview.dot \
### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker)
+# The full tcmalloc does not work on windows yet
+if !MINGW
+
### The header files we use. We divide into categories based on directory
S_TCMALLOC_INCLUDES = src/internal_logging.h \
src/system-alloc.h \
@@ -438,12 +466,12 @@ googleinclude_HEADERS += $(SG_TCMALLOC_INCLUDES)
lib_LTLIBRARIES += libtcmalloc.la
# Note: heap-checker-bcad is last, in hopes its global ctor will run first
libtcmalloc_la_SOURCES = src/internal_logging.cc \
- src/system-alloc.cc \
+ $(SYSTEM_ALLOC_CC) \
src/memfs_malloc.cc \
src/tcmalloc.cc \
src/malloc_hook.cc \
src/malloc_extension.cc \
- src/maybe_threads.cc \
+ $(MAYBE_THREADS_CC) \
src/memory_region_map.cc \
src/heap-profiler.cc \
src/heap-profile-table.cc \
@@ -457,7 +485,7 @@ libtcmalloc_la_SOURCES = src/internal_logging.cc \
libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
libtcmalloc_la_LIBADD = $(PTHREAD_LIBS) \
- libstacktrace.la libspinlock.la liblogging.la
+ libstacktrace.la $(LIBSPINLOCK) liblogging.la
# See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this.
# Basically it's to work around systems where --rpath doesn't work right.
@@ -467,18 +495,37 @@ LIBTCMALLOC = libstacktrace.la libtcmalloc.la
### Unittests
+TESTS += tcmalloc_unittest
+TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \
+ src/google/malloc_extension.h
+tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
+ src/tcmalloc.h \
+ src/tests/testutil.h src/tests/testutil.cc \
+ $(TCMALLOC_UNITTEST_INCLUDES)
+tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
+
+# This makes sure it's safe to link in both tcmalloc and tcmalloc_minimal.
+# (One would never do this on purpose, but perhaps by accident...)
+TESTS += tcmalloc_both_unittest
+tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
+ src/tests/testutil.h src/tests/testutil.cc \
+ $(TCMALLOC_UNITTEST_INCLUDES)
+tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+ liblogging.la $(PTHREAD_LIBS)
+
+TESTS += tcmalloc_large_unittest
+tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
+tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+
# These unittests often need to run binaries. They're in the current dir
TESTS_ENVIRONMENT += BINDIR=.
-
-TESTS += addressmap_unittest
-WINDOWS_PROJECTS += vsprojects/addressmap_unittest/addressmap_unittest.vcproj
-ADDRESSMAP_UNITTEST_INCLUDES = src/addressmap-inl.h \
- src/base/commandlineflags.h \
- $(LOGGING_INCLUDES)
-addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc \
- $(ADDRESSMAP_UNITTEST_INCLUDES)
-addressmap_unittest_CXXFLAGS = -g $(AM_CXXFLAGS)
-addressmap_unittest_LDADD = liblogging.la
+TESTS_ENVIRONMENT += TMPDIR=/tmp/perftools
TESTS += heap-profiler_unittest.sh
heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh
@@ -534,11 +581,16 @@ dist_doc_DATA += doc/heapprofile.html \
doc/heap-example1.png \
doc/heap_checker.html
+endif !MINGW
### ------- CPU profiler
+# The CPU profiler doesn't work on windows yet
+if !MINGW
+
### The header files we use. We divide into categories based on directory
-S_CPU_PROFILER_INCLUDES = src/getpc.h \
+S_CPU_PROFILER_INCLUDES = src/profiledata.h \
+ src/getpc.h \
src/base/basictypes.h \
src/base/commandlineflags.h \
src/base/googleinit.h \
@@ -555,10 +607,12 @@ googleinclude_HEADERS += $(SG_CPU_PROFILER_INCLUDES)
### Making the library
lib_LTLIBRARIES += libprofiler.la
libprofiler_la_SOURCES = src/profiler.cc \
+ src/profiledata.cc \
src/base/sysinfo.cc \
$(CPU_PROFILER_INCLUDES)
-libprofiler_la_LIBADD = libspinlock.la liblogging.la libstacktrace.la
-CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStop|ProfilerEnable|ProfilerDisable|ProfilerFlush|ProfilerRegisterThread|ProfilerThreadState)'
+libprofiler_la_LIBADD = $(LIBSPINLOCK) liblogging.la libstacktrace.la
+# We have to include ProfileData for profiledata_unittest
+CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStop|ProfilerEnable|ProfilerDisable|ProfilerFlush|ProfilerRegisterThread|ProfilerThreadState|ProfileData)'
libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS)
# See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this.
@@ -570,6 +624,15 @@ TESTS += getpc_test
#WINDOWS_PROJECTS += vsprojects/getpc_test/getpc_test.vcproj
getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h
+TESTS += profiledata_unittest
+#WINDOWS_PROJECTS += vsprojects/profiledata_unittest/profiledata_unittest.vcproj
+profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \
+ src/profiledata.h \
+ src/base/commandlineflags.h \
+ src/base/logging.h \
+ src/base/basictypes.h
+profiledata_unittest_LDADD = -lprofiler
+
TESTS += profiler_unittest.sh
profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh
noinst_SCRIPTS += $(profiler_unittest_sh_SOURCES)
@@ -614,6 +677,8 @@ dist_doc_DATA += doc/cpuprofile.html \
doc/pprof-vsnprintf-big.gif \
doc/pprof-vsnprintf.gif
+endif !MINGW
+
## ^^^^ END OF RULES TO MAKE YOUR LIBRARIES, BINARIES, AND UNITTESTS
@@ -638,4 +703,5 @@ dist-hook:
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
$(SCRIPTS) libtool \
- src/windows $(WINDOWS_PROJECTS) src/solaris/libstdc++.la
+ src/windows/config.h src/windows/vc7and8.def $(WINDOWS_PROJECTS) \
+ src/solaris/libstdc++.la
diff --git a/Makefile.in b/Makefile.in
index 2c44355..0c0e850 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -44,6 +44,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+target_triplet = @target@
# These are good warnings to turn on by default,
@GCC_TRUE@am__append_1 = -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
@@ -51,14 +52,65 @@ host_triplet = @host@
# These are x86-specific, having to do with frame-pointers
@ENABLE_FRAME_POINTER_TRUE@@X86_64_TRUE@am__append_2 = -fno-omit-frame-pointer
@ENABLE_FRAME_POINTER_FALSE@@X86_64_TRUE@am__append_3 = -DNO_FRAME_POINTER
-noinst_PROGRAMS = heap-profiler_unittest$(EXEEXT) \
- heap-checker_unittest$(EXEEXT) profiler1_unittest$(EXEEXT) \
- profiler2_unittest$(EXEEXT) profiler3_unittest$(EXEEXT) \
- profiler4_unittest$(EXEEXT) $(am__EXEEXT_1)
+noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_5)
+@MINGW_TRUE@am__append_4 = libwindows.la
+@MINGW_FALSE@am__append_5 = libspinlock.la
+@MINGW_FALSE@am__append_6 = atomicops_unittest
+
+# Let unittests find pprof if they need to run it
+
+# These unittests often need to run binaries. They're in the current dir
+@MINGW_FALSE@am__append_7 = PPROF_PATH=$(top_srcdir)/src/pprof \
+@MINGW_FALSE@ BINDIR=. TMPDIR=/tmp/perftools
+@MINGW_FALSE@am__append_8 = system_alloc_unittest
+@MINGW_FALSE@am__append_9 = vsprojects/system_alloc_unittest/system_alloc_unittest.vcproj
EXTRA_PROGRAMS = ptmalloc_unittest1$(EXEEXT) \
ptmalloc_unittest2$(EXEEXT)
-DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
- $(dist_man_MANS) $(googleinclude_HEADERS) \
+@MINGW_FALSE@am__append_10 = $(SG_TCMALLOC_INCLUDES) \
+@MINGW_FALSE@ $(SG_CPU_PROFILER_INCLUDES)
+
+### Making the library
+
+### Making the library
+@MINGW_FALSE@am__append_11 = libtcmalloc.la libprofiler.la
+
+### Unittests
+
+# This makes sure it's safe to link in both tcmalloc and tcmalloc_minimal.
+# (One would never do this on purpose, but perhaps by accident...)
+
+### Unittests
+@MINGW_FALSE@am__append_12 = tcmalloc_unittest tcmalloc_both_unittest \
+@MINGW_FALSE@ tcmalloc_large_unittest heap-profiler_unittest.sh \
+@MINGW_FALSE@ heap-checker_unittest.sh \
+@MINGW_FALSE@ heap-checker-death_unittest.sh getpc_test \
+@MINGW_FALSE@ profiledata_unittest profiler_unittest.sh
+@MINGW_FALSE@am__append_13 = $(heap_profiler_unittest_sh_SOURCES) \
+@MINGW_FALSE@ $(heap_checker_unittest_sh_SOURCES) \
+@MINGW_FALSE@ $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) \
+@MINGW_FALSE@ $(profiler_unittest_sh_SOURCES)
+
+# These are sub-programs used by heap-profiler_unittest.sh
+
+# These are sub-programs used by heap-checker_unittest.sh
+
+# These are sub-programs used by profiler_unittest.sh
+@MINGW_FALSE@am__append_14 = heap-profiler_unittest \
+@MINGW_FALSE@ heap-checker_unittest profiler1_unittest \
+@MINGW_FALSE@ profiler2_unittest profiler3_unittest \
+@MINGW_FALSE@ profiler4_unittest
+
+### Documentation (above and beyond tcmalloc_minimal documentation)
+
+### Documentation
+@MINGW_FALSE@am__append_15 = doc/heapprofile.html \
+@MINGW_FALSE@ doc/heap-example1.png doc/heap_checker.html \
+@MINGW_FALSE@ doc/cpuprofile.html doc/pprof-test-big.gif \
+@MINGW_FALSE@ doc/pprof-test.gif doc/pprof-vsnprintf-big.gif \
+@MINGW_FALSE@ doc/pprof-vsnprintf.gif
+@MINGW_TRUE@profiler2_unittest_DEPENDENCIES =
+DIST_COMMON = README $(am__configure_deps) $(am__dist_doc_DATA_DIST) \
+ $(am__googleinclude_HEADERS_DIST) $(dist_man_MANS) \
$(srcdir)/Makefile.am $(srcdir)/Makefile.in \
$(top_srcdir)/configure $(top_srcdir)/src/config.h.in AUTHORS \
COPYING ChangeLog INSTALL NEWS TODO compile config.guess \
@@ -95,119 +147,236 @@ liblogging_la_LIBADD =
am__objects_1 =
am_liblogging_la_OBJECTS = logging.lo $(am__objects_1)
liblogging_la_OBJECTS = $(am_liblogging_la_OBJECTS)
-libprofiler_la_DEPENDENCIES = libspinlock.la liblogging.la \
- libstacktrace.la
-am__objects_2 = $(am__objects_1) $(am__objects_1)
-am__objects_3 = $(am__objects_2) $(am__objects_1)
-am_libprofiler_la_OBJECTS = profiler.lo sysinfo.lo $(am__objects_3)
+@MINGW_FALSE@am__DEPENDENCIES_1 = libspinlock.la
+@MINGW_TRUE@am__DEPENDENCIES_1 = libwindows.la
+@MINGW_FALSE@libprofiler_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@MINGW_FALSE@ liblogging.la libstacktrace.la
+am__libprofiler_la_SOURCES_DIST = src/profiler.cc src/profiledata.cc \
+ src/base/sysinfo.cc src/profiledata.h src/getpc.h \
+ src/base/basictypes.h src/base/commandlineflags.h \
+ src/base/googleinit.h src/base/logging.h src/base/mutex.h \
+ src/base/sysinfo.h src/base/spinlock.h src/base/atomicops.h \
+ src/base/atomicops-internals-macosx.h \
+ src/base/atomicops-internals-x86-msvc.h \
+ src/base/atomicops-internals-x86.h src/google/profiler.h \
+ src/google/stacktrace.h
+@MINGW_FALSE@am__objects_2 = $(am__objects_1) $(am__objects_1)
+@MINGW_FALSE@am__objects_3 = $(am__objects_2) $(am__objects_1)
+@MINGW_FALSE@am_libprofiler_la_OBJECTS = profiler.lo profiledata.lo \
+@MINGW_FALSE@ sysinfo.lo $(am__objects_3)
libprofiler_la_OBJECTS = $(am_libprofiler_la_OBJECTS)
+@MINGW_FALSE@am_libprofiler_la_rpath = -rpath $(libdir)
libspinlock_la_LIBADD =
-am_libspinlock_la_OBJECTS = spinlock.lo atomicops-internals-x86.lo \
- $(am__objects_1)
+am__libspinlock_la_SOURCES_DIST = src/base/spinlock.cc \
+ src/base/atomicops-internals-x86.cc src/base/spinlock.h \
+ src/base/atomicops.h src/base/atomicops-internals-macosx.h \
+ src/base/atomicops-internals-x86-msvc.h \
+ src/base/atomicops-internals-x86.h
+@MINGW_FALSE@am_libspinlock_la_OBJECTS = spinlock.lo \
+@MINGW_FALSE@ atomicops-internals-x86.lo $(am__objects_1)
libspinlock_la_OBJECTS = $(am_libspinlock_la_OBJECTS)
-am__DEPENDENCIES_1 =
-libstacktrace_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libspinlock.la
-am_libstacktrace_la_OBJECTS = stacktrace.lo $(am__objects_2)
+@MINGW_FALSE@am_libspinlock_la_rpath =
+am__DEPENDENCIES_2 =
+libstacktrace_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
+am__objects_4 = $(am__objects_1) $(am__objects_1)
+am_libstacktrace_la_OBJECTS = stacktrace.lo $(am__objects_4)
libstacktrace_la_OBJECTS = $(am_libstacktrace_la_OBJECTS)
-libtcmalloc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libstacktrace.la \
- libspinlock.la liblogging.la
-am_libtcmalloc_la_OBJECTS = libtcmalloc_la-internal_logging.lo \
- libtcmalloc_la-system-alloc.lo libtcmalloc_la-memfs_malloc.lo \
- libtcmalloc_la-tcmalloc.lo libtcmalloc_la-malloc_hook.lo \
- libtcmalloc_la-malloc_extension.lo \
- libtcmalloc_la-maybe_threads.lo \
- libtcmalloc_la-memory_region_map.lo \
- libtcmalloc_la-heap-profiler.lo \
- libtcmalloc_la-heap-profile-table.lo \
- libtcmalloc_la-heap-checker.lo linuxthreads.lo \
- thread_lister.lo libtcmalloc_la-sysinfo.lo \
- libtcmalloc_la-low_level_alloc.lo $(am__objects_3) \
- libtcmalloc_la-heap-checker-bcad.lo
+@MINGW_FALSE@libtcmalloc_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+@MINGW_FALSE@ libstacktrace.la $(am__DEPENDENCIES_1) \
+@MINGW_FALSE@ liblogging.la
+am__libtcmalloc_la_SOURCES_DIST = src/internal_logging.cc \
+ src/system-alloc.cc src/memfs_malloc.cc src/tcmalloc.cc \
+ src/malloc_hook.cc src/malloc_extension.cc \
+ src/maybe_threads.cc src/memory_region_map.cc \
+ src/heap-profiler.cc src/heap-profile-table.cc \
+ src/heap-checker.cc src/base/linuxthreads.c \
+ src/base/thread_lister.c src/base/sysinfo.cc \
+ src/base/low_level_alloc.cc src/internal_logging.h \
+ src/system-alloc.h src/pagemap.h src/addressmap-inl.h \
+ src/packed-cache-inl.h src/heap-profile-table.h \
+ src/base/basictypes.h src/base/commandlineflags.h \
+ src/base/googleinit.h src/base/elfcore.h \
+ src/base/linux_syscall_support.h src/base/linuxthreads.h \
+ src/base/thread_lister.h src/base/sysinfo.h \
+ src/base/stl_allocator.h src/maybe_threads.h \
+ src/base/spinlock.h src/base/atomicops.h \
+ src/base/atomicops-internals-macosx.h \
+ src/base/atomicops-internals-x86-msvc.h \
+ src/base/atomicops-internals-x86.h src/base/logging.h \
+ src/google/malloc_hook.h src/google/malloc_extension.h \
+ src/google/heap-profiler.h src/google/heap-checker.h \
+ src/google/stacktrace.h src/heap-checker-bcad.cc
+@MINGW_FALSE@am__objects_5 = libtcmalloc_la-system-alloc.lo
+@MINGW_FALSE@am__objects_6 = libtcmalloc_la-maybe_threads.lo
+@MINGW_FALSE@am_libtcmalloc_la_OBJECTS = \
+@MINGW_FALSE@ libtcmalloc_la-internal_logging.lo \
+@MINGW_FALSE@ $(am__objects_5) libtcmalloc_la-memfs_malloc.lo \
+@MINGW_FALSE@ libtcmalloc_la-tcmalloc.lo \
+@MINGW_FALSE@ libtcmalloc_la-malloc_hook.lo \
+@MINGW_FALSE@ libtcmalloc_la-malloc_extension.lo \
+@MINGW_FALSE@ $(am__objects_6) \
+@MINGW_FALSE@ libtcmalloc_la-memory_region_map.lo \
+@MINGW_FALSE@ libtcmalloc_la-heap-profiler.lo \
+@MINGW_FALSE@ libtcmalloc_la-heap-profile-table.lo \
+@MINGW_FALSE@ libtcmalloc_la-heap-checker.lo linuxthreads.lo \
+@MINGW_FALSE@ thread_lister.lo libtcmalloc_la-sysinfo.lo \
+@MINGW_FALSE@ libtcmalloc_la-low_level_alloc.lo \
+@MINGW_FALSE@ $(am__objects_3) \
+@MINGW_FALSE@ libtcmalloc_la-heap-checker-bcad.lo
libtcmalloc_la_OBJECTS = $(am_libtcmalloc_la_OBJECTS)
-libtcmalloc_minimal_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
- libstacktrace.la libspinlock.la liblogging.la
-am__objects_4 = $(am__objects_1)
-am__objects_5 = $(am__objects_4) $(am__objects_1)
+@MINGW_FALSE@am_libtcmalloc_la_rpath = -rpath $(libdir)
+libtcmalloc_minimal_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ libstacktrace.la $(am__DEPENDENCIES_1) liblogging.la
+am__libtcmalloc_minimal_la_SOURCES_DIST = src/internal_logging.cc \
+ src/system-alloc.cc src/memfs_malloc.cc src/tcmalloc.cc \
+ src/malloc_hook.cc src/malloc_extension.cc \
+ src/maybe_threads.cc src/internal_logging.h src/system-alloc.h \
+ src/packed-cache-inl.h src/base/spinlock.h \
+ src/base/atomicops.h src/base/atomicops-internals-macosx.h \
+ src/base/atomicops-internals-x86-msvc.h \
+ src/base/atomicops-internals-x86.h src/base/commandlineflags.h \
+ src/base/basictypes.h src/pagemap.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_extension.h \
+ src/google/stacktrace.h
+@MINGW_FALSE@am__objects_7 = libtcmalloc_minimal_la-system-alloc.lo
+@MINGW_FALSE@am__objects_8 = libtcmalloc_minimal_la-maybe_threads.lo
+am__objects_9 = $(am__objects_1)
+am__objects_10 = $(am__objects_9) $(am__objects_1)
am_libtcmalloc_minimal_la_OBJECTS = \
- libtcmalloc_minimal_la-internal_logging.lo \
- libtcmalloc_minimal_la-system-alloc.lo \
+ libtcmalloc_minimal_la-internal_logging.lo $(am__objects_7) \
libtcmalloc_minimal_la-memfs_malloc.lo \
libtcmalloc_minimal_la-tcmalloc.lo \
libtcmalloc_minimal_la-malloc_hook.lo \
- libtcmalloc_minimal_la-malloc_extension.lo \
- libtcmalloc_minimal_la-maybe_threads.lo $(am__objects_5)
+ libtcmalloc_minimal_la-malloc_extension.lo $(am__objects_8) \
+ $(am__objects_10)
libtcmalloc_minimal_la_OBJECTS = $(am_libtcmalloc_minimal_la_OBJECTS)
-am__EXEEXT_1 = low_level_alloc_unittest$(EXEEXT) \
- atomicops_unittest$(EXEEXT) stacktrace_unittest$(EXEEXT) \
- tcmalloc_unittest$(EXEEXT) tcmalloc_minimal_unittest$(EXEEXT) \
- tcmalloc_both_unittest$(EXEEXT) \
- tcmalloc_large_unittest$(EXEEXT) \
+libwindows_la_LIBADD =
+am__libwindows_la_SOURCES_DIST = src/windows/port.h \
+ src/windows/mingw.h src/windows/mini_disassembler.h \
+ src/windows/mini_disassembler_types.h \
+ src/windows/preamble_patcher.h src/windows/port.cc \
+ src/windows/ia32_modrm_map.cc src/windows/ia32_opcode_map.cc \
+ src/windows/mini_disassembler.cc \
+ src/windows/patch_functions.cc src/windows/preamble_patcher.cc \
+ src/windows/preamble_patcher_with_stub.cc
+@MINGW_TRUE@am_libwindows_la_OBJECTS = $(am__objects_1) port.lo \
+@MINGW_TRUE@ ia32_modrm_map.lo ia32_opcode_map.lo \
+@MINGW_TRUE@ mini_disassembler.lo patch_functions.lo \
+@MINGW_TRUE@ preamble_patcher.lo preamble_patcher_with_stub.lo
+libwindows_la_OBJECTS = $(am_libwindows_la_OBJECTS)
+@MINGW_TRUE@am_libwindows_la_rpath =
+@MINGW_FALSE@am__EXEEXT_1 = heap-profiler_unittest$(EXEEXT) \
+@MINGW_FALSE@ heap-checker_unittest$(EXEEXT) \
+@MINGW_FALSE@ profiler1_unittest$(EXEEXT) \
+@MINGW_FALSE@ profiler2_unittest$(EXEEXT) \
+@MINGW_FALSE@ profiler3_unittest$(EXEEXT) \
+@MINGW_FALSE@ profiler4_unittest$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_2 = atomicops_unittest$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_3 = system_alloc_unittest$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_4 = tcmalloc_unittest$(EXEEXT) \
+@MINGW_FALSE@ tcmalloc_both_unittest$(EXEEXT) \
+@MINGW_FALSE@ tcmalloc_large_unittest$(EXEEXT) \
+@MINGW_FALSE@ heap-profiler_unittest.sh$(EXEEXT) \
+@MINGW_FALSE@ heap-checker_unittest.sh$(EXEEXT) \
+@MINGW_FALSE@ heap-checker-death_unittest.sh$(EXEEXT) \
+@MINGW_FALSE@ getpc_test$(EXEEXT) profiledata_unittest$(EXEEXT) \
+@MINGW_FALSE@ profiler_unittest.sh$(EXEEXT)
+am__EXEEXT_5 = low_level_alloc_unittest$(EXEEXT) $(am__EXEEXT_2) \
+ stacktrace_unittest$(EXEEXT) \
+ tcmalloc_minimal_unittest$(EXEEXT) \
tcmalloc_minimal_large_unittest$(EXEEXT) \
maybe_threads_unittest.sh$(EXEEXT) \
- system_alloc_unittest$(EXEEXT) packed_cache_test$(EXEEXT) \
- frag_unittest$(EXEEXT) markidle_unittest$(EXEEXT) \
- memalign_unittest$(EXEEXT) thread_dealloc_unittest$(EXEEXT) \
- addressmap_unittest$(EXEEXT) \
- heap-profiler_unittest.sh$(EXEEXT) \
- heap-checker_unittest.sh$(EXEEXT) \
- heap-checker-death_unittest.sh$(EXEEXT) getpc_test$(EXEEXT) \
- profiler_unittest.sh$(EXEEXT)
+ addressmap_unittest$(EXEEXT) $(am__EXEEXT_3) \
+ packed_cache_test$(EXEEXT) frag_unittest$(EXEEXT) \
+ markidle_unittest$(EXEEXT) memalign_unittest$(EXEEXT) \
+ thread_dealloc_unittest$(EXEEXT) $(am__EXEEXT_4)
PROGRAMS = $(noinst_PROGRAMS)
am_addressmap_unittest_OBJECTS = \
addressmap_unittest-addressmap_unittest.$(OBJEXT) \
- $(am__objects_4)
+ $(am__objects_9)
addressmap_unittest_OBJECTS = $(am_addressmap_unittest_OBJECTS)
addressmap_unittest_DEPENDENCIES = liblogging.la
-am_atomicops_unittest_OBJECTS = atomicops_unittest.$(OBJEXT) \
- $(am__objects_4)
+am__atomicops_unittest_SOURCES_DIST = src/tests/atomicops_unittest.cc \
+ src/base/atomicops.h src/base/atomicops-internals-macosx.h \
+ src/base/atomicops-internals-x86-msvc.h \
+ src/base/atomicops-internals-x86.h src/base/logging.h \
+ src/base/commandlineflags.h src/base/basictypes.h
+@MINGW_FALSE@am__objects_11 = $(am__objects_1)
+@MINGW_FALSE@am_atomicops_unittest_OBJECTS = \
+@MINGW_FALSE@ atomicops_unittest.$(OBJEXT) $(am__objects_11)
atomicops_unittest_OBJECTS = $(am_atomicops_unittest_OBJECTS)
-atomicops_unittest_DEPENDENCIES = libspinlock.la liblogging.la
+@MINGW_FALSE@atomicops_unittest_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@MINGW_FALSE@ liblogging.la
am_frag_unittest_OBJECTS = frag_unittest-frag_unittest.$(OBJEXT)
frag_unittest_OBJECTS = $(am_frag_unittest_OBJECTS)
-am__DEPENDENCIES_2 = libstacktrace.la libtcmalloc_minimal.la
-frag_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(am__DEPENDENCIES_1)
-am_getpc_test_OBJECTS = getpc_test.$(OBJEXT)
+am__DEPENDENCIES_3 = libstacktrace.la libtcmalloc_minimal.la
+frag_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_2)
+am__getpc_test_SOURCES_DIST = src/tests/getpc_test.cc src/getpc.h
+@MINGW_FALSE@am_getpc_test_OBJECTS = getpc_test.$(OBJEXT)
getpc_test_OBJECTS = $(am_getpc_test_OBJECTS)
getpc_test_LDADD = $(LDADD)
+am__heap_checker_death_unittest_sh_SOURCES_DIST = \
+ src/tests/heap-checker-death_unittest.sh
am_heap_checker_death_unittest_sh_OBJECTS =
heap_checker_death_unittest_sh_OBJECTS = \
$(am_heap_checker_death_unittest_sh_OBJECTS)
heap_checker_death_unittest_sh_LDADD = $(LDADD)
-am_heap_checker_unittest_OBJECTS = \
- heap_checker_unittest-heap-checker_unittest.$(OBJEXT) \
- $(am__objects_4)
+am__heap_checker_unittest_SOURCES_DIST = \
+ src/tests/heap-checker_unittest.cc src/config_for_unittests.h \
+ src/memory_region_map.h src/base/commandlineflags.h \
+ src/base/googleinit.h src/google/heap-checker.h \
+ src/base/logging.h src/base/basictypes.h
+@MINGW_FALSE@am_heap_checker_unittest_OBJECTS = heap_checker_unittest-heap-checker_unittest.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_11)
heap_checker_unittest_OBJECTS = $(am_heap_checker_unittest_OBJECTS)
-am__DEPENDENCIES_3 = libstacktrace.la libtcmalloc.la
-heap_checker_unittest_DEPENDENCIES = $(am__DEPENDENCIES_1) \
- liblogging.la $(am__DEPENDENCIES_3)
+@MINGW_FALSE@am__DEPENDENCIES_4 = libstacktrace.la libtcmalloc.la
+@MINGW_FALSE@heap_checker_unittest_DEPENDENCIES = \
+@MINGW_FALSE@ $(am__DEPENDENCIES_2) liblogging.la \
+@MINGW_FALSE@ $(am__DEPENDENCIES_4)
+am__heap_checker_unittest_sh_SOURCES_DIST = \
+ src/tests/heap-checker_unittest.sh
am_heap_checker_unittest_sh_OBJECTS =
heap_checker_unittest_sh_OBJECTS = \
$(am_heap_checker_unittest_sh_OBJECTS)
heap_checker_unittest_sh_LDADD = $(LDADD)
-am_heap_profiler_unittest_OBJECTS = \
- heap_profiler_unittest-heap-profiler_unittest.$(OBJEXT) \
- $(am__objects_1)
+am__heap_profiler_unittest_SOURCES_DIST = \
+ src/tests/heap-profiler_unittest.cc src/config_for_unittests.h \
+ src/google/heap-profiler.h
+@MINGW_FALSE@am_heap_profiler_unittest_OBJECTS = heap_profiler_unittest-heap-profiler_unittest.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_1)
heap_profiler_unittest_OBJECTS = $(am_heap_profiler_unittest_OBJECTS)
-heap_profiler_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
- $(am__DEPENDENCIES_1)
+@MINGW_FALSE@heap_profiler_unittest_DEPENDENCIES = \
+@MINGW_FALSE@ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_2)
+am__heap_profiler_unittest_sh_SOURCES_DIST = \
+ src/tests/heap-profiler_unittest.sh
am_heap_profiler_unittest_sh_OBJECTS =
heap_profiler_unittest_sh_OBJECTS = \
$(am_heap_profiler_unittest_sh_OBJECTS)
heap_profiler_unittest_sh_LDADD = $(LDADD)
+am__low_level_alloc_unittest_SOURCES_DIST = \
+ src/base/low_level_alloc.cc src/malloc_hook.cc \
+ src/tests/low_level_alloc_unittest.cc \
+ src/base/low_level_alloc.h src/base/basictypes.h \
+ src/google/malloc_hook.h src/base/spinlock.h \
+ src/base/atomicops.h src/base/atomicops-internals-macosx.h \
+ src/base/atomicops-internals-x86-msvc.h \
+ src/base/atomicops-internals-x86.h src/base/logging.h \
+ src/base/commandlineflags.h
am_low_level_alloc_unittest_OBJECTS = low_level_alloc.$(OBJEXT) \
malloc_hook.$(OBJEXT) low_level_alloc_unittest.$(OBJEXT) \
- $(am__objects_2)
+ $(am__objects_4)
low_level_alloc_unittest_OBJECTS = \
$(am_low_level_alloc_unittest_OBJECTS)
-low_level_alloc_unittest_DEPENDENCIES = libspinlock.la liblogging.la \
- libstacktrace.la
+low_level_alloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ liblogging.la libstacktrace.la
am_markidle_unittest_OBJECTS = \
markidle_unittest-markidle_unittest.$(OBJEXT) \
markidle_unittest-testutil.$(OBJEXT)
markidle_unittest_OBJECTS = $(am_markidle_unittest_OBJECTS)
-markidle_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(am__DEPENDENCIES_1)
+markidle_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_2)
am_maybe_threads_unittest_sh_OBJECTS =
maybe_threads_unittest_sh_OBJECTS = \
$(am_maybe_threads_unittest_sh_OBJECTS)
@@ -215,88 +384,134 @@ maybe_threads_unittest_sh_LDADD = $(LDADD)
am_memalign_unittest_OBJECTS = \
memalign_unittest-memalign_unittest.$(OBJEXT)
memalign_unittest_OBJECTS = $(am_memalign_unittest_OBJECTS)
-memalign_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(am__DEPENDENCIES_1)
+memalign_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_2)
am_packed_cache_test_OBJECTS = packed-cache_test.$(OBJEXT)
packed_cache_test_OBJECTS = $(am_packed_cache_test_OBJECTS)
packed_cache_test_LDADD = $(LDADD)
-am__objects_6 = profiler1_unittest-profiler_unittest.$(OBJEXT) \
- profiler1_unittest-testutil.$(OBJEXT) $(am__objects_1)
-am_profiler1_unittest_OBJECTS = $(am__objects_6)
+am__profiledata_unittest_SOURCES_DIST = \
+ src/tests/profiledata_unittest.cc src/profiledata.h \
+ src/base/commandlineflags.h src/base/logging.h \
+ src/base/basictypes.h
+@MINGW_FALSE@am_profiledata_unittest_OBJECTS = \
+@MINGW_FALSE@ profiledata_unittest.$(OBJEXT)
+profiledata_unittest_OBJECTS = $(am_profiledata_unittest_OBJECTS)
+profiledata_unittest_DEPENDENCIES =
+am__profiler1_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
+ src/tests/testutil.h src/tests/testutil.cc \
+ src/config_for_unittests.h src/google/profiler.h
+@MINGW_FALSE@am__objects_12 = \
+@MINGW_FALSE@ profiler1_unittest-profiler_unittest.$(OBJEXT) \
+@MINGW_FALSE@ profiler1_unittest-testutil.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_1)
+@MINGW_FALSE@am_profiler1_unittest_OBJECTS = $(am__objects_12)
profiler1_unittest_OBJECTS = $(am_profiler1_unittest_OBJECTS)
-am__DEPENDENCIES_4 = libstacktrace.la libprofiler.la
-profiler1_unittest_DEPENDENCIES = $(am__DEPENDENCIES_4)
-am__objects_7 = profiler2_unittest-profiler_unittest.$(OBJEXT) \
- profiler2_unittest-testutil.$(OBJEXT) $(am__objects_1)
-am_profiler2_unittest_OBJECTS = $(am__objects_7)
+@MINGW_FALSE@am__DEPENDENCIES_5 = libstacktrace.la libprofiler.la
+@MINGW_FALSE@profiler1_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5)
+am__profiler2_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
+ src/tests/testutil.h src/tests/testutil.cc \
+ src/config_for_unittests.h src/google/profiler.h
+@MINGW_FALSE@am__objects_13 = \
+@MINGW_FALSE@ profiler2_unittest-profiler_unittest.$(OBJEXT) \
+@MINGW_FALSE@ profiler2_unittest-testutil.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_1)
+@MINGW_FALSE@am_profiler2_unittest_OBJECTS = $(am__objects_13)
profiler2_unittest_OBJECTS = $(am_profiler2_unittest_OBJECTS)
-am__objects_8 = profiler3_unittest-profiler_unittest.$(OBJEXT) \
- profiler3_unittest-testutil.$(OBJEXT) $(am__objects_1)
-am_profiler3_unittest_OBJECTS = $(am__objects_8)
+am__profiler3_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
+ src/tests/testutil.h src/tests/testutil.cc \
+ src/config_for_unittests.h src/google/profiler.h
+@MINGW_FALSE@am__objects_14 = \
+@MINGW_FALSE@ profiler3_unittest-profiler_unittest.$(OBJEXT) \
+@MINGW_FALSE@ profiler3_unittest-testutil.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_1)
+@MINGW_FALSE@am_profiler3_unittest_OBJECTS = $(am__objects_14)
profiler3_unittest_OBJECTS = $(am_profiler3_unittest_OBJECTS)
-profiler3_unittest_DEPENDENCIES = $(am__DEPENDENCIES_4) \
- $(am__DEPENDENCIES_1)
-am__objects_9 = profiler4_unittest-profiler_unittest.$(OBJEXT) \
- profiler4_unittest-testutil.$(OBJEXT) $(am__objects_1)
-am_profiler4_unittest_OBJECTS = $(am__objects_9)
+@MINGW_FALSE@profiler3_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \
+@MINGW_FALSE@ $(am__DEPENDENCIES_2)
+am__profiler4_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
+ src/tests/testutil.h src/tests/testutil.cc \
+ src/config_for_unittests.h src/google/profiler.h
+@MINGW_FALSE@am__objects_15 = \
+@MINGW_FALSE@ profiler4_unittest-profiler_unittest.$(OBJEXT) \
+@MINGW_FALSE@ profiler4_unittest-testutil.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_1)
+@MINGW_FALSE@am_profiler4_unittest_OBJECTS = $(am__objects_15)
profiler4_unittest_OBJECTS = $(am_profiler4_unittest_OBJECTS)
+am__profiler_unittest_sh_SOURCES_DIST = \
+ src/tests/profiler_unittest.sh
am_profiler_unittest_sh_OBJECTS =
profiler_unittest_sh_OBJECTS = $(am_profiler_unittest_sh_OBJECTS)
profiler_unittest_sh_LDADD = $(LDADD)
am_ptmalloc_unittest1_OBJECTS = ptmalloc_unittest1-t-test1.$(OBJEXT) \
$(am__objects_1)
ptmalloc_unittest1_OBJECTS = $(am_ptmalloc_unittest1_OBJECTS)
-ptmalloc_unittest1_DEPENDENCIES = $(am__DEPENDENCIES_1)
+ptmalloc_unittest1_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_ptmalloc_unittest2_OBJECTS = ptmalloc_unittest2-t-test2.$(OBJEXT) \
$(am__objects_1)
ptmalloc_unittest2_OBJECTS = $(am_ptmalloc_unittest2_OBJECTS)
-ptmalloc_unittest2_DEPENDENCIES = $(am__DEPENDENCIES_1)
+ptmalloc_unittest2_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am__objects_16 = $(am__objects_4) $(am__objects_1)
am_stacktrace_unittest_OBJECTS = stacktrace_unittest.$(OBJEXT) \
- $(am__objects_3)
+ $(am__objects_16)
stacktrace_unittest_OBJECTS = $(am_stacktrace_unittest_OBJECTS)
stacktrace_unittest_DEPENDENCIES = libstacktrace.la liblogging.la
-am_system_alloc_unittest_OBJECTS = \
- system_alloc_unittest-system-alloc_unittest.$(OBJEXT)
+am__system_alloc_unittest_SOURCES_DIST = src/config_for_unittests.h \
+ src/tests/system-alloc_unittest.cc
+@MINGW_FALSE@am_system_alloc_unittest_OBJECTS = system_alloc_unittest-system-alloc_unittest.$(OBJEXT)
system_alloc_unittest_OBJECTS = $(am_system_alloc_unittest_OBJECTS)
-system_alloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(am__DEPENDENCIES_1)
-am_tcmalloc_both_unittest_OBJECTS = \
- tcmalloc_both_unittest-tcmalloc_unittest.$(OBJEXT) \
- tcmalloc_both_unittest-testutil.$(OBJEXT) $(am__objects_1)
+@MINGW_FALSE@system_alloc_unittest_DEPENDENCIES = \
+@MINGW_FALSE@ $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2)
+am__tcmalloc_both_unittest_SOURCES_DIST = \
+ src/tests/tcmalloc_unittest.cc src/tests/testutil.h \
+ src/tests/testutil.cc src/config_for_unittests.h \
+ src/google/malloc_extension.h
+@MINGW_FALSE@am_tcmalloc_both_unittest_OBJECTS = tcmalloc_both_unittest-tcmalloc_unittest.$(OBJEXT) \
+@MINGW_FALSE@ tcmalloc_both_unittest-testutil.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_1)
tcmalloc_both_unittest_OBJECTS = $(am_tcmalloc_both_unittest_OBJECTS)
-tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
- $(am__DEPENDENCIES_2) liblogging.la $(am__DEPENDENCIES_1)
-am_tcmalloc_large_unittest_OBJECTS = \
- tcmalloc_large_unittest-tcmalloc_large_unittest.$(OBJEXT)
+@MINGW_FALSE@tcmalloc_both_unittest_DEPENDENCIES = \
+@MINGW_FALSE@ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_3) \
+@MINGW_FALSE@ liblogging.la $(am__DEPENDENCIES_2)
+am__tcmalloc_large_unittest_SOURCES_DIST = \
+ src/tests/tcmalloc_large_unittest.cc
+@MINGW_FALSE@am_tcmalloc_large_unittest_OBJECTS = tcmalloc_large_unittest-tcmalloc_large_unittest.$(OBJEXT)
tcmalloc_large_unittest_OBJECTS = \
$(am_tcmalloc_large_unittest_OBJECTS)
-tcmalloc_large_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
- $(am__DEPENDENCIES_1)
+@MINGW_FALSE@tcmalloc_large_unittest_DEPENDENCIES = \
+@MINGW_FALSE@ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_2)
am_tcmalloc_minimal_large_unittest_OBJECTS = tcmalloc_minimal_large_unittest-tcmalloc_large_unittest.$(OBJEXT)
tcmalloc_minimal_large_unittest_OBJECTS = \
$(am_tcmalloc_minimal_large_unittest_OBJECTS)
-tcmalloc_minimal_large_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(am__DEPENDENCIES_1)
+tcmalloc_minimal_large_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_2)
+am__tcmalloc_minimal_unittest_SOURCES_DIST = \
+ src/tests/tcmalloc_unittest.cc src/tests/testutil.h \
+ src/tests/testutil.cc src/config_for_unittests.h \
+ src/google/malloc_extension.h
am_tcmalloc_minimal_unittest_OBJECTS = \
tcmalloc_minimal_unittest-tcmalloc_unittest.$(OBJEXT) \
tcmalloc_minimal_unittest-testutil.$(OBJEXT) $(am__objects_1)
tcmalloc_minimal_unittest_OBJECTS = \
$(am_tcmalloc_minimal_unittest_OBJECTS)
-tcmalloc_minimal_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- liblogging.la $(am__DEPENDENCIES_1)
-am_tcmalloc_unittest_OBJECTS = \
- tcmalloc_unittest-tcmalloc_unittest.$(OBJEXT) \
- tcmalloc_unittest-testutil.$(OBJEXT) $(am__objects_1)
+tcmalloc_minimal_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ liblogging.la $(am__DEPENDENCIES_2)
+am__tcmalloc_unittest_SOURCES_DIST = src/tests/tcmalloc_unittest.cc \
+ src/tcmalloc.h src/tests/testutil.h src/tests/testutil.cc \
+ src/config_for_unittests.h src/google/malloc_extension.h
+@MINGW_FALSE@am_tcmalloc_unittest_OBJECTS = \
+@MINGW_FALSE@ tcmalloc_unittest-tcmalloc_unittest.$(OBJEXT) \
+@MINGW_FALSE@ tcmalloc_unittest-testutil.$(OBJEXT) \
+@MINGW_FALSE@ $(am__objects_1)
tcmalloc_unittest_OBJECTS = $(am_tcmalloc_unittest_OBJECTS)
-tcmalloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) liblogging.la \
- $(am__DEPENDENCIES_1)
+@MINGW_FALSE@tcmalloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_4) \
+@MINGW_FALSE@ liblogging.la $(am__DEPENDENCIES_2)
am_thread_dealloc_unittest_OBJECTS = \
thread_dealloc_unittest-thread_dealloc_unittest.$(OBJEXT) \
thread_dealloc_unittest-testutil.$(OBJEXT)
thread_dealloc_unittest_OBJECTS = \
$(am_thread_dealloc_unittest_OBJECTS)
-thread_dealloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(am__DEPENDENCIES_1)
+thread_dealloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_2)
binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
SCRIPTS = $(bin_SCRIPTS) $(noinst_SCRIPTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/src
@@ -321,8 +536,9 @@ CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \
SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \
$(libspinlock_la_SOURCES) $(libstacktrace_la_SOURCES) \
$(libtcmalloc_la_SOURCES) $(libtcmalloc_minimal_la_SOURCES) \
- $(addressmap_unittest_SOURCES) $(atomicops_unittest_SOURCES) \
- $(frag_unittest_SOURCES) $(getpc_test_SOURCES) \
+ $(libwindows_la_SOURCES) $(addressmap_unittest_SOURCES) \
+ $(atomicops_unittest_SOURCES) $(frag_unittest_SOURCES) \
+ $(getpc_test_SOURCES) \
$(heap_checker_death_unittest_sh_SOURCES) \
$(heap_checker_unittest_SOURCES) \
$(heap_checker_unittest_sh_SOURCES) \
@@ -332,10 +548,11 @@ SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \
$(markidle_unittest_SOURCES) \
$(maybe_threads_unittest_sh_SOURCES) \
$(memalign_unittest_SOURCES) $(packed_cache_test_SOURCES) \
- $(profiler1_unittest_SOURCES) $(profiler2_unittest_SOURCES) \
- $(profiler3_unittest_SOURCES) $(profiler4_unittest_SOURCES) \
- $(profiler_unittest_sh_SOURCES) $(ptmalloc_unittest1_SOURCES) \
- $(ptmalloc_unittest2_SOURCES) $(stacktrace_unittest_SOURCES) \
+ $(profiledata_unittest_SOURCES) $(profiler1_unittest_SOURCES) \
+ $(profiler2_unittest_SOURCES) $(profiler3_unittest_SOURCES) \
+ $(profiler4_unittest_SOURCES) $(profiler_unittest_sh_SOURCES) \
+ $(ptmalloc_unittest1_SOURCES) $(ptmalloc_unittest2_SOURCES) \
+ $(stacktrace_unittest_SOURCES) \
$(system_alloc_unittest_SOURCES) \
$(tcmalloc_both_unittest_SOURCES) \
$(tcmalloc_large_unittest_SOURCES) \
@@ -343,36 +560,79 @@ SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \
$(tcmalloc_minimal_unittest_SOURCES) \
$(tcmalloc_unittest_SOURCES) \
$(thread_dealloc_unittest_SOURCES)
-DIST_SOURCES = $(liblogging_la_SOURCES) $(libprofiler_la_SOURCES) \
- $(libspinlock_la_SOURCES) $(libstacktrace_la_SOURCES) \
- $(libtcmalloc_la_SOURCES) $(libtcmalloc_minimal_la_SOURCES) \
- $(addressmap_unittest_SOURCES) $(atomicops_unittest_SOURCES) \
- $(frag_unittest_SOURCES) $(getpc_test_SOURCES) \
- $(heap_checker_death_unittest_sh_SOURCES) \
- $(heap_checker_unittest_SOURCES) \
- $(heap_checker_unittest_sh_SOURCES) \
- $(heap_profiler_unittest_SOURCES) \
- $(heap_profiler_unittest_sh_SOURCES) \
- $(low_level_alloc_unittest_SOURCES) \
+DIST_SOURCES = $(liblogging_la_SOURCES) \
+ $(am__libprofiler_la_SOURCES_DIST) \
+ $(am__libspinlock_la_SOURCES_DIST) $(libstacktrace_la_SOURCES) \
+ $(am__libtcmalloc_la_SOURCES_DIST) \
+ $(am__libtcmalloc_minimal_la_SOURCES_DIST) \
+ $(am__libwindows_la_SOURCES_DIST) \
+ $(addressmap_unittest_SOURCES) \
+ $(am__atomicops_unittest_SOURCES_DIST) \
+ $(frag_unittest_SOURCES) $(am__getpc_test_SOURCES_DIST) \
+ $(am__heap_checker_death_unittest_sh_SOURCES_DIST) \
+ $(am__heap_checker_unittest_SOURCES_DIST) \
+ $(am__heap_checker_unittest_sh_SOURCES_DIST) \
+ $(am__heap_profiler_unittest_SOURCES_DIST) \
+ $(am__heap_profiler_unittest_sh_SOURCES_DIST) \
+ $(am__low_level_alloc_unittest_SOURCES_DIST) \
$(markidle_unittest_SOURCES) \
$(maybe_threads_unittest_sh_SOURCES) \
$(memalign_unittest_SOURCES) $(packed_cache_test_SOURCES) \
- $(profiler1_unittest_SOURCES) $(profiler2_unittest_SOURCES) \
- $(profiler3_unittest_SOURCES) $(profiler4_unittest_SOURCES) \
- $(profiler_unittest_sh_SOURCES) $(ptmalloc_unittest1_SOURCES) \
- $(ptmalloc_unittest2_SOURCES) $(stacktrace_unittest_SOURCES) \
- $(system_alloc_unittest_SOURCES) \
- $(tcmalloc_both_unittest_SOURCES) \
- $(tcmalloc_large_unittest_SOURCES) \
+ $(am__profiledata_unittest_SOURCES_DIST) \
+ $(am__profiler1_unittest_SOURCES_DIST) \
+ $(am__profiler2_unittest_SOURCES_DIST) \
+ $(am__profiler3_unittest_SOURCES_DIST) \
+ $(am__profiler4_unittest_SOURCES_DIST) \
+ $(am__profiler_unittest_sh_SOURCES_DIST) \
+ $(ptmalloc_unittest1_SOURCES) $(ptmalloc_unittest2_SOURCES) \
+ $(stacktrace_unittest_SOURCES) \
+ $(am__system_alloc_unittest_SOURCES_DIST) \
+ $(am__tcmalloc_both_unittest_SOURCES_DIST) \
+ $(am__tcmalloc_large_unittest_SOURCES_DIST) \
$(tcmalloc_minimal_large_unittest_SOURCES) \
- $(tcmalloc_minimal_unittest_SOURCES) \
- $(tcmalloc_unittest_SOURCES) \
+ $(am__tcmalloc_minimal_unittest_SOURCES_DIST) \
+ $(am__tcmalloc_unittest_SOURCES_DIST) \
$(thread_dealloc_unittest_SOURCES)
man1dir = $(mandir)/man1
NROFF = nroff
MANS = $(dist_man_MANS)
+am__dist_doc_DATA_DIST = AUTHORS COPYING ChangeLog INSTALL NEWS README \
+ README.windows TODO doc/index.html doc/designstyle.css \
+ doc/pprof_remote_servers.html doc/tcmalloc.html \
+ doc/overview.gif doc/pageheap.gif doc/spanmap.gif \
+ doc/threadheap.gif doc/t-test1.times.txt \
+ doc/tcmalloc-opspercpusec.vs.threads.1024.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.128.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.131072.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.16384.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.2048.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.256.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.32768.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.4096.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.512.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.64.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.65536.bytes.png \
+ doc/tcmalloc-opspercpusec.vs.threads.8192.bytes.png \
+ doc/tcmalloc-opspersec.vs.size.1.threads.png \
+ doc/tcmalloc-opspersec.vs.size.12.threads.png \
+ doc/tcmalloc-opspersec.vs.size.16.threads.png \
+ doc/tcmalloc-opspersec.vs.size.2.threads.png \
+ doc/tcmalloc-opspersec.vs.size.20.threads.png \
+ doc/tcmalloc-opspersec.vs.size.3.threads.png \
+ doc/tcmalloc-opspersec.vs.size.4.threads.png \
+ doc/tcmalloc-opspersec.vs.size.5.threads.png \
+ doc/tcmalloc-opspersec.vs.size.8.threads.png doc/overview.dot \
+ doc/pageheap.dot doc/spanmap.dot doc/threadheap.dot \
+ doc/heapprofile.html doc/heap-example1.png \
+ doc/heap_checker.html doc/cpuprofile.html \
+ doc/pprof-test-big.gif doc/pprof-test.gif \
+ doc/pprof-vsnprintf-big.gif doc/pprof-vsnprintf.gif
dist_docDATA_INSTALL = $(INSTALL_DATA)
DATA = $(dist_doc_DATA)
+am__googleinclude_HEADERS_DIST = src/google/stacktrace.h \
+ src/google/malloc_hook.h src/google/malloc_extension.h \
+ src/google/heap-profiler.h src/google/heap-checker.h \
+ src/google/profiler.h
googleincludeHEADERS_INSTALL = $(INSTALL_HEADER)
HEADERS = $(googleinclude_HEADERS)
ETAGS = etags
@@ -433,6 +693,8 @@ LIBTOOL_DEPS = @LIBTOOL_DEPS@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
+MINGW_FALSE = @MINGW_FALSE@
+MINGW_TRUE = @MINGW_TRUE@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
@@ -495,7 +757,11 @@ program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
+target = @target@
target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
# Make sure that when we re-make ./configure, we get the macros we need
ACLOCAL_AMFLAGS = -I m4
@@ -510,13 +776,13 @@ googleincludedir = $(includedir)/google
# who install this package can include in their own applications.)
# We'll add to this later, on a library-by-library basis
googleinclude_HEADERS = $(SG_STACKTRACE_INCLUDES) \
- $(SG_TCMALLOC_MINIMAL_INCLUDES) $(SG_TCMALLOC_INCLUDES) \
- $(SG_CPU_PROFILER_INCLUDES)
+ $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_10)
docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
# This is for HTML and other documentation you want to install.
# Add your documentation files (in doc/) in addition to these
# top-level boilerplate files. Also add a TODO file if you have one.
# We'll add to this later, on a library-by-library basis
+#endif !MINGW
### Documentation
@@ -526,10 +792,6 @@ docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
# noinst doesn't seem to work with data. I separate them out anyway, in case
# one day we figure it out. Regardless, installing the dot files isn't the
# end of the world.
-
-### Documentation (above and beyond tcmalloc_minimal documentation)
-
-### Documentation
dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
README.windows TODO doc/index.html doc/designstyle.css \
doc/pprof_remote_servers.html doc/tcmalloc.html \
@@ -557,10 +819,7 @@ dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
doc/tcmalloc-opspersec.vs.size.5.threads.png \
doc/tcmalloc-opspersec.vs.size.8.threads.png doc/overview.dot \
doc/pageheap.dot doc/spanmap.dot doc/threadheap.dot \
- doc/heapprofile.html doc/heap-example1.png \
- doc/heap_checker.html doc/cpuprofile.html \
- doc/pprof-test-big.gif doc/pprof-test.gif \
- doc/pprof-vsnprintf-big.gif doc/pprof-vsnprintf.gif
+ $(am__append_15)
# The libraries (.so's) you want to install
# We'll add to this later, on a library-by-library basis
@@ -568,29 +827,23 @@ dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
### Making the library
### Making the library
-
-### Making the library
-
-### Making the library
lib_LTLIBRARIES = libstacktrace.la libtcmalloc_minimal.la \
- libtcmalloc.la libprofiler.la
+ $(am__append_11)
# This is for 'convenience libraries' -- basically just a container for sources
-
-# This is a 'convenience library' -- it's not actually installed or anything
-noinst_LTLIBRARIES = libspinlock.la liblogging.la
+noinst_LTLIBRARIES = liblogging.la $(am__append_4) $(am__append_5)
WINDOWS_PROJECTS = google-perftools.sln \
vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj \
vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj \
vsprojects/tcmalloc_minimal_unittest/tcmalloc_minimal_unittest.vcproj \
vsprojects/tcmalloc_minimal_unittest-static/tcmalloc_minimal_unittest-static.vcproj \
vsprojects/tcmalloc_minimal_large/tcmalloc_minimal_large_unittest.vcproj \
- vsprojects/system_alloc_unittest/system_alloc_unittest.vcproj \
+ vsprojects/addressmap_unittest/addressmap_unittest.vcproj \
+ $(am__append_9) \
vsprojects/packed-cache_test/packed-cache_test.vcproj \
vsprojects/frag_unittest/frag_unittest.vcproj \
vsprojects/markidle_unittest/markidle_unittest.vcproj \
vsprojects/memalign_unittest/memalign_unittest.vcproj \
- vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj \
- vsprojects/addressmap_unittest/addressmap_unittest.vcproj
+ vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj
# unittests you want to run when people type 'make check'.
# Note: tests cannot take any arguments!
@@ -604,57 +857,31 @@ WINDOWS_PROJECTS = google-perftools.sln \
### Unittests
### Unittests
+#if !MINGW
### Unittests
# Commented out for the moment because malloc(very_big_num) is broken in
# standard libc! At least, in some situations, some of the time.
-# This makes sure it's safe to link in both tcmalloc and tcmalloc_minimal.
-# (One would never do this on purpose, but perhaps by accident...)
-
# This tests it works to LD_PRELOAD libtcmalloc (tests maybe_threads.cc)
-### Unittests
-TESTS = low_level_alloc_unittest atomicops_unittest \
- stacktrace_unittest tcmalloc_unittest \
- tcmalloc_minimal_unittest tcmalloc_both_unittest \
- tcmalloc_large_unittest tcmalloc_minimal_large_unittest \
- maybe_threads_unittest.sh system_alloc_unittest \
+# These all tests components of tcmalloc_minimal
+TESTS = low_level_alloc_unittest $(am__append_6) stacktrace_unittest \
+ tcmalloc_minimal_unittest tcmalloc_minimal_large_unittest \
+ maybe_threads_unittest.sh addressmap_unittest $(am__append_8) \
packed_cache_test frag_unittest markidle_unittest \
- memalign_unittest thread_dealloc_unittest addressmap_unittest \
- heap-profiler_unittest.sh heap-checker_unittest.sh \
- heap-checker-death_unittest.sh getpc_test profiler_unittest.sh
+ memalign_unittest thread_dealloc_unittest $(am__append_12)
# TESTS_ENVIRONMENT sets environment variables for when you run unittest.
# We always get "srcdir" set for free.
# We'll add to this later, on a library-by-library basis.
-
-# Let unittests find pprof if they need to run it
-
-### Unittests
-
-# These unittests often need to run binaries. They're in the current dir
-TESTS_ENVIRONMENT = PPROF_PATH=$(top_srcdir)/src/pprof BINDIR=.
+TESTS_ENVIRONMENT = $(am__append_7)
# All script tests should be added here
-noinst_SCRIPTS = $(maybe_threads_unittest_sh_SOURCES) \
- $(heap_profiler_unittest_sh_SOURCES) \
- $(heap_checker_unittest_sh_SOURCES) \
- $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) \
- $(profiler_unittest_sh_SOURCES)
+noinst_SCRIPTS = $(maybe_threads_unittest_sh_SOURCES) $(am__append_13)
### ------- library routines, in src/base
-# spinlock is the only code that uses atomicops.
-SPINLOCK_INCLUDES = src/base/spinlock.h \
- src/base/atomicops.h \
- src/base/atomicops-internals-macosx.h \
- src/base/atomicops-internals-x86-msvc.h \
- src/base/atomicops-internals-x86.h
-
-libspinlock_la_SOURCES = src/base/spinlock.cc \
- src/base/atomicops-internals-x86.cc \
- $(SPINLOCK_INCLUDES)
-
+# This is a 'convenience library' -- it's not actually installed or anything
LOGGING_INCLUDES = src/base/logging.h \
src/base/commandlineflags.h \
src/base/basictypes.h
@@ -662,6 +889,46 @@ LOGGING_INCLUDES = src/base/logging.h \
liblogging_la_SOURCES = src/base/logging.cc \
$(LOGGING_INCLUDES)
+
+# For MinGW, we use libwindows and not libspinlock. For every other
+# unix system, we use libspinlock and don't need libwindows. Luckily,
+# we need the windows.a library in exactly the same place we need
+# spinlock.a (pretty much everywhere), so we can use the same variable
+# name for each. In addition, there is a bunch of functionality in
+# libwindows that obsoletes the need for other files like
+# system_alloc.cc.
+@MINGW_TRUE@WINDOWS_INCLUDES = src/windows/port.h \
+@MINGW_TRUE@ src/windows/mingw.h \
+@MINGW_TRUE@ src/windows/mini_disassembler.h \
+@MINGW_TRUE@ src/windows/mini_disassembler_types.h \
+@MINGW_TRUE@ src/windows/preamble_patcher.h
+
+@MINGW_TRUE@libwindows_la_SOURCES = $(WINDOWS_INCLUDES) \
+@MINGW_TRUE@ src/windows/port.cc \
+@MINGW_TRUE@ src/windows/ia32_modrm_map.cc \
+@MINGW_TRUE@ src/windows/ia32_opcode_map.cc \
+@MINGW_TRUE@ src/windows/mini_disassembler.cc \
+@MINGW_TRUE@ src/windows/patch_functions.cc \
+@MINGW_TRUE@ src/windows/preamble_patcher.cc \
+@MINGW_TRUE@ src/windows/preamble_patcher_with_stub.cc
+
+@MINGW_FALSE@LIBSPINLOCK = libspinlock.la
+@MINGW_TRUE@LIBSPINLOCK = libwindows.la
+@MINGW_FALSE@MAYBE_THREADS_CC = src/maybe_threads.cc
+@MINGW_TRUE@MAYBE_THREADS_CC =
+@MINGW_FALSE@SYSTEM_ALLOC_CC = src/system-alloc.cc
+@MINGW_TRUE@SYSTEM_ALLOC_CC =
+# spinlock is the only code that uses atomicops.
+@MINGW_FALSE@SPINLOCK_INCLUDES = src/base/spinlock.h \
+@MINGW_FALSE@ src/base/atomicops.h \
+@MINGW_FALSE@ src/base/atomicops-internals-macosx.h \
+@MINGW_FALSE@ src/base/atomicops-internals-x86-msvc.h \
+@MINGW_FALSE@ src/base/atomicops-internals-x86.h
+
+@MINGW_FALSE@libspinlock_la_SOURCES = src/base/spinlock.cc \
+@MINGW_FALSE@ src/base/atomicops-internals-x86.cc \
+@MINGW_FALSE@ $(SPINLOCK_INCLUDES)
+
LOW_LEVEL_ALLOC_UNITTEST_INCLUDES = src/base/low_level_alloc.h \
src/base/basictypes.h \
src/google/malloc_hook.h \
@@ -673,17 +940,17 @@ low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \
src/tests/low_level_alloc_unittest.cc \
$(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES)
-low_level_alloc_unittest_LDADD = libspinlock.la liblogging.la libstacktrace.la
-ATOMICOPS_UNITTEST_INCLUDES = src/base/atomicops.h \
- src/base/atomicops-internals-macosx.h \
- src/base/atomicops-internals-x86-msvc.h \
- src/base/atomicops-internals-x86.h \
- $(LOGGING_INCLUDES)
+low_level_alloc_unittest_LDADD = $(LIBSPINLOCK) liblogging.la libstacktrace.la
+@MINGW_FALSE@ATOMICOPS_UNITTEST_INCLUDES = src/base/atomicops.h \
+@MINGW_FALSE@ src/base/atomicops-internals-macosx.h \
+@MINGW_FALSE@ src/base/atomicops-internals-x86-msvc.h \
+@MINGW_FALSE@ src/base/atomicops-internals-x86.h \
+@MINGW_FALSE@ $(LOGGING_INCLUDES)
-atomicops_unittest_SOURCES = src/tests/atomicops_unittest.cc \
- $(ATOMICOPS_UNITTEST_INCLUDES)
+@MINGW_FALSE@atomicops_unittest_SOURCES = src/tests/atomicops_unittest.cc \
+@MINGW_FALSE@ $(ATOMICOPS_UNITTEST_INCLUDES)
-atomicops_unittest_LDADD = libspinlock.la liblogging.la
+@MINGW_FALSE@atomicops_unittest_LDADD = $(LIBSPINLOCK) liblogging.la
### ------- stack trace
@@ -701,7 +968,7 @@ libstacktrace_la_SOURCES = src/stacktrace.cc \
# TODO(csilvers): only add these two things when stacktrace.cc would
# #include "stacktrace_libunwind-inl.h"
-libstacktrace_la_LIBADD = $(UNWIND_LIBS) libspinlock.la
+libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK)
STACKTRACE_SYMBOLS = '(GetStackTrace)'
libstacktrace_la_LDFLAGS = -export-symbols-regex $(STACKTRACE_SYMBOLS)
STACKTRACE_UNITTEST_INLCUDES = src/config_for_unittests.h \
@@ -718,7 +985,7 @@ stacktrace_unittest_LDADD = libstacktrace.la liblogging.la
bin_SCRIPTS = src/pprof
### Unittests
-check_SCRIPTS = pprof_unittest
+@MINGW_FALSE@check_SCRIPTS = pprof_unittest
### Documentation
dist_man_MANS = doc/pprof.1
@@ -741,18 +1008,18 @@ SG_TCMALLOC_MINIMAL_INCLUDES = src/google/malloc_hook.h \
TCMALLOC_MINIMAL_INCLUDES = $(S_TCMALLOC_MINIMAL_INCLUDES) $(SG_TCMALLOC_MINIMAL_INCLUDES)
libtcmalloc_minimal_la_SOURCES = src/internal_logging.cc \
- src/system-alloc.cc \
+ $(SYSTEM_ALLOC_CC) \
src/memfs_malloc.cc \
src/tcmalloc.cc \
src/malloc_hook.cc \
src/malloc_extension.cc \
- src/maybe_threads.cc \
+ $(MAYBE_THREADS_CC) \
$(TCMALLOC_MINIMAL_INCLUDES)
libtcmalloc_minimal_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
libtcmalloc_minimal_la_LDFLAGS = $(PTHREAD_CFLAGS)
libtcmalloc_minimal_la_LIBADD = $(PTHREAD_LIBS) \
- libstacktrace.la libspinlock.la liblogging.la
+ libstacktrace.la $(LIBSPINLOCK) liblogging.la
# Whenever we link in tcmalloc_minimal, we also need to link in
@@ -766,17 +1033,6 @@ libtcmalloc_minimal_la_LIBADD = $(PTHREAD_LIBS) \
# linker search path, so the value of -rpath doesn't matter.)
# Remember tcmalloc should always be linked in last!
LIBTCMALLOC_MINIMAL = libstacktrace.la libtcmalloc_minimal.la
-TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \
- src/google/malloc_extension.h
-
-tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
- src/tcmalloc.h \
- src/tests/testutil.h src/tests/testutil.cc \
- $(TCMALLOC_UNITTEST_INCLUDES)
-
-tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
tcmalloc_minimal_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
$(TCMALLOC_UNITTEST_INCLUDES)
@@ -786,52 +1042,30 @@ tcmalloc_minimal_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
tcmalloc_minimal_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) \
liblogging.la $(PTHREAD_LIBS)
-tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
- src/tests/testutil.h src/tests/testutil.cc \
- $(TCMALLOC_UNITTEST_INCLUDES)
-
-tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
- liblogging.la $(PTHREAD_LIBS)
-
-tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
-tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
tcmalloc_minimal_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
tcmalloc_minimal_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
tcmalloc_minimal_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
tcmalloc_minimal_large_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
maybe_threads_unittest_sh_SOURCES = src/tests/maybe_threads_unittest.sh
-system_alloc_unittest_SOURCES = src/config_for_unittests.h \
- src/tests/system-alloc_unittest.cc
+ADDRESSMAP_UNITTEST_INCLUDES = src/addressmap-inl.h \
+ src/base/commandlineflags.h \
+ $(LOGGING_INCLUDES)
+
+addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc \
+ $(ADDRESSMAP_UNITTEST_INCLUDES)
-system_alloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-system_alloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-system_alloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+addressmap_unittest_CXXFLAGS = -g $(AM_CXXFLAGS)
+addressmap_unittest_LDADD = liblogging.la
+@MINGW_FALSE@system_alloc_unittest_SOURCES = src/config_for_unittests.h \
+@MINGW_FALSE@ src/tests/system-alloc_unittest.cc
+
+@MINGW_FALSE@system_alloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@system_alloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@MINGW_FALSE@system_alloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
packed_cache_test_SOURCES = src/tests/packed-cache_test.cc \
src/packed-cache-inl.h \
src/base/logging.h
-PTMALLOC_UNITTEST_INCLUDES = src/tests/ptmalloc/t-test.h \
- src/tests/ptmalloc/thread-m.h \
- src/tests/ptmalloc/lran2.h \
- src/tests/ptmalloc/thread-st.h \
- src/tests/ptmalloc/malloc-machine.h
-
-ptmalloc_unittest1_SOURCES = src/tests/ptmalloc/t-test1.c \
- $(PTMALLOC_UNITTEST_INCLUDES)
-
-ptmalloc_unittest1_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
-ptmalloc_unittest1_LDFLAGS = $(PTHREAD_CFLAGS)
-ptmalloc_unittest1_LDADD = $(PTHREAD_LIBS)
-ptmalloc_unittest2_SOURCES = src/tests/ptmalloc/t-test2.c \
- $(PTMALLOC_UNITTEST_INCLUDES)
-
-ptmalloc_unittest2_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
-ptmalloc_unittest2_LDFLAGS = $(PTHREAD_CFLAGS)
-ptmalloc_unittest2_LDADD = $(PTHREAD_LIBS)
frag_unittest_SOURCES = src/tests/frag_unittest.cc src/config_for_unittests.h
frag_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
frag_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
@@ -857,160 +1091,209 @@ thread_dealloc_unittest_SOURCES = src/tests/thread_dealloc_unittest.cc \
thread_dealloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
thread_dealloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+PTMALLOC_UNITTEST_INCLUDES = src/tests/ptmalloc/t-test.h \
+ src/tests/ptmalloc/thread-m.h \
+ src/tests/ptmalloc/lran2.h \
+ src/tests/ptmalloc/thread-st.h \
+ src/tests/ptmalloc/malloc-machine.h
+
+ptmalloc_unittest1_SOURCES = src/tests/ptmalloc/t-test1.c \
+ $(PTMALLOC_UNITTEST_INCLUDES)
+
+ptmalloc_unittest1_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
+ptmalloc_unittest1_LDFLAGS = $(PTHREAD_CFLAGS)
+ptmalloc_unittest1_LDADD = $(PTHREAD_LIBS)
+ptmalloc_unittest2_SOURCES = src/tests/ptmalloc/t-test2.c \
+ $(PTMALLOC_UNITTEST_INCLUDES)
+
+ptmalloc_unittest2_CFLAGS = $(PTHREAD_CFLAGS) -DUSE_PTHREADS
+ptmalloc_unittest2_LDFLAGS = $(PTHREAD_CFLAGS)
+ptmalloc_unittest2_LDADD = $(PTHREAD_LIBS)
### ------- tcmalloc (thread-caching malloc + heap profiler + heap checker)
+# The full tcmalloc does not work on windows yet
+
### The header files we use. We divide into categories based on directory
-S_TCMALLOC_INCLUDES = src/internal_logging.h \
- src/system-alloc.h \
- src/pagemap.h \
- src/addressmap-inl.h \
- src/packed-cache-inl.h \
- src/heap-profile-table.h \
- src/base/basictypes.h \
- src/base/commandlineflags.h \
- src/base/googleinit.h \
- src/base/elfcore.h \
- src/base/linux_syscall_support.h \
- src/base/linuxthreads.h \
- src/base/thread_lister.h \
- src/base/sysinfo.h \
- src/base/stl_allocator.h \
- src/maybe_threads.h \
- $(SPINLOCK_INCLUDES) \
- $(LOGGING_INCLUDES)
-
-SG_TCMALLOC_INCLUDES = src/google/malloc_hook.h \
- src/google/malloc_extension.h \
- src/google/heap-profiler.h \
- src/google/heap-checker.h \
- src/google/stacktrace.h
-
-TCMALLOC_INCLUDES = $(S_TCMALLOC_INCLUDES) $(SG_TCMALLOC_INCLUDES)
+@MINGW_FALSE@S_TCMALLOC_INCLUDES = src/internal_logging.h \
+@MINGW_FALSE@ src/system-alloc.h \
+@MINGW_FALSE@ src/pagemap.h \
+@MINGW_FALSE@ src/addressmap-inl.h \
+@MINGW_FALSE@ src/packed-cache-inl.h \
+@MINGW_FALSE@ src/heap-profile-table.h \
+@MINGW_FALSE@ src/base/basictypes.h \
+@MINGW_FALSE@ src/base/commandlineflags.h \
+@MINGW_FALSE@ src/base/googleinit.h \
+@MINGW_FALSE@ src/base/elfcore.h \
+@MINGW_FALSE@ src/base/linux_syscall_support.h \
+@MINGW_FALSE@ src/base/linuxthreads.h \
+@MINGW_FALSE@ src/base/thread_lister.h \
+@MINGW_FALSE@ src/base/sysinfo.h \
+@MINGW_FALSE@ src/base/stl_allocator.h \
+@MINGW_FALSE@ src/maybe_threads.h \
+@MINGW_FALSE@ $(SPINLOCK_INCLUDES) \
+@MINGW_FALSE@ $(LOGGING_INCLUDES)
+
+@MINGW_FALSE@SG_TCMALLOC_INCLUDES = src/google/malloc_hook.h \
+@MINGW_FALSE@ src/google/malloc_extension.h \
+@MINGW_FALSE@ src/google/heap-profiler.h \
+@MINGW_FALSE@ src/google/heap-checker.h \
+@MINGW_FALSE@ src/google/stacktrace.h
+
+@MINGW_FALSE@TCMALLOC_INCLUDES = $(S_TCMALLOC_INCLUDES) $(SG_TCMALLOC_INCLUDES)
# Note: heap-checker-bcad is last, in hopes its global ctor will run first
-libtcmalloc_la_SOURCES = src/internal_logging.cc \
- src/system-alloc.cc \
- src/memfs_malloc.cc \
- src/tcmalloc.cc \
- src/malloc_hook.cc \
- src/malloc_extension.cc \
- src/maybe_threads.cc \
- src/memory_region_map.cc \
- src/heap-profiler.cc \
- src/heap-profile-table.cc \
- src/heap-checker.cc \
- src/base/linuxthreads.c \
- src/base/thread_lister.c \
- src/base/sysinfo.cc \
- src/base/low_level_alloc.cc \
- $(TCMALLOC_INCLUDES) \
- src/heap-checker-bcad.cc
-
-libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
-libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
-libtcmalloc_la_LIBADD = $(PTHREAD_LIBS) \
- libstacktrace.la libspinlock.la liblogging.la
+@MINGW_FALSE@libtcmalloc_la_SOURCES = src/internal_logging.cc \
+@MINGW_FALSE@ $(SYSTEM_ALLOC_CC) \
+@MINGW_FALSE@ src/memfs_malloc.cc \
+@MINGW_FALSE@ src/tcmalloc.cc \
+@MINGW_FALSE@ src/malloc_hook.cc \
+@MINGW_FALSE@ src/malloc_extension.cc \
+@MINGW_FALSE@ $(MAYBE_THREADS_CC) \
+@MINGW_FALSE@ src/memory_region_map.cc \
+@MINGW_FALSE@ src/heap-profiler.cc \
+@MINGW_FALSE@ src/heap-profile-table.cc \
+@MINGW_FALSE@ src/heap-checker.cc \
+@MINGW_FALSE@ src/base/linuxthreads.c \
+@MINGW_FALSE@ src/base/thread_lister.c \
+@MINGW_FALSE@ src/base/sysinfo.cc \
+@MINGW_FALSE@ src/base/low_level_alloc.cc \
+@MINGW_FALSE@ $(TCMALLOC_INCLUDES) \
+@MINGW_FALSE@ src/heap-checker-bcad.cc
+
+@MINGW_FALSE@libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
+@MINGW_FALSE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS)
+@MINGW_FALSE@libtcmalloc_la_LIBADD = $(PTHREAD_LIBS) \
+@MINGW_FALSE@ libstacktrace.la $(LIBSPINLOCK) liblogging.la
# See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this.
# Basically it's to work around systems where --rpath doesn't work right.
# Remember tcmalloc should always be linked in last!
-LIBTCMALLOC = libstacktrace.la libtcmalloc.la
-ADDRESSMAP_UNITTEST_INCLUDES = src/addressmap-inl.h \
- src/base/commandlineflags.h \
- $(LOGGING_INCLUDES)
-
-addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc \
- $(ADDRESSMAP_UNITTEST_INCLUDES)
-
-addressmap_unittest_CXXFLAGS = -g $(AM_CXXFLAGS)
-addressmap_unittest_LDADD = liblogging.la
-heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh
-HEAP_PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
- src/google/heap-profiler.h
-
-heap_profiler_unittest_SOURCES = src/tests/heap-profiler_unittest.cc \
- $(HEAP_PROFILER_UNITTEST_INCLUDES)
-
-heap_profiler_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-heap_profiler_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS)
-heap_profiler_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
-heap_checker_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh
-heap_checker_death_unittest_sh_SOURCES = src/tests/heap-checker-death_unittest.sh
-HEAP_CHECKER_UNITTEST_INCLUDES = src/config_for_unittests.h \
- src/memory_region_map.h \
- src/base/commandlineflags.h \
- src/base/googleinit.h \
- src/google/heap-checker.h \
- $(LOGGING_INCLUDES)
-
-heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc \
- $(HEAP_CHECKER_UNITTEST_INCLUDES)
-
-heap_checker_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-heap_checker_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS)
+@MINGW_FALSE@LIBTCMALLOC = libstacktrace.la libtcmalloc.la
+@MINGW_FALSE@TCMALLOC_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@MINGW_FALSE@ src/google/malloc_extension.h
+
+@MINGW_FALSE@tcmalloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
+@MINGW_FALSE@ src/tcmalloc.h \
+@MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc \
+@MINGW_FALSE@ $(TCMALLOC_UNITTEST_INCLUDES)
+
+@MINGW_FALSE@tcmalloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@tcmalloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@MINGW_FALSE@tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
+@MINGW_FALSE@tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
+@MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc \
+@MINGW_FALSE@ $(TCMALLOC_UNITTEST_INCLUDES)
+
+@MINGW_FALSE@tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@MINGW_FALSE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+@MINGW_FALSE@ liblogging.la $(PTHREAD_LIBS)
+
+@MINGW_FALSE@tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
+@MINGW_FALSE@tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@MINGW_FALSE@tcmalloc_large_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+@MINGW_FALSE@heap_profiler_unittest_sh_SOURCES = src/tests/heap-profiler_unittest.sh
+@MINGW_FALSE@HEAP_PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@MINGW_FALSE@ src/google/heap-profiler.h
+
+@MINGW_FALSE@heap_profiler_unittest_SOURCES = src/tests/heap-profiler_unittest.cc \
+@MINGW_FALSE@ $(HEAP_PROFILER_UNITTEST_INCLUDES)
+
+@MINGW_FALSE@heap_profiler_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@heap_profiler_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS)
+@MINGW_FALSE@heap_profiler_unittest_LDADD = $(LIBTCMALLOC) $(PTHREAD_LIBS)
+@MINGW_FALSE@heap_checker_unittest_sh_SOURCES = src/tests/heap-checker_unittest.sh
+@MINGW_FALSE@heap_checker_death_unittest_sh_SOURCES = src/tests/heap-checker-death_unittest.sh
+@MINGW_FALSE@HEAP_CHECKER_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@MINGW_FALSE@ src/memory_region_map.h \
+@MINGW_FALSE@ src/base/commandlineflags.h \
+@MINGW_FALSE@ src/base/googleinit.h \
+@MINGW_FALSE@ src/google/heap-checker.h \
+@MINGW_FALSE@ $(LOGGING_INCLUDES)
+
+@MINGW_FALSE@heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc \
+@MINGW_FALSE@ $(HEAP_CHECKER_UNITTEST_INCLUDES)
+
+@MINGW_FALSE@heap_checker_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@heap_checker_unittest_LDFLAGS = -g $(PTHREAD_CFLAGS)
# tcmalloc has to be specified last!
-heap_checker_unittest_LDADD = $(PTHREAD_LIBS) liblogging.la $(LIBTCMALLOC)
+@MINGW_FALSE@heap_checker_unittest_LDADD = $(PTHREAD_LIBS) liblogging.la $(LIBTCMALLOC)
### ------- CPU profiler
+# The CPU profiler doesn't work on windows yet
+
### The header files we use. We divide into categories based on directory
-S_CPU_PROFILER_INCLUDES = src/getpc.h \
- src/base/basictypes.h \
- src/base/commandlineflags.h \
- src/base/googleinit.h \
- src/base/logging.h \
- src/base/mutex.h \
- src/base/sysinfo.h \
- $(SPINLOCK_INCLUDES) \
- $(LOGGING_INCLUDES)
-
-SG_CPU_PROFILER_INCLUDES = src/google/profiler.h \
- src/google/stacktrace.h
-
-CPU_PROFILER_INCLUDES = $(S_CPU_PROFILER_INCLUDES) $(SG_CPU_PROFILER_INCLUDES)
-libprofiler_la_SOURCES = src/profiler.cc \
- src/base/sysinfo.cc \
- $(CPU_PROFILER_INCLUDES)
-
-libprofiler_la_LIBADD = libspinlock.la liblogging.la libstacktrace.la
-CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStop|ProfilerEnable|ProfilerDisable|ProfilerFlush|ProfilerRegisterThread|ProfilerThreadState)'
-libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS)
+@MINGW_FALSE@S_CPU_PROFILER_INCLUDES = src/profiledata.h \
+@MINGW_FALSE@ src/getpc.h \
+@MINGW_FALSE@ src/base/basictypes.h \
+@MINGW_FALSE@ src/base/commandlineflags.h \
+@MINGW_FALSE@ src/base/googleinit.h \
+@MINGW_FALSE@ src/base/logging.h \
+@MINGW_FALSE@ src/base/mutex.h \
+@MINGW_FALSE@ src/base/sysinfo.h \
+@MINGW_FALSE@ $(SPINLOCK_INCLUDES) \
+@MINGW_FALSE@ $(LOGGING_INCLUDES)
+
+@MINGW_FALSE@SG_CPU_PROFILER_INCLUDES = src/google/profiler.h \
+@MINGW_FALSE@ src/google/stacktrace.h
+
+@MINGW_FALSE@CPU_PROFILER_INCLUDES = $(S_CPU_PROFILER_INCLUDES) $(SG_CPU_PROFILER_INCLUDES)
+@MINGW_FALSE@libprofiler_la_SOURCES = src/profiler.cc \
+@MINGW_FALSE@ src/profiledata.cc \
+@MINGW_FALSE@ src/base/sysinfo.cc \
+@MINGW_FALSE@ $(CPU_PROFILER_INCLUDES)
+
+@MINGW_FALSE@libprofiler_la_LIBADD = $(LIBSPINLOCK) liblogging.la libstacktrace.la
+# We have to include ProfileData for profiledata_unittest
+@MINGW_FALSE@CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStop|ProfilerEnable|ProfilerDisable|ProfilerFlush|ProfilerRegisterThread|ProfilerThreadState|ProfileData)'
+@MINGW_FALSE@libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS)
# See discussion above (under LIBTCMALLOC_MINIMAL) for why we do this.
# Basically it's to work around systems where --rpath doesn't work right.
-LIBPROFILER = libstacktrace.la libprofiler.la
+@MINGW_FALSE@LIBPROFILER = libstacktrace.la libprofiler.la
#WINDOWS_PROJECTS += vsprojects/getpc_test/getpc_test.vcproj
-getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h
-profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh
-PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
- src/google/profiler.h
-
-PROFILER_UNITTEST_SRCS = src/tests/profiler_unittest.cc \
- src/tests/testutil.h src/tests/testutil.cc \
- $(PROFILER_UNITTEST_INCLUDES)
-
-profiler1_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-profiler1_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
-profiler1_unittest_LDADD = $(LIBPROFILER)
-profiler2_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-profiler2_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
-profiler2_unittest_LDADD = -lstacktrace -lprofiler
+@MINGW_FALSE@getpc_test_SOURCES = src/tests/getpc_test.cc src/getpc.h
+#WINDOWS_PROJECTS += vsprojects/profiledata_unittest/profiledata_unittest.vcproj
+@MINGW_FALSE@profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \
+@MINGW_FALSE@ src/profiledata.h \
+@MINGW_FALSE@ src/base/commandlineflags.h \
+@MINGW_FALSE@ src/base/logging.h \
+@MINGW_FALSE@ src/base/basictypes.h
+
+@MINGW_FALSE@profiledata_unittest_LDADD = -lprofiler
+@MINGW_FALSE@profiler_unittest_sh_SOURCES = src/tests/profiler_unittest.sh
+@MINGW_FALSE@PROFILER_UNITTEST_INCLUDES = src/config_for_unittests.h \
+@MINGW_FALSE@ src/google/profiler.h
+
+@MINGW_FALSE@PROFILER_UNITTEST_SRCS = src/tests/profiler_unittest.cc \
+@MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc \
+@MINGW_FALSE@ $(PROFILER_UNITTEST_INCLUDES)
+
+@MINGW_FALSE@profiler1_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@MINGW_FALSE@profiler1_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
+@MINGW_FALSE@profiler1_unittest_LDADD = $(LIBPROFILER)
+@MINGW_FALSE@profiler2_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@MINGW_FALSE@profiler2_unittest_CXXFLAGS = -g -DNO_THREADS $(AM_CXXFLAGS)
+@MINGW_FALSE@profiler2_unittest_LDADD = -lstacktrace -lprofiler
# We depend on -lprofiler but haven't yet said how to build it. Do so now.
-profiler2_unittest_DEPENDENCIES = $(LIBPROFILER)
-profiler3_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-profiler3_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-profiler3_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-profiler3_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS)
-profiler4_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
-profiler4_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-profiler4_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
-profiler4_unittest_LDADD = -lstacktrace -lprofiler $(PTHREAD_LIBS)
+@MINGW_FALSE@profiler2_unittest_DEPENDENCIES = $(LIBPROFILER)
+@MINGW_FALSE@profiler3_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@MINGW_FALSE@profiler3_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@profiler3_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@MINGW_FALSE@profiler3_unittest_LDADD = $(LIBPROFILER) $(PTHREAD_LIBS)
+@MINGW_FALSE@profiler4_unittest_SOURCES = $(PROFILER_UNITTEST_SRCS)
+@MINGW_FALSE@profiler4_unittest_CXXFLAGS = -g $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@profiler4_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
+@MINGW_FALSE@profiler4_unittest_LDADD = -lstacktrace -lprofiler $(PTHREAD_LIBS)
# We depend on -lprofiler but haven't yet said how to build it. Do so now.
-profiler4_unittest_DEPENDENCIES = $(LIBPROFILER)
+@MINGW_FALSE@profiler4_unittest_DEPENDENCIES = $(LIBPROFILER)
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
$(SCRIPTS) libtool \
- src/windows $(WINDOWS_PROJECTS) src/solaris/libstdc++.la
+ src/windows/config.h src/windows/vc7and8.def $(WINDOWS_PROJECTS) \
+ src/solaris/libstdc++.la
all: all-am
@@ -1105,15 +1388,17 @@ clean-noinstLTLIBRARIES:
liblogging.la: $(liblogging_la_OBJECTS) $(liblogging_la_DEPENDENCIES)
$(CXXLINK) $(liblogging_la_LDFLAGS) $(liblogging_la_OBJECTS) $(liblogging_la_LIBADD) $(LIBS)
libprofiler.la: $(libprofiler_la_OBJECTS) $(libprofiler_la_DEPENDENCIES)
- $(CXXLINK) -rpath $(libdir) $(libprofiler_la_LDFLAGS) $(libprofiler_la_OBJECTS) $(libprofiler_la_LIBADD) $(LIBS)
+ $(CXXLINK) $(am_libprofiler_la_rpath) $(libprofiler_la_LDFLAGS) $(libprofiler_la_OBJECTS) $(libprofiler_la_LIBADD) $(LIBS)
libspinlock.la: $(libspinlock_la_OBJECTS) $(libspinlock_la_DEPENDENCIES)
- $(CXXLINK) $(libspinlock_la_LDFLAGS) $(libspinlock_la_OBJECTS) $(libspinlock_la_LIBADD) $(LIBS)
+ $(CXXLINK) $(am_libspinlock_la_rpath) $(libspinlock_la_LDFLAGS) $(libspinlock_la_OBJECTS) $(libspinlock_la_LIBADD) $(LIBS)
libstacktrace.la: $(libstacktrace_la_OBJECTS) $(libstacktrace_la_DEPENDENCIES)
$(CXXLINK) -rpath $(libdir) $(libstacktrace_la_LDFLAGS) $(libstacktrace_la_OBJECTS) $(libstacktrace_la_LIBADD) $(LIBS)
libtcmalloc.la: $(libtcmalloc_la_OBJECTS) $(libtcmalloc_la_DEPENDENCIES)
- $(CXXLINK) -rpath $(libdir) $(libtcmalloc_la_LDFLAGS) $(libtcmalloc_la_OBJECTS) $(libtcmalloc_la_LIBADD) $(LIBS)
+ $(CXXLINK) $(am_libtcmalloc_la_rpath) $(libtcmalloc_la_LDFLAGS) $(libtcmalloc_la_OBJECTS) $(libtcmalloc_la_LIBADD) $(LIBS)
libtcmalloc_minimal.la: $(libtcmalloc_minimal_la_OBJECTS) $(libtcmalloc_minimal_la_DEPENDENCIES)
$(CXXLINK) -rpath $(libdir) $(libtcmalloc_minimal_la_LDFLAGS) $(libtcmalloc_minimal_la_OBJECTS) $(libtcmalloc_minimal_la_LIBADD) $(LIBS)
+libwindows.la: $(libwindows_la_OBJECTS) $(libwindows_la_DEPENDENCIES)
+ $(CXXLINK) $(am_libwindows_la_rpath) $(libwindows_la_LDFLAGS) $(libwindows_la_OBJECTS) $(libwindows_la_LIBADD) $(LIBS)
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; for p in $$list; do \
@@ -1133,12 +1418,21 @@ frag_unittest$(EXEEXT): $(frag_unittest_OBJECTS) $(frag_unittest_DEPENDENCIES)
getpc_test$(EXEEXT): $(getpc_test_OBJECTS) $(getpc_test_DEPENDENCIES)
@rm -f getpc_test$(EXEEXT)
$(CXXLINK) $(getpc_test_LDFLAGS) $(getpc_test_OBJECTS) $(getpc_test_LDADD) $(LIBS)
+@MINGW_TRUE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_DEPENDENCIES)
+@MINGW_TRUE@ @rm -f heap-checker-death_unittest.sh$(EXEEXT)
+@MINGW_TRUE@ $(LINK) $(heap_checker_death_unittest_sh_LDFLAGS) $(heap_checker_death_unittest_sh_OBJECTS) $(heap_checker_death_unittest_sh_LDADD) $(LIBS)
heap-checker_unittest$(EXEEXT): $(heap_checker_unittest_OBJECTS) $(heap_checker_unittest_DEPENDENCIES)
@rm -f heap-checker_unittest$(EXEEXT)
$(CXXLINK) $(heap_checker_unittest_LDFLAGS) $(heap_checker_unittest_OBJECTS) $(heap_checker_unittest_LDADD) $(LIBS)
+@MINGW_TRUE@heap-checker_unittest.sh$(EXEEXT): $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_DEPENDENCIES)
+@MINGW_TRUE@ @rm -f heap-checker_unittest.sh$(EXEEXT)
+@MINGW_TRUE@ $(LINK) $(heap_checker_unittest_sh_LDFLAGS) $(heap_checker_unittest_sh_OBJECTS) $(heap_checker_unittest_sh_LDADD) $(LIBS)
heap-profiler_unittest$(EXEEXT): $(heap_profiler_unittest_OBJECTS) $(heap_profiler_unittest_DEPENDENCIES)
@rm -f heap-profiler_unittest$(EXEEXT)
$(CXXLINK) $(heap_profiler_unittest_LDFLAGS) $(heap_profiler_unittest_OBJECTS) $(heap_profiler_unittest_LDADD) $(LIBS)
+@MINGW_TRUE@heap-profiler_unittest.sh$(EXEEXT): $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_DEPENDENCIES)
+@MINGW_TRUE@ @rm -f heap-profiler_unittest.sh$(EXEEXT)
+@MINGW_TRUE@ $(LINK) $(heap_profiler_unittest_sh_LDFLAGS) $(heap_profiler_unittest_sh_OBJECTS) $(heap_profiler_unittest_sh_LDADD) $(LIBS)
low_level_alloc_unittest$(EXEEXT): $(low_level_alloc_unittest_OBJECTS) $(low_level_alloc_unittest_DEPENDENCIES)
@rm -f low_level_alloc_unittest$(EXEEXT)
$(CXXLINK) $(low_level_alloc_unittest_LDFLAGS) $(low_level_alloc_unittest_OBJECTS) $(low_level_alloc_unittest_LDADD) $(LIBS)
@@ -1151,6 +1445,9 @@ memalign_unittest$(EXEEXT): $(memalign_unittest_OBJECTS) $(memalign_unittest_DEP
packed_cache_test$(EXEEXT): $(packed_cache_test_OBJECTS) $(packed_cache_test_DEPENDENCIES)
@rm -f packed_cache_test$(EXEEXT)
$(CXXLINK) $(packed_cache_test_LDFLAGS) $(packed_cache_test_OBJECTS) $(packed_cache_test_LDADD) $(LIBS)
+profiledata_unittest$(EXEEXT): $(profiledata_unittest_OBJECTS) $(profiledata_unittest_DEPENDENCIES)
+ @rm -f profiledata_unittest$(EXEEXT)
+ $(CXXLINK) $(profiledata_unittest_LDFLAGS) $(profiledata_unittest_OBJECTS) $(profiledata_unittest_LDADD) $(LIBS)
profiler1_unittest$(EXEEXT): $(profiler1_unittest_OBJECTS) $(profiler1_unittest_DEPENDENCIES)
@rm -f profiler1_unittest$(EXEEXT)
$(CXXLINK) $(profiler1_unittest_LDFLAGS) $(profiler1_unittest_OBJECTS) $(profiler1_unittest_LDADD) $(LIBS)
@@ -1163,6 +1460,9 @@ profiler3_unittest$(EXEEXT): $(profiler3_unittest_OBJECTS) $(profiler3_unittest_
profiler4_unittest$(EXEEXT): $(profiler4_unittest_OBJECTS) $(profiler4_unittest_DEPENDENCIES)
@rm -f profiler4_unittest$(EXEEXT)
$(CXXLINK) $(profiler4_unittest_LDFLAGS) $(profiler4_unittest_OBJECTS) $(profiler4_unittest_LDADD) $(LIBS)
+@MINGW_TRUE@profiler_unittest.sh$(EXEEXT): $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_DEPENDENCIES)
+@MINGW_TRUE@ @rm -f profiler_unittest.sh$(EXEEXT)
+@MINGW_TRUE@ $(LINK) $(profiler_unittest_sh_LDFLAGS) $(profiler_unittest_sh_OBJECTS) $(profiler_unittest_sh_LDADD) $(LIBS)
ptmalloc_unittest1$(EXEEXT): $(ptmalloc_unittest1_OBJECTS) $(ptmalloc_unittest1_DEPENDENCIES)
@rm -f ptmalloc_unittest1$(EXEEXT)
$(LINK) $(ptmalloc_unittest1_LDFLAGS) $(ptmalloc_unittest1_OBJECTS) $(ptmalloc_unittest1_LDADD) $(LIBS)
@@ -1226,6 +1526,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getpc_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_checker_unittest-heap-checker_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_profiler_unittest-heap-profiler_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_modrm_map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ia32_opcode_map.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-checker-bcad.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-checker.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtcmalloc_la-heap-profile-table.Plo@am__quote@
@@ -1255,7 +1557,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/markidle_unittest-markidle_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/markidle_unittest-testutil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memalign_unittest-memalign_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mini_disassembler.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packed-cache_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/patch_functions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preamble_patcher.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/preamble_patcher_with_stub.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiledata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiledata_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler1_unittest-profiler_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profiler1_unittest-testutil.Po@am__quote@
@@ -1382,6 +1691,13 @@ profiler.lo: src/profiler.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 profiler.lo `test -f 'src/profiler.cc' || echo '$(srcdir)/'`src/profiler.cc
+profiledata.lo: src/profiledata.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiledata.lo -MD -MP -MF "$(DEPDIR)/profiledata.Tpo" -c -o profiledata.lo `test -f 'src/profiledata.cc' || echo '$(srcdir)/'`src/profiledata.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiledata.Tpo" "$(DEPDIR)/profiledata.Plo"; else rm -f "$(DEPDIR)/profiledata.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/profiledata.cc' object='profiledata.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 profiledata.lo `test -f 'src/profiledata.cc' || echo '$(srcdir)/'`src/profiledata.cc
+
sysinfo.lo: src/base/sysinfo.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sysinfo.lo -MD -MP -MF "$(DEPDIR)/sysinfo.Tpo" -c -o sysinfo.lo `test -f 'src/base/sysinfo.cc' || echo '$(srcdir)/'`src/base/sysinfo.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/sysinfo.Tpo" "$(DEPDIR)/sysinfo.Plo"; else rm -f "$(DEPDIR)/sysinfo.Tpo"; exit 1; fi
@@ -1557,6 +1873,55 @@ libtcmalloc_minimal_la-maybe_threads.lo: src/maybe_threads.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtcmalloc_minimal_la_CXXFLAGS) $(CXXFLAGS) -c -o libtcmalloc_minimal_la-maybe_threads.lo `test -f 'src/maybe_threads.cc' || echo '$(srcdir)/'`src/maybe_threads.cc
+port.lo: src/windows/port.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT port.lo -MD -MP -MF "$(DEPDIR)/port.Tpo" -c -o port.lo `test -f 'src/windows/port.cc' || echo '$(srcdir)/'`src/windows/port.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/port.Tpo" "$(DEPDIR)/port.Plo"; else rm -f "$(DEPDIR)/port.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/port.cc' object='port.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 port.lo `test -f 'src/windows/port.cc' || echo '$(srcdir)/'`src/windows/port.cc
+
+ia32_modrm_map.lo: src/windows/ia32_modrm_map.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ia32_modrm_map.lo -MD -MP -MF "$(DEPDIR)/ia32_modrm_map.Tpo" -c -o ia32_modrm_map.lo `test -f 'src/windows/ia32_modrm_map.cc' || echo '$(srcdir)/'`src/windows/ia32_modrm_map.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ia32_modrm_map.Tpo" "$(DEPDIR)/ia32_modrm_map.Plo"; else rm -f "$(DEPDIR)/ia32_modrm_map.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/ia32_modrm_map.cc' object='ia32_modrm_map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ia32_modrm_map.lo `test -f 'src/windows/ia32_modrm_map.cc' || echo '$(srcdir)/'`src/windows/ia32_modrm_map.cc
+
+ia32_opcode_map.lo: src/windows/ia32_opcode_map.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ia32_opcode_map.lo -MD -MP -MF "$(DEPDIR)/ia32_opcode_map.Tpo" -c -o ia32_opcode_map.lo `test -f 'src/windows/ia32_opcode_map.cc' || echo '$(srcdir)/'`src/windows/ia32_opcode_map.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/ia32_opcode_map.Tpo" "$(DEPDIR)/ia32_opcode_map.Plo"; else rm -f "$(DEPDIR)/ia32_opcode_map.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/ia32_opcode_map.cc' object='ia32_opcode_map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ia32_opcode_map.lo `test -f 'src/windows/ia32_opcode_map.cc' || echo '$(srcdir)/'`src/windows/ia32_opcode_map.cc
+
+mini_disassembler.lo: src/windows/mini_disassembler.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mini_disassembler.lo -MD -MP -MF "$(DEPDIR)/mini_disassembler.Tpo" -c -o mini_disassembler.lo `test -f 'src/windows/mini_disassembler.cc' || echo '$(srcdir)/'`src/windows/mini_disassembler.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/mini_disassembler.Tpo" "$(DEPDIR)/mini_disassembler.Plo"; else rm -f "$(DEPDIR)/mini_disassembler.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/mini_disassembler.cc' object='mini_disassembler.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 mini_disassembler.lo `test -f 'src/windows/mini_disassembler.cc' || echo '$(srcdir)/'`src/windows/mini_disassembler.cc
+
+patch_functions.lo: src/windows/patch_functions.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT patch_functions.lo -MD -MP -MF "$(DEPDIR)/patch_functions.Tpo" -c -o patch_functions.lo `test -f 'src/windows/patch_functions.cc' || echo '$(srcdir)/'`src/windows/patch_functions.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/patch_functions.Tpo" "$(DEPDIR)/patch_functions.Plo"; else rm -f "$(DEPDIR)/patch_functions.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/patch_functions.cc' object='patch_functions.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 patch_functions.lo `test -f 'src/windows/patch_functions.cc' || echo '$(srcdir)/'`src/windows/patch_functions.cc
+
+preamble_patcher.lo: src/windows/preamble_patcher.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT preamble_patcher.lo -MD -MP -MF "$(DEPDIR)/preamble_patcher.Tpo" -c -o preamble_patcher.lo `test -f 'src/windows/preamble_patcher.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/preamble_patcher.Tpo" "$(DEPDIR)/preamble_patcher.Plo"; else rm -f "$(DEPDIR)/preamble_patcher.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/preamble_patcher.cc' object='preamble_patcher.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 preamble_patcher.lo `test -f 'src/windows/preamble_patcher.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher.cc
+
+preamble_patcher_with_stub.lo: src/windows/preamble_patcher_with_stub.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT preamble_patcher_with_stub.lo -MD -MP -MF "$(DEPDIR)/preamble_patcher_with_stub.Tpo" -c -o preamble_patcher_with_stub.lo `test -f 'src/windows/preamble_patcher_with_stub.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher_with_stub.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/preamble_patcher_with_stub.Tpo" "$(DEPDIR)/preamble_patcher_with_stub.Plo"; else rm -f "$(DEPDIR)/preamble_patcher_with_stub.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/windows/preamble_patcher_with_stub.cc' object='preamble_patcher_with_stub.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 preamble_patcher_with_stub.lo `test -f 'src/windows/preamble_patcher_with_stub.cc' || echo '$(srcdir)/'`src/windows/preamble_patcher_with_stub.cc
+
addressmap_unittest-addressmap_unittest.o: src/tests/addressmap_unittest.cc
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(addressmap_unittest_CXXFLAGS) $(CXXFLAGS) -MT addressmap_unittest-addressmap_unittest.o -MD -MP -MF "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo" -c -o addressmap_unittest-addressmap_unittest.o `test -f 'src/tests/addressmap_unittest.cc' || echo '$(srcdir)/'`src/tests/addressmap_unittest.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo" "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Po"; else rm -f "$(DEPDIR)/addressmap_unittest-addressmap_unittest.Tpo"; exit 1; fi
@@ -1739,6 +2104,20 @@ packed-cache_test.obj: src/tests/packed-cache_test.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o packed-cache_test.obj `if test -f 'src/tests/packed-cache_test.cc'; then $(CYGPATH_W) 'src/tests/packed-cache_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/packed-cache_test.cc'; fi`
+profiledata_unittest.o: src/tests/profiledata_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiledata_unittest.o -MD -MP -MF "$(DEPDIR)/profiledata_unittest.Tpo" -c -o profiledata_unittest.o `test -f 'src/tests/profiledata_unittest.cc' || echo '$(srcdir)/'`src/tests/profiledata_unittest.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiledata_unittest.Tpo" "$(DEPDIR)/profiledata_unittest.Po"; else rm -f "$(DEPDIR)/profiledata_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiledata_unittest.cc' object='profiledata_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o profiledata_unittest.o `test -f 'src/tests/profiledata_unittest.cc' || echo '$(srcdir)/'`src/tests/profiledata_unittest.cc
+
+profiledata_unittest.obj: src/tests/profiledata_unittest.cc
+@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT profiledata_unittest.obj -MD -MP -MF "$(DEPDIR)/profiledata_unittest.Tpo" -c -o profiledata_unittest.obj `if test -f 'src/tests/profiledata_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiledata_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiledata_unittest.cc'; fi`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiledata_unittest.Tpo" "$(DEPDIR)/profiledata_unittest.Po"; else rm -f "$(DEPDIR)/profiledata_unittest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/tests/profiledata_unittest.cc' object='profiledata_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o profiledata_unittest.obj `if test -f 'src/tests/profiledata_unittest.cc'; then $(CYGPATH_W) 'src/tests/profiledata_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tests/profiledata_unittest.cc'; fi`
+
profiler1_unittest-profiler_unittest.o: src/tests/profiler_unittest.cc
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(profiler1_unittest_CXXFLAGS) $(CXXFLAGS) -MT profiler1_unittest-profiler_unittest.o -MD -MP -MF "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo" -c -o profiler1_unittest-profiler_unittest.o `test -f 'src/tests/profiler_unittest.cc' || echo '$(srcdir)/'`src/tests/profiler_unittest.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo" "$(DEPDIR)/profiler1_unittest-profiler_unittest.Po"; else rm -f "$(DEPDIR)/profiler1_unittest-profiler_unittest.Tpo"; exit 1; fi
@@ -2232,7 +2611,7 @@ check-TESTS: $(TESTS)
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
- $(mkdir_p) $(distdir)/$(top_srcdir) $(distdir)/doc $(distdir)/m4 $(distdir)/packages $(distdir)/packages/rpm $(distdir)/src $(distdir)/src/google $(distdir)/src/solaris $(distdir)/src/tests $(distdir)/vsprojects/addressmap_unittest $(distdir)/vsprojects/frag_unittest $(distdir)/vsprojects/libtcmalloc_minimal $(distdir)/vsprojects/low_level_alloc_unittest $(distdir)/vsprojects/markidle_unittest $(distdir)/vsprojects/memalign_unittest $(distdir)/vsprojects/packed-cache_test $(distdir)/vsprojects/system_alloc_unittest $(distdir)/vsprojects/tcmalloc_minimal_large $(distdir)/vsprojects/tcmalloc_minimal_unittest $(distdir)/vsprojects/tcmalloc_minimal_unittest-static $(distdir)/vsprojects/thread_dealloc_unittest
+ $(mkdir_p) $(distdir)/$(top_srcdir) $(distdir)/doc $(distdir)/m4 $(distdir)/packages $(distdir)/packages/rpm $(distdir)/src $(distdir)/src/google $(distdir)/src/solaris $(distdir)/src/tests $(distdir)/src/windows $(distdir)/vsprojects/addressmap_unittest $(distdir)/vsprojects/frag_unittest $(distdir)/vsprojects/libtcmalloc_minimal $(distdir)/vsprojects/low_level_alloc_unittest $(distdir)/vsprojects/markidle_unittest $(distdir)/vsprojects/memalign_unittest $(distdir)/vsprojects/packed-cache_test $(distdir)/vsprojects/system_alloc_unittest $(distdir)/vsprojects/tcmalloc_minimal_large $(distdir)/vsprojects/tcmalloc_minimal_unittest $(distdir)/vsprojects/tcmalloc_minimal_unittest-static $(distdir)/vsprojects/thread_dealloc_unittest
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
@@ -2475,31 +2854,31 @@ uninstall-man: uninstall-man1
@ENABLE_FRAME_POINTER_FALSE@@X86_64_TRUE@ # TODO(csilvers): check if -fomit-frame-pointer might be in $(CXXFLAGS),
@ENABLE_FRAME_POINTER_FALSE@@X86_64_TRUE@ # before setting this.
-pprof_unittest: $(top_srcdir)/src/pprof
- $(top_srcdir)/src/pprof -test
+@MINGW_FALSE@pprof_unittest: $(top_srcdir)/src/pprof
+@MINGW_FALSE@ $(top_srcdir)/src/pprof -test
# This script preloads libtcmalloc, and calls two other binaries as well
maybe_threads_unittest.sh$(EXEEXT): $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) \
- $(LIBTCMALLOC) \
- low_level_alloc_unittest profiler1_unittest
+ $(LIBTCMALLOC_MINIMAL) \
+ low_level_alloc_unittest
rm -f $@
cp -p $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) $@
-heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \
- heap-profiler_unittest
- rm -f $@
- cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@
-heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \
- heap-checker_unittest
- rm -f $@
- cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@
-heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCES) \
- heap-checker_unittest
- rm -f $@
- cp -p $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) $@
-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \
- profiler1_unittest profiler2_unittest \
- profiler3_unittest profiler4_unittest
- rm -f $@
- cp -p $(top_srcdir)/$(profiler_unittest_sh_SOURCES) $@
+@MINGW_FALSE@heap-profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) \
+@MINGW_FALSE@ heap-profiler_unittest
+@MINGW_FALSE@ rm -f $@
+@MINGW_FALSE@ cp -p $(top_srcdir)/$(heap_profiler_unittest_sh_SOURCES) $@
+@MINGW_FALSE@heap-checker_unittest.sh$(EXEEXT): $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) \
+@MINGW_FALSE@ heap-checker_unittest
+@MINGW_FALSE@ rm -f $@
+@MINGW_FALSE@ cp -p $(top_srcdir)/$(heap_checker_unittest_sh_SOURCES) $@
+@MINGW_FALSE@heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCES) \
+@MINGW_FALSE@ heap-checker_unittest
+@MINGW_FALSE@ rm -f $@
+@MINGW_FALSE@ cp -p $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES) $@
+@MINGW_FALSE@profiler_unittest.sh$(EXEEXT): $(top_srcdir)/$(profiler_unittest_sh_SOURCES) \
+@MINGW_FALSE@ profiler1_unittest profiler2_unittest \
+@MINGW_FALSE@ profiler3_unittest profiler4_unittest
+@MINGW_FALSE@ rm -f $@
+@MINGW_FALSE@ cp -p $(top_srcdir)/$(profiler_unittest_sh_SOURCES) $@
rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec
@cd packages && ./rpm.sh ${PACKAGE} ${VERSION}
diff --git a/configure b/configure
index b8e2b13..56a6b64 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for google-perftools 0.93.
+# Generated by GNU Autoconf 2.59 for google-perftools 0.94.
#
# Report bugs to <opensource@google.com>.
#
@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='google-perftools'
PACKAGE_TARNAME='google-perftools'
-PACKAGE_VERSION='0.93'
-PACKAGE_STRING='google-perftools 0.93'
+PACKAGE_VERSION='0.94'
+PACKAGE_STRING='google-perftools 0.94'
PACKAGE_BUGREPORT='opensource@google.com'
ac_unique_file="README"
@@ -465,7 +465,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE GCC_TRUE GCC_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBTOOL_DEPS UNWIND_LIBS ENABLE_FRAME_POINTER_TRUE ENABLE_FRAME_POINTER_FALSE X86_64_TRUE X86_64_FALSE acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE GCC_TRUE GCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBTOOL_DEPS UNWIND_LIBS ENABLE_FRAME_POINTER_TRUE ENABLE_FRAME_POINTER_FALSE X86_64_TRUE X86_64_FALSE acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS MINGW_TRUE MINGW_FALSE LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures google-perftools 0.93 to adapt to many kinds of systems.
+\`configure' configures google-perftools 0.94 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1015,12 +1015,13 @@ Program names:
System types:
--build=BUILD configure for building on BUILD [guessed]
--host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of google-perftools 0.93:";;
+ short | recursive ) echo "Configuration of google-perftools 0.94:";;
esac
cat <<\_ACEOF
@@ -1161,7 +1162,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-google-perftools configure 0.93
+google-perftools configure 0.94
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1175,7 +1176,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by google-perftools $as_me 0.93, which was
+It was created by google-perftools $as_me 0.94, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
@@ -1514,7 +1515,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# The argument here is just something that should be in the current directory
# (for sanity checking)
-am__api_version="1.9"
ac_aux_dir=
for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
if test -f $ac_dir/install-sh; then
@@ -1540,6 +1540,89 @@ ac_config_guess="$SHELL $ac_aux_dir/config.guess"
ac_config_sub="$SHELL $ac_aux_dir/config.sub"
ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6
+if test "${ac_cv_target+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_target_alias=$target_alias
+test "x$ac_cv_target_alias" = "x" &&
+ ac_cv_target_alias=$ac_cv_host_alias
+ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
+ { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6
+target=$ac_cv_target
+target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+am__api_version="1.9"
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
# incompatible versions:
@@ -1821,7 +1904,7 @@ fi
# Define the identity of the package.
PACKAGE='google-perftools'
- VERSION='0.93'
+ VERSION='0.94'
cat >>confdefs.h <<_ACEOF
@@ -3830,60 +3913,6 @@ else
enable_fast_install=yes
fi;
-# Make sure we can run config.sub.
-$ac_config_sub sun4 >/dev/null 2>&1 ||
- { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
-echo "$as_me: error: cannot run $ac_config_sub" >&2;}
- { (exit 1); exit 1; }; }
-
-echo "$as_me:$LINENO: checking build system type" >&5
-echo $ECHO_N "checking build system type... $ECHO_C" >&6
-if test "${ac_cv_build+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_build_alias=$build_alias
-test -z "$ac_cv_build_alias" &&
- ac_cv_build_alias=`$ac_config_guess`
-test -z "$ac_cv_build_alias" &&
- { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
-echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
- { (exit 1); exit 1; }; }
-ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
- { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
-echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
- { (exit 1); exit 1; }; }
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_build" >&5
-echo "${ECHO_T}$ac_cv_build" >&6
-build=$ac_cv_build
-build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-
-echo "$as_me:$LINENO: checking host system type" >&5
-echo $ECHO_N "checking host system type... $ECHO_C" >&6
-if test "${ac_cv_host+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_host_alias=$host_alias
-test -z "$ac_cv_host_alias" &&
- ac_cv_host_alias=$ac_cv_build_alias
-ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
- { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
-echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
- { (exit 1); exit 1; }; }
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_host" >&5
-echo "${ECHO_T}$ac_cv_host" >&6
-host=$ac_cv_host
-host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-
echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6
if test "${lt_cv_path_SED+set}" = set; then
@@ -4378,7 +4407,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 4381 "configure"' > conftest.$ac_ext
+ echo '#line 4410 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -5275,7 +5304,7 @@ fi
# Provide some information about the compiler.
-echo "$as_me:5278:" \
+echo "$as_me:5307:" \
"checking for Fortran 77 compiler version" >&5
ac_compiler=`set X $ac_compile; echo $2`
{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
@@ -6336,11 +6365,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6339: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6368: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:6343: \$? = $ac_status" >&5
+ echo "$as_me:6372: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -6604,11 +6633,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6607: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6636: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:6611: \$? = $ac_status" >&5
+ echo "$as_me:6640: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -6708,11 +6737,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6711: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6740: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:6715: \$? = $ac_status" >&5
+ echo "$as_me:6744: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9066,7 +9095,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 9069 "configure"
+#line 9098 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9166,7 +9195,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 9169 "configure"
+#line 9198 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11504,11 +11533,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:11507: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:11536: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:11511: \$? = $ac_status" >&5
+ echo "$as_me:11540: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -11608,11 +11637,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:11611: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:11640: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:11615: \$? = $ac_status" >&5
+ echo "$as_me:11644: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -13196,11 +13225,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13199: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13228: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:13203: \$? = $ac_status" >&5
+ echo "$as_me:13232: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -13300,11 +13329,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13303: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13332: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13307: \$? = $ac_status" >&5
+ echo "$as_me:13336: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -15523,11 +15552,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15526: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15555: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:15530: \$? = $ac_status" >&5
+ echo "$as_me:15559: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -15791,11 +15820,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15794: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15823: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:15798: \$? = $ac_status" >&5
+ echo "$as_me:15827: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -15895,11 +15924,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15898: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15927: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15902: \$? = $ac_status" >&5
+ echo "$as_me:15931: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -22015,9 +22044,12 @@ pc_fields="$pc_fields uc_mcontext.gregs[REG_RIP]" # Linux (x86_64)
pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64)
pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386)
pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [untested])
-pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386)
+pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4)
+pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5)
pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64)
+pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (>=10.5 [untested])
pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [untested])
+pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (>=10.5 [untested])
pc_field_found=false
for pc_field in $pc_fields; do
if ! $pc_field_found; then
@@ -23628,6 +23660,23 @@ cat >>confdefs.h <<\_ACEOF
_ACEOF
+# MinGW uses autoconf, but also needs the windows shim routines
+# (since it doesn't have its own support for, say, pthreads).
+# This requires us to #include a special header file, and also to
+# link in some windows versions of .o's instead of the unix versions.
+
+
+
+
+if expr $target : '.*-mingw' >/dev/null 2>&1; then
+ MINGW_TRUE=
+ MINGW_FALSE='#'
+else
+ MINGW_TRUE='#'
+ MINGW_FALSE=
+fi
+
+
# Write generated configuration file
ac_config_files="$ac_config_files Makefile"
@@ -23764,6 +23813,13 @@ echo "$as_me: error: conditional \"X86_64\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"MINGW\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"MINGW\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
: ${CONFIG_STATUS=./config.status}
ac_clean_files_save=$ac_clean_files
@@ -24035,7 +24091,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by google-perftools $as_me 0.93, which was
+This file was extended by google-perftools $as_me 0.94, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -24098,7 +24154,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-google-perftools config.status 0.93
+google-perftools config.status 0.94
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@@ -24296,6 +24352,18 @@ s,@ECHO_C@,$ECHO_C,;t t
s,@ECHO_N@,$ECHO_N,;t t
s,@ECHO_T@,$ECHO_T,;t t
s,@LIBS@,$LIBS,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@target@,$target,;t t
+s,@target_cpu@,$target_cpu,;t t
+s,@target_vendor@,$target_vendor,;t t
+s,@target_os@,$target_os,;t t
s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
s,@INSTALL_DATA@,$INSTALL_DATA,;t t
@@ -24343,14 +24411,6 @@ s,@am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t
s,@am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t
s,@GCC_TRUE@,$GCC_TRUE,;t t
s,@GCC_FALSE@,$GCC_FALSE,;t t
-s,@build@,$build,;t t
-s,@build_cpu@,$build_cpu,;t t
-s,@build_vendor@,$build_vendor,;t t
-s,@build_os@,$build_os,;t t
-s,@host@,$host,;t t
-s,@host_cpu@,$host_cpu,;t t
-s,@host_vendor@,$host_vendor,;t t
-s,@host_os@,$host_os,;t t
s,@EGREP@,$EGREP,;t t
s,@LN_S@,$LN_S,;t t
s,@ECHO@,$ECHO,;t t
@@ -24373,6 +24433,8 @@ s,@acx_pthread_config@,$acx_pthread_config,;t t
s,@PTHREAD_CC@,$PTHREAD_CC,;t t
s,@PTHREAD_LIBS@,$PTHREAD_LIBS,;t t
s,@PTHREAD_CFLAGS@,$PTHREAD_CFLAGS,;t t
+s,@MINGW_TRUE@,$MINGW_TRUE,;t t
+s,@MINGW_FALSE@,$MINGW_FALSE,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t
CEOF
diff --git a/configure.ac b/configure.ac
index 2a9474e..32482e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,10 +4,11 @@
# make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57)
-AC_INIT(google-perftools, 0.93, opensource@google.com)
+AC_INIT(google-perftools, 0.94, opensource@google.com)
# The argument here is just something that should be in the current directory
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
+AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([dist-zip])
AM_CONFIG_HEADER(src/config.h)
@@ -76,9 +77,12 @@ pc_fields="$pc_fields uc_mcontext.gregs[[REG_RIP]]" # Linux (x86_64)
pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64)
pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386)
pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [untested])
-pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386)
+pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4)
+pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5)
pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64)
+pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (>=10.5 [untested])
pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [untested])
+pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (>=10.5 [untested])
pc_field_found=false
for pc_field in $pc_fields; do
if ! $pc_field_found; then
@@ -165,6 +169,17 @@ AC_DEFINE(PERFTOOLS_DLL_DECL,,
internally, to compile the DLL, and every DLL source file
#includes "config.h" before anything else.])
+# MinGW uses autoconf, but also needs the windows shim routines
+# (since it doesn't have its own support for, say, pthreads).
+# This requires us to #include a special header file, and also to
+# link in some windows versions of .o's instead of the unix versions.
+AH_BOTTOM([
+#ifdef __MINGW32__
+#include "windows/mingw.h"
+#endif
+])
+AM_CONDITIONAL(MINGW, expr $target : '.*-mingw' >/dev/null 2>&1)
+
# Write generated configuration file
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
diff --git a/doc/cpuprofile-fileformat.html b/doc/cpuprofile-fileformat.html
new file mode 100644
index 0000000..3f90e6b
--- /dev/null
+++ b/doc/cpuprofile-fileformat.html
@@ -0,0 +1,264 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <link rel="stylesheet" href="designstyle.css">
+ <title>Google CPU Profiler Binary Data File Format</title>
+</HEAD>
+
+<BODY>
+
+<h1>Google CPU Profiler Binary Data File Format</h1>
+
+<p align=right>
+ <i>Last modified
+ <script type=text/javascript>
+ var lm = new Date(document.lastModified);
+ document.write(lm.toDateString());
+ </script></i>
+</p>
+
+<p>This file documents the binary data file format produced by the
+Google CPU Profiler. For information about using the CPU Profiler,
+see <a href="cpuprofile.html">its user guide</a>.
+
+<p>The profiler source code, which generates files using this format, is at
+<code>src/profiler.cc</code></a>.
+
+
+<h2>CPU Profile Data File Structure</h2>
+
+<p>CPU profile data files each consist of four parts, in order:
+
+<ul>
+ <li> Binary header
+ <li> Binary profile records
+ <li> Binary trailer
+ <li> Text list of mapped objects
+</ul>
+
+<p>The binary data is expressed in terms of "slots." These are words
+large enough to hold the program's pointer type, i.e., for 32-bit
+programs they are 4 bytes in size, and for 64-bit programs they are 8
+bytes. They are stored in the profile data file in the native byte
+order (i.e., little-endian for x86 and x86_64).
+
+
+<h2>Binary Header</h2>
+
+<p>The binary header format is show below. Values written by the
+profiler, along with requirements currently enforced by the analysis
+tools, are shown in parentheses.
+
+<p>
+<table summary="Header Format"
+ frame="box" rules="sides" cellpadding="5" width="50%">
+ <tr>
+ <th width="30%">slot</th>
+ <th width="70%">data</th>
+ </tr>
+
+ <tr>
+ <td>0</td>
+ <td>header count (0; must be 0)</td>
+ </tr>
+
+ <tr>
+ <td>1</td>
+ <td>header slots after this one (3; must be &gt;= 3)</td>
+ </tr>
+
+ <tr>
+ <td>2</td>
+ <td>format version (0; must be 0)</td>
+ </tr>
+
+ <tr>
+ <td>3</td>
+ <td>sampling period, in microseconds</td>
+ </tr>
+
+ <tr>
+ <td>4</td>
+ <td>padding (0)</td>
+ </tr>
+</table>
+
+<p>The headers currently generated for 32-bit and 64-bit little-endian
+(x86 and x86_64) profiles are shown below, for comparison.
+
+<p>
+<table summary="Header Example" frame="box" rules="sides" cellpadding="5">
+ <tr>
+ <th></th>
+ <th>hdr count</th>
+ <th>hdr words</th>
+ <th>version</th>
+ <th>sampling period</th>
+ <th>pad</th>
+ </tr>
+ <tr>
+ <td>32-bit or 64-bit (slots)</td>
+ <td>0</td>
+ <td>3</td>
+ <td>0</td>
+ <td>10000</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>32-bit (4-byte words in file)</td>
+ <td><tt>0x00000</tt></td>
+ <td><tt>0x00003</tt></td>
+ <td><tt>0x00000</tt></td>
+ <td><tt>0x02710</tt></td>
+ <td><tt>0x00000</tt></td>
+ </tr>
+ <tr>
+ <td>64-bit LE (4-byte words in file)</td>
+ <td><tt>0x00000&nbsp;0x00000</tt></td>
+ <td><tt>0x00003&nbsp;0x00000</tt></td>
+ <td><tt>0x00000&nbsp;0x00000</tt></td>
+ <td><tt>0x02710&nbsp;0x00000</tt></td>
+ <td><tt>0x00000&nbsp;0x00000</tt></td>
+ </tr>
+</table>
+
+<p>The contents are shown in terms of slots, and in terms of 4-byte
+words in the profile data file. The slot contents for 32-bit and
+64-bit headers are identical. For 32-bit profiles, the 4-byte word
+view matches the slot view. For 64-bit profiles, each (8-byte) slot
+is shown as two 4-byte words, ordered as they would appear in the
+file.
+
+<p>The profiling tools examine the contents of the file and use the
+expected locations and values of the header words field to detect
+whether the file is 32-bit or 64-bit.
+
+
+<h2>Binary Profile Records</h2>
+
+<p>The binary profile record format is shown below.
+
+<p>
+<table summary="Profile Record Format"
+ frame="box" rules="sides" cellpadding="5" width="50%">
+ <tr>
+ <th width="30%">slot</th>
+ <th width="70%">data</th>
+ </tr>
+
+ <tr>
+ <td>0</td>
+ <td>sample count, must be &gt;= 1</td>
+ </tr>
+
+ <tr>
+ <td>1</td>
+ <td>number of call chain PCs (num_pcs), must be &gt;= 1</td>
+ </tr>
+
+ <tr>
+ <td>2 .. (num_pcs + 1)</td>
+ <td>call chain PCs, most-recently-called function first.
+ </tr>
+</table>
+
+<p>The total length of a given record is 2 + num_pcs.
+
+<p>Note that multiple profile records can be emitted by the profiler
+having an identical call chain. In that case, analysis tools should
+sum the counts of all records having identical call chains.
+
+<p><b>Note:</b> Some profile analysis tools terminate if they see
+<em>any</em> profile record with a call chain with its first entry
+having the address 0. (This is similar to the binary trailer.)
+
+<h3>Example</h3>
+
+This example shows the slots contained in a sample profile record.
+
+<p>
+<table summary="Profile Record Example"
+ frame="box" rules="sides" cellpadding="5">
+ <tr>
+ <td>5</td>
+ <td>3</td>
+ <td>0xa0000</td>
+ <td>0xc0000</td>
+ <td>0xe0000</td>
+ </tr>
+</table>
+
+<p>In this example, 5 ticks were received at PC 0xa0000, whose
+function had been called by the function containing 0xc0000, which had
+been called from the function containing 0xe0000.
+
+
+<h2>Binary Trailer</h2>
+
+<p>The binary trailer consists of three slots of data with fixed
+values, shown below.
+
+<p>
+<table summary="Trailer Format"
+ frame="box" rules="sides" cellpadding="5" width="50%">
+ <tr>
+ <th width="30%">slot</th>
+ <th width="70%">value</th>
+ </tr>
+
+ <tr>
+ <td>0</td>
+ <td>0</td>
+ </tr>
+
+ <tr>
+ <td>1</td>
+ <td>1</td>
+ </tr>
+
+ <tr>
+ <td>2</td>
+ <td>0</td>
+ </tr>
+</table>
+
+<p>Note that this is the same data that would contained in a profile
+record with sample count = 0, num_pcs = 1, and a one-element call
+chain containing the address 0.
+
+
+<h2>Text List of Mapped Objects</h2>
+
+<p>The binary data in the file is followed immediately by a list of
+mapped objects. This list consists of lines of text separated by
+newline characters.
+
+<p>Each line is one of the following types:
+
+<ul>
+ <li>Build specifier, starting with "<tt>build=</tt>". For example:
+ <pre> build=/path/to/binary</pre>
+ Leading spaces on the line are ignored.
+
+ <li>Mapping line from ProcMapsIterator::FormatLine. For example:
+ <pre> 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so</pre>
+ The first address must start at the beginning of the line.
+</ul>
+
+<p>Unrecognized lines should be ignored by analysis tools.
+
+<p>When processing the paths see in mapping lines, occurrences of
+<tt>$build</tt> followed by a non-word character (i.e., characters
+other than underscore or alphanumeric characters), should be replaced
+by the path given on the last build specifier line.
+
+<hr>
+<address>Chris Demetriou<br>
+<!-- Created: Mon Aug 27 12:18:26 PDT 2007 -->
+<!-- hhmts start -->
+Last modified: Mon Aug 27 12:18:26 PDT 2007 (cgd)
+<!-- hhmts end -->
+</address>
+</BODY>
+</HTML>
diff --git a/doc/cpuprofile.html b/doc/cpuprofile.html
index 54c90c2..d30a8aa 100644
--- a/doc/cpuprofile.html
+++ b/doc/cpuprofile.html
@@ -20,6 +20,10 @@
to using it: linking the library into an application, running the
code, and analyzing the output.</p>
+<p>On the off-chance that you should need to understand it, the CPU
+profiler data file format is documented separately,
+<a href="cpuprofile-fileformat.html">here</a>.
+
<H1>Linking in the Library</H1>
diff --git a/packages/deb/changelog b/packages/deb/changelog
index e26ba9a..ee237af 100644
--- a/packages/deb/changelog
+++ b/packages/deb/changelog
@@ -1,3 +1,9 @@
+google-perftools (0.94-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Google Inc. <opensource@google.com> Thu, 29 Nov 2007 07:59:43 -0800
+
google-perftools (0.93-1) unstable; urgency=low
* New upstream release.
diff --git a/src/base/linux_syscall_support.h b/src/base/linux_syscall_support.h
index b308ced..0c11170 100644
--- a/src/base/linux_syscall_support.h
+++ b/src/base/linux_syscall_support.h
@@ -98,14 +98,17 @@ extern "C" {
#include <syscall.h>
#include <unistd.h>
#include <linux/unistd.h>
+#include <endian.h>
-/* libc defines versions of stat, dirent, and dirent64 that are incompatible
- * with the structures that the kernel API expects. If you wish to use
- * sys_fstat(), sys_stat(), sys_getdents(), or sys_getdents64(), you will
- * need to include the kernel headers in your code.
+/* libc defines versions of stat, dirent, dirent64, and statfs64 that are
+ * incompatible with the structures that the kernel API expects. If you wish
+ * to use sys_fstat(), sys_stat(), sys_getdents(), sys_getdents64(),
+ * sys_statfs64(), or sys_statfs() you will need to include the kernel
+ * headers in your code.
*
* asm/posix_types.h
* asm/stat.h
+ * asm/statfs.h
* asm/types.h
* linux/dirent.h
*/
@@ -118,6 +121,8 @@ struct rlimit;
struct sockaddr;
struct stat;
struct stat64;
+struct statfs;
+struct statfs64;
#endif
@@ -177,6 +182,21 @@ struct stat64;
#ifndef __NR_gettid
#define __NR_gettid 224
#endif
+#ifndef __NR_readahead
+#define __NR_readahead 225
+#endif
+#ifndef __NR_setxattr
+#define __NR_setxattr 226
+#endif
+#ifndef __NR_lsetxattr
+#define __NR_lsetxattr 227
+#endif
+#ifndef __NR_getxattr
+#define __NR_getxattr 229
+#endif
+#ifndef __NR_lgetxattr
+#define __NR_lgetxattr 230
+#endif
#ifndef __NR_futex
#define __NR_futex 240
#endif
@@ -187,6 +207,15 @@ struct stat64;
#ifndef __NR_set_tid_address
#define __NR_set_tid_address 258
#endif
+#ifndef __NR_statfs64
+#define __NR_statfs64 268
+#endif
+#ifndef __NR_fstatfs64
+#define __NR_fstatfs64 269
+#endif
+#ifndef __NR_fadvise64_64
+#define __NR_fadvise64_64 272
+#endif
#ifndef __NR_openat
#define __NR_openat 295
#endif
@@ -222,6 +251,21 @@ struct stat64;
#ifndef __NR_gettid
#define __NR_gettid (__NR_SYSCALL_BASE + 224)
#endif
+#ifndef __NR_readahead
+#define __NR_readahead (__NR_SYSCALL_BASE + 225)
+#endif
+#ifndef __NR_setxattr
+#define __NR_setxattr (__NR_SYSCALL_BASE + 226)
+#endif
+#ifndef __NR_lsetxattr
+#define __NR_lsetxattr (__NR_SYSCALL_BASE + 227)
+#endif
+#ifndef __NR_getxattr
+#define __NR_getxattr (__NR_SYSCALL_BASE + 229)
+#endif
+#ifndef __NR_lgetxattr
+#define __NR_lgetxattr (__NR_SYSCALL_BASE + 230)
+#endif
#ifndef __NR_futex
#define __NR_futex (__NR_SYSCALL_BASE + 240)
#endif
@@ -232,6 +276,12 @@ struct stat64;
#ifndef __NR_set_tid_address
#define __NR_set_tid_address (__NR_SYSCALL_BASE + 256)
#endif
+#ifndef __NR_statfs64
+#define __NR_statfs64 (__NR_SYSCALL_BASE + 266)
+#endif
+#ifndef __NR_fstatfs64
+#define __NR_fstatfs64 (__NR_SYSCALL_BASE + 267)
+#endif
#ifndef __NR_move_pages
#define __NR_move_pages (__NR_SYSCALL_BASE + 344)
#endif
@@ -244,6 +294,21 @@ struct stat64;
#ifndef __NR_gettid
#define __NR_gettid 186
#endif
+#ifndef __NR_readahead
+#define __NR_readahead 187
+#endif
+#ifndef __NR_setxattr
+#define __NR_setxattr 188
+#endif
+#ifndef __NR_lsetxattr
+#define __NR_lsetxattr 189
+#endif
+#ifndef __NR_getxattr
+#define __NR_getxattr 191
+#endif
+#ifndef __NR_lgetxattr
+#define __NR_lgetxattr 192
+#endif
#ifndef __NR_futex
#define __NR_futex 202
#endif
@@ -257,6 +322,9 @@ struct stat64;
#ifndef __NR_set_tid_address
#define __NR_set_tid_address 218
#endif
+#ifndef __NR_fadvise64
+#define __NR_fadvise64 221
+#endif
#ifndef __NR_openat
#define __NR_openat 257
#endif
@@ -282,6 +350,21 @@ struct stat64;
#ifndef __NR_gettid
#define __NR_gettid (__NR_Linux + 222)
#endif
+#ifndef __NR_readahead
+#define __NR_readahead (__NR_Linux + 223)
+#endif
+#ifndef __NR_setxattr
+#define __NR_setxattr (__NR_Linux + 224)
+#endif
+#ifndef __NR_lsetxattr
+#define __NR_lsetxattr (__NR_Linux + 225)
+#endif
+#ifndef __NR_getxattr
+#define __NR_getxattr (__NR_Linux + 227)
+#endif
+#ifndef __NR_lgetxattr
+#define __NR_lgetxattr (__NR_Linux + 228)
+#endif
#ifndef __NR_futex
#define __NR_futex (__NR_Linux + 238)
#endif
@@ -292,6 +375,12 @@ struct stat64;
#ifndef __NR_set_tid_address
#define __NR_set_tid_address (__NR_Linux + 252)
#endif
+#ifndef __NR_statfs64
+#define __NR_statfs64 (__NR_Linux + 255)
+#endif
+#ifndef __NR_fstatfs64
+#define __NR_fstatfs64 (__NR_Linux + 256)
+#endif
#ifndef __NR_openat
#define __NR_openat (__NR_Linux + 288)
#endif
@@ -313,6 +402,21 @@ struct stat64;
#ifndef __NR_gettid
#define __NR_gettid (__NR_Linux + 178)
#endif
+#ifndef __NR_readahead
+#define __NR_readahead (__NR_Linux + 179)
+#endif
+#ifndef __NR_setxattr
+#define __NR_setxattr (__NR_Linux + 180)
+#endif
+#ifndef __NR_lsetxattr
+#define __NR_lsetxattr (__NR_Linux + 181)
+#endif
+#ifndef __NR_getxattr
+#define __NR_getxattr (__NR_Linux + 183)
+#endif
+#ifndef __NR_lgetxattr
+#define __NR_lgetxattr (__NR_Linux + 184)
+#endif
#ifndef __NR_futex
#define __NR_futex (__NR_Linux + 194)
#endif
@@ -344,6 +448,21 @@ struct stat64;
#ifndef __NR_gettid
#define __NR_gettid (__NR_Linux + 178)
#endif
+#ifndef __NR_readahead
+#define __NR_readahead (__NR_Linux + 179)
+#endif
+#ifndef __NR_setxattr
+#define __NR_setxattr (__NR_Linux + 180)
+#endif
+#ifndef __NR_lsetxattr
+#define __NR_lsetxattr (__NR_Linux + 181)
+#endif
+#ifndef __NR_getxattr
+#define __NR_getxattr (__NR_Linux + 183)
+#endif
+#ifndef __NR_lgetxattr
+#define __NR_lgetxattr (__NR_Linux + 184)
+#endif
#ifndef __NR_futex
#define __NR_futex (__NR_Linux + 194)
#endif
@@ -354,6 +473,12 @@ struct stat64;
#ifndef __NR_set_tid_address
#define __NR_set_tid_address (__NR_Linux + 213)
#endif
+#ifndef __NR_statfs64
+#define __NR_statfs64 (__NR_Linux + 217)
+#endif
+#ifndef __NR_fstatfs64
+#define __NR_fstatfs64 (__NR_Linux + 218)
+#endif
#ifndef __NR_openat
#define __NR_openat (__NR_Linux + 251)
#endif
@@ -641,6 +766,30 @@ struct stat64;
: "memory", "ecx", "edx", "esi", "edi");
LSS_RETURN(int, __res);
}
+
+ #define __NR__fadvise64_64 __NR_fadvise64_64
+ LSS_INLINE _syscall6(int, _fadvise64_64, int, fd,
+ unsigned, offset_lo, unsigned, offset_hi,
+ unsigned, len_lo, unsigned, len_hi,
+ int, advice)
+
+ LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset,
+ loff_t len, int advice) {
+ return LSS_NAME(_fadvise64_64)(fd,
+ (unsigned)offset, (unsigned)(offset >> 32),
+ (unsigned)len, (unsigned)(len >> 32),
+ advice);
+ }
+
+ #define __NR__readahead32 __NR_readahead
+ LSS_INLINE _syscall4(int, _readahead32, int, fd, unsigned, offset_lo,
+ unsigned, offset_hi, unsigned, len);
+ LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t offset, int len) {
+ return LSS_NAME(_readahead32)(fd,
+ (unsigned)offset, (unsigned)(offset >> 32),
+ (unsigned)len);
+ }
+
#elif defined(__x86_64__)
/* There are no known problems with any of the _syscallX() macros
* currently shipping for x86_64, but we still need to be able to define
@@ -784,6 +933,10 @@ struct stat64;
}
LSS_RETURN(int, __res);
}
+ LSS_INLINE _syscall4(int, fadvise64, int, fd, loff_t, offset, loff_t, len,
+ int, advice)
+ LSS_INLINE _syscall2(int, statfs, const char *, path, struct statfs *, buf)
+ LSS_INLINE _syscall2(int, fstatfs, int, fd, struct statfs *, buf)
#elif defined(__ARM_ARCH_3__)
/* Most definitions of _syscallX() neglect to mark "memory" as being
* clobbered. This causes problems with compilers, that do a better job
@@ -1159,6 +1312,16 @@ struct stat64;
struct rlimit*, l)
LSS_INLINE _syscall1(pid_t, getsid, pid_t, p)
LSS_INLINE _syscall0(pid_t, _gettid)
+ LSS_INLINE _syscall5(int, setxattr, const char *,p,
+ const char *, n, const void *,v,
+ size_t, s, int, f)
+ LSS_INLINE _syscall5(int, lsetxattr, const char *,p,
+ const char *, n, const void *,v,
+ size_t, s, int, f)
+ LSS_INLINE _syscall4(ssize_t, getxattr, const char *,p,
+ const char *, n, void *, v, size_t, s)
+ LSS_INLINE _syscall4(ssize_t, lgetxattr, const char *,p,
+ const char *, n, void *, v, size_t, s)
LSS_INLINE _syscall2(int, kill, pid_t, p,
int, s)
LSS_INLINE _syscall3(off_t, lseek, int, f,
@@ -1201,6 +1364,7 @@ struct stat64;
uid_t, e, uid_t, s)
LSS_INLINE _syscall2(int, setrlimit, int, r,
const struct rlimit*, l)
+ LSS_INLINE _syscall0(pid_t, setsid)
LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s,
const stack_t*, o)
LSS_INLINE _syscall2(int, stat, const char*, f,
@@ -1444,7 +1608,14 @@ struct stat64;
}
}
#else
- LSS_INLINE _syscall1(int, pipe, int*, p)
+ LSS_INLINE _syscall1(int, pipe, int *, p)
+ #endif
+ #if defined(__i386__) || defined(__ARM_ARCH_3__) || \
+ (defined(mips) && _MIPS_SIM != _MIPS_SIM_ABI64)
+ LSS_INLINE _syscall2(int, statfs64, const char*, p,
+ struct statfs64 *, b)
+ LSS_INLINE _syscall2(int, fstatfs64, int, f,
+ struct statfs64 *, b)
#endif
LSS_INLINE int LSS_NAME(execv)(const char *path, const char * const argv[]) {
@@ -1511,6 +1682,29 @@ struct stat64;
return -1;
}
}
+
+ #if defined(__x86_64__) || \
+ (defined(mips) && _MIPS_SIM == _MIPS_SIM_ABI64)
+ LSS_INLINE _syscall3(int, readahead, int, fd, loff_t, offset,
+ unsigned, len)
+ #elif defined(mips) || defined(__ARM_ARCH_3__)
+ LSS_INLINE _syscall4(int, _readahead32, int, fd, unsigned, offset_lo,
+ unsigned, offset_hi, unsigned, len);
+ LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t offset, int len) {
+ return LSS_NAME(_readahead32)(fd,
+ #if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || \
+ (defined(__LITTLE_ENDIAN__))
+ (unsigned)offset, (unsigned)(offset >> 32),
+ #elif (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || \
+ (defined(__BIG_ENDIAN__))
+ (unsigned)(offset >> 32), (unsigned)offset,
+ #else
+ #error "unknown endinness, don't know how to pass syscall arguments"
+ #endif
+ (unsigned)len);
+ }
+ #endif
+
#endif
#if defined(__cplusplus) && !defined(SYS_CPLUSPLUS)
diff --git a/src/base/spinlock.cc b/src/base/spinlock.cc
index 878346d..12761b1 100644
--- a/src/base/spinlock.cc
+++ b/src/base/spinlock.cc
@@ -37,6 +37,10 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* For nanosleep() on Windows, read() */
#endif
+#if defined(__MACH__) && defined(__APPLE__)
+#include <sys/types.h>
+#include <sys/sysctl.h> /* how we figure out numcpu's on OS X */
+#endif
#include <fcntl.h> /* for open(), O_RDONLY */
#include <string.h> /* for strncmp */
#include <errno.h>
@@ -48,9 +52,20 @@ static int num_cpus = -1;
// It's important this not call malloc! -- it is called at global-construct
// time, before we've set up all our proper malloc hooks and such.
static int NumCPUs() {
- if (num_cpus >= 0)
+ if (num_cpus > 0)
return num_cpus; // value is cached
+#if defined(__MACH__) && defined(__APPLE__)
+ int cpus;
+ size_t size = sizeof(cpus);
+ int numcpus_name[] = { CTL_HW, HW_NCPU };
+ if (::sysctl(numcpus_name, arraysize(numcpus_name), &cpus, &size, 0, 0) == 0
+ && (size == sizeof(cpus)))
+ num_cpus = cpus;
+ else
+ num_cpus = 1; // conservative assumption
+ return num_cpus;
+#else /* hope the information is in /proc */
const char* pname = "/proc/cpuinfo";
int fd = open(pname, O_RDONLY);
if (fd == -1) {
@@ -72,7 +87,10 @@ static int NumCPUs() {
num_cpus++;
} while (chars_read > 0); // stop when we get to EOF
close(fd);
- return num_cpus == 0 ? 1 : num_cpus;
+ if (num_cpus == 0)
+ num_cpus = 1; // conservative assumption
+ return num_cpus;
+#endif
}
struct SpinLock_InitHelper {
diff --git a/src/base/sysinfo.cc b/src/base/sysinfo.cc
index 4c06782..2d7a593 100644
--- a/src/base/sysinfo.cc
+++ b/src/base/sysinfo.cc
@@ -59,6 +59,10 @@
#undef Module32Next
#undef PMODULEENTRY32
#undef LPMODULEENTRY32
+// MinGW doesn't seem to define this, perhaps some windowsen don't either.
+#ifndef TH32CS_SNAPMODULE32
+#define TH32CS_SNAPMODULE32 0
+#endif
#endif
// Re-run fn until it doesn't cause EINTR.
@@ -179,10 +183,7 @@ void ProcMapsIterator::Init(pid_t pid, Buffer *buffer,
}
NO_INTR(fd_ = open(ibuf_, O_RDONLY));
#elif defined(__MACH__)
- if (_dyld_present())
- current_image_ = _dyld_image_count(); // count down from the top
- else
- current_image_ = -1;
+ current_image_ = _dyld_image_count(); // count down from the top
current_load_cmd_ = -1;
#elif defined(WIN32)
snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE |
@@ -211,7 +212,7 @@ bool ProcMapsIterator::Valid() const {
#if defined(WIN32)
return snapshot_ != INVALID_HANDLE_VALUE;
#elif defined(__MACH__)
- return _dyld_present();
+ return 1;
#else
return fd_ != -1;
#endif
@@ -271,7 +272,7 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
uint64 tmpstart, tmpend, tmpoffset;
int64 tmpinode;
int major, minor;
- unsigned filename_offset;
+ unsigned filename_offset = 0;
#if defined(__linux__) // for now, assume all linuxes have the same format
if (sscanf(stext_, "%"SCNx64"-%"SCNx64" %4s %"SCNx64" %x:%x %"SCNd64" %n",
start ? start : &tmpstart,
@@ -299,6 +300,15 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
&filename_offset) != 3) continue;
#endif
+ // Depending on the Linux kernel being used, there may or may not be a space
+ // after the inode if there is no filename. sscanf will in such situations
+ // nondeterministically either fill in filename_offset or not (the results
+ // differ on multiple calls in the same run even with identical arguments).
+ // We don't want to wander off somewhere beyond the end of the string.
+ size_t stext_length = strlen(stext_);
+ if (filename_offset == 0 || filename_offset > stext_length)
+ filename_offset = stext_length;
+
// We found an entry
if (flags) *flags = flags_;
if (filename) *filename = stext_ + filename_offset;
diff --git a/src/config.h.in b/src/config.h.in
index b7cea41..d656452 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -210,3 +210,9 @@
#ifndef __cplusplus
#undef inline
#endif
+
+
+#ifdef __MINGW32__
+#include "windows/mingw.h"
+#endif
+
diff --git a/src/getpc.h b/src/getpc.h
index b7cfce9..74ba080 100644
--- a/src/getpc.h
+++ b/src/getpc.h
@@ -157,7 +157,9 @@ inline void* GetPC(const ucontext_t& signal_ucontext) {
// how we'd get the PC (using StackWalk64?)
// http://msdn2.microsoft.com/en-us/library/ms680650.aspx
-inline void* GetPC(const ucontext_t& signal_ucontext) {
+#include "base/logging.h" // for RAW_LOG
+
+inline void* GetPC(const struct ucontext_t& signal_ucontext) {
RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n");
return NULL;
}
diff --git a/src/google/heap-checker.h b/src/google/heap-checker.h
index 8ba6e21..4cd077a 100644
--- a/src/google/heap-checker.h
+++ b/src/google/heap-checker.h
@@ -33,7 +33,7 @@
//
// Module for detecing heap (memory) leaks.
//
-// For full(er) information, see doc/heap-checker.html
+// For full(er) information, see doc/heap_checker.html
//
// This module can be linked into programs with
// no slowdown caused by this unless you activate the leak-checker:
diff --git a/src/google/profiler.h b/src/google/profiler.h
index fce25e2..3c4106b 100644
--- a/src/google/profiler.h
+++ b/src/google/profiler.h
@@ -70,6 +70,27 @@
// Start profiling and write profile info into fname.
extern "C" PERFTOOLS_DLL_DECL bool ProfilerStart(const char* fname);
+// Start profiling and write profile info into fname, filtering out
+// threads using a filter function.
+//
+// When a profiling tick is delivered, the profiler will call:
+//
+// (*filter_in_thread)(filter_in_thread_arg)
+//
+// If it returns true, the sample will be included in the profile.
+// Note that filter_in_thread runs in a signal handler, so must be
+// async-signal-safe.
+//
+// A typical use would be to set up filter results for each thread in
+// the system before starting the profiler, then to make
+// filter_in_thread be a very simple function which retrieves those
+// results in an async-signal-safe way. Retrieval could be done using
+// thread-specific data, or using a shared data structure that
+// supports async-signal-safe lookups.
+extern "C" bool ProfilerStartFiltered(const char* fname,
+ bool (*filter_in_thread)(void* arg),
+ void *filter_in_thread_arg);
+
// Stop profiling. Can be started again with ProfilerStart(), but
// the currently accumulated profiling data will be cleared.
extern "C" PERFTOOLS_DLL_DECL void ProfilerStop();
diff --git a/src/google/stacktrace.h b/src/google/stacktrace.h
index cc1b353..2140f9b 100644
--- a/src/google/stacktrace.h
+++ b/src/google/stacktrace.h
@@ -46,28 +46,55 @@
// Skips the most recent "skip_count" stack frames (also skips the
-// frame generated for the "GetStackTrace" routine itself), and then
+// frame generated for the "GetStackFrames" routine itself), and then
// records the pc values for up to the next "max_depth" frames in
-// "result". Returns the number of values recorded in "result".
+// "pcs", and the corresponding stack frame sizes in "sizes". Returns
+// the number of values recorded in "pcs"/"sizes".
//
// Example:
// main() { foo(); }
// foo() { bar(); }
// bar() {
-// void* result[10];
-// int depth = GetStackTrace(result, 10, 1);
+// void* pcs[10];
+// int sizes[10];
+// int depth = GetStackFrames(pcs, sizes, 10, 1);
// }
//
-// The GetStackTrace call will skip the frame for "bar". It will
+// The GetStackFrames call will skip the frame for "bar". It will
// return 2 and will produce pc values that map to the following
// procedures:
-// result[0] foo
-// result[1] main
+// pcs[0] foo
+// pcs[1] main
// (Actually, there may be a few more entries after "main" to account for
// startup procedures.)
+// And corresponding stack frame sizes will also be recorded:
+// sizes[0] 16
+// sizes[1] 16
+// (Stack frame sizes of 16 above are just for illustration purposes.)
+// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
+// be identified.
+//
+// This routine may return fewer stack frame entries than are
+// available. Also note that "pcs" and "sizes" must both be non-NULL.
+extern PERFTOOLS_DLL_DECL int GetStackFrames(void** pcs, int* sizes, int max_depth,
+ int skip_count);
+
+// This is similar to the GetStackFrames routine, except that it returns
+// the stack trace only, and not the stack frame sizes as well.
+// Example:
+// main() { foo(); }
+// foo() { bar(); }
+// bar() {
+// void* result[10];
+// int depth = GetStackFrames(result, 10, 1);
+// }
+//
+// This produces:
+// result[0] foo
+// result[1] main
+// .... ...
//
-// This routine may return fewer stack trace entries than are
-// available.
+// "result" must not be NULL.
extern PERFTOOLS_DLL_DECL int GetStackTrace(void** result, int max_depth,
int skip_count);
diff --git a/src/heap-checker.cc b/src/heap-checker.cc
index c523810..7af372d 100644
--- a/src/heap-checker.cc
+++ b/src/heap-checker.cc
@@ -61,6 +61,7 @@
#include <map>
#include <set>
#include <algorithm>
+#include <functional>
#include <google/heap-checker.h>
@@ -1863,7 +1864,7 @@ void HeapLeakChecker::CancelGlobalCheck() {
static bool in_initial_malloc_hook = false;
-#ifdef HAVE___ATTRIBUTE___ // we need __attribute__((weak)) for this to work
+#ifdef HAVE___ATTRIBUTE__ // we need __attribute__((weak)) for this to work
#define INSTALLED_INITIAL_MALLOC_HOOKS
void HeapLeakChecker_BeforeConstructors(); // below
diff --git a/src/heap-profile-table.cc b/src/heap-profile-table.cc
index f1d76d0..877951a 100644
--- a/src/heap-profile-table.cc
+++ b/src/heap-profile-table.cc
@@ -42,11 +42,11 @@
#include <glob.h>
#endif
#ifdef HAVE_INTTYPES_H
-#include <inttypes.h> // for PRIxPTR
+#include <inttypes.h> // for PRIxPTR
#endif
#include <errno.h>
#include <string>
-#include <algorithm> // for sort()
+#include <algorithm> // for sort(), equal(), and copy()
#include "heap-profile-table.h"
@@ -57,6 +57,8 @@
#include "base/sysinfo.h"
using std::sort;
+using std::equal;
+using std::copy;
using std::string;
//----------------------------------------------------------------------
@@ -198,19 +200,19 @@ HeapProfileTable::Bucket* HeapProfileTable::GetBucket(int skip_count) {
h ^= h >> 11;
// Lookup stack trace in table
- const size_t key_size = sizeof(key[0]) * depth;
unsigned int buck = ((unsigned int) h) % kHashTableSize;
for (Bucket* b = table_[buck]; b != 0; b = b->next) {
if ((b->hash == h) &&
(b->depth == depth) &&
- (memcmp(b->stack, key, key_size) == 0)) {
+ equal(key, key + depth, b->stack)) {
return b;
}
}
// Create new bucket
+ const size_t key_size = sizeof(key[0]) * depth;
const void** kcopy = reinterpret_cast<const void**>(alloc_(key_size));
- memcpy(kcopy, key, key_size);
+ copy(key, key + depth, kcopy);
Bucket* b = reinterpret_cast<Bucket*>(alloc_(sizeof(Bucket)));
memset(b, 0, sizeof(*b));
b->hash = h;
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index 8718111..2ffbef8 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -247,22 +247,29 @@ static void DeleteHook(const void* ptr) {
if (ptr != NULL) RecordFree(ptr);
}
+// TODO(jandrews): Re-enable stack tracing
+#ifdef TODO_REENABLE_STACK_TRACING
+static void RawInfoStackDumper(const char* message, void*) {
+ RAW_LOG(INFO, "%.*s", static_cast<int>(strlen(message) - 1), message);
+ // -1 is to chop the \n which will be added by RAW_LOG
+}
+#endif
+
static void MmapHook(const void* result, const void* start, size_t size,
int prot, int flags, int fd, off_t offset) {
// Log the mmap if necessary
if (FLAGS_mmap_log) {
- char buf[200];
// We use PRIxS not just '%p' to avoid deadlocks
// in pretty-printing of NULL as "nil".
// TODO(maxim): instead should use a safe snprintf reimplementation
- snprintf(buf, sizeof(buf),
- "mmap(start=0x%"PRIxS", len=%"PRIuS", prot=0x%x, flags=0x%x, "
- "fd=%d, offset=0x%x) = 0x%"PRIxS"",
- (uintptr_t) start, size, prot, flags, fd, (unsigned int) offset,
- (uintptr_t) result);
- LOG(INFO, "%s", buf);
- // TODO(jandrews): Re-enable stack tracing
- //DumpStackTrace(1, DebugWriteToStream, &LOG(INFO));
+ RAW_LOG(INFO,
+ "mmap(start=0x%"PRIxS", len=%"PRIuS", prot=0x%x, flags=0x%x, "
+ "fd=%d, offset=0x%x) = 0x%"PRIxS"",
+ (uintptr_t) start, size, prot, flags, fd, (unsigned int) offset,
+ (uintptr_t) result);
+#ifdef TODO_REENABLE_STACK_TRACING
+ DumpStackTrace(1, RawInfoStackDumper, NULL);
+#endif
}
// Record mmap in profile if appropriate
@@ -276,13 +283,11 @@ static void MunmapHook(const void* ptr, size_t size) {
RecordFree(ptr);
}
if (FLAGS_mmap_log) {
- char buf[200];
// We use PRIxS not just '%p' to avoid deadlocks
// in pretty-printing of NULL as "nil".
// TODO(maxim): instead should use a safe snprintf reimplementation
- snprintf(buf, sizeof(buf),
- "munmap(start=0x%"PRIxS", len=%"PRIuS")", (uintptr_t) ptr, size);
- LOG(INFO, "%s", buf);
+ RAW_LOG(INFO, "munmap(start=0x%"PRIxS", len=%"PRIuS")",
+ (uintptr_t) ptr, size);
}
}
diff --git a/src/malloc_hook.cc b/src/malloc_hook.cc
index 4104229..a84973f 100644
--- a/src/malloc_hook.cc
+++ b/src/malloc_hook.cc
@@ -41,6 +41,7 @@
# undef mremap
#endif
+#include <algorithm>
#include <google/malloc_hook.h>
#include "base/basictypes.h"
#include "base/logging.h"
@@ -53,6 +54,9 @@
# define __THROW // __THROW is just an optimization, so ok to make it ""
#endif
+using std::copy;
+
+
// Declarations of three default weak hook functions, that can be overridden by
// linking-in a strong definition (as heap-checker.cc does)
//
@@ -211,7 +215,7 @@ int MallocHook::GetCallerStackTrace(void** result, int max_depth,
i += 1; // skip hook caller frame
depth -= i; // correct depth
if (depth > max_depth) depth = max_depth;
- memcpy(result, stack+i, depth * sizeof(stack[0]));
+ copy(stack + i, stack + i + depth, result);
if (depth < max_depth && depth + i == kStackSize) {
// get frames for the missing depth
depth +=
diff --git a/src/memfs_malloc.cc b/src/memfs_malloc.cc
index 438758d..93de8bf 100644
--- a/src/memfs_malloc.cc
+++ b/src/memfs_malloc.cc
@@ -41,6 +41,7 @@
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
+#include <inttypes.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -59,6 +60,8 @@ DEFINE_string(memfs_malloc_path, EnvToString("TCMALLOC_MEMFS_MALLOC_PATH", ""),
"Path where hugetlbfs or tmpfs is mounted. The caller is "
"responsible for ensuring that the path is unique and does "
"not conflict with another process");
+DEFINE_int64(memfs_malloc_limit_mb, 0, "Limit total allocation size to the "
+ "specified number of MiB. 0 == no limit.");
// Hugetlbfs based allocator for tcmalloc
class HugetlbSysAllocator: public SysAllocator {
@@ -71,12 +74,19 @@ public:
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
+ void DumpStats(TCMalloc_Printer* printer);
+
private:
int64 big_page_size_;
int hugetlb_fd_; // file descriptor for hugetlb
off_t hugetlb_base_;
};
+void HugetlbSysAllocator::DumpStats(TCMalloc_Printer* printer) {
+ printer->printf("HugetlbSysAllocator: failed_=%d allocated=%"PRId64"\n",
+ failed_, static_cast<int64_t>(hugetlb_base_));
+}
+
// No locking needed here since we assume that tcmalloc calls
// us with an internal lock held (see tcmalloc/system-alloc.cc).
void* HugetlbSysAllocator::Alloc(size_t size, size_t *actual_size,
@@ -102,6 +112,16 @@ void* HugetlbSysAllocator::Alloc(size_t size, size_t *actual_size,
extra = alignment - big_page_size_;
}
+ // Test if this allocation would put us over the limit.
+ off_t limit = FLAGS_memfs_malloc_limit_mb*1024*1024;
+ if (limit > 0 && hugetlb_base_ + size + extra > limit) {
+ // Disable the allocator when there's less than one page left.
+ if (limit - hugetlb_base_ < big_page_size_) {
+ failed_ = true;
+ }
+ return NULL;
+ }
+
// This is not needed for hugetlbfs, but needed for tmpfs. Annoyingly
// hugetlbfs returns EINVAL for ftruncate.
int ret = ftruncate(hugetlb_fd_, hugetlb_base_ + size + extra);
diff --git a/src/memory_region_map.cc b/src/memory_region_map.cc
index 96d4f32..064b1f3 100644
--- a/src/memory_region_map.cc
+++ b/src/memory_region_map.cc
@@ -329,8 +329,12 @@ void MemoryRegionMap::RecordRegionRemoval(const void* start, size_t size) {
reinterpret_cast<void*>(start_addr),
reinterpret_cast<void*>(end_addr),
regions_->size());
- for (RegionSet::iterator region = regions_->begin();
- region != regions_->end(); /*noop*/) {
+ Region start_point;
+ memset(&start_point, 0, sizeof(start_point)); // zero out don't-care fields
+ start_point.start_addr = start_point.end_addr = start_addr;
+ for (RegionSet::iterator region = regions_->lower_bound(start_point);
+ region != regions_->end() && region->start_addr < end_addr;
+ /*noop*/) {
RAW_VLOG(5, "Looking at region %p..%p",
reinterpret_cast<void*>(region->start_addr),
reinterpret_cast<void*>(region->end_addr));
diff --git a/src/packed-cache-inl.h b/src/packed-cache-inl.h
index 90fb6ac..6114553 100644
--- a/src/packed-cache-inl.h
+++ b/src/packed-cache-inl.h
@@ -220,7 +220,9 @@ class PackedCache {
// For masking a V or a T.
static const V kValueMask = N_ONES_(V, kValuebits);
- T array_[1 << kHashbits];
+ // array_ is the cache. Its elements are volatile because any
+ // thread can write any array element at any time.
+ volatile T array_[1 << kHashbits];
};
#undef N_ONES_
diff --git a/src/pprof b/src/pprof
index 625829e..42d141f 100755
--- a/src/pprof
+++ b/src/pprof
@@ -1516,8 +1516,9 @@ sub RemoveUninterestingFrames {
# Drop signal handlers used for CPU profile collection
# TODO(dpeng): this should not be necessary; it's taken
# care of by the general 2nd-pc mechanism below.
- foreach my $name ('ProfileData::Add',
- 'ProfileData::prof_handler',
+ foreach my $name ('ProfileData::Add', # historical
+ 'ProfileData::prof_handler', # historical
+ 'CpuProfiler::prof_handler',
'__pthread_sighandler',
'__restore') {
$skip{$name} = 1;
@@ -1784,7 +1785,8 @@ sub IsProfileURL {
sub ParseProfileURL {
my $profile_name = shift;
- if ($profile_name =~ m,^(http://|)([^/:]+):(\d+)(|/|$PROFILE_PAGE|$HEAP_PAGE|$GROWTH_PAGE|$CONTENTION_PAGE)$,o) {
+ if (defined($profile_name) &&
+ $profile_name =~ m,^(http://|)([^/:]+):(\d+)(|/|$PROFILE_PAGE|$HEAP_PAGE|$GROWTH_PAGE|$CONTENTION_PAGE)$,o) {
return ($2, $3, $4);
}
return ();
@@ -2754,12 +2756,13 @@ sub MapToSymbols {
# Ignore empty binaries
if ($#{$pclist} < 0) { return; }
- MapSymbolsWithNM($image, $offset, $pclist, $symbols);
+ my $got_symbols = MapSymbolsWithNM($image, $offset, $pclist, $symbols);
if ($main::opt_interactive ||
$main::opt_addresses ||
$main::opt_lines ||
$main::opt_files ||
- $main::opt_list) {
+ $main::opt_list ||
+ !$got_symbols) {
GetLineNumbers($image, $offset, $pclist, $symbols);
}
}
@@ -2808,7 +2811,8 @@ sub GetLineNumbers {
close(SYMBOLS);
}
-# Use nm to map the list of referenced PCs to symbols
+# Use nm to map the list of referenced PCs to symbols. Return true iff we
+# are able to read procedure information via nm.
sub MapSymbolsWithNM {
my $image = shift;
my $offset = shift;
@@ -2817,6 +2821,9 @@ sub MapSymbolsWithNM {
# Get nm output sorted by increasing address
my $symbol_table = GetProcedureBoundaries($image, ".");
+ if (!%{$symbol_table}) {
+ return 0;
+ }
# Start addresses are already the right length (8 or 16 hex digits).
my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] }
keys(%{$symbol_table});
@@ -2827,7 +2834,7 @@ sub MapSymbolsWithNM {
my $pcstr = "0x" . $pc;
$symbols->{$pc} = [$pcstr, "?", $pcstr];
}
- return;
+ return 0;
}
# Sort addresses so we can do a join against nm output
@@ -2849,6 +2856,7 @@ sub MapSymbolsWithNM {
$symbols->{$pc} = [$pcstr, "?", $pcstr];
}
}
+ return 1;
}
sub ShortFunctionName {
@@ -2887,7 +2895,8 @@ sub ConfigureObjTools {
# Go fill in %obj_tool_map with the pathnames to use:
foreach my $tool (keys %obj_tool_map) {
- $obj_tool_map{$tool} = ConfigureTool($tool, $default_prefix);
+ $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool},
+ $default_prefix);
}
}
@@ -2988,7 +2997,8 @@ sub GetProcedureBoundariesViaNm {
# Gets the procedure boundaries for all routines in "$image" whose names
# match "$regexp" and returns them in a hashtable mapping from procedure
-# name to a two-element vector of [start address, end address]
+# name to a two-element vector of [start address, end address].
+# Will return an empty map if nm is not installed or not working properly.
sub GetProcedureBoundaries {
my $image = shift;
my $regexp = shift;
@@ -3008,11 +3018,14 @@ sub GetProcedureBoundaries {
foreach my $nm_command ("$nm -n --demangle $image 2>/dev/null",
"$nm -n $image 2>&1 | $cppfilt",
"$nm -D -n --demangle $image 2>/dev/null",
- "$nm -D -n $image 2>&1 | $cppfilt") {
+ "$nm -D -n $image 2>&1 | $cppfilt",
+ "$nm -n $image 2>/dev/null",
+ "$nm -D -n $image 2>/dev/null") {
my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp);
return $symbol_table if (%{$symbol_table});
}
- return GetProcedureBoundariesViaNm("$nm -n $image", $regexp); # last hope
+ my $symbol_table = {};
+ return $symbol_table;
}
diff --git a/src/profiledata.cc b/src/profiledata.cc
new file mode 100644
index 0000000..ae79bdc
--- /dev/null
+++ b/src/profiledata.cc
@@ -0,0 +1,312 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+// Author: Sanjay Ghemawat
+// Chris Demetriou (refactoring)
+//
+// Collect profiling data.
+
+#include "config.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/time.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "profiledata.h"
+
+#include "base/logging.h"
+#include "base/sysinfo.h"
+
+// All of these are initialized in profiledata.h.
+const int ProfileData::kMaxStackDepth;
+const int ProfileData::kAssociativity;
+const int ProfileData::kBuckets;
+const int ProfileData::kBufferLength;
+
+// This function is safe to call from asynchronous signals (but is not
+// re-entrant). However, that's not part of its public interface.
+void ProfileData::Evict(const Entry& entry) {
+ const int d = entry.depth;
+ const int nslots = d + 2; // Number of slots needed in eviction buffer
+ if (num_evicted_ + nslots > kBufferLength) {
+ FlushEvicted();
+ assert(num_evicted_ == 0);
+ assert(nslots <= kBufferLength);
+ }
+ evict_[num_evicted_++] = entry.count;
+ evict_[num_evicted_++] = d;
+ memcpy(&evict_[num_evicted_], entry.stack, d * sizeof(Slot));
+ num_evicted_ += d;
+}
+
+ProfileData::ProfileData()
+ : hash_(0),
+ evict_(0),
+ num_evicted_(0),
+ out_(-1),
+ count_(0),
+ evictions_(0),
+ total_bytes_(0),
+ fname_(0),
+ start_time_(0) {
+}
+
+bool ProfileData::Start(const char* fname, int frequency) {
+ if (enabled()) {
+ return false;
+ }
+
+ // Open output file and initialize various data structures
+ int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ if (fd < 0) {
+ // Can't open outfile for write
+ return false;
+ }
+
+ start_time_ = time(NULL);
+ fname_ = strdup(fname);
+
+ // Reset counters
+ num_evicted_ = 0;
+ count_ = 0;
+ evictions_ = 0;
+ total_bytes_ = 0;
+
+ hash_ = new Bucket[kBuckets];
+ evict_ = new Slot[kBufferLength];
+ memset(hash_, 0, sizeof(hash_[0]) * kBuckets);
+
+ // Record special entries
+ evict_[num_evicted_++] = 0; // count for header
+ evict_[num_evicted_++] = 3; // depth for header
+ evict_[num_evicted_++] = 0; // Version number
+ evict_[num_evicted_++] = 1000000 / frequency; // Period (microseconds)
+ evict_[num_evicted_++] = 0; // Padding
+
+ out_ = fd;
+
+ return true;
+}
+
+ProfileData::~ProfileData() {
+ Stop();
+}
+
+// Dump /proc/maps data to fd. Copied from heap-profile-table.cc.
+#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
+
+static void FDWrite(int fd, const char* buf, size_t len) {
+ while (len > 0) {
+ ssize_t r;
+ NO_INTR(r = write(fd, buf, len));
+ RAW_CHECK(r >= 0, "write failed");
+ buf += r;
+ len -= r;
+ }
+}
+
+static void DumpProcSelfMaps(int fd) {
+ ProcMapsIterator::Buffer iterbuf;
+ ProcMapsIterator it(0, &iterbuf); // 0 means "current pid"
+
+ uint64 start, end, offset;
+ int64 inode;
+ char *flags, *filename;
+ ProcMapsIterator::Buffer linebuf;
+ while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) {
+ int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_),
+ start, end, flags, offset, inode, filename,
+ 0);
+ FDWrite(fd, linebuf.buf_, written);
+ }
+}
+
+void ProfileData::Stop() {
+ if (!enabled()) {
+ return;
+ }
+
+ // Move data from hash table to eviction buffer
+ for (int b = 0; b < kBuckets; b++) {
+ Bucket* bucket = &hash_[b];
+ for (int a = 0; a < kAssociativity; a++) {
+ if (bucket->entry[a].count > 0) {
+ Evict(bucket->entry[a]);
+ }
+ }
+ }
+
+ if (num_evicted_ + 3 > kBufferLength) {
+ // Ensure there is enough room for end of data marker
+ FlushEvicted();
+ }
+
+ // Write end of data marker
+ evict_[num_evicted_++] = 0; // count
+ evict_[num_evicted_++] = 1; // depth
+ evict_[num_evicted_++] = 0; // end of data marker
+ FlushEvicted();
+
+ // Dump "/proc/self/maps" so we get list of mapped shared libraries
+ DumpProcSelfMaps(out_);
+
+ close(out_);
+ fprintf(stderr, "PROFILE: interrupts/evictions/bytes = %d/%d/%" PRIuS "\n",
+ count_, evictions_, total_bytes_);
+ delete[] hash_;
+ hash_ = 0;
+ delete[] evict_;
+ evict_ = 0;
+ free(fname_);
+ fname_ = 0;
+ start_time_ = 0;
+
+ out_ = -1;
+}
+
+// This function is safe to call from asynchronous signals (but is not
+// re-entrant). However, that's not part of its public interface.
+void ProfileData::GetCurrentState(State* state) const {
+ if (enabled()) {
+ state->enabled = true;
+ state->start_time = start_time_;
+ state->samples_gathered = count_;
+ int buf_size = sizeof(state->profile_name);
+ strncpy(state->profile_name, fname_, buf_size);
+ state->profile_name[buf_size-1] = '\0';
+ } else {
+ state->enabled = false;
+ state->start_time = 0;
+ state->samples_gathered = 0;
+ state->profile_name[0] = '\0';
+ }
+}
+
+// This function is safe to call from asynchronous signals (but is not
+// re-entrant). However, that's not part of its public interface.
+void ProfileData::FlushTable() {
+ if (!enabled()) {
+ return;
+ }
+
+ // Move data from hash table to eviction buffer
+ for (int b = 0; b < kBuckets; b++) {
+ Bucket* bucket = &hash_[b];
+ for (int a = 0; a < kAssociativity; a++) {
+ if (bucket->entry[a].count > 0) {
+ Evict(bucket->entry[a]);
+ bucket->entry[a].depth = 0;
+ bucket->entry[a].count = 0;
+ }
+ }
+ }
+
+ // Write out all pending data
+ FlushEvicted();
+}
+
+void ProfileData::Add(int depth, const void* const* stack) {
+ if (!enabled()) {
+ return;
+ }
+
+ if (depth > kMaxStackDepth) depth = kMaxStackDepth;
+ RAW_CHECK(depth > 0, "ProfileData::Add depth <= 0");
+
+ // Make hash-value
+ Slot h = 0;
+ for (int i = 0; i < depth; i++) {
+ Slot slot = reinterpret_cast<Slot>(stack[i]);
+ h = (h << 8) | (h >> (8*(sizeof(h)-1)));
+ h += (slot * 31) + (slot * 7) + (slot * 3);
+ }
+
+ count_++;
+
+ // See if table already has an entry for this trace
+ bool done = false;
+ Bucket* bucket = &hash_[h % kBuckets];
+ for (int a = 0; a < kAssociativity; a++) {
+ Entry* e = &bucket->entry[a];
+ if (e->depth == depth) {
+ bool match = true;
+ for (int i = 0; i < depth; i++) {
+ if (e->stack[i] != reinterpret_cast<Slot>(stack[i])) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ e->count++;
+ done = true;
+ break;
+ }
+ }
+ }
+
+ if (!done) {
+ // Evict entry with smallest count
+ Entry* e = &bucket->entry[0];
+ for (int a = 1; a < kAssociativity; a++) {
+ if (bucket->entry[a].count < e->count) {
+ e = &bucket->entry[a];
+ }
+ }
+ if (e->count > 0) {
+ evictions_++;
+ Evict(*e);
+ }
+
+ // Use the newly evicted entry
+ e->depth = depth;
+ e->count = 1;
+ for (int i = 0; i < depth; i++) {
+ e->stack[i] = reinterpret_cast<Slot>(stack[i]);
+ }
+ }
+}
+
+// This function is safe to call from asynchronous signals (but is not
+// re-entrant). However, that's not part of its public interface.
+void ProfileData::FlushEvicted() {
+ if (num_evicted_ > 0) {
+ const char* buf = reinterpret_cast<char*>(evict_);
+ size_t bytes = sizeof(evict_[0]) * num_evicted_;
+ total_bytes_ += bytes;
+ FDWrite(out_, buf, bytes);
+ }
+ num_evicted_ = 0;
+}
diff --git a/src/profiledata.h b/src/profiledata.h
new file mode 100644
index 0000000..f39dfe1
--- /dev/null
+++ b/src/profiledata.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+// Author: Sanjay Ghemawat
+// Chris Demetriou (refactoring)
+//
+// Collect profiling data.
+//
+// The profile data file format is documented in
+// doc/cpuprofile-fileformat.html
+
+
+#ifndef BASE_PROFILEDATA_H__
+#define BASE_PROFILEDATA_H__
+
+#include "config.h"
+#include <time.h> // for time_t
+#include "base/basictypes.h"
+
+// A class that accumulates profile samples and writes them to a file.
+//
+// Each sample contains a stack trace and a count. Memory usage is
+// reduced by combining profile samples that have the same stack trace
+// by adding up the associated counts.
+//
+// Profile data is accumulated in a bounded amount of memory, and will
+// flushed to a file as necessary to stay within the memory limit.
+//
+// Use of this class assumes external synchronization. The exact
+// requirements of that synchronization are that:
+//
+// - 'Add' may be called from asynchronous signals, but is not
+// re-entrant.
+//
+// - None of 'Start', 'Stop', 'Flush', and 'Add' may be called at the
+// same time.
+//
+// - 'Start' and 'Stop' should not be called while 'Enabled' or
+// 'GetCurrent' are running, and vice versa.
+//
+// A profiler which uses asyncronous signals to add samples will
+// typically use two locks to protect this data structure:
+//
+// - A MutexLock, which is held over all calls except for the 'Add'
+// call made from the signal handler.
+//
+// - A SpinLock, which is held over calls to 'Start', 'Stop',
+// 'Flush', and 'Add'. (This SpinLock should be acquired after
+// the MutexLock in all cases where both are needed.)
+class ProfileData {
+ public:
+ struct State {
+ bool enabled; // Is profiling currently enabled?
+ time_t start_time; // If enabled, when was profiling started?
+ char profile_name[1024]; // Name of file being written, or '\0'
+ int samples_gathered; // Number of samples gathered to far (or 0)
+ };
+
+ static const int kMaxStackDepth = 64; // Max stack depth stored in profile
+
+ ProfileData();
+ ~ProfileData();
+
+ // If data collection is not already enabled start to collect data
+ // into fname. The data includes the frequency of samples, as
+ // provided by 'frequency'.
+ //
+ // Returns true if data collection could be started, otherwise (if an
+ // error occurred or if data collection was already enabled) returns
+ // false.
+ bool Start(const char* fname, int frequency);
+
+ // If data collection is enabled, stop data collection and write the
+ // data to disk.
+ void Stop();
+
+ // If data collection is enabled, record a sample with 'depth'
+ // entries from 'stack'. (depth must be > 0.) At most
+ // kMaxStackDepth stack entries will be recorded, starting with
+ // stack[0].
+ //
+ // This function is safe to call from asynchronous signals (but is
+ // not re-entrant).
+ void Add(int depth, const void* const* stack);
+
+ // If data collection is enabled, write the data to disk (and leave
+ // the collector enabled).
+ void FlushTable();
+
+ // Is data collection currently enabled?
+ bool enabled() const { return out_ >= 0; }
+
+ // Get the current state of the data collector.
+ void GetCurrentState(State* state) const;
+
+ private:
+ static const int kAssociativity = 4; // For hashtable
+ static const int kBuckets = 1 << 10; // For hashtable
+ static const int kBufferLength = 1 << 18; // For eviction buffer
+
+ // Type of slots: each slot can be either a count, or a PC value
+ typedef uintptr_t Slot;
+
+ // Hash-table/eviction-buffer entry (a.k.a. a sample)
+ struct Entry {
+ Slot count; // Number of hits
+ Slot depth; // Stack depth
+ Slot stack[kMaxStackDepth]; // Stack contents
+ };
+
+ // Hash table bucket
+ struct Bucket {
+ Entry entry[kAssociativity];
+ };
+
+ Bucket* hash_; // hash table
+ Slot* evict_; // evicted entries
+ int num_evicted_; // how many evicted entries?
+ int out_; // fd for output file.
+ int count_; // How many samples recorded
+ int evictions_; // How many evictions
+ size_t total_bytes_; // How much output
+ char* fname_; // Profile file name
+ time_t start_time_; // Start time, or 0
+
+ // Move 'entry' to the eviction buffer.
+ void Evict(const Entry& entry);
+
+ // Write contents of eviction buffer to disk.
+ void FlushEvicted();
+
+ DISALLOW_EVIL_CONSTRUCTORS(ProfileData);
+};
+
+#endif // BASE_PROFILEDATA_H__
diff --git a/src/profiler.cc b/src/profiler.cc
index ffd39be..cca1d03 100644
--- a/src/profiler.cc
+++ b/src/profiler.cc
@@ -29,6 +29,7 @@
// ---
// Author: Sanjay Ghemawat
+// Chris Demetriou (refactoring)
//
// Profile current program by sampling stack-trace every so often
//
@@ -42,24 +43,11 @@
#include <signal.h>
#include <assert.h>
#include <stdio.h>
-#include <stdlib.h>
-#if defined HAVE_STDINT_H
-#include <stdint.h>
-#elif defined HAVE_INTTYPES_H
-#include <inttypes.h>
-#else
-#include <sys/types.h>
-#endif
#include <errno.h>
-#ifdef HAVE_UCONTEXT_H
-#include <ucontext.h> // for ucontext_t (and also mcontext_t)
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <sys/time.h>
+#include <ucontext.h>
#include <string.h>
-#include <fcntl.h>
+#include <sys/time.h>
+#include <string>
#include <google/profiler.h>
#include <google/stacktrace.h>
#include "base/commandlineflags.h"
@@ -68,6 +56,7 @@
#include "base/mutex.h"
#include "base/spinlock.h"
#include "base/sysinfo.h"
+#include "profiledata.h"
#ifdef HAVE_CONFLICT_SIGNAL_H
#include "conflict-signal.h" /* used on msvc machines */
#endif
@@ -118,113 +107,83 @@ static bool GetUniquePathFromEnv(const char* env_name, string* path) {
}
-// Collects up all profile data
-class ProfileData {
+// Collects up all profile data. This is a singleton, which is
+// initialized by a constructor at startup.
+class CpuProfiler {
public:
- ProfileData();
- ~ProfileData();
-
- // Is profiling turned on at all
- inline bool enabled() const { return out_ >= 0; }
+ CpuProfiler();
+ ~CpuProfiler();
- // What is the frequency of interrupts (ticks per second)
- inline int frequency() const { return frequency_; }
+ // Start profiler to write profile info into fname
+ bool Start(const char* fname, bool (*filter)(void*), void* filter_arg);
- // Record an interrupt at "pc"
- void Add(void* pc);
+ // Stop profiling and write the data to disk.
+ void Stop();
+ // Write the data to disk (and continue profiling).
void FlushTable();
- // Start profiler to write profile info into fname
- bool Start(const char* fname);
- // Stop profiling and flush the data
- void Stop();
+ bool Enabled();
void GetCurrentState(ProfilerState* state);
+ // Start interval timer for the current thread. We do this for
+ // every known thread. If profiling is off, the generated signals
+ // are ignored, otherwise they are captured by prof_handler().
+ void RegisterThread();
+
+ static CpuProfiler instance_;
+
private:
- static const int kMaxStackDepth = 64; // Max stack depth profiled
static const int kMaxFrequency = 4000; // Largest allowed frequency
static const int kDefaultFrequency = 100; // Default frequency
- static const int kAssociativity = 4; // For hashtable
- static const int kBuckets = 1 << 10; // For hashtable
- static const int kBufferLength = 1 << 18; // For eviction buffer
-
- // Type of slots: each slot can be either a count, or a PC value
- typedef uintptr_t Slot;
-
- // Hash-table/eviction-buffer entry
- struct Entry {
- Slot count; // Number of hits
- Slot depth; // Stack depth
- Slot stack[kMaxStackDepth]; // Stack contents
- };
-
- // Hash table bucket
- struct Bucket {
- Entry entry[kAssociativity];
- };
-
- // Invariant: table_lock_ is only grabbed by handler, or by other code
- // when the signal is being ignored (via SIG_IGN).
- //
- // Locking order is "state_lock_" first, and then "table_lock_"
- Mutex state_lock_; // Protects filename, etc.(not used in handler)
- SpinLock table_lock_; // SpinLock is safer in signal handlers
- Bucket* hash_; // hash table
-
- Slot* evict_; // evicted entries
- int num_evicted_; // how many evicted entries?
- int out_; // fd for output file
- int count_; // How many interrupts recorded
- int evictions_; // How many evictions
- size_t total_bytes_; // How much output
- char* fname_; // Profile file name
- int frequency_; // Interrupts per second
- time_t start_time_; // Start time, or 0
-
- // Add "pc -> count" to eviction buffer
- void Evict(const Entry& entry);
-
- // Write contents of eviction buffer to disk
- void FlushEvicted();
-
- // Handler that records the interrupted pc in the profile data
- static void prof_handler(int sig, siginfo_t*, void* signal_ucontext);
- // Sets the timer interrupt signal handler to one that stores the pc
+ // Sample frequency, read-only after construction.
+ int frequency_;
+
+ // These locks implement the locking requirements described in the
+ // ProfileData documentation, specifically:
+ //
+ // control_lock_ is held all over all collector_ method calls except for
+ // the 'Add' call made from the signal handler, to protect against
+ // concurrent use of collector_'s control routines.
+ //
+ // signal_lock_ is held over calls to 'Start', 'Stop', 'Flush', and
+ // 'Add', to protect against concurrent use of data collection and
+ // writing routines. Code other than the signal handler must disable
+ // the timer signal while holding signal_lock, to prevent deadlock.
+ //
+ // Locking order is control_lock_ first, and then signal_lock_.
+ // signal_lock_ is acquired by the prof_handler without first
+ // acquiring control_lock_.
+ Mutex control_lock_;
+ SpinLock signal_lock_;
+ ProfileData collector_;
+
+ // Filter function and its argument, if any. (NULL means include
+ // all samples). Set at start, read-only while running. Written
+ // while holding both control_lock_ and signal_lock_, read and
+ // executed under signal_lock_.
+ bool (*filter_)(void*);
+ void* filter_arg_;
+
+ // Sets the timer interrupt signal handler to one that stores the pc.
static void EnableHandler();
- // "Turn off" the timer interrupt signal handler
+
+ // Disables (ignores) the timer interrupt signal.
static void DisableHandler();
+
+ // Signale handler that records the interrupted pc in the profile data
+ static void prof_handler(int sig, siginfo_t*, void* signal_ucontext);
};
-// Evict the specified entry to the evicted-entry buffer
-inline void ProfileData::Evict(const Entry& entry) {
- const int d = entry.depth;
- const int nslots = d + 2; // Number of slots needed in eviction buffer
- if (num_evicted_ + nslots > kBufferLength) {
- FlushEvicted();
- assert(num_evicted_ == 0);
- assert(nslots <= kBufferLength);
- }
- evict_[num_evicted_++] = entry.count;
- evict_[num_evicted_++] = d;
- memcpy(&evict_[num_evicted_], entry.stack, d * sizeof(Slot));
- num_evicted_ += d;
-}
+// Profile data structure singleton: Constructor will check to see if
+// profiling should be enabled. Destructor will write profile data
+// out to disk.
+CpuProfiler CpuProfiler::instance_;
// Initialize profiling: activated if getenv("CPUPROFILE") exists.
-ProfileData::ProfileData()
- : hash_(0),
- evict_(0),
- num_evicted_(0),
- out_(-1),
- count_(0),
- evictions_(0),
- total_bytes_(0),
- fname_(0),
- frequency_(0),
- start_time_(0) {
+CpuProfiler::CpuProfiler() {
// Get frequency of interrupts (if specified)
char junk;
const char* fr = getenv("CPUPROFILE_FREQUENCY");
@@ -236,10 +195,11 @@ ProfileData::ProfileData()
frequency_ = kDefaultFrequency;
}
- // Ignore signals until we decide to turn profiling on
+ // Ignore signals until we decide to turn profiling on. (Paranoia;
+ // should already be ignored.)
DisableHandler();
- ProfilerRegisterThread();
+ RegisterThread();
// Should profiling be enabled automatically at start?
string fname;
@@ -252,52 +212,35 @@ ProfileData::ProfileData()
return;
#endif
- if (!Start(fname.c_str())) {
+ if (!Start(fname.c_str(), NULL, NULL)) {
RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
fname.c_str(), strerror(errno));
}
}
-bool ProfileData::Start(const char* fname) {
- MutexLock l(&state_lock_);
- if (enabled()) {
- // profiling is already enabled
- return false;
- }
+bool CpuProfiler::Start(const char* fname,
+ bool (*filter)(void*), void* filter_arg) {
+ MutexLock cl(&control_lock_);
- // Open output file and initialize various data structures
- int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
- if (fd < 0) {
- // Can't open outfile for write
+ if (collector_.enabled()) {
return false;
}
- start_time_ = time(NULL);
- fname_ = strdup(fname);
-
{
- SpinLockHolder l2(&table_lock_);
-
- // Reset counters
- num_evicted_ = 0;
- count_ = 0;
- evictions_ = 0;
- total_bytes_ = 0;
- // But leave frequency_ alone (i.e., ProfilerStart() doesn't affect
- // their values originally set in the constructor)
-
- out_ = fd;
-
- hash_ = new Bucket[kBuckets];
- evict_ = new Slot[kBufferLength];
- memset(hash_, 0, sizeof(hash_[0]) * kBuckets);
+ // spin lock really is needed to protect init here, since it's
+ // conceivable that prof_handler may still be running from a
+ // previous profiler run. (For instance, if prof_handler just
+ // started, had not grabbed the spinlock, then was switched out,
+ // it might start again right now.) Any such late sample will be
+ // recorded against the new profile, but there's no harm in that.
+ SpinLockHolder sl(&signal_lock_);
+
+ if (!collector_.Start(fname, frequency_)) {
+ return false;
+ }
- // Record special entries
- evict_[num_evicted_++] = 0; // count for header
- evict_[num_evicted_++] = 3; // depth for header
- evict_[num_evicted_++] = 0; // Version number
- evict_[num_evicted_++] = 1000000 / frequency_; // Period (microseconds)
- evict_[num_evicted_++] = 0; // Padding
+ filter_ = filter;
+ filter_arg_ = filter_arg;
// Must unlock before setting prof_handler to avoid deadlock
// with signal delivered to this thread.
@@ -309,111 +252,79 @@ bool ProfileData::Start(const char* fname) {
return true;
}
-// Write out any collected profile data
-ProfileData::~ProfileData() {
+CpuProfiler::~CpuProfiler() {
Stop();
}
-// Dump /proc/maps data to fd. Copied from heap-profile-table.cc.
-#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
+// Stop profiling and write out any collected profile data
+void CpuProfiler::Stop() {
+ MutexLock cl(&control_lock_);
-static void FDWrite(int fd, const char* buf, size_t len) {
- while (len > 0) {
- ssize_t r;
- NO_INTR(r = write(fd, buf, len));
- RAW_CHECK(r >= 0, "write failed");
- buf += r;
- len -= r;
+ if (!collector_.enabled()) {
+ return;
}
-}
-static void DumpProcSelfMaps(int fd) {
- ProcMapsIterator::Buffer iterbuf;
- ProcMapsIterator it(0, &iterbuf); // 0 means "current pid"
-
- uint64 start, end, offset;
- int64 inode;
- char *flags, *filename;
- ProcMapsIterator::Buffer linebuf;
- while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) {
- int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_),
- start, end, flags, offset, inode, filename,
- 0);
- FDWrite(fd, linebuf.buf_, written);
+ // Ignore timer signals. Note that the handler may have just
+ // started and might not have taken signal_lock_ yet. Holding
+ // signal_lock_ here along with the semantics of collector_.Add()
+ // (which does nothing if collection is not enabled) prevents that
+ // late sample from causing a problem.
+ DisableHandler();
+
+ {
+ SpinLockHolder sl(&signal_lock_);
+ collector_.Stop();
}
}
-// Stop profiling and write out any collected profile data
-void ProfileData::Stop() {
- MutexLock l(&state_lock_);
-
- // Prevent handler from running anymore
- DisableHandler();
+void CpuProfiler::FlushTable() {
+ MutexLock cl(&control_lock_);
- // This lock prevents interference with signal handlers in other threads
- SpinLockHolder l2(&table_lock_);
-
- if (out_ < 0) {
- // Profiling is not enabled
+ if (!collector_.enabled()) {
return;
}
- // Move data from hash table to eviction buffer
- for (int b = 0; b < kBuckets; b++) {
- Bucket* bucket = &hash_[b];
- for (int a = 0; a < kAssociativity; a++) {
- if (bucket->entry[a].count > 0) {
- Evict(bucket->entry[a]);
- }
- }
+ // Disable timer signal while hoding signal_lock_, to prevent deadlock
+ // if we take a timer signal while flushing.
+ DisableHandler();
+ {
+ SpinLockHolder sl(&signal_lock_);
+ collector_.FlushTable();
}
+ EnableHandler();
+}
+
+bool CpuProfiler::Enabled() {
+ MutexLock cl(&control_lock_);
+ return collector_.enabled();
+}
- if (num_evicted_ + 3 > kBufferLength) {
- // Ensure there is enough room for end of data marker
- FlushEvicted();
+void CpuProfiler::GetCurrentState(ProfilerState* state) {
+ ProfileData::State collector_state;
+ {
+ MutexLock cl(&control_lock_);
+ collector_.GetCurrentState(&collector_state);
}
- // Write end of data marker
- evict_[num_evicted_++] = 0; // count
- evict_[num_evicted_++] = 1; // depth
- evict_[num_evicted_++] = 0; // end of data marker
- FlushEvicted();
-
- // Dump "/proc/self/maps" so we get list of mapped shared libraries
- DumpProcSelfMaps(out_);
-
- close(out_);
- fprintf(stderr, "PROFILE: interrupts/evictions/bytes = %d/%d/%" PRIuS "\n",
- count_, evictions_, total_bytes_);
- delete[] hash_;
- hash_ = 0;
- delete[] evict_;
- evict_ = 0;
- free(fname_);
- fname_ = 0;
- start_time_ = 0;
-
- out_ = -1;
+ state->enabled = collector_state.enabled;
+ state->start_time = static_cast<time_t>(collector_state.start_time);
+ state->samples_gathered = collector_state.samples_gathered;
+ int buf_size = sizeof(state->profile_name);
+ strncpy(state->profile_name, collector_state.profile_name, buf_size);
+ state->profile_name[buf_size-1] = '\0';
}
-void ProfileData::GetCurrentState(ProfilerState* state) {
- MutexLock l(&state_lock_);
- if (enabled()) {
- state->enabled = true;
- state->start_time = start_time_;
- state->samples_gathered = count_;
- int buf_size = sizeof(state->profile_name);
- strncpy(state->profile_name, fname_, buf_size);
- state->profile_name[buf_size-1] = '\0';
- } else {
- state->enabled = false;
- state->start_time = 0;
- state->samples_gathered = 0;
- state->profile_name[0] = '\0';
- }
+void CpuProfiler::RegisterThread() {
+ // TODO: Randomize the initial interrupt value?
+ // TODO: Randomize the inter-interrupt period on every interrupt?
+ struct itimerval timer;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 1000000 / frequency_;
+ timer.it_value = timer.it_interval;
+ setitimer(ITIMER_PROF, &timer, 0);
}
-void ProfileData::EnableHandler() {
+void CpuProfiler::EnableHandler() {
struct sigaction sa;
sa.sa_sigaction = prof_handler;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
@@ -421,7 +332,7 @@ void ProfileData::EnableHandler() {
RAW_CHECK(sigaction(SIGPROF, &sa, NULL) == 0, "sigaction failed");
}
-void ProfileData::DisableHandler() {
+void CpuProfiler::DisableHandler() {
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_RESTART;
@@ -429,150 +340,48 @@ void ProfileData::DisableHandler() {
RAW_CHECK(sigaction(SIGPROF, &sa, NULL) == 0, "sigaction failed");
}
+// Signal handler that records the pc in the profile-data structure
+//
+// NOTE: it is possible for profiling to be disabled just as this
+// signal handler starts, before signal_lock_ is acquired. Therefore,
+// collector_.Add must check whether profiling is enabled before
+// trying to record any data. (See also comments in Start and Stop.)
+void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext) {
+ int saved_errno = errno;
-void ProfileData::FlushTable() {
- MutexLock l(&state_lock_);
- if (out_ < 0) {
- // Profiling is not enabled
- return;
- }
- DisableHandler(); // Disable timer interrupts while we're flushing
+ // Hold the spin lock while we're gathering the trace because there's
+ // no real harm in holding it and there's little point in releasing
+ // and re-acquiring it. (We'll only be blocking Start, Stop, and
+ // Flush.) We make sure to release it before restoring errno.
{
- // Move data from hash table to eviction buffer
- SpinLockHolder l(&table_lock_);
- for (int b = 0; b < kBuckets; b++) {
- Bucket* bucket = &hash_[b];
- for (int a = 0; a < kAssociativity; a++) {
- if (bucket->entry[a].count > 0) {
- Evict(bucket->entry[a]);
- bucket->entry[a].depth = 0;
- bucket->entry[a].count = 0;
- }
- }
+ SpinLockHolder sl(&instance_.signal_lock_);
+
+ if (instance_.filter_ == NULL ||
+ (*instance_.filter_)(instance_.filter_arg_)) {
+ void* stack[ProfileData::kMaxStackDepth];
+
+ // The top-most active routine doesn't show up as a normal
+ // frame, but as the "pc" value in the signal handler context.
+ stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
+
+ // We skip the top two stack trace entries (this function and one
+ // signal handler frame) since they are artifacts of profiling and
+ // should not be measured. Other profiling related frames may be
+ // removed by "pprof" at analysis time. Instead of skipping the top
+ // frames, we could skip nothing, but that would increase the
+ // profile size unnecessarily.
+ int depth = GetStackTrace(stack + 1, arraysize(stack) - 1, 2);
+ depth++; // To account for pc value in stack[0];
+
+ instance_.collector_.Add(depth, stack);
}
-
- // Write out all pending data
- FlushEvicted();
- }
- EnableHandler();
-}
-
-// Record the specified "pc" in the profile data
-void ProfileData::Add(void* pc) {
- void* stack[kMaxStackDepth];
-
- // The top-most active routine doesn't show up as a normal
- // frame, but as the "pc" value in the signal handler context.
- stack[0] = pc;
-
- // We remove the top three entries (typically Add, prof_handler, and
- // a signal handler setup routine) since they are artifacts of
- // profiling and should not be measured. Other profiling related
- // frames (signal handler setup) will be removed by "pprof" at
- // analysis time. Instead of skipping the top frames, we could skip
- // nothing, but that would increase the profile size unnecessarily.
- int depth = GetStackTrace(stack+1, kMaxStackDepth-1, 3);
- depth++; // To account for pc value
-
- // Make hash-value
- Slot h = 0;
- for (int i = 0; i < depth; i++) {
- Slot slot = reinterpret_cast<Slot>(stack[i]);
- h = (h << 8) | (h >> (8*(sizeof(h)-1)));
- h += (slot * 31) + (slot * 7) + (slot * 3);
- }
-
- SpinLockHolder l(&table_lock_);
-
- // If the signal handler starts executing (and calls this function)
- // just as a thread calls Stop, it is possible for Stop to acquire
- // state_lock_, disable the signal, and acquire table_lock_ before
- // this function can grab table_lock_. If that happens, Stop will
- // delete hash_ and the rest of the allocated structures before this
- // function grabs table_lock_ and continues. In that case, hash_
- // will be NULL here.
- if (hash_ == NULL) {
- return;
}
- count_++;
-
- // See if table already has an entry for this stack trace
- bool done = false;
- Bucket* bucket = &hash_[h % kBuckets];
- for (int a = 0; a < kAssociativity; a++) {
- Entry* e = &bucket->entry[a];
- if (e->depth == depth) {
- bool match = true;
- for (int i = 0; i < depth; i++) {
- if (e->stack[i] != reinterpret_cast<Slot>(stack[i])) {
- match = false;
- break;
- }
- }
- if (match) {
- e->count++;
- done = true;
- break;
- }
- }
- }
-
- if (!done) {
- // Evict entry with smallest count
- Entry* e = &bucket->entry[0];
- for (int a = 1; a < kAssociativity; a++) {
- if (bucket->entry[a].count < e->count) {
- e = &bucket->entry[a];
- }
- }
- if (e->count > 0) {
- evictions_++;
- Evict(*e);
- }
-
- // Use the newly evicted entry
- e->depth = depth;
- e->count = 1;
- for (int i = 0; i < depth; i++) {
- e->stack[i] = reinterpret_cast<Slot>(stack[i]);
- }
- }
-}
-
-// Write all evicted data to the profile file
-void ProfileData::FlushEvicted() {
- if (num_evicted_ > 0) {
- const char* buf = reinterpret_cast<char*>(evict_);
- size_t bytes = sizeof(evict_[0]) * num_evicted_;
- total_bytes_ += bytes;
- FDWrite(out_, buf, bytes);
- }
- num_evicted_ = 0;
-}
-
-// Profile data structure: Constructor will check to see if profiling
-// should be enabled. Destructor will write profile data out to disk.
-static ProfileData pdata;
-
-// Signal handler that records the pc in the profile-data structure
-void ProfileData::prof_handler(int sig, siginfo_t*, void* signal_ucontext) {
- int saved_errno = errno;
- pdata.Add(GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext)));
errno = saved_errno;
}
-// Start interval timer for the current thread. We do this for
-// every known thread. If profiling is off, the generated signals
-// are ignored, otherwise they are captured by prof_handler().
extern "C" void ProfilerRegisterThread() {
- // TODO: Randomize the initial interrupt value?
- // TODO: Randomize the inter-interrupt period on every interrupt?
- struct itimerval timer;
- timer.it_interval.tv_sec = 0;
- timer.it_interval.tv_usec = 1000000 / pdata.frequency();
- timer.it_value = timer.it_interval;
- setitimer(ITIMER_PROF, &timer, 0);
+ CpuProfiler::instance_.RegisterThread();
}
// DEPRECATED routines
@@ -580,23 +389,30 @@ extern "C" void ProfilerEnable() { }
extern "C" void ProfilerDisable() { }
extern "C" void ProfilerFlush() {
- pdata.FlushTable();
+ CpuProfiler::instance_.FlushTable();
}
extern "C" bool ProfilingIsEnabledForAllThreads() {
- return pdata.enabled();
+ return CpuProfiler::instance_.Enabled();
}
extern "C" bool ProfilerStart(const char* fname) {
- return pdata.Start(fname);
+ return CpuProfiler::instance_.Start(fname, NULL, NULL);
+}
+
+extern "C" bool ProfilerStartFiltered(const char* fname,
+ bool (*filter_in_thread)(void* arg),
+ void *filter_in_thread_arg) {
+ return CpuProfiler::instance_.Start(fname, filter_in_thread,
+ filter_in_thread_arg);
}
extern "C" void ProfilerStop() {
- pdata.Stop();
+ CpuProfiler::instance_.Stop();
}
extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
- pdata.GetCurrentState(state);
+ CpuProfiler::instance_.GetCurrentState(state);
}
diff --git a/src/stacktrace_generic-inl.h b/src/stacktrace_generic-inl.h
index 3375ada..9392ffc 100644
--- a/src/stacktrace_generic-inl.h
+++ b/src/stacktrace_generic-inl.h
@@ -38,6 +38,7 @@
#include <stdlib.h>
#include "google/stacktrace.h"
+// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
static const int kStackLength = 64;
void * stack[kStackLength];
@@ -55,3 +56,51 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return result_count;
}
+
+// If you change this function, also change GetStackTrace above:
+//
+// This GetStackFrames routine shares a lot of code with GetStackTrace
+// above. This code could have been refactored into a common routine,
+// and then both GetStackTrace/GetStackFrames could call that routine.
+// There are two problems with that:
+//
+// (1) The performance of the refactored-code suffers substantially - the
+// refactored needs to be able to record the stack trace when called
+// from GetStackTrace, and both the stack trace and stack frame sizes,
+// when called from GetStackFrames - this introduces enough new
+// conditionals that GetStackTrace performance can degrade by as much
+// as 50%.
+//
+// (2) Whether the refactored routine gets inlined into GetStackTrace and
+// GetStackFrames depends on the compiler, and we can't guarantee the
+// behavior either-way, even with "__attribute__ ((always_inline))"
+// or "__attribute__ ((noinline))". But we need this guarantee or the
+// frame counts may be off by one.
+//
+// Both (1) and (2) can be addressed without this code duplication, by
+// clever use of template functions, and by defining GetStackTrace and
+// GetStackFrames as macros that expand to these template functions.
+// However, this approach comes with its own set of problems - namely,
+// macros and preprocessor trouble - for example, if GetStackTrace
+// and/or GetStackFrames is ever defined as a member functions in some
+// class, we are in trouble.
+int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
+ static const int kStackLength = 64;
+ void * stack[kStackLength];
+ int size;
+
+ size = backtrace(stack, kStackLength);
+ skip_count++; // we want to skip the current frame as well
+ int result_count = size - skip_count;
+ if (result_count < 0)
+ result_count = 0;
+ if (result_count > max_depth)
+ result_count = max_depth;
+ for (int i = 0; i < result_count; i++)
+ pcs[i] = stack[i + skip_count];
+
+ // No implementation for finding out the stack frame sizes yet.
+ memset(sizes, 0, sizeof(*sizes) * result_count);
+
+ return result_count;
+}
diff --git a/src/stacktrace_libunwind-inl.h b/src/stacktrace_libunwind-inl.h
index 20112d9..282c4f4 100644
--- a/src/stacktrace_libunwind-inl.h
+++ b/src/stacktrace_libunwind-inl.h
@@ -49,6 +49,7 @@ extern "C" {
static SpinLock libunwind_lock(SpinLock::LINKER_INITIALIZED);
static bool in_get_stack_trace = false;
+// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void *ip;
int n = 0;
@@ -88,3 +89,72 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return n;
}
+
+// If you change this function, also change GetStackTrace above:
+//
+// This GetStackFrames routine shares a lot of code with GetStackTrace
+// above. This code could have been refactored into a common routine,
+// and then both GetStackTrace/GetStackFrames could call that routine.
+// There are two problems with that:
+//
+// (1) The performance of the refactored-code suffers substantially - the
+// refactored needs to be able to record the stack trace when called
+// from GetStackTrace, and both the stack trace and stack frame sizes,
+// when called from GetStackFrames - this introduces enough new
+// conditionals that GetStackTrace performance can degrade by as much
+// as 50%.
+//
+// (2) Whether the refactored routine gets inlined into GetStackTrace and
+// GetStackFrames depends on the compiler, and we can't guarantee the
+// behavior either-way, even with "__attribute__ ((always_inline))"
+// or "__attribute__ ((noinline))". But we need this guarantee or the
+// frame counts may be off by one.
+//
+// Both (1) and (2) can be addressed without this code duplication, by
+// clever use of template functions, and by defining GetStackTrace and
+// GetStackFrames as macros that expand to these template functions.
+// However, this approach comes with its own set of problems - namely,
+// macros and preprocessor trouble - for example, if GetStackTrace
+// and/or GetStackFrames is ever defined as a member functions in some
+// class, we are in trouble.
+int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
+ void *ip;
+ int n = 0;
+ unw_cursor_t cursor;
+ unw_context_t uc;
+
+ {
+ SpinLockHolder sh(&libunwind_lock);
+ if (in_get_stack_trace) {
+ return 0;
+ } else {
+ in_get_stack_trace = true;
+ }
+ }
+
+ unw_getcontext(&uc);
+ RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
+ skip_count++; // Do not include the "GetStackFrames" frame
+
+ while (n < max_depth) {
+ int ret = unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip);
+ if (ret < 0)
+ break;
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ pcs[n++] = ip;
+ }
+ ret = unw_step(&cursor);
+ if (ret <= 0)
+ break;
+ }
+
+ // No implementation for finding out the stack frame sizes yet.
+ memset(sizes, 0, sizeof(*sizes) * n);
+
+ SpinLockHolder sh(&libunwind_lock);
+ in_get_stack_trace = false;
+
+ return n;
+}
diff --git a/src/stacktrace_powerpc-inl.h b/src/stacktrace_powerpc-inl.h
index a3be131..bf64284 100644
--- a/src/stacktrace_powerpc-inl.h
+++ b/src/stacktrace_powerpc-inl.h
@@ -1,4 +1,33 @@
-// Copyright 2007 and onwards Google Inc.
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
// Author: Craig Silverstein
//
// Produce stack trace. I'm guessing (hoping!) the code is much like
@@ -12,19 +41,34 @@
#include <google/stacktrace.h>
// Given a pointer to a stack frame, locate and return the calling
-// stackframe, or return NULL if no stackframe can be found. Perform
-// sanity checks to reduce the chance that a bad pointer is returned.
+// stackframe, or return NULL if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = (void **) *old_sp;
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
- if (new_sp <= old_sp) return NULL;
+ if (STRICT_UNWINDING) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_sp <= old_sp) return NULL;
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
+ } else {
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_sp == old_sp) return NULL;
+ // And allow frames upto about 1MB.
+ if ((new_sp > old_sp)
+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
+ }
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
- if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
return new_sp;
}
+// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
@@ -56,7 +100,83 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
// But I'm not sure what this is doing, exactly, or how reliable it is.
result[n++] = *(sp+2); // sp[2] holds the Link Record (return address)
}
- sp = NextStackFrame(sp);
+ // Use strict unwinding rules.
+ sp = NextStackFrame<true>(sp);
+ }
+ return n;
+}
+
+// If you change this function, also change GetStackTrace above:
+//
+// This GetStackFrames routine shares a lot of code with GetStackTrace
+// above. This code could have been refactored into a common routine,
+// and then both GetStackTrace/GetStackFrames could call that routine.
+// There are two problems with that:
+//
+// (1) The performance of the refactored-code suffers substantially - the
+// refactored needs to be able to record the stack trace when called
+// from GetStackTrace, and both the stack trace and stack frame sizes,
+// when called from GetStackFrames - this introduces enough new
+// conditionals that GetStackTrace performance can degrade by as much
+// as 50%.
+//
+// (2) Whether the refactored routine gets inlined into GetStackTrace and
+// GetStackFrames depends on the compiler, and we can't guarantee the
+// behavior either-way, even with "__attribute__ ((always_inline))"
+// or "__attribute__ ((noinline))". But we need this guarantee or the
+// frame counts may be off by one.
+//
+// Both (1) and (2) can be addressed without this code duplication, by
+// clever use of template functions, and by defining GetStackTrace and
+// GetStackFrames as macros that expand to these template functions.
+// However, this approach comes with its own set of problems - namely,
+// macros and preprocessor trouble - for example, if GetStackTrace
+// and/or GetStackFrames is ever defined as a member functions in some
+// class, we are in trouble.
+int GetStackFrames(void** pcs, int *sizes, int max_depth, int skip_count) {
+ void **sp;
+ // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+ // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
+ // different asm syntax. I don't know quite the best way to discriminate
+ // systems using the old as from the new one; I've gone with __APPLE__.
+#ifdef __APPLE__
+ __asm__ volatile ("mr %0,r1" : "=r" (sp));
+#else
+ __asm__ volatile ("mr %0,1" : "=r" (sp));
+#endif
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ // The GetStackFrames routine is called when we are in some
+ // informational context (the failure signal handler for example).
+ // Use the non-strict unwinding rules to produce a stack trace
+ // that is as complete as possible (even if it contains a few bogus
+ // entries in some rare cases).
+ void **next_sp = NextStackFrame<false>(sp);
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ // sp[2] holds the "Link Record", according to RTArch-59.html.
+ // On PPC, the Link Record is the return address of the
+ // subroutine call (what instruction we run after our function
+ // finishes). This is the same as the stack-pointer of our
+ // parent routine, which is what we want here. We believe that
+ // the compiler will always set up the LR for subroutine calls.
+ //
+ // It may be possible to get the stack-pointer of the parent
+ // routine directly. In my experiments, this code works:
+ // pcs[n] = NextStackFrame(sp)[-18]
+ // But I'm not sure what this is doing, exactly, or how reliable it is.
+ pcs[n] = *(sp+2); // sp[2] holds the Link Record (return address)
+ if (next_sp > sp) {
+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
+ n++;
+ }
+ sp = next_sp;
}
return n;
}
diff --git a/src/stacktrace_x86-inl.h b/src/stacktrace_x86-inl.h
index 5dcbc7a..794aaf5 100644
--- a/src/stacktrace_x86-inl.h
+++ b/src/stacktrace_x86-inl.h
@@ -37,14 +37,29 @@
#include "google/stacktrace.h"
// Given a pointer to a stack frame, locate and return the calling
-// stackframe, or return NULL if no stackframe can be found. Perform
-// sanity checks to reduce the chance that a bad pointer is returned.
+// stackframe, or return NULL if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = (void **) *old_sp;
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
- if (new_sp <= old_sp) return NULL;
+ if (STRICT_UNWINDING) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_sp <= old_sp) return NULL;
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
+ } else {
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_sp == old_sp) return NULL;
+ // And allow frames upto about 1MB.
+ if ((new_sp > old_sp)
+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
+ }
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
#ifdef __i386__
// On 64-bit machines, the stack pointer can be very close to
@@ -52,10 +67,10 @@ static void **NextStackFrame(void **old_sp) {
// last two pages in the address space
if ((uintptr_t)new_sp >= 0xffffe000) return NULL;
#endif
- if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
return new_sp;
}
+// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
#ifdef __i386__
@@ -95,7 +110,92 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
} else {
result[n++] = *(sp+1);
}
- sp = NextStackFrame(sp);
+ // Use strict unwinding rules.
+ sp = NextStackFrame<true>(sp);
+ }
+ return n;
+}
+
+// If you change this function, also change GetStackTrace above:
+//
+// This GetStackFrames routine shares a lot of code with GetStackTrace
+// above. This code could have been refactored into a common routine,
+// and then both GetStackTrace/GetStackFrames could call that routine.
+// There are two problems with that:
+//
+// (1) The performance of the refactored-code suffers substantially - the
+// refactored needs to be able to record the stack trace when called
+// from GetStackTrace, and both the stack trace and stack frame sizes,
+// when called from GetStackFrames - this introduces enough new
+// conditionals that GetStackTrace performance can degrade by as much
+// as 50%.
+//
+// (2) Whether the refactored routine gets inlined into GetStackTrace and
+// GetStackFrames depends on the compiler, and we can't guarantee the
+// behavior either-way, even with "__attribute__ ((always_inline))"
+// or "__attribute__ ((noinline))". But we need this guarantee or the
+// frame counts may be off by one.
+//
+// Both (1) and (2) can be addressed without this code duplication, by
+// clever use of template functions, and by defining GetStackTrace and
+// GetStackFrames as macros that expand to these template functions.
+// However, this approach comes with its own set of problems - namely,
+// macros and preprocessor trouble - for example, if GetStackTrace
+// and/or GetStackFrames is ever defined as a member functions in some
+// class, we are in trouble.
+int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
+ void **sp;
+#ifdef __i386__
+ // Stack frame format:
+ // sp[0] pointer to previous frame
+ // sp[1] caller address
+ // sp[2] first argument
+ // ...
+ sp = (void **)&pcs - 2;
+#endif
+
+#ifdef __x86_64__
+ // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
+ unsigned long rbp;
+ // Move the value of the register %rbp into the local variable rbp.
+ // We need 'volatile' to prevent this instruction from getting moved
+ // around during optimization to before function prologue is done.
+ // An alternative way to achieve this
+ // would be (before this __asm__ instruction) to call Noop() defined as
+ // static void Noop() __attribute__ ((noinline)); // prevent inlining
+ // static void Noop() { asm(""); } // prevent optimizing-away
+ __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
+ // Arguments are passed in registers on x86-64, so we can't just
+ // offset from &pcs
+ sp = (void **) rbp;
+#endif
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ if (*(sp+1) == (void *)0) {
+ // In 64-bit code, we often see a frame that
+ // points to itself and has a return address of 0.
+ break;
+ }
+ // The GetStackFrames routine is called when we are in some
+ // informational context (the failure signal handler for example).
+ // Use the non-strict unwinding rules to produce a stack trace
+ // that is as complete as possible (even if it contains a few bogus
+ // entries in some rare cases).
+ void **next_sp = NextStackFrame<false>(sp);
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ pcs[n] = *(sp+1);
+ if (next_sp > sp) {
+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
+ n++;
+ }
+ sp = next_sp;
}
return n;
}
diff --git a/src/stacktrace_x86_64-inl.h b/src/stacktrace_x86_64-inl.h
index 578b50a..41ec5c5 100644
--- a/src/stacktrace_x86_64-inl.h
+++ b/src/stacktrace_x86_64-inl.h
@@ -82,6 +82,7 @@ static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
return _URC_NO_REASON;
}
+// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
if (!ready_to_run)
return 0;
@@ -99,3 +100,51 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return targ.count;
}
+
+// If you change this function, also change GetStackTrace above:
+//
+// This GetStackFrames routine shares a lot of code with GetStackTrace
+// above. This code could have been refactored into a common routine,
+// and then both GetStackTrace/GetStackFrames could call that routine.
+// There are two problems with that:
+//
+// (1) The performance of the refactored-code suffers substantially - the
+// refactored needs to be able to record the stack trace when called
+// from GetStackTrace, and both the stack trace and stack frame sizes,
+// when called from GetStackFrames - this introduces enough new
+// conditionals that GetStackTrace performance can degrade by as much
+// as 50%.
+//
+// (2) Whether the refactored routine gets inlined into GetStackTrace and
+// GetStackFrames depends on the compiler, and we can't guarantee the
+// behavior either-way, even with "__attribute__ ((always_inline))"
+// or "__attribute__ ((noinline))". But we need this guarantee or the
+// frame counts may be off by one.
+//
+// Both (1) and (2) can be addressed without this code duplication, by
+// clever use of template functions, and by defining GetStackTrace and
+// GetStackFrames as macros that expand to these template functions.
+// However, this approach comes with its own set of problems - namely,
+// macros and preprocessor trouble - for example, if GetStackTrace
+// and/or GetStackFrames is ever defined as a member functions in some
+// class, we are in trouble.
+int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
+ if (!ready_to_run)
+ return 0;
+
+ trace_arg_t targ;
+
+ skip_count += 1; // Do not include the "GetStackFrames" frame
+
+ targ.result = pcs;
+ targ.max_depth = max_depth;
+ targ.skip_count = skip_count;
+ targ.count = 0;
+
+ _Unwind_Backtrace(GetOneFrame, &targ);
+
+ // No implementation for finding out the stack frame sizes yet.
+ memset(sizes, 0, sizeof(*sizes) * targ.count);
+
+ return targ.count;
+}
diff --git a/src/system-alloc.cc b/src/system-alloc.cc
index 8b400aa..96906ca 100644
--- a/src/system-alloc.cc
+++ b/src/system-alloc.cc
@@ -97,6 +97,7 @@ public:
SbrkSysAllocator() : SysAllocator() {
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
+ void DumpStats(TCMalloc_Printer* printer);
};
static char sbrk_space[sizeof(SbrkSysAllocator)];
@@ -105,6 +106,7 @@ public:
MmapSysAllocator() : SysAllocator() {
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
+ void DumpStats(TCMalloc_Printer* printer);
};
static char mmap_space[sizeof(MmapSysAllocator)];
@@ -113,6 +115,7 @@ public:
DevMemSysAllocator() : SysAllocator() {
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
+ void DumpStats(TCMalloc_Printer* printer);
};
static char devmem_space[sizeof(DevMemSysAllocator)];
@@ -126,7 +129,7 @@ bool RegisterSystemAllocator(SysAllocator *a, int priority) {
// No two allocators should have a priority conflict, since the order
// is determined at compile time.
- CHECK(allocators[priority] == NULL);
+ CHECK_CONDITION(allocators[priority] == NULL);
allocators[priority] = a;
return true;
}
@@ -179,6 +182,10 @@ void* SbrkSysAllocator::Alloc(size_t size, size_t *actual_size,
return reinterpret_cast<void*>(ptr);
}
+void SbrkSysAllocator::DumpStats(TCMalloc_Printer* printer) {
+ printer->printf("SbrkSysAllocator: failed_=%d\n", failed_);
+}
+
void* MmapSysAllocator::Alloc(size_t size, size_t *actual_size,
size_t alignment) {
// could theoretically return the "extra" bytes here, but this
@@ -234,6 +241,10 @@ void* MmapSysAllocator::Alloc(size_t size, size_t *actual_size,
return reinterpret_cast<void*>(ptr);
}
+void MmapSysAllocator::DumpStats(TCMalloc_Printer* printer) {
+ printer->printf("MmapSysAllocator: failed_=%d\n", failed_);
+}
+
void* DevMemSysAllocator::Alloc(size_t size, size_t *actual_size,
size_t alignment) {
static bool initialized = false;
@@ -322,6 +333,10 @@ void* DevMemSysAllocator::Alloc(size_t size, size_t *actual_size,
return reinterpret_cast<void*>(ptr);
}
+void DevMemSysAllocator::DumpStats(TCMalloc_Printer* printer) {
+ printer->printf("DevMemSysAllocator: failed_=%d\n", failed_);
+}
+
static bool system_alloc_inited = false;
void InitSystemAllocators(void) {
// This determines the order in which system allocators are called
@@ -403,3 +418,13 @@ void TCMalloc_SystemRelease(void* start, size_t length) {
}
#endif
}
+
+void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
+ for (int j = 0; j < kMaxAllocators; j++) {
+ SysAllocator *a = allocators[j];
+ if (a == NULL) continue;
+ if (a->usable_) {
+ a->DumpStats(printer);
+ }
+ }
+}
diff --git a/src/system-alloc.h b/src/system-alloc.h
index 13f01a8..2859a54 100644
--- a/src/system-alloc.h
+++ b/src/system-alloc.h
@@ -37,6 +37,7 @@
#define TCMALLOC_SYSTEM_ALLOC_H__
#include "config.h"
+#include "internal_logging.h"
// REQUIRES: "alignment" is a power of two or "0" to indicate default alignment
//
@@ -75,6 +76,12 @@ class SysAllocator {
virtual void* Alloc(size_t size, size_t *actual_size, size_t alignment) = 0;
+ // Populate the map with whatever properties the specified allocator finds
+ // useful for debugging (such as number of bytes allocated and whether the
+ // allocator has failed). The callee is responsible for any necessary
+ // locking (and avoiding deadlock).
+ virtual void DumpStats(TCMalloc_Printer* printer) = 0;
+
// So the allocator can be turned off at compile time
bool usable_;
@@ -100,4 +107,7 @@ extern PERFTOOLS_DLL_DECL bool RegisterSystemAllocator(SysAllocator *allocator,
// Number of SysAllocators known to call RegisterSystemAllocator
static const int kMaxDynamicAllocators = 2;
+// Retrieve the current state of various system allocators.
+extern PERFTOOLS_DLL_DECL void DumpSystemAllocatorStats(TCMalloc_Printer* printer);
+
#endif /* TCMALLOC_SYSTEM_ALLOC_H__ */
diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc
index c4577c1..76435a7 100644
--- a/src/tcmalloc.cc
+++ b/src/tcmalloc.cc
@@ -653,10 +653,10 @@ struct Span {
Span* next; // Used when in link list
Span* prev; // Used when in link list
void* objects; // Linked list of free objects
+ unsigned int refcount : 16; // Number of non-free objects
+ unsigned int sizeclass : 8; // Size-class for small objects (or 0)
unsigned int free : 1; // Is the span free
unsigned int sample : 1; // Sampled object?
- unsigned int sizeclass : 8; // Size-class for small objects (or 0)
- unsigned int refcount : 11; // Number of non-free objects
#undef SPAN_HISTORY
#ifdef SPAN_HISTORY
@@ -2325,6 +2325,9 @@ static void DumpStats(TCMalloc_Printer* out, int level) {
SpinLockHolder h(&pageheap_lock);
pageheap->Dump(out);
+
+ out->printf("------------------------------------------------\n");
+ DumpSystemAllocatorStats(out);
}
const uint64_t bytes_in_use = stats.system_bytes
@@ -2952,6 +2955,9 @@ extern "C" void* realloc(void* old_ptr, size_t new_size) __THROW {
do_free(old_ptr);
return new_ptr;
} else {
+ // We still need to call hooks to report the updated size:
+ MallocHook::InvokeDeleteHook(old_ptr);
+ MallocHook::InvokeNewHook(old_ptr, new_size);
return old_ptr;
}
}
diff --git a/src/tests/addressmap_unittest.cc b/src/tests/addressmap_unittest.cc
index 2cf125d..50d9b94 100644
--- a/src/tests/addressmap_unittest.cc
+++ b/src/tests/addressmap_unittest.cc
@@ -33,6 +33,7 @@
#include <vector>
#include <set>
#include <algorithm>
+#include <utility>
#include "addressmap-inl.h"
#include "base/logging.h"
#include "base/commandlineflags.h"
diff --git a/src/tests/heap-checker_unittest.cc b/src/tests/heap-checker_unittest.cc
index 594323a..5b64b8b 100644
--- a/src/tests/heap-checker_unittest.cc
+++ b/src/tests/heap-checker_unittest.cc
@@ -95,6 +95,7 @@
#include <iomanip> // for hex
#include <set>
#include <map>
+#include <memory>
#include <vector>
#include <string>
diff --git a/src/tests/low_level_alloc_unittest.cc b/src/tests/low_level_alloc_unittest.cc
index 1e6f0a5..c1de5ae 100644
--- a/src/tests/low_level_alloc_unittest.cc
+++ b/src/tests/low_level_alloc_unittest.cc
@@ -167,6 +167,13 @@ static void FreeHook(const void *p) {
}
int main(int argc, char *argv[]) {
+ // This is needed by maybe_threads_unittest.sh, which parses argv[0]
+ // to figure out what directory low_level_alloc_unittest is in.
+ if (argc != 1) {
+ fprintf(stderr, "USAGE: %s\n", argv[0]);
+ return 1;
+ }
+
old_alloc_hook = MallocHook::SetNewHook(AllocHook);
old_free_hook = MallocHook::SetDeleteHook(FreeHook);
CHECK_EQ(allocates, 0);
diff --git a/src/tests/maybe_threads_unittest.sh b/src/tests/maybe_threads_unittest.sh
index f319ea1..1c1a1d0 100755
--- a/src/tests/maybe_threads_unittest.sh
+++ b/src/tests/maybe_threads_unittest.sh
@@ -57,12 +57,12 @@ fi
UNITTEST_DIR=${1:-$BINDIR}
# Figure out the "real" unittest directory. Also holds the .so files.
-UNITTEST_DIR=`$UNITTEST_DIR/profiler1_unittest 2>&1 \
+UNITTEST_DIR=`$UNITTEST_DIR/low_level_alloc_unittest --help 2>&1 \
| awk '{print $2; exit;}' \
| xargs dirname`
# We need to set the library-path too: libtcmalloc depends on libstacktrace
# (Note we try several different names: OS X uses its own libpath varname).
LD_LIBRARY_PATH="$UNITTEST_DIR" DYLD_LIBRARY_PATH="$UNITTEST_DIR" \
-LD_PRELOAD="$UNITTEST_DIR/libtcmalloc.so" \
+LD_PRELOAD="$UNITTEST_DIR/libtcmalloc_minimal.so" \
$UNITTEST_DIR/low_level_alloc_unittest
diff --git a/src/tests/profiledata_unittest.cc b/src/tests/profiledata_unittest.cc
new file mode 100644
index 0000000..a49257d
--- /dev/null
+++ b/src/tests/profiledata_unittest.cc
@@ -0,0 +1,320 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+// Author: Chris Demetriou
+//
+// This file contains the unit tests for the ProfileData class.
+
+#if defined HAVE_STDINT_H
+#include <stdint.h> // to get uintptr_t
+#elif defined HAVE_INTTYPES_H
+#include <inttypes.h> // another place uintptr_t might be defined
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <string>
+
+#include "profiledata.h"
+
+#include "base/commandlineflags.h"
+#include "base/logging.h"
+
+using std::string;
+
+// Some helpful macros for the test class
+#define EXPECT_TRUE(cond) CHECK(cond)
+#define EXPECT_FALSE(cond) CHECK(!(cond))
+#define EXPECT_EQ(a, b) CHECK_EQ(a, b)
+#define EXPECT_GT(a, b) CHECK_GT(a, b)
+#define EXPECT_LT(a, b) CHECK_LT(a, b)
+#define EXPECT_GE(a, b) CHECK_GE(a, b)
+#define EXPECT_LE(a, b) CHECK_LE(a, b)
+#define EXPECT_STREQ(a, b) CHECK(strcmp(a, b) == 0)
+#define TEST_F(cls, fn) void cls :: fn()
+
+
+namespace {
+
+// must be the same as with ProfileData::Slot.
+typedef uintptr_t ProfileDataSlot;
+
+// Quick and dirty function to make a number into a void* for use in a
+// sample.
+inline void* V(intptr_t x) { return reinterpret_cast<void*>(x); }
+
+class ProfileDataChecker {
+ public:
+ ProfileDataChecker() {
+ const char* tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = "/tmp";
+ mkdir(tmpdir, 0755); // if necessary
+ filename_ = string(tmpdir) + "/profiledata_unittest.tmp";
+ }
+
+ string filename() const { return filename_; }
+
+ void Check(const ProfileDataSlot* slots, int num_slots) {
+ size_t num_bytes = num_slots * sizeof slots[0];
+ char* filedata = new char[num_bytes];
+
+ int fd = open(filename_.c_str(), O_RDONLY);
+ EXPECT_GE(fd, 0);
+ ssize_t numread = read(fd, filedata, num_bytes);
+ EXPECT_EQ(numread, num_bytes);
+ EXPECT_EQ(0, memcmp(slots, filedata, num_bytes));
+ close(fd);
+
+ delete[] filedata;
+ }
+
+ private:
+ string filename_;
+};
+
+class ProfileDataTest {
+ protected:
+ void ExpectStopped() {
+ EXPECT_FALSE(collector_.enabled());
+ }
+
+ void ExpectRunningSamples(int samples) {
+ ProfileData::State state;
+ collector_.GetCurrentState(&state);
+ EXPECT_TRUE(state.enabled);
+ EXPECT_EQ(samples, state.samples_gathered);
+ }
+
+ void ExpectSameState(const ProfileData::State& before,
+ const ProfileData::State& after) {
+ EXPECT_EQ(before.enabled, after.enabled);
+ EXPECT_EQ(before.samples_gathered, after.samples_gathered);
+ EXPECT_EQ(before.start_time, after.start_time);
+ EXPECT_STREQ(before.profile_name, after.profile_name);
+ }
+
+ ProfileData collector_;
+ ProfileDataChecker checker_;
+
+ private:
+ // The tests to run
+ void OpsWhenStopped();
+ void StartStopEmpty();
+ void StartWhenStarted();
+ void StartStopEmpty2();
+ void CollectOne();
+ void CollectTwoMatching();
+ void CollectTwoFlush();
+
+ public:
+#define RUN(test) do { \
+ printf("Running %s\n", #test); \
+ ProfileDataTest pdt; \
+ pdt.test(); \
+} while (0)
+
+ static int RUN_ALL_TESTS() {
+ RUN(OpsWhenStopped);
+ RUN(StartStopEmpty);
+ RUN(StartWhenStarted);
+ RUN(StartStopEmpty2);
+ RUN(CollectOne);
+ RUN(CollectTwoMatching);
+ RUN(CollectTwoFlush);
+ return 0;
+ }
+};
+
+// Check that various operations are safe when stopped.
+TEST_F(ProfileDataTest, OpsWhenStopped) {
+ ExpectStopped();
+ EXPECT_FALSE(collector_.enabled());
+
+ // Verify that state is disabled, all-empty/all-0
+ ProfileData::State state_before;
+ collector_.GetCurrentState(&state_before);
+ EXPECT_FALSE(state_before.enabled);
+ EXPECT_EQ(0, state_before.samples_gathered);
+ EXPECT_EQ(0, state_before.start_time);
+ EXPECT_STREQ("", state_before.profile_name);
+
+ // Safe to call stop again.
+ collector_.Stop();
+
+ // Safe to call FlushTable.
+ collector_.FlushTable();
+
+ // Safe to call Add.
+ const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
+ collector_.Add(arraysize(trace), trace);
+
+ ProfileData::State state_after;
+ collector_.GetCurrentState(&state_after);
+
+ ExpectSameState(state_before, state_after);
+}
+
+// Start and Stop, collecting no samples. Verify output contents.
+TEST_F(ProfileDataTest, StartStopEmpty) {
+ const int frequency = 1;
+ ProfileDataSlot slots[] = {
+ 0, 3, 0, 1000000 / frequency, 0, // binary header
+ 0, 1, 0 // binary trailer
+ };
+
+ ExpectStopped();
+ EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency));
+ ExpectRunningSamples(0);
+ collector_.Stop();
+ ExpectStopped();
+ checker_.Check(slots, arraysize(slots));
+}
+
+// Start after already started. Should return false and not impact
+// collected data or state.
+TEST_F(ProfileDataTest, StartWhenStarted) {
+ const int frequency = 1;
+ ProfileDataSlot slots[] = {
+ 0, 3, 0, 1000000 / frequency, 0, // binary header
+ 0, 1, 0 // binary trailer
+ };
+
+ EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency));
+
+ ProfileData::State state_before;
+ collector_.GetCurrentState(&state_before);
+
+ CHECK(!collector_.Start("foobar", frequency * 2));
+
+ ProfileData::State state_after;
+ collector_.GetCurrentState(&state_after);
+ ExpectSameState(state_before, state_after);
+
+ collector_.Stop();
+ ExpectStopped();
+ checker_.Check(slots, arraysize(slots));
+}
+
+// Like StartStopEmpty, but uses a different file name and frequency.
+TEST_F(ProfileDataTest, StartStopEmpty2) {
+ const int frequency = 2;
+ ProfileDataSlot slots[] = {
+ 0, 3, 0, 1000000 / frequency, 0, // binary header
+ 0, 1, 0 // binary trailer
+ };
+
+ ExpectStopped();
+ EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency));
+ ExpectRunningSamples(0);
+ collector_.Stop();
+ ExpectStopped();
+ checker_.Check(slots, arraysize(slots));
+}
+
+TEST_F(ProfileDataTest, CollectOne) {
+ const int frequency = 2;
+ ProfileDataSlot slots[] = {
+ 0, 3, 0, 1000000 / frequency, 0, // binary header
+ 1, 5, 100, 101, 102, 103, 104, // our sample
+ 0, 1, 0 // binary trailer
+ };
+
+ ExpectStopped();
+ EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency));
+ ExpectRunningSamples(0);
+
+ const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
+ collector_.Add(arraysize(trace), trace);
+ ExpectRunningSamples(1);
+
+ collector_.Stop();
+ ExpectStopped();
+ checker_.Check(slots, arraysize(slots));
+}
+
+TEST_F(ProfileDataTest, CollectTwoMatching) {
+ const int frequency = 2;
+ ProfileDataSlot slots[] = {
+ 0, 3, 0, 1000000 / frequency, 0, // binary header
+ 2, 5, 100, 201, 302, 403, 504, // our two samples
+ 0, 1, 0 // binary trailer
+ };
+
+ ExpectStopped();
+ EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency));
+ ExpectRunningSamples(0);
+
+ for (int i = 0; i < 2; ++i) {
+ const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };
+ collector_.Add(arraysize(trace), trace);
+ ExpectRunningSamples(i + 1);
+ }
+
+ collector_.Stop();
+ ExpectStopped();
+ checker_.Check(slots, arraysize(slots));
+}
+
+TEST_F(ProfileDataTest, CollectTwoFlush) {
+ const int frequency = 2;
+ ProfileDataSlot slots[] = {
+ 0, 3, 0, 1000000 / frequency, 0, // binary header
+ 1, 5, 100, 201, 302, 403, 504, // first sample (flushed)
+ 1, 5, 100, 201, 302, 403, 504, // second identical sample
+ 0, 1, 0 // binary trailer
+ };
+
+ ExpectStopped();
+ EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), frequency));
+ ExpectRunningSamples(0);
+
+ const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };
+
+ collector_.Add(arraysize(trace), trace);
+ ExpectRunningSamples(1);
+ collector_.FlushTable();
+
+ collector_.Add(arraysize(trace), trace);
+ ExpectRunningSamples(2);
+
+ collector_.Stop();
+ ExpectStopped();
+ checker_.Check(slots, arraysize(slots));
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ int rc = ProfileDataTest::RUN_ALL_TESTS();
+ printf("%s\n", rc == 0 ? "PASS" : "FAIL");
+ return rc;
+}
diff --git a/src/tests/system-alloc_unittest.cc b/src/tests/system-alloc_unittest.cc
index 7045abe..a160a34 100644
--- a/src/tests/system-alloc_unittest.cc
+++ b/src/tests/system-alloc_unittest.cc
@@ -72,6 +72,10 @@ public:
ptr_ += size;
return reinterpret_cast<void *>(ptr);
}
+
+ void DumpStats(TCMalloc_Printer* printer) {
+ }
+
private:
static const int kArraySize = 8 * 1024 * 1024;
char array_[kArraySize];
diff --git a/src/tests/tcmalloc_unittest.cc b/src/tests/tcmalloc_unittest.cc
index c4c18cd..e818a21 100644
--- a/src/tests/tcmalloc_unittest.cc
+++ b/src/tests/tcmalloc_unittest.cc
@@ -332,7 +332,7 @@ class TesterThread {
case UPDATE: UpdateObject(); break;
case PASS: PassObject(); break;
case -1: goto done;
- default: assert("" == "Unknown type");
+ default: assert(NULL == "Unknown type");
}
ShrinkHeap();
diff --git a/src/tests/testutil.cc b/src/tests/testutil.cc
index cb523de..9ab4c3c 100644
--- a/src/tests/testutil.cc
+++ b/src/tests/testutil.cc
@@ -36,7 +36,12 @@
#include <stdlib.h> // for NULL, abort()
#include "tests/testutil.h"
-#if defined(NO_THREADS) || !defined(HAVE_PTHREADS)
+struct FunctionAndId {
+ void (*ptr_to_function)(int);
+ int id;
+};
+
+#if defined(NO_THREADS) || !(defined(HAVE_PTHREADS) || defined(WIN32))
extern "C" void RunThread(void (*fn)()) {
(*fn)();
@@ -53,19 +58,70 @@ extern "C" void RunManyThreadsWithId(void (*fn)(int), int count, int) {
(*fn)(i); // stacksize doesn't make sense in a non-threaded context
}
-#else // NO_THREADS || !HAVE_PTHREAD
+#elif defined(WIN32)
+
+#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
+#include <windows.h>
+
+extern "C" {
+ // This helper function has the signature that pthread_create wants.
+ DWORD WINAPI RunFunctionInThread(LPVOID ptr_to_ptr_to_fn) {
+ (**static_cast<void (**)()>(ptr_to_ptr_to_fn))(); // runs fn
+ return 0;
+ }
+
+ DWORD WINAPI RunFunctionInThreadWithId(LPVOID ptr_to_fnid) {
+ FunctionAndId* fn_and_id = static_cast<FunctionAndId*>(ptr_to_fnid);
+ (*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn
+ return 0;
+ }
+
+ void RunManyThreads(void (*fn)(), int count) {
+ DWORD dummy;
+ HANDLE* hThread = new HANDLE[count];
+ for (int i = 0; i < count; i++) {
+ hThread[i] = CreateThread(NULL, 0, RunFunctionInThread, &fn, 0, &dummy);
+ if (hThread[i] == NULL) ExitProcess(i);
+ }
+ WaitForMultipleObjects(count, hThread, TRUE, INFINITE);
+ for (int i = 0; i < count; i++) {
+ CloseHandle(hThread[i]);
+ }
+ delete[] hThread;
+ }
+
+ void RunThread(void (*fn)()) {
+ RunManyThreads(fn, 1);
+ }
+
+ void RunManyThreadsWithId(void (*fn)(int), int count, int stacksize) {
+ DWORD dummy;
+ HANDLE* hThread = new HANDLE[count];
+ FunctionAndId* fn_and_ids = new FunctionAndId[count];
+ for (int i = 0; i < count; i++) {
+ fn_and_ids[i].ptr_to_function = fn;
+ fn_and_ids[i].id = i;
+ hThread[i] = CreateThread(NULL, stacksize, RunFunctionInThreadWithId,
+ &fn_and_ids[i], 0, &dummy);
+ if (hThread[i] == NULL) ExitProcess(i);
+ }
+ WaitForMultipleObjects(count, hThread, TRUE, INFINITE);
+ for (int i = 0; i < count; i++) {
+ CloseHandle(hThread[i]);
+ }
+ delete[] fn_and_ids;
+ delete[] hThread;
+ }
+}
+
+#else // not NO_THREADS, not !HAVE_PTHREAD, not WIN32
#include <pthread.h>
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
extern "C" {
- struct FunctionAndId {
- void (*ptr_to_function)(int);
- int id;
- };
-
-// This helper function has the signature that pthread_create wants.
+ // This helper function has the signature that pthread_create wants.
static void* RunFunctionInThread(void *ptr_to_ptr_to_fn) {
(**static_cast<void (**)()>(ptr_to_ptr_to_fn))(); // runs fn
return NULL;
diff --git a/src/windows/config.h b/src/windows/config.h
index 8b38b32..8a74cda 100644
--- a/src/windows/config.h
+++ b/src/windows/config.h
@@ -1,4 +1,14 @@
/* A manual version of config.h fit for windows machines. */
+
+/* Sometimes we accidentally #include this config.h instead of the one
+ in .. -- this is particularly true for msys/mingw, which uses the
+ unix config.h but also runs code in the windows directory.
+ */
+#ifdef __MINGW32__
+#include "../config.h"
+#define GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H__
+#endif
+
#ifndef GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H__
#define GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H__
@@ -229,10 +239,4 @@
// TODO(csilvers): include windows/port.h in every relevant source file instead?
#include "windows/port.h"
-// windows/port.h defines compatibility APIs for several .h files, which
-// we therefore shouldn't be #including directly. This hack keeps us from
-// doing so. TODO(csilvers): do something more principled.
-#define BASE_SPINLOCK_H__ 1
-#define GOOGLE_MAYBE_THREADS_H__ 1
-
#endif /* GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H__ */
diff --git a/src/windows/mingw.h b/src/windows/mingw.h
new file mode 100644
index 0000000..40bc104
--- /dev/null
+++ b/src/windows/mingw.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2007, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Craig Silverstein
+ *
+ * MinGW is an interesting mix of unix and windows. We use a normal
+ * configure script, but still need the windows port.h to define some
+ * stuff that MinGW doesn't support, like pthreads.
+ */
+
+#ifndef GOOGLE_PERFTOOLS_WINDOWS_MINGW_H__
+#define GOOGLE_PERFTOOLS_WINDOWS_MINGW_H__
+
+#ifdef __MINGW32__
+
+#include "windows/port.h"
+
+#endif /* __MINGW32__ */
+
+#endif /* GOOGLE_PERFTOOLS_WINDOWS_MINGW_H__ */
diff --git a/src/windows/mini_disassembler.h b/src/windows/mini_disassembler.h
index ac14da9..e0bbd76 100644
--- a/src/windows/mini_disassembler.h
+++ b/src/windows/mini_disassembler.h
@@ -166,17 +166,17 @@ class MiniDisassembler {
bool address_default_is_32_bits_;
// Huge big opcode table based on the IA-32 manual, defined
- // in Ia32OpcodeMap.cpp
+ // in Ia32OpcodeMap.cc
static const OpcodeTable s_ia32_opcode_map_[];
// Somewhat smaller table to help with decoding ModR/M bytes
// when 16-bit addressing mode is being used. Defined in
- // Ia32ModrmMap.cpp
+ // Ia32ModrmMap.cc
static const ModrmEntry s_ia16_modrm_map_[];
// Somewhat smaller table to help with decoding ModR/M bytes
// when 32-bit addressing mode is being used. Defined in
- // Ia32ModrmMap.cpp
+ // Ia32ModrmMap.cc
static const ModrmEntry s_ia32_modrm_map_[];
// Indicators of whether we got certain prefixes that certain
diff --git a/src/windows/patch_functions.cc b/src/windows/patch_functions.cc
index a5cadd1..8679a15 100644
--- a/src/windows/patch_functions.cc
+++ b/src/windows/patch_functions.cc
@@ -39,6 +39,11 @@
#include "google/malloc_hook.h"
#include "preamble_patcher.h"
+// MinGW doesn't seem to define this, perhaps some windowsen don't either.
+#ifndef TH32CS_SNAPMODULE32
+#define TH32CS_SNAPMODULE32 0
+#endif
+
// These functions are how we override the memory allocation functions,
// just like tcmalloc.cc and malloc_hook.cc do.
@@ -49,10 +54,23 @@ extern "C" void Perftools_free(void* ptr) __THROW;
extern "C" void* Perftools_realloc(void* ptr, size_t size) __THROW;
extern "C" void* Perftools_calloc(size_t nmemb, size_t size) __THROW;
+// According to the c++ standard, __THROW cannot be part of a typedef
+// specification. However, it is part of a function specification, so
+// it's impossible to have typdefs for malloc/etc that exactly match
+// the function specification. Luckily, gcc doesn't care if the match
+// is exact or not. MSVC *does* care, but (contra the spec) allows
+// __THROW as part of a typedef specification. So we fork the code.
+#ifdef _MSC_VER
typedef void* (*Type_malloc)(size_t size) __THROW;
typedef void (*Type_free)(void* ptr) __THROW;
typedef void* (*Type_realloc)(void* ptr, size_t size) __THROW;
-typedef void* (*Type_calloc)(size_t nmemb, size_t size) __THROW;
+typedef void* (*Type_calloc)(size_t nmemb, size_t size) __THROW;
+#else
+typedef void* (*Type_malloc)(size_t size);
+typedef void (*Type_free)(void* ptr);
+typedef void* (*Type_realloc)(void* ptr, size_t size);
+typedef void* (*Type_calloc)(size_t nmemb, size_t size);
+#endif
// A Windows-API equivalent of malloc and free
typedef LPVOID (WINAPI *Type_HeapAlloc)(HANDLE hHeap, DWORD dwFlags,
@@ -74,7 +92,7 @@ typedef LPVOID (WINAPI *Type_MapViewOfFileEx)(HANDLE hFileMappingObject,
LPVOID lpBaseAddress);
typedef BOOL (WINAPI *Type_UnmapViewOfFile)(LPCVOID lpBaseAddress);
-// all libc memory-alloaction routines go through one of these.
+// All libc memory-alloaction routines go through one of these.
static Type_malloc Windows_malloc;
static Type_calloc Windows_calloc;
static Type_realloc Windows_realloc;
@@ -88,9 +106,23 @@ static Type_VirtualFreeEx Windows_VirtualFreeEx;
static Type_MapViewOfFileEx Windows_MapViewOfFileEx;
static Type_UnmapViewOfFile Windows_UnmapViewOfFile;
+// To unpatch, we also need to keep around a "stub" that points to the
+// pre-patched Windows function.
+static Type_malloc origstub_malloc;
+static Type_calloc origstub_calloc;
+static Type_realloc origstub_realloc;
+static Type_free origstub_free;
+static Type_HeapAlloc origstub_HeapAlloc;
+static Type_HeapFree origstub_HeapFree;
+static Type_VirtualAllocEx origstub_VirtualAllocEx;
+static Type_VirtualFreeEx origstub_VirtualFreeEx;
+static Type_MapViewOfFileEx origstub_MapViewOfFileEx;
+static Type_UnmapViewOfFile origstub_UnmapViewOfFile;
+
+
static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
DWORD_PTR dwBytes) {
- LPVOID result = Windows_HeapAlloc(hHeap, dwFlags, dwBytes);
+ LPVOID result = origstub_HeapAlloc(hHeap, dwFlags, dwBytes);
MallocHook::InvokeNewHook(result, dwBytes);
return result;
}
@@ -98,13 +130,13 @@ static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
static BOOL WINAPI Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags,
LPVOID lpMem) {
MallocHook::InvokeDeleteHook(lpMem);
- return Windows_HeapFree(hHeap, dwFlags, lpMem);
+ return origstub_HeapFree(hHeap, dwFlags, lpMem);
}
static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address,
SIZE_T size, DWORD type,
DWORD protect) {
- LPVOID result = Windows_VirtualAllocEx(process, address, size, type, protect);
+ LPVOID result = origstub_VirtualAllocEx(process, address, size, type, protect);
// VirtualAllocEx() seems to be the Windows equivalent of mmap()
MallocHook::InvokeMmapHook(result, address, size, protect, type, -1, 0);
return result;
@@ -113,7 +145,7 @@ static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address,
static BOOL WINAPI Perftools_VirtualFreeEx(HANDLE process, LPVOID address,
SIZE_T size, DWORD type) {
MallocHook::InvokeMunmapHook(address, size);
- return Windows_VirtualFreeEx(process, address, size, type);
+ return origstub_VirtualFreeEx(process, address, size, type);
}
static LPVOID WINAPI Perftools_MapViewOfFileEx(HANDLE hFileMappingObject,
@@ -124,31 +156,39 @@ static LPVOID WINAPI Perftools_MapViewOfFileEx(HANDLE hFileMappingObject,
LPVOID lpBaseAddress) {
// For this function pair, you always deallocate the full block of
// data that you allocate, so NewHook/DeleteHook is the right API.
- LPVOID result = Windows_MapViewOfFileEx(hFileMappingObject, dwDesiredAccess,
- dwFileOffsetHigh, dwFileOffsetLow,
- dwNumberOfBytesToMap, lpBaseAddress);
+ LPVOID result = origstub_MapViewOfFileEx(hFileMappingObject, dwDesiredAccess,
+ dwFileOffsetHigh, dwFileOffsetLow,
+ dwNumberOfBytesToMap, lpBaseAddress);
MallocHook::InvokeNewHook(result, dwNumberOfBytesToMap);
return result;
}
static BOOL WINAPI Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress) {
MallocHook::InvokeDeleteHook(lpBaseAddress);
- return Windows_UnmapViewOfFile(lpBaseAddress);
+ return origstub_UnmapViewOfFile(lpBaseAddress);
}
// ---------------------------------------------------------------------
-#define PATCH_KERNEL32(name) do { \
- CHECK_EQ(sidestep::SIDESTEP_SUCCESS, \
- sidestep::PreamblePatcher::Patch( \
- "kernel32", #name, \
- &Perftools_##name, &Windows_##name)); \
-} while (0)
+// Calls GetProcAddress, but casts to the correct type.
+#define GET_PROC_ADDRESS(hmodule, name) \
+ ( (Type_##name)(::GetProcAddress(hmodule, #name)) )
-#define UNPATCH(name) do { \
+#define PATCH(name) do { \
+ CHECK_NE(Windows_##name, NULL); \
CHECK_EQ(sidestep::SIDESTEP_SUCCESS, \
- sidestep::PreamblePatcher::Unpatch( \
- (Type_##name)&name, &Perftools_##name, Windows_##name)); \
+ sidestep::PreamblePatcher::Patch( \
+ Windows_##name, &Perftools_##name, &origstub_##name)); \
+} while (0)
+
+// NOTE: casting from a function to a pointer is contra the C++
+// spec. It's not safe on IA64, but is on i386. We use
+// a C-style cast here to emphasize this is not legal C++.
+#define UNPATCH(name) do { \
+ CHECK_EQ(sidestep::SIDESTEP_SUCCESS, \
+ sidestep::PreamblePatcher::Unpatch( \
+ (void*)Windows_##name, (void*)&Perftools_##name, \
+ (void*)origstub_##name)); \
} while (0)
void PatchWindowsFunctions() {
@@ -158,14 +198,16 @@ void PatchWindowsFunctions() {
// TODO(csilvers): should we be patching GlobalAlloc/LocalAlloc instead,
// for pre-XP systems?
- PATCH_KERNEL32(HeapAlloc);
- PATCH_KERNEL32(HeapFree);
- PATCH_KERNEL32(VirtualAllocEx);
- PATCH_KERNEL32(VirtualFreeEx);
- PATCH_KERNEL32(MapViewOfFileEx);
- PATCH_KERNEL32(UnmapViewOfFile);
-
- // Now we need to override malloc, calloc, realloc, and free. Note
+ HMODULE hkernel32 = ::GetModuleHandle("kernel32");
+ CHECK_NE(hkernel32, NULL);
+ Windows_HeapAlloc = GET_PROC_ADDRESS(hkernel32, HeapAlloc);
+ Windows_HeapFree = GET_PROC_ADDRESS(hkernel32, HeapFree);
+ Windows_VirtualAllocEx = GET_PROC_ADDRESS(hkernel32, VirtualAllocEx);
+ Windows_VirtualFreeEx = GET_PROC_ADDRESS(hkernel32, VirtualFreeEx);
+ Windows_MapViewOfFileEx = GET_PROC_ADDRESS(hkernel32, MapViewOfFileEx);
+ Windows_UnmapViewOfFile = GET_PROC_ADDRESS(hkernel32, UnmapViewOfFile);
+
+ // Now we need to handle malloc, calloc, realloc, and free. Note
// that other memory-allocation routines (including new/delete) are
// overridden in tcmalloc.cc. These are overridden here because
// they're special for windows: they're the only libc memory
@@ -180,56 +222,44 @@ void PatchWindowsFunctions() {
GetCurrentProcessId());
if (hModuleSnap != INVALID_HANDLE_VALUE) {
MODULEENTRY32 me32;
- me32.dwSize = sizeof(me32); // needed by windows, apparently
+ me32.dwSize = sizeof(me32);
if (Module32First(hModuleSnap, &me32)) {
do {
- LPCSTR lib = me32.szModule;
- if (sidestep::SIDESTEP_SUCCESS ==
- sidestep::PreamblePatcher::Patch(
- lib, "malloc", &Perftools_malloc, &Windows_malloc)
- &&
- sidestep::SIDESTEP_SUCCESS ==
- sidestep::PreamblePatcher::Patch(
- lib, "calloc", &Perftools_calloc, &Windows_calloc)
- &&
- sidestep::SIDESTEP_SUCCESS ==
- sidestep::PreamblePatcher::Patch(
- lib, "realloc", &Perftools_realloc, &Windows_realloc)
- &&
- sidestep::SIDESTEP_SUCCESS ==
- sidestep::PreamblePatcher::Patch(
- lib, "free", &Perftools_free, &Windows_free)
- ) {
+ Windows_malloc = GET_PROC_ADDRESS(me32.hModule, malloc);
+ Windows_calloc = GET_PROC_ADDRESS(me32.hModule, calloc);
+ Windows_realloc = GET_PROC_ADDRESS(me32.hModule, realloc);
+ Windows_free = GET_PROC_ADDRESS(me32.hModule, free);
+ if (Windows_malloc != NULL && Windows_calloc != NULL &&
+ Windows_realloc != NULL && Windows_free != NULL)
break;
- } else {
- Windows_malloc = NULL; // reset to indicate failure
- Windows_calloc = NULL;
- Windows_realloc = NULL;
- Windows_free = NULL;
- }
} while (Module32Next(hModuleSnap, &me32));
}
CloseHandle(hModuleSnap);
}
- if (Windows_malloc == NULL && Windows_calloc == NULL &&
- Windows_realloc == NULL && Windows_free == NULL) {
- // probably means we're statically linked
+ if (Windows_malloc == NULL || Windows_calloc == NULL ||
+ Windows_realloc == NULL || Windows_free == NULL) {
+ // Probably means we're statically linked.
// NOTE: we need to cast the windows calls, because we're not quite
// sure of their type (in particular, some versions have __THROW, some
// don't). We don't care to that level of detail, hence the cast.
- CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
- sidestep::PreamblePatcher::Patch(
- (Type_malloc)&malloc, &Perftools_malloc, &Windows_malloc));
- CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
- sidestep::PreamblePatcher::Patch(
- (Type_calloc)&calloc, &Perftools_calloc, &Windows_calloc));
- CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
- sidestep::PreamblePatcher::Patch(
- (Type_realloc)&realloc, &Perftools_realloc, &Windows_realloc));
- CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
- sidestep::PreamblePatcher::Patch(
- (Type_free)&free, &Perftools_free, &Windows_free));
+ Windows_malloc = (Type_malloc)&malloc;
+ Windows_calloc = (Type_calloc)&calloc;
+ Windows_realloc = (Type_realloc)&realloc;
+ Windows_free = (Type_free)&free;
}
+
+ // Now that we've found all the functions, patch them
+ PATCH(HeapAlloc);
+ PATCH(HeapFree);
+ PATCH(VirtualAllocEx);
+ PATCH(VirtualFreeEx);
+ PATCH(MapViewOfFileEx);
+ PATCH(UnmapViewOfFile);
+
+ PATCH(malloc);
+ PATCH(calloc);
+ PATCH(realloc);
+ PATCH(free);
}
void UnpatchWindowsFunctions() {
diff --git a/src/windows/port.cc b/src/windows/port.cc
index 1e5b586..87aab9a 100644
--- a/src/windows/port.cc
+++ b/src/windows/port.cc
@@ -40,7 +40,6 @@
#include <assert.h>
#include <stdarg.h> // for va_list, va_start, va_end
#include <windows.h>
-#include <dbghelp.h> // Provided with Microsoft Debugging Tools for Windows
#include "port.h"
#include "base/logging.h"
#include "system-alloc.h"
@@ -99,7 +98,9 @@ bool CheckIfKernelSupportsTLS() {
// This makes the linker create the TLS directory if it's not already
// there (that is, even if __declspec(thead) is not used).
+#ifdef _MSC_VER
#pragma comment(linker, "/INCLUDE:__tls_used")
+#endif
// When destr_fn eventually runs, it's supposed to take as its
// argument the tls-value associated with key that pthread_key_create
@@ -119,6 +120,10 @@ static DestrFnClosure destr_fn_info; // initted to all NULL/0.
static int on_process_term(void) {
if (destr_fn_info.destr_fn) {
void *ptr = TlsGetValue(destr_fn_info.key_for_destr_fn_arg);
+ // This shouldn't be necessary, but in Release mode, Windows
+ // sometimes trashes the pointer in the TLS slot, so we need to
+ // remove the pointer from the TLS slot before the thread dies.
+ TlsSetValue(destr_fn_info.key_for_destr_fn_arg, NULL);
if (ptr) // pthread semantics say not to call if ptr is NULL
(*destr_fn_info.destr_fn)(ptr);
}
@@ -131,7 +136,9 @@ static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) {
}
}
-// This tells the linker to run these functions
+#ifdef _MSC_VER
+
+// This tells the linker to run these functions.
#pragma data_seg(push, old_seg)
#pragma data_seg(".CRT$XLB")
static void (NTAPI *p_thread_callback)(HINSTANCE h, DWORD dwReason, PVOID pv)
@@ -140,6 +147,20 @@ static void (NTAPI *p_thread_callback)(HINSTANCE h, DWORD dwReason, PVOID pv)
static int (*p_process_term)(void) = on_process_term;
#pragma data_seg(pop, old_seg)
+#else // #ifdef _MSC_VER [probably msys/mingw]
+
+// We have to try the DllMain solution here, because we can't use the
+// msvc-specific pragmas.
+BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) {
+ if (dwReason == DLL_THREAD_DETACH)
+ on_tls_callback(h, dwReason, pv);
+ else if (dwReason == DLL_PROCESS_DETACH)
+ on_process_term();
+ return TRUE;
+}
+
+#endif // #ifdef _MSC_VER
+
pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) {
// Semantics are: we create a new key, and then promise to call
// destr_fn with TlsGetValue(key) when the thread is destroyed
@@ -154,61 +175,6 @@ pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) {
return key;
}
-// This replaces testutil.cc
-struct FunctionAndId {
- void (*ptr_to_function)(int);
- int id;
-};
-
-// This helper function has the signature that pthread_create wants.
-DWORD WINAPI RunFunctionInThread(LPVOID ptr_to_ptr_to_fn) {
- (**static_cast<void (**)()>(ptr_to_ptr_to_fn))(); // runs fn
- return NULL;
-}
-
-DWORD WINAPI RunFunctionInThreadWithId(LPVOID ptr_to_fnid) {
- FunctionAndId* fn_and_id = static_cast<FunctionAndId*>(ptr_to_fnid);
- (*fn_and_id->ptr_to_function)(fn_and_id->id); // runs fn
- return NULL;
-}
-
-void RunManyInThread(void (*fn)(), int count) {
- DWORD dummy;
- HANDLE* hThread = new HANDLE[count];
- for (int i = 0; i < count; i++) {
- hThread[i] = CreateThread(NULL, 0, RunFunctionInThread, &fn, 0, &dummy);
- if (hThread[i] == NULL) ExitProcess(i);
- }
- WaitForMultipleObjects(count, hThread, TRUE, INFINITE);
- for (int i = 0; i < count; i++) {
- CloseHandle(hThread[i]);
- }
- delete[] hThread;
-}
-
-void RunInThread(void (*fn)()) {
- RunManyInThread(fn, 1);
-}
-
-void RunManyInThreadWithId(void (*fn)(int), int count, int stacksize) {
- DWORD dummy;
- HANDLE* hThread = new HANDLE[count];
- FunctionAndId* fn_and_ids = new FunctionAndId[count];
- for (int i = 0; i < count; i++) {
- fn_and_ids[i].ptr_to_function = fn;
- fn_and_ids[i].id = i;
- hThread[i] = CreateThread(NULL, stacksize, RunFunctionInThreadWithId,
- &fn_and_ids[i], 0, &dummy);
- if (hThread[i] == NULL) ExitProcess(i);
- }
- WaitForMultipleObjects(count, hThread, TRUE, INFINITE);
- for (int i = 0; i < count; i++) {
- CloseHandle(hThread[i]);
- }
- delete[] fn_and_ids;
- delete[] hThread;
-}
-
// -----------------------------------------------------------------------
// These functions replace system-alloc.cc
@@ -260,6 +226,10 @@ bool RegisterSystemAllocator(SysAllocator *allocator, int priority) {
return false; // we don't allow registration on windows, right now
}
+void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
+ // We don't dump stats on windows, right now
+}
+
// -----------------------------------------------------------------------
// These functions rework existing functions of the same name in the
@@ -319,6 +289,9 @@ static SpinLock get_stack_trace_lock(SpinLock::LINKER_INITIALIZED);
// value of context.Esp (on x86). The initial stack pointer can be
// crucial to a stackwalk in the FPO cases I mentioned.
+#if 0
+#include <dbghelp.h> // Provided with Microsoft Debugging Tools for Windows
+#endif
int GetStackTrace(void** result, int max_depth, int skip_count) {
int n = 0;
diff --git a/src/windows/port.h b/src/windows/port.h
index f5c6e53..8bbdeb7 100644
--- a/src/windows/port.h
+++ b/src/windows/port.h
@@ -40,7 +40,12 @@
#ifndef GOOGLE_BASE_WINDOWS_H__
#define GOOGLE_BASE_WINDOWS_H__
-#include "config.h"
+// You should never include this file directly, but always include it
+// from either config.h (MSVC) or mingw.h (MinGW/msys).
+#if !defined(GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H__) && \
+ !defined(GOOGLE_PERFTOOLS_WINDOWS_MINGW_H__)
+# error "port.h should only be included from config.h or mingw.h"
+#endif
#ifdef WIN32
@@ -56,7 +61,9 @@
// 4267: too many false positives for "conversion gives possible data loss"
// 4290: it's ok windows ignores the "throw" directive
// 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv()
+#ifdef _MSC_VER
#pragma warning(disable:4018 4244 4288 4267 4290 4996)
+#endif
// ----------------------------------- BASIC TYPES
@@ -64,6 +71,7 @@
#ifndef HAVE___INT64 /* we need to have all the __intX names */
# error Do not know how to set up type aliases. Edit port.h for your system.
#endif
+
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
@@ -72,15 +80,17 @@ typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
-#endif
+#endif // #ifndef HAVE_STDINT_H
-// I guess windows <types.h> doesn't include ssize_t by default?
+// I guess MSVC's <types.h> doesn't include ssize_t by default?
+#ifdef _MSC_VER
typedef intptr_t ssize_t;
+#endif
// ----------------------------------- THREADS
typedef DWORD pthread_t;
typedef DWORD pthread_key_t;
-typedef volatile LONG pthread_once_t;
+typedef LONG pthread_once_t;
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
#define pthread_self GetCurrentThreadId
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
@@ -109,6 +119,7 @@ extern pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); // in port.cc
// linker initialize a bool to 0, and check that before accessing the mutex.
// TODO(csilvers): figure out a faster way.
// This replaces spinlock.{h,cc}, and all the stuff it depends on (atomicops)
+#ifdef __cplusplus
class SpinLock {
public:
SpinLock() : initialize_token_(PTHREAD_ONCE_INIT) {}
@@ -149,6 +160,7 @@ class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts
inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { l->Lock(); }
inline ~SpinLockHolder() { lock_->Unlock(); }
};
+#endif
// This replaces testutil.{h,cc}
extern PERFTOOLS_DLL_DECL void RunInThread(void (*fn)());
@@ -192,8 +204,12 @@ extern PERFTOOLS_DLL_DECL int safe_vsnprintf(char *str, size_t size,
#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
// ----------------------------------- FILE IO
+#ifndef PATH_MAX
#define PATH_MAX 1024
+#endif
+#ifndef __MINGW32__
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
+#endif
#define getcwd _getcwd
#define access _access
#define open _open
@@ -203,6 +219,7 @@ enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
#define close _close
#define popen _popen
#define pclose _pclose
+#define mkdir(dirname, mode) _mkdir(dirname)
// ----------------------------------- SYSTEM/PROCESS
typedef int pid_t;
@@ -214,6 +231,7 @@ extern PERFTOOLS_DLL_DECL int getpagesize(); // in port.cc
#define srandom srand
#define random rand
+#define sleep(t) Sleep(t * 1000)
#define __THROW throw()
@@ -239,6 +257,15 @@ extern PERFTOOLS_DLL_DECL int getpagesize(); // in port.cc
extern PERFTOOLS_DLL_DECL void PatchWindowsFunctions();
extern PERFTOOLS_DLL_DECL void UnpatchWindowsFunctions();
+// ----------------------------------- BUILD-SPECIFIC
+
+// windows/port.h defines compatibility APIs for several .h files, which
+// we therefore shouldn't be #including directly. This hack keeps us from
+// doing so. TODO(csilvers): do something more principled.
+#define BASE_SPINLOCK_H__ 1
+#define GOOGLE_MAYBE_THREADS_H__ 1
+
+
#endif /* WIN32 */
#endif /* GOOGLE_BASE_WINDOWS_H__ */
diff --git a/src/windows/preamble_patcher.h b/src/windows/preamble_patcher.h
index 9d5040e..cc69d72 100644
--- a/src/windows/preamble_patcher.h
+++ b/src/windows/preamble_patcher.h
@@ -72,7 +72,7 @@ enum SideStepError {
//
// NOTE: This patching mechanism should currently only be used for
// non-production code, e.g. unit tests, because it is not threadsafe.
-// See the TODO in preamble_patcher_with_stub.cpp for instructions on what
+// See the TODO in preamble_patcher_with_stub.cc for instructions on what
// we need to do before using it in production code; it's fairly simple
// but unnecessary for now since we only intend to use it in unit tests.
//
@@ -122,7 +122,7 @@ enum SideStepError {
// the compiler can reason do not have side effects, the compiler may
// reuse the result of calling the function with a given parameter, which
// may mean if you patch the function in between your patch will never get
-// invoked. See preamble_patcher_unittest.cpp for an example.
+// invoked. See preamble_patcher_test.cc for an example.
class PreamblePatcher {
public:
@@ -142,9 +142,12 @@ class PreamblePatcher {
static SideStepError Patch(T target_function,
T replacement_function,
T* original_function_stub) {
- return RawPatch(reinterpret_cast<void*>(target_function),
- reinterpret_cast<void*>(replacement_function),
- reinterpret_cast<void**>(original_function_stub));
+ // NOTE: casting from a function to a pointer is contra the C++
+ // spec. It's not safe on IA64, but is on i386. We use
+ // a C-style cast here to emphasize this is not legal C++.
+ return RawPatch((void*)(target_function),
+ (void*)(replacement_function),
+ (void**)(original_function_stub));
}
// Patches a named function imported from the named module using
@@ -191,8 +194,11 @@ class PreamblePatcher {
if (!existing_function) {
return SIDESTEP_NO_SUCH_FUNCTION;
}
- return RawPatch(existing_function, replacement_function,
- reinterpret_cast<void**>(original_function_stub));
+ // NOTE: casting from a function to a pointer is contra the C++
+ // spec. It's not safe on IA64, but is on i386. We use
+ // a C-style cast here to emphasize this is not legal C++.
+ return RawPatch((void*)existing_function, (void*)replacement_function,
+ (void**)(original_function_stub));
}
// Patches a function by overwriting its first few bytes with
diff --git a/src/windows/preamble_patcher_with_stub.cc b/src/windows/preamble_patcher_with_stub.cc
index 1ad4326..d1ca251 100644
--- a/src/windows/preamble_patcher_with_stub.cc
+++ b/src/windows/preamble_patcher_with_stub.cc
@@ -43,14 +43,14 @@
namespace sidestep {
-SideStepError PreamblePatcher::RawPatchWithStub(
- void* target_function,
- void *replacement_function,
- unsigned char* preamble_stub,
- unsigned long stub_size,
+SideStepError PreamblePatcher::RawPatchWithStub(
+ void* target_function,
+ void *replacement_function,
+ unsigned char* preamble_stub,
+ unsigned long stub_size,
unsigned long* bytes_needed) {
- if ((NULL == target_function) ||
- (NULL == replacement_function) ||
+ if ((NULL == target_function) ||
+ (NULL == replacement_function) ||
(NULL == preamble_stub)) {
ASSERT(false, "Invalid parameters - either pTargetFunction or "
"pReplacementFunction or pPreambleStub were NULL.");
@@ -104,7 +104,7 @@ SideStepError PreamblePatcher::RawPatchWithStub(
MiniDisassembler disassembler;
unsigned int preamble_bytes = 0;
while (preamble_bytes < 5) {
- InstructionType instruction_type =
+ InstructionType instruction_type =
disassembler.Disassemble(target + preamble_bytes, preamble_bytes);
if (IT_JUMP == instruction_type) {
ASSERT(false, "Unable to patch because there is a jump instruction "
@@ -139,12 +139,16 @@ SideStepError PreamblePatcher::RawPatchWithStub(
// Now, make a jmp instruction to the rest of the target function (minus the
// preamble bytes we moved into the stub) and copy it into our preamble-stub.
// find address to jump to, relative to next address after jmp instruction
+#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4244)
+#endif
int relative_offset_to_target_rest
- = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) -
+ = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) -
(preamble_stub + preamble_bytes + 5));
+#ifdef _MSC_VER
#pragma warning(pop)
+#endif
// jmp (Jump near, relative, displacement relative to next instruction)
preamble_stub[preamble_bytes] = ASM_JMP32REL;
// copy the address
@@ -161,12 +165,16 @@ SideStepError PreamblePatcher::RawPatchWithStub(
target[0] = ASM_JMP32REL;
// Find offset from instruction after jmp, to the replacement function.
+#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4244)
+#endif
int offset_to_replacement_function =
reinterpret_cast<unsigned char*>(replacement_function) -
reinterpret_cast<unsigned char*>(target) - 5;
+#ifdef _MSC_VER
#pragma warning(pop)
+#endif
// complete the jmp instruction
memcpy(reinterpret_cast<void*>(target + 1),
reinterpret_cast<void*>(&offset_to_replacement_function), 4);
diff --git a/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj b/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
index d1356bd..212c860 100755
--- a/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
+++ b/vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj
@@ -37,7 +37,7 @@
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/libtcmalloc_minimal.pdb"
SubSystem="2"
- ImportLibrary="$(OutDir)/libtcmalloc_minimal.lib"
+ ImportLibrary="$(OutDir)/libtcmalloc_minimal-debug.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>