* Make kHideMask use all 64 bits (ppluzhnikov)

* Add new IsDebuggerAttached method (ppluzhnikov)
	* Document some tricks for maybe getting perftools to work on OS X
	* Redo file-top pprof commands (csilvers)
	* Clean up pprof input-file handling (csilvers)
	* 16-byte align debug allocs (jyasskin)
	* Ignore JVM memory leakage in the heap checker (davidyu, kkurimoto)
	* Better internal-function list for contentionz (ruemmler)
	* mmap2 on i386 takes an off_t, not an off64_t (csilvers)
	* Fix up fake-VDSO handling for unittest (ppluzhnikov)
	* Don't try to check valgrind for windows (csilvers)


git-svn-id: http://gperftools.googlecode.com/svn/trunk@101 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
This commit is contained in:
csilvers 2011-01-19 21:37:15 +00:00
parent a0a2ff3b49
commit 3d77cbf7d5
13 changed files with 188 additions and 88 deletions

22
README
View File

@ -196,6 +196,28 @@ that error. To fix it, just comment out (or delete) the line
in your config.h file before building. in your config.h file before building.
OS X ISSUES
-----------
You may need to set the environment variable DYLD_FORCE_FLAT_NAMESPACE
to use perftools with OS X. Because of how OS X does symbol binding,
libc routines will use libc malloc even when the binary is linked with
-ltcmalloc. This is not usually a problem, but becomes one if the
application is responsible for freeing that memory: the application
will use tcmalloc's free() to try to free memory allocated with libc's
malloc(), which will cause no end of confusion.
One (or both) of these workaround may fix the problem:
DYLD_FORCE_FLAT_NAMESPACE=1 myapp
DYLD_INSERT_LIBRARIES=path/to/libtcmalloc.dylib myapp
The best solution may depend on the version of OS X being used.
Neither solution is likely to work if you dlopen() libraries from
within your application. If you have any experience with this, we'd
appreciate you sharing it at
http://groups.google.com/group/google-perftools
64-BIT ISSUES 64-BIT ISSUES
------------- -------------

View File

@ -127,13 +127,23 @@ static int GetRunningOnValgrind(void) {
#ifdef RUNNING_ON_VALGRIND #ifdef RUNNING_ON_VALGRIND
if (RUNNING_ON_VALGRIND) return 1; if (RUNNING_ON_VALGRIND) return 1;
#endif #endif
// TODO(csilvers): use GetenvBeforeMain() instead? Will need to #ifdef _MSC_VER
// change it to be extern "C". /* Visual Studio can complain about getenv, so use a windows equivalent. */
char value[100] = "1"; /* something that is not "0" */
int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND",
value, sizeof(value));
/* value will remain "1" if the called failed for some reason. */
return (res > 0 && strcmp(value, "0") != 0);
#else
/* TODO(csilvers): use GetenvBeforeMain() instead? Will need to
* change it to be extern "C".
*/
char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
if (running_on_valgrind_str) { if (running_on_valgrind_str) {
return strcmp(running_on_valgrind_str, "0") != 0; return strcmp(running_on_valgrind_str, "0") != 0;
} }
return 0; return 0;
#endif
} }
/* See the comments in dynamic_annotations.h */ /* See the comments in dynamic_annotations.h */

View File

@ -2593,7 +2593,7 @@ struct kernel_statfs {
LSS_INLINE _syscall6(void*, mmap2, void*, s, LSS_INLINE _syscall6(void*, mmap2, void*, s,
size_t, l, int, p, size_t, l, int, p,
int, f, int, d, int, f, int, d,
__off64_t, o) off_t, o)
#endif #endif
LSS_INLINE _syscall3(int, _sigaction, int, s, LSS_INLINE _syscall3(int, _sigaction, int, s,
const struct kernel_old_sigaction*, a, const struct kernel_old_sigaction*, a,

View File

@ -207,6 +207,10 @@ void VDSOSupport::ElfMemImage::Init(const void *base) {
if (!base) { if (!base) {
return; return;
} }
const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base);
// Fake VDSO has low bit set.
const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1);
const char *const base_as_char = reinterpret_cast<const char *>(base); const char *const base_as_char = reinterpret_cast<const char *>(base);
if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 || if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) { base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
@ -266,17 +270,6 @@ void VDSOSupport::ElfMemImage::Init(const void *base) {
ElfW(Dyn) *dynamic_entry = ElfW(Dyn) *dynamic_entry =
reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr + reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
relocation); relocation);
bool fake_vdso = false; // Assume we are dealing with the real VDSO.
for (ElfW(Dyn) *de = dynamic_entry; de->d_tag != DT_NULL; ++de) {
ElfW(Sxword) tag = de->d_tag;
if (tag == DT_PLTGOT || tag == DT_RELA || tag == DT_JMPREL ||
tag == DT_NEEDED || tag == DT_RPATH || tag == DT_VERNEED ||
tag == DT_INIT || tag == DT_FINI) {
/* Real vdso can not reasonably have any of the above entries. */
fake_vdso = true;
break;
}
}
for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
ElfW(Xword) value = dynamic_entry->d_un.d_val; ElfW(Xword) value = dynamic_entry->d_un.d_val;
if (fake_vdso) { if (fake_vdso) {

View File

@ -147,6 +147,10 @@ class VDSOSupport {
// kInvalidBase => value hasn't been determined yet. // kInvalidBase => value hasn't been determined yet.
// 0 => there is no VDSO. // 0 => there is no VDSO.
// else => vma of VDSO Elf{32,64}_Ehdr. // else => vma of VDSO Elf{32,64}_Ehdr.
//
// When testing with mock VDSO, low bit is set.
// The low bit is always available because vdso_base_ is
// page-aligned.
static const void *vdso_base_; static const void *vdso_base_;
// NOLINT on 'long' because these routines mimic kernel api. // NOLINT on 'long' because these routines mimic kernel api.

View File

@ -273,12 +273,13 @@ class MallocBlock {
// NOTE: tcmalloc.cc depends on the value of kMagicDeletedByte // NOTE: tcmalloc.cc depends on the value of kMagicDeletedByte
// to work around a bug in the pthread library. // to work around a bug in the pthread library.
static const int kMagicDeletedByte = 0xCD; static const int kMagicDeletedByte = 0xCD;
// An int (type of alloc_type_ below) in a deallocated storage // A size_t (type of alloc_type_ below) in a deallocated storage
// filled with kMagicDeletedByte. // filled with kMagicDeletedByte.
static const int kMagicDeletedInt = 0xCDCDCDCD | ((0xCDCDCDCD << 16) << 16); static const size_t kMagicDeletedSizeT =
// Initializer works for 32 and 64 bit ints; 0xCDCDCDCD | (((size_t)0xCDCDCDCD << 16) << 16);
// Initializer works for 32 and 64 bit size_ts;
// "<< 16 << 16" is to fool gcc from issuing a warning // "<< 16 << 16" is to fool gcc from issuing a warning
// when ints are 32 bits. // when size_ts are 32 bits.
// NOTE: on Linux, you can enable malloc debugging support in libc by // NOTE: on Linux, you can enable malloc debugging support in libc by
// setting the environment variable MALLOC_CHECK_ to 1 before you // setting the environment variable MALLOC_CHECK_ to 1 before you
@ -297,12 +298,17 @@ class MallocBlock {
private: // data layout private: // data layout
// The four fields size1_,offset_,magic1_,alloc_type_ // The four fields size1_,offset_,magic1_,alloc_type_
// should together occupy a multiple of 8 bytes. // should together occupy a multiple of 16 bytes. (At the
// moment, sizeof(size_t) == 4 or 8 depending on piii vs
// k8, and 4 of those sum to 16 or 32 bytes).
// This, combined with BASE_MALLOC's alignment guarantees,
// ensures that SSE types can be stored into the returned
// block, at &size2_.
size_t size1_; size_t size1_;
size_t offset_; // normally 0 unless memaligned memory size_t offset_; // normally 0 unless memaligned memory
// see comments in memalign() and FromRawPointer(). // see comments in memalign() and FromRawPointer().
int magic1_; size_t magic1_;
int alloc_type_; size_t alloc_type_;
// here comes the actual data (variable length) // here comes the actual data (variable length)
// ... // ...
// then come the size2_ and magic2_, or a full page of mprotect-ed memory // then come the size2_ and magic2_, or a full page of mprotect-ed memory
@ -435,7 +441,7 @@ class MallocBlock {
"has been already deallocated (it was allocated with %s)", "has been already deallocated (it was allocated with %s)",
data_addr(), AllocName(map_type & ~kDeallocatedTypeBit)); data_addr(), AllocName(map_type & ~kDeallocatedTypeBit));
} }
if (alloc_type_ == kMagicDeletedInt) { if (alloc_type_ == kMagicDeletedSizeT) {
RAW_LOG(FATAL, "memory stomping bug: a word before object at %p " RAW_LOG(FATAL, "memory stomping bug: a word before object at %p "
"has been corrupted; or else the object has been already " "has been corrupted; or else the object has been already "
"deallocated and our memory map has been corrupted", "deallocated and our memory map has been corrupted",
@ -701,8 +707,8 @@ class MallocBlock {
// Find the header just before client's memory. // Find the header just before client's memory.
MallocBlock *mb = reinterpret_cast<MallocBlock *>( MallocBlock *mb = reinterpret_cast<MallocBlock *>(
reinterpret_cast<char *>(p) - data_offset); reinterpret_cast<char *>(p) - data_offset);
// If mb->alloc_type_ is kMagicDeletedInt, we're not an ok pointer. // If mb->alloc_type_ is kMagicDeletedSizeT, we're not an ok pointer.
if (mb->alloc_type_ == kMagicDeletedInt) { if (mb->alloc_type_ == kMagicDeletedSizeT) {
RAW_LOG(FATAL, "memory allocation bug: object at %p has been already" RAW_LOG(FATAL, "memory allocation bug: object at %p has been already"
" deallocated; or else a word before the object has been" " deallocated; or else a word before the object has been"
" corrupted (memory stomping bug)", p); " corrupted (memory stomping bug)", p);

View File

@ -106,6 +106,32 @@ using std::max;
using std::less; using std::less;
using std::char_traits; using std::char_traits;
// If current process is being ptrace()d, 'TracerPid' in /proc/self/status
// will be non-zero.
static bool IsDebuggerAttached(void) { // only works under linux, probably
// Since we could be called from FailureSignalHandler, avoid stdio
// which could have been corrupted.
// Limit stack usage as well. Currently, TracerPid is at max offset 76
// (depending on length of argv[0]) into /proc/self/status.
char buf[100];
int fd = open("/proc/self/status", O_RDONLY);
if (fd == -1) {
return false; // Can't tell for sure.
}
const int len = read(fd, buf, sizeof(buf));
bool rc = false;
if (len > 0) {
const char *const kTracerPid = "TracerPid:\t";
buf[len - 1] = '\0';
const char *p = strstr(buf, kTracerPid);
if (p != NULL) {
rc = (strncmp(p + strlen(kTracerPid), "0\n", 2) != 0);
}
}
close(fd);
return rc;
}
// This is the default if you don't link in -lprofiler // This is the default if you don't link in -lprofiler
extern "C" { extern "C" {
ATTRIBUTE_WEAK PERFTOOLS_DLL_DECL bool ProfilingIsEnabledForAllThreads(); ATTRIBUTE_WEAK PERFTOOLS_DLL_DECL bool ProfilingIsEnabledForAllThreads();
@ -798,7 +824,7 @@ void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library,
// pthread_setspecific (which can be the only pointer to a heap object). // pthread_setspecific (which can be the only pointer to a heap object).
IsLibraryNamed(library, "/libdl") || IsLibraryNamed(library, "/libdl") ||
// library loaders leak some "system" heap that we don't care about // library loaders leak some "system" heap that we don't care about
IsLibraryNamed(library, "/libcrypto") IsLibraryNamed(library, "/libcrypto") ||
// Sometimes libcrypto of OpenSSH is compiled with -fomit-frame-pointer // Sometimes libcrypto of OpenSSH is compiled with -fomit-frame-pointer
// (any library can be, of course, but this one often is because speed // (any library can be, of course, but this one often is because speed
// is so important for making crypto usable). We ignore all its // is so important for making crypto usable). We ignore all its
@ -806,6 +832,10 @@ void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library,
// to ignore allocations done in files/symbols that match // to ignore allocations done in files/symbols that match
// "default_malloc_ex|default_realloc_ex" // "default_malloc_ex|default_realloc_ex"
// but that doesn't work when the end-result binary is stripped. // but that doesn't work when the end-result binary is stripped.
IsLibraryNamed(library, "/libjvm") ||
// JVM has a lot of leaks we don't care about.
IsLibraryNamed(library, "/libzip")
// The JVM leaks java.util.zip.Inflater after loading classes.
) { ) {
depth = 1; // only disable allocation calls directly from the library code depth = 1; // only disable allocation calls directly from the library code
} else if (IsLibraryNamed(library, "/ld") } else if (IsLibraryNamed(library, "/ld")
@ -1637,6 +1667,13 @@ bool HeapLeakChecker::DoNoLeaks(ShouldSymbolize should_symbolize) {
return true; return true;
} }
// Update global_region_caller_ranges. They may need to change since
// e.g. initialization because shared libraries might have been loaded or
// unloaded.
Allocator::DeleteAndNullIfNot(&global_region_caller_ranges);
ProcMapsResult pm_result = UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS);
RAW_CHECK(pm_result == PROC_MAPS_USED, "");
// Keep track of number of internally allocated objects so we // Keep track of number of internally allocated objects so we
// can detect leaks in the heap-leak-checket itself // can detect leaks in the heap-leak-checket itself
const int initial_allocs = Allocator::alloc_count(); const int initial_allocs = Allocator::alloc_count();
@ -1867,25 +1904,11 @@ static bool internal_init_start_has_run = false;
} }
// Changing this to false can be useful when debugging heap-checker itself: // Changing this to false can be useful when debugging heap-checker itself:
if (!FLAGS_heap_check_run_under_gdb) { if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) {
// See if heap checker should turn itself off because we are RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off");
// running under gdb (to avoid conflicts over ptrace-ing rights): SpinLockHolder l(&heap_checker_lock);
char name_buf[15+15]; TurnItselfOffLocked();
snprintf(name_buf, sizeof(name_buf), return;
"/proc/%d/cmdline", static_cast<int>(getppid()));
char cmdline[1024*8]; // /proc/*/cmdline is at most 4Kb anyway usually
int size = GetCommandLineFrom(name_buf, cmdline, sizeof(cmdline)-1);
cmdline[size] = '\0';
// look for "gdb" in the executable's name:
const char* last = strrchr(cmdline, '/');
if (last) last += 1;
else last = cmdline;
if (strncmp(last, "gdb", 3) == 0) {
RAW_LOG(WARNING, "We seem to be running under gdb; will turn itself off");
SpinLockHolder l(&heap_checker_lock);
TurnItselfOffLocked();
return;
}
} }
{ SpinLockHolder l(&heap_checker_lock); { SpinLockHolder l(&heap_checker_lock);

View File

@ -412,7 +412,8 @@ static inline void* do_mmap64(void *start, size_t length,
} }
result = (void *)syscall(SYS_mmap2, result = (void *)syscall(SYS_mmap2,
start, length, prot, flags, fd, offset / pagesize); start, length, prot, flags, fd,
(off_t) (offset / pagesize));
if (result != MAP_FAILED || errno != ENOSYS) goto out; if (result != MAP_FAILED || errno != ENOSYS) goto out;
// We don't have mmap2() after all - don't bother trying it in future // We don't have mmap2() after all - don't bother trying it in future

103
src/pprof
View File

@ -2437,7 +2437,16 @@ sub RemoveUninterestingFrames {
# old code out of the system. # old code out of the system.
$skip_regexp = "TCMalloc|^tcmalloc::"; $skip_regexp = "TCMalloc|^tcmalloc::";
} elsif ($main::profile_type eq 'contention') { } elsif ($main::profile_type eq 'contention') {
foreach my $vname ('Mutex::Unlock', 'Mutex::UnlockSlow') { foreach my $vname ('base::RecordLockProfileData',
'base::SubmitMutexProfileData',
'base::SubmitSpinLockProfileData',
'Mutex::Unlock',
'Mutex::UnlockSlow',
'Mutex::ReaderUnlock',
'MutexLock::~MutexLock',
'SpinLock::Unlock',
'SpinLock::SlowUnlock',
'SpinLockHolder::~SpinLockHolder') {
$skip{$vname} = 1; $skip{$vname} = 1;
} }
} elsif ($main::profile_type eq 'cpu') { } elsif ($main::profile_type eq 'cpu') {
@ -3176,24 +3185,47 @@ BEGIN {
} }
} }
# Return the next line from the profile file, assuming it's a text # Reads the top, 'header' section of a profile, and returns the last
# line (which in this case means, doesn't start with a NUL byte). If # line of the header, commonly called a 'header line'. The header
# it's not a text line, return "". At EOF, return undef, like perl does. # section of a profile consists of zero or more 'command' lines that
# Input file should be in binmode. # are instructions to pprof, which pprof executes when reading the
sub ReadProfileLine { # header. All 'command' lines start with a %. After the command
# lines is the 'header line', which is a profile-specific line that
# indicates what type of profile it is, and perhaps other global
# information about the profile. For instance, here's a header line
# for a heap profile:
# heap profile: 53: 38236 [ 5525: 1284029] @ heapprofile
# For historical reasons, the CPU profile does not contain a text-
# readable header line. If the profile looks like a CPU profile,
# this function returns "". If no header line could be found, this
# function returns undef.
#
# The following commands are recognized:
# %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:'
#
# The input file should be in binmode.
sub ReadProfileHeader {
local *PROFILE = shift; local *PROFILE = shift;
my $firstchar = ""; my $firstchar = "";
my $line = ""; my $line = "";
read(PROFILE, $firstchar, 1); read(PROFILE, $firstchar, 1);
seek(PROFILE, -1, 1); # unread the firstchar seek(PROFILE, -1, 1); # unread the firstchar
if ($firstchar eq "\0") { if ($firstchar !~ /[[:print:]]/) { # is not a text character
return ""; return "";
} }
$line = <PROFILE>; while (defined($line = <PROFILE>)) {
if (defined($line)) {
$line =~ s/\r//g; # turn windows-looking lines into unix-looking lines $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
if ($line =~ /^%warn\s+(.*)/) { # 'warn' command
# Note this matches both '%warn blah\n' and '%warn\n'.
print STDERR "WARNING: $1\n"; # print the rest of the line
} elsif ($line =~ /^%/) {
print STDERR "Ignoring unknown command from profile header: $line";
} else {
# End of commands, must be the header line.
return $line;
}
} }
return $line; return undef; # got to EOF without seeing a header line
} }
sub IsSymbolizedProfileFile { sub IsSymbolizedProfileFile {
@ -3204,7 +3236,7 @@ sub IsSymbolizedProfileFile {
# Check if the file contains a symbol-section marker. # Check if the file contains a symbol-section marker.
open(TFILE, "<$file_name"); open(TFILE, "<$file_name");
binmode TFILE; binmode TFILE;
my $firstline = ReadProfileLine(*TFILE); my $firstline = ReadProfileHeader(*TFILE);
close(TFILE); close(TFILE);
if (!$firstline) { if (!$firstline) {
return 0; return 0;
@ -3224,14 +3256,7 @@ sub IsSymbolizedProfileFile {
sub ReadProfile { sub ReadProfile {
my $prog = shift; my $prog = shift;
my $fname = shift; my $fname = shift;
my $result; # return value
if (IsSymbolizedProfileFile($fname) && !$main::use_symbolized_profile) {
# we have both a binary and symbolized profiles, abort
usage("Symbolized profile '$fname' cannot be used with a binary arg. " .
"Try again without passing '$prog'.");
}
$main::profile_type = '';
$CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
my $contention_marker = $&; my $contention_marker = $&;
@ -3248,40 +3273,45 @@ sub ReadProfile {
# whole firstline, since it may be gigabytes(!) of data. # whole firstline, since it may be gigabytes(!) of data.
open(PROFILE, "<$fname") || error("$fname: $!\n"); open(PROFILE, "<$fname") || error("$fname: $!\n");
binmode PROFILE; # New perls do UTF-8 processing binmode PROFILE; # New perls do UTF-8 processing
my $header = ReadProfileLine(*PROFILE); my $header = ReadProfileHeader(*PROFILE);
if (!defined($header)) { # means "at EOF" if (!defined($header)) { # means "at EOF"
error("Profile is empty.\n"); error("Profile is empty.\n");
} }
my $symbols; my $symbols;
if ($header =~ m/^--- *$symbol_marker/o) { if ($header =~ m/^--- *$symbol_marker/o) {
# Verify that the user asked for a symbolized profile
if (!$main::use_symbolized_profile) {
# we have both a binary and symbolized profiles, abort
error("FATAL ERROR: Symbolized profile\n $fname\ncannot be used with " .
"a binary arg. Try again without passing\n $prog\n");
}
# Read the symbol section of the symbolized profile file. # Read the symbol section of the symbolized profile file.
$symbols = ReadSymbols(*PROFILE{IO}); $symbols = ReadSymbols(*PROFILE{IO});
# Read the next line to get the header for the remaining profile. # Read the next line to get the header for the remaining profile.
$header = ReadProfileLine(*PROFILE) || ""; $header = ReadProfileHeader(*PROFILE) || "";
} }
my $result; $main::profile_type = '';
if ($header =~ m/^heap profile:.*$growth_marker/o) { if ($header =~ m/^heap profile:.*$growth_marker/o) {
$main::profile_type = 'growth'; $main::profile_type = 'growth';
$result = ReadHeapProfile($prog, $fname, $header); $result = ReadHeapProfile($prog, *PROFILE, $header);
} elsif ($header =~ m/^heap profile:/) { } elsif ($header =~ m/^heap profile:/) {
$main::profile_type = 'heap'; $main::profile_type = 'heap';
$result = ReadHeapProfile($prog, $fname, $header); $result = ReadHeapProfile($prog, *PROFILE, $header);
} elsif ($header =~ m/^--- *$contention_marker/o) { } elsif ($header =~ m/^--- *$contention_marker/o) {
$main::profile_type = 'contention'; $main::profile_type = 'contention';
$result = ReadSynchProfile($prog, $fname); $result = ReadSynchProfile($prog, *PROFILE);
} elsif ($header =~ m/^--- *Stacks:/) { } elsif ($header =~ m/^--- *Stacks:/) {
print STDERR print STDERR
"Old format contention profile: mistakenly reports " . "Old format contention profile: mistakenly reports " .
"condition variable signals as lock contentions.\n"; "condition variable signals as lock contentions.\n";
$main::profile_type = 'contention'; $main::profile_type = 'contention';
$result = ReadSynchProfile($prog, $fname); $result = ReadSynchProfile($prog, *PROFILE);
} elsif ($header =~ m/^--- *$profile_marker/) { } elsif ($header =~ m/^--- *$profile_marker/) {
# the binary cpu profile data starts immediately after this line # the binary cpu profile data starts immediately after this line
$main::profile_type = 'cpu'; $main::profile_type = 'cpu';
$result = ReadCPUProfile($prog, $fname); $result = ReadCPUProfile($prog, $fname, *PROFILE);
} else { } else {
if (defined($symbols)) { if (defined($symbols)) {
# a symbolized profile contains a format we don't recognize, bail out # a symbolized profile contains a format we don't recognize, bail out
@ -3289,9 +3319,11 @@ sub ReadProfile {
} }
# no ascii header present -- must be a CPU profile # no ascii header present -- must be a CPU profile
$main::profile_type = 'cpu'; $main::profile_type = 'cpu';
$result = ReadCPUProfile($prog, $fname); $result = ReadCPUProfile($prog, $fname, *PROFILE);
} }
close(PROFILE);
# if we got symbols along with the profile, return those as well # if we got symbols along with the profile, return those as well
if (defined($symbols)) { if (defined($symbols)) {
$result->{symbols} = $symbols; $result->{symbols} = $symbols;
@ -3330,7 +3362,8 @@ sub FixCallerAddresses {
# CPU profile reader # CPU profile reader
sub ReadCPUProfile { sub ReadCPUProfile {
my $prog = shift; my $prog = shift;
my $fname = shift; my $fname = shift; # just used for logging
local *PROFILE = shift;
my $version; my $version;
my $period; my $period;
my $i; my $i;
@ -3397,7 +3430,6 @@ sub ReadCPUProfile {
my $map = ''; my $map = '';
seek(PROFILE, $i * 4, 0); seek(PROFILE, $i * 4, 0);
read(PROFILE, $map, (stat PROFILE)[7]); read(PROFILE, $map, (stat PROFILE)[7]);
close(PROFILE);
my $r = {}; my $r = {};
$r->{version} = $version; $r->{version} = $version;
@ -3411,7 +3443,7 @@ sub ReadCPUProfile {
sub ReadHeapProfile { sub ReadHeapProfile {
my $prog = shift; my $prog = shift;
my $fname = shift; local *PROFILE = shift;
my $header = shift; my $header = shift;
my $index = 1; my $index = 1;
@ -3596,7 +3628,9 @@ sub ReadHeapProfile {
} }
sub ReadSynchProfile { sub ReadSynchProfile {
my ($prog, $fname, $header) = @_; my $prog = shift;
local *PROFILE = shift;
my $header = shift;
my $map = ''; my $map = '';
my $profile = {}; my $profile = {};
@ -3671,7 +3705,6 @@ sub ReadSynchProfile {
$map .= $line; $map .= $line;
} }
} }
close PROFILE;
if (!$seen_clockrate) { if (!$seen_clockrate) {
printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n", printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n",

View File

@ -630,11 +630,13 @@ class TCMallocImplementation : public MallocExtension {
virtual void GetHeapSample(MallocExtensionWriter* writer) { virtual void GetHeapSample(MallocExtensionWriter* writer) {
if (FLAGS_tcmalloc_sample_parameter == 0) { if (FLAGS_tcmalloc_sample_parameter == 0) {
const char* const kWarningMsg = const char* const kWarningMsg =
"#\n# WARNING: This heap profile does not have any data in it,\n" "%warn\n"
"# because the application was run with heap sampling turned off.\n" "%warn This heap profile does not have any data in it, because\n"
"# To get useful data from from GetHeapSample(), you must first\n" "%warn the application was run with heap sampling turned off.\n"
"# set the environment variable TCMALLOC_SAMPLE_PARAMETER to a\n" "%warn To get useful data from GetHeapSample(), you must\n"
"# positive sampling period, such as 524288.\n#\n"; "%warn set the environment variable TCMALLOC_SAMPLE_PARAMETER to\n"
"%warn a positive sampling period, such as 524288.\n"
"%warn\n";
writer->append(kWarningMsg, strlen(kWarningMsg)); writer->append(kWarningMsg, strlen(kWarningMsg));
} }
MallocExtension::GetHeapSample(writer); MallocExtension::GetHeapSample(writer);

View File

@ -291,7 +291,8 @@ static void Use(T** foo) {
// Arbitrary value, but not such that xor'ing with it is likely // Arbitrary value, but not such that xor'ing with it is likely
// to map one valid pointer to another valid pointer: // to map one valid pointer to another valid pointer:
static const uintptr_t kHideMask = 0xF03A5F7B; static const uintptr_t kHideMask =
static_cast<uintptr_t>(0xF03A5F7BF03A5F7BLL);
// Helpers to hide a pointer from live data traversal. // Helpers to hide a pointer from live data traversal.
// We just xor the pointer so that (with high probability) // We just xor the pointer so that (with high probability)

View File

@ -721,11 +721,9 @@ static void TestAlignmentForSize(int size) {
CHECK((p % sizeof(double)) == 0); CHECK((p % sizeof(double)) == 0);
// Must have 16-byte alignment for large enough objects // Must have 16-byte alignment for large enough objects
#ifndef DEBUGALLOCATION // debug allocation doesn't need to align like this
if (size >= 16) { if (size >= 16) {
CHECK((p % 16) == 0); CHECK((p % 16) == 0);
} }
#endif
} }
for (int i = 0; i < kNum; i++) { for (int i = 0; i < kNum; i++) {
free(ptrs[i]); free(ptrs[i]);

View File

@ -136,6 +136,9 @@
/* Define to 1 if the system has the type `struct mallinfo'. */ /* Define to 1 if the system has the type `struct mallinfo'. */
#undef HAVE_STRUCT_MALLINFO #undef HAVE_STRUCT_MALLINFO
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/prctl.h> header file. */ /* Define to 1 if you have the <sys/prctl.h> header file. */
#undef HAVE_SYS_PRCTL_H #undef HAVE_SYS_PRCTL_H
@ -190,6 +193,10 @@
/* Define to 1 if int32_t is equivalent to intptr_t */ /* Define to 1 if int32_t is equivalent to intptr_t */
#undef INT32_EQUALS_INTPTR #undef INT32_EQUALS_INTPTR
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O #undef NO_MINUS_C_MINUS_O