diff options
author | sgk@chromium.org <sgk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-25 23:31:03 +0000 |
---|---|---|
committer | sgk@chromium.org <sgk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-25 23:31:03 +0000 |
commit | 165349b753d41461e75903b42f79efd741a18472 (patch) | |
tree | eb0c0024738ba754a8c3b4936e6816ae80001839 /third_party/tcmalloc | |
parent | 1e625a41a9145a10c4c003f081f408ca59fea8cb (diff) | |
download | chromium_src-165349b753d41461e75903b42f79efd741a18472.zip chromium_src-165349b753d41461e75903b42f79efd741a18472.tar.gz chromium_src-165349b753d41461e75903b42f79efd741a18472.tar.bz2 |
Merge r77 from upstream tcmalloc to the local chromium branch.
BUG=27911
TEST=none
Review URL: http://codereview.chromium.org/440027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33151 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/tcmalloc')
19 files changed, 263 insertions, 734 deletions
diff --git a/third_party/tcmalloc/README.chromium b/third_party/tcmalloc/README.chromium index c30ae73..33dcb0f 100644 --- a/third_party/tcmalloc/README.chromium +++ b/third_party/tcmalloc/README.chromium @@ -2,38 +2,74 @@ This contains Chromium's locally patched copy of tcmalloc. Contents:
- README.chromium
+ README.chromium
- This file you're looking at right now.
+ This file you're looking at right now.
- chromium/
+ chromium/
- The chromium patched sources, copied from the vendor/
- subdirectory and containing our local modifications.
+ The chromium patched sources, copied from the vendor/
+ subdirectory and containing our local modifications.
- We only copy over the vendor/src/ subdirectory (the only piece
- we need) but still leave it in a chromium/src/ subdirectory to
- keep the directory structures in parallel.
+ We only copy over the vendor/src/ subdirectory (the only piece
+ we need) but still leave it in a chromium/src/ subdirectory to
+ keep the directory structures in parallel.
- vendor/
+ vendor/
- Vanilla sources from upstream:
+ Vanilla sources from upstream:
- http://google-perftools.googlecode.com/svn/trunk
+ http://google-perftools.googlecode.com/svn/trunk
- The current revision is:
+ The current revision is:
- Last Changed Rev: 78
- Last Changed Date: 2009-11-10 08:24:57 -0800 (Tue, 10 Nov 2009)
+ Last Changed Rev: 77
+ Last Changed Date: 2009-10-27 10:30:52 -0700 (Tue, 27 Oct 2009)
-
+
HOWTOs:
- Take a new version from upstream:
+ Take a new version from upstream:
- TODO(sgk)
+ 1) Grab the revision:
- Merge a new upstream version with our local patched copy:
+ $ svn export [-r {tcmalloc-rev}] \
+ http://google-perftools.googlecode.com/svn/trunk \
+ vendor-{tcmalloc-rev}
- TODO(sgk)
+ 2) Check for added or deleted files:
+
+ $ diff -q -r -x .svn vendor vendor-{tcmalloc-rev}
+
+ 3) Copy the new revision on top of the checked-in vendor branch:
+
+ $ cp -r vendor-{tcmalloc-rev}/* vendor
+
+ C:\> xcopy /e/y/i vendor-{tcmalloc-rev}\* vendor
+
+ 4) "svn add" or "svn rm" added or removed files (based on your
+ "diff -q -r" output from above)
+
+ 5) Create the CL, upload, check it in:
+
+ $ gcl change CL
+ $ gcl upload CL
+ $ gcl commit CL
+
+ Note the revision number since you're going to want to merge
+ that to the local chromium branch.
+
+ Merge a new upstream version with our local patched copy:
+
+ 1) Merge the local revision to chromium/src
+
+ $ svn merge -c {chrome-rev} svn://chrome-svn/chrome/trunk/src/third_party/tcmalloc/vendor/src chromium/src
+
+ 2) Resolve any conflicts
+
+ 3) Create the CL, upload, check in:
+
+ $ gcl change CL
+ $ gcl upload CL
+ $ gcl commit CL
diff --git a/third_party/tcmalloc/chromium/src/base/basictypes.h b/third_party/tcmalloc/chromium/src/base/basictypes.h index 9991413..e4d4140 100644 --- a/third_party/tcmalloc/chromium/src/base/basictypes.h +++ b/third_party/tcmalloc/chromium/src/base/basictypes.h @@ -240,7 +240,7 @@ struct CompileAssert { # define HAVE_ATTRIBUTE_SECTION_START 1 #elif defined(HAVE___ATTRIBUTE__) && defined(__MACH__) -# define ATTRIBUTE_SECTION(name) __attribute__ ((section ("__TEXT, " #name))) +# define ATTRIBUTE_SECTION(name) __attribute__ ((section ("__DATA, " #name))) #include <mach-o/getsect.h> #include <mach-o/dyld.h> @@ -251,32 +251,18 @@ class AssignAttributeStartEnd { if (_dyld_present()) { for (int i = _dyld_image_count() - 1; i >= 0; --i) { const mach_header* hdr = _dyld_get_image_header(i); -#ifdef MH_MAGIC_64 - if (hdr->magic == MH_MAGIC_64) { - uint64_t len; - *pstart = getsectdatafromheader_64((mach_header_64*)hdr, - "__TEXT", name, &len); - if (*pstart) { // NULL if not defined in this dynamic library - *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc - *pend = *pstart + len; - return; - } - } -#endif - if (hdr->magic == MH_MAGIC) { - uint32_t len; - *pstart = getsectdatafromheader(hdr, "__TEXT", name, &len); - if (*pstart) { // NULL if not defined in this dynamic library - *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc - *pend = *pstart + len; - return; - } + uint32_t len; + *pstart = getsectdatafromheader(hdr, "__DATA", name, &len); + if (*pstart) { // NULL if not defined in this dynamic library + *pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc + *pend = *pstart + len; + return; } } } // If we get here, not defined in a dll at all. See if defined statically. unsigned long len; // don't ask me why this type isn't uint32_t too... - *pstart = getsectdata("__TEXT", name, &len); + *pstart = getsectdata("__DATA", name, &len); *pend = *pstart + len; } }; diff --git a/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h b/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h index a2a268f..5995ac4 100644 --- a/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h +++ b/third_party/tcmalloc/chromium/src/base/dynamic_annotations.h @@ -203,16 +203,9 @@ } while (0) // Instruct the tool to create a happens-before arc between mu->Unlock() and - // mu->Lock(). This annotation may slow down the race detector and hide real - // races. Normally it is used only when it would be difficult to annotate each - // of the mutex's critical sections individually using the annotations above. - // This annotation makes sense only for hybrid race detectors. For pure - // happens-before detectors this is a no-op. For more details see - // http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . - #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ - AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu) - - // Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. + // mu->Lock(). This annotation may slow down the race detector; normally it + // is used only when it would be difficult to annotate each of the mutex's + // critical sections individually using the annotations above. #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \ AnnotateMutexIsUsedAsCondVar(__FILE__, __LINE__, mu) @@ -364,7 +357,6 @@ #define ANNOTATE_NEW_MEMORY(address, size) // empty #define ANNOTATE_EXPECT_RACE(address, description) // empty #define ANNOTATE_BENIGN_RACE(address, description) // empty - #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) // empty #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) // empty #define ANNOTATE_TRACE_MEMORY(arg) // empty #define ANNOTATE_THREAD_NAME(name) // empty diff --git a/third_party/tcmalloc/chromium/src/base/sysinfo.cc b/third_party/tcmalloc/chromium/src/base/sysinfo.cc index 3919ba45..a2bc2a9 100644 --- a/third_party/tcmalloc/chromium/src/base/sysinfo.cc +++ b/third_party/tcmalloc/chromium/src/base/sysinfo.cc @@ -441,48 +441,6 @@ static void ConstructFilename(const char* spec, pid_t pid, } #endif -// A templatized helper function instantiated for Mach (OS X) only. -// It can handle finding info for both 32 bits and 64 bits. -// Returns true if it successfully handled the hdr, false else. -#ifdef __MACH__ // Mac OS X, almost certainly -template<uint32_t kMagic, uint32_t kLCSegment, - typename MachHeader, typename SegmentCommand> -static bool NextExtMachHelper(const mach_header* hdr, - int current_image, int current_load_cmd, - uint64 *start, uint64 *end, char **flags, - uint64 *offset, int64 *inode, char **filename, - uint64 *file_mapping, uint64 *file_pages, - uint64 *anon_mapping, uint64 *anon_pages, - dev_t *dev) { - static char kDefaultPerms[5] = "r-xp"; - if (hdr->magic != kMagic) - return false; - const char* lc = (const char *)hdr + sizeof(MachHeader); - // TODO(csilvers): make this not-quadradic (increment and hold state) - for (int j = 0; j < current_load_cmd; j++) // advance to *our* load_cmd - lc += ((const load_command *)lc)->cmdsize; - if (((const load_command *)lc)->cmd == kLCSegment) { - const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image); - const SegmentCommand* sc = (const SegmentCommand *)lc; - if (start) *start = sc->vmaddr + dlloff; - if (end) *end = sc->vmaddr + sc->vmsize + dlloff; - if (flags) *flags = kDefaultPerms; // can we do better? - if (offset) *offset = sc->fileoff; - if (inode) *inode = 0; - if (filename) - *filename = const_cast<char*>(_dyld_get_image_name(current_image)); - if (file_mapping) *file_mapping = 0; - if (file_pages) *file_pages = 0; // could we use sc->filesize? - if (anon_mapping) *anon_mapping = 0; - if (anon_pages) *anon_pages = 0; - if (dev) *dev = 0; - return true; - } - - return false; -} -#endif - ProcMapsIterator::ProcMapsIterator(pid_t pid) { Init(pid, NULL, false); } @@ -498,7 +456,6 @@ ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer, void ProcMapsIterator::Init(pid_t pid, Buffer *buffer, bool use_maps_backing) { - pid_ = pid; using_maps_backing_ = use_maps_backing; dynamic_buffer_ = NULL; if (!buffer) { @@ -734,7 +691,6 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4); COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2); COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1); - Buffer object_path; int nread = 0; // fill up buffer with text NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t))); if (nread == sizeof(prmap_t)) { @@ -744,27 +700,13 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, // two middle ints are major and minor device numbers, but I'm not sure. sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); - if (pid_ == 0) { - CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, - "/proc/self/path/%s", mapinfo->pr_mapname), - Buffer::kBufSize); - } else { - CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, - "/proc/%d/path/%s", pid_, mapinfo->pr_mapname), - Buffer::kBufSize); - } - ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); - CHECK_LT(len, PATH_MAX); - if (len < 0) - len = 0; - current_filename_[len] = '\0'; - if (start) *start = mapinfo->pr_vaddr; if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; if (flags) *flags = kPerms[mapinfo->pr_mflags & 7]; if (offset) *offset = mapinfo->pr_offset; if (inode) *inode = inode_from_mapname; - if (filename) *filename = current_filename_; + // TODO(csilvers): How to map from /proc/map/object to filename? + if (filename) *filename = mapinfo->pr_mapname; // format is ufs.?.?.inode if (file_mapping) *file_mapping = 0; if (file_pages) *file_pages = 0; if (anon_mapping) *anon_mapping = 0; @@ -773,6 +715,7 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, return true; } #elif defined(__MACH__) + static char kDefaultPerms[5] = "r-xp"; // We return a separate entry for each segment in the DLL. (TODO(csilvers): // can we do better?) A DLL ("image") has load-commands, some of which // talk about segment boundaries. @@ -785,22 +728,25 @@ bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, // We start with the next load command (we've already looked at this one). for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) { -#ifdef MH_MAGIC_64 - if (NextExtMachHelper<MH_MAGIC_64, LC_SEGMENT_64, - struct mach_header_64, struct segment_command_64>( - hdr, current_image_, current_load_cmd_, - start, end, flags, offset, inode, filename, - file_mapping, file_pages, anon_mapping, - anon_pages, dev)) { - return true; - } -#endif - if (NextExtMachHelper<MH_MAGIC, LC_SEGMENT, - struct mach_header, struct segment_command>( - hdr, current_image_, current_load_cmd_, - start, end, flags, offset, inode, filename, - file_mapping, file_pages, anon_mapping, - anon_pages, dev)) { + const char* lc = ((const char *)hdr + sizeof(struct mach_header)); + // TODO(csilvers): make this not-quadradic (increment and hold state) + for (int j = 0; j < current_load_cmd_; j++) // advance to *our* load_cmd + lc += ((const load_command *)lc)->cmdsize; + if (((const load_command *)lc)->cmd == LC_SEGMENT) { + const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image_); + const segment_command* sc = (const segment_command *)lc; + if (start) *start = sc->vmaddr + dlloff; + if (end) *end = sc->vmaddr + sc->vmsize + dlloff; + if (flags) *flags = kDefaultPerms; // can we do better? + if (offset) *offset = sc->fileoff; + if (inode) *inode = 0; + if (filename) + *filename = const_cast<char*>(_dyld_get_image_name(current_image_)); + if (file_mapping) *file_mapping = 0; + if (file_pages) *file_pages = 0; // could we use sc->filesize? + if (anon_mapping) *anon_mapping = 0; + if (anon_pages) *anon_pages = 0; + if (dev) *dev = 0; return true; } } diff --git a/third_party/tcmalloc/chromium/src/base/sysinfo.h b/third_party/tcmalloc/chromium/src/base/sysinfo.h index 0bcc1f5..b4b5c9f 100644 --- a/third_party/tcmalloc/chromium/src/base/sysinfo.h +++ b/third_party/tcmalloc/chromium/src/base/sysinfo.h @@ -209,13 +209,9 @@ class ProcMapsIterator { #elif defined(__MACH__) int current_image_; // dll's are called "images" in macos parlance int current_load_cmd_; // the segment of this dll we're examining -#elif defined(__sun__) // Solaris - int fd_; - char current_filename_[PATH_MAX]; #else int fd_; // filehandle on /proc/*/maps #endif - pid_t pid_; char flags_[10]; Buffer* dynamic_buffer_; // dynamically-allocated Buffer bool using_maps_backing_; // true if we are looking at maps_backing instead of maps. diff --git a/third_party/tcmalloc/chromium/src/debugallocation.cc b/third_party/tcmalloc/chromium/src/debugallocation.cc index 47fef16..dcf722d 100644 --- a/third_party/tcmalloc/chromium/src/debugallocation.cc +++ b/third_party/tcmalloc/chromium/src/debugallocation.cc @@ -674,7 +674,7 @@ class MallocBlock { uintptr_t pc = reinterpret_cast<uintptr_t>(queue_entry.deleter_pcs[i]) - 1; TracePrintf(STDERR_FILENO, " @ %p %s\n", - reinterpret_cast<void*>(pc), symbolization_table[pc]); + pc, symbolization_table[pc]); } } else { RAW_LOG(ERROR, diff --git a/third_party/tcmalloc/chromium/src/google/malloc_extension.h b/third_party/tcmalloc/chromium/src/google/malloc_extension.h index 0342843..bc53e0f 100644 --- a/third_party/tcmalloc/chromium/src/google/malloc_extension.h +++ b/third_party/tcmalloc/chromium/src/google/malloc_extension.h @@ -42,13 +42,6 @@ #define BASE_MALLOC_EXTENSION_H_ #include <stddef.h> -// I can't #include config.h in this public API file, but I should -// really use configure (and make malloc_extension.h a .in file) to -// figure out if the system has stdint.h or not. But I'm lazy, so -// for now I'm assuming it's a problem only with MSVC. -#ifndef _MSC_VER -#include <stdint.h> -#endif #include <string> // Annoying stuff for windows -- makes sure clients can import these functions @@ -65,10 +58,6 @@ static const int kMallocHistogramSize = 64; // One day, we could support other types of writers (perhaps for C?) typedef std::string MallocExtensionWriter; -namespace base { -struct MallocRange; -} - // The default implementations of the following routines do nothing. // All implementations should be thread-safe; the current one // (TCMallocImplementation) is. @@ -110,14 +99,6 @@ class PERFTOOLS_DLL_DECL MallocExtension { // be passed to "pprof". virtual void GetHeapGrowthStacks(MallocExtensionWriter* writer); - // Invokes func(arg, range) for every controlled memory - // range. *range is filled in with information about the range. - // - // This is a best-effort interface useful only for performance - // analysis. The implementation may not call func at all. - typedef void (RangeFunction)(void*, const base::MallocRange*); - virtual void Ranges(void* arg, RangeFunction func); - // ------------------------------------------------------------------- // Control operations for getting and setting malloc implementation // specific parameters. Some currently useful properties: @@ -146,20 +127,12 @@ class PERFTOOLS_DLL_DECL MallocExtension { // This property is not writable. // // "tcmalloc.slack_bytes" - // Number of bytes allocated from system, but not currently in - // use by malloced objects. I.e., bytes available for - // allocation without needing more bytes from system. It is - // the sum of pageheap_free_bytes and pageheap_unmapped_bytes. - // This property is not writable. - // - // "tcmalloc.pageheap_free_bytes" - // Number of bytes in free, mapped pages in pageheap - // This property is not writable. - // - // "tcmalloc.pageheap_unmapped_bytes" - // Number of bytes in free, unmapped pages in pageheap + // Number of bytes allocated from system, but not currently + // in use by malloced objects. I.e., bytes available for + // allocation without needing more bytes from system. // This property is not writable. // + // TODO: Add more properties as necessary // ------------------------------------------------------------------- // Get the named "property"'s value. Returns true if the property @@ -194,14 +167,12 @@ class PERFTOOLS_DLL_DECL MallocExtension { // Most malloc implementations ignore this routine. virtual void MarkThreadBusy(); - // Try to release num_bytes of free memory back to the operating - // system for reuse. Use this extension with caution -- to get this - // memory back may require faulting pages back in by the OS, and - // that may be slow. (Currently only implemented in tcmalloc.) - // A negative values for num_bytes results in a noop. - virtual void ReleaseToSystem(ssize_t num_bytes); - - // Same as ReleaseToSystem() but release as much memory as possible. + // Try to free memory back to the operating system for reuse. Only + // use this extension if the application has recently freed a lot of + // memory, and does not anticipate using it again for a long time -- + // to get this memory back may require faulting pages back in by the + // OS, and that may be slow. (Currently only implemented in + // tcmalloc.) virtual void ReleaseFreeMemory(); // Sets the rate at which we release unused memory to the system. @@ -268,29 +239,4 @@ class PERFTOOLS_DLL_DECL MallocExtension { virtual void** ReadHeapGrowthStackTraces(); }; -namespace base { - -// Information passed per range. More fields may be added later. -struct MallocRange { - enum Type { - INUSE, // Application is using this range - FREE, // Range is currently free - UNMAPPED, // Backing physical memory has been returned to the OS - UNKNOWN, - // More enum values may be added in the future - }; - - uintptr_t address; // Address of range - size_t length; // Byte length of range - Type type; // Type of this range - double fraction; // Fraction of range that is being used (0 if !INUSE) - - // Perhaps add the following: - // - stack trace if this range was sampled - // - heap growth stack trace if applicable to this range - // - age when allocated (for inuse) or freed (if not in use) -}; - -} // namespace base - #endif // BASE_MALLOC_EXTENSION_H_ diff --git a/third_party/tcmalloc/chromium/src/google/malloc_extension_c.h b/third_party/tcmalloc/chromium/src/google/malloc_extension_c.h index 95f7f4c..514305e 100644 --- a/third_party/tcmalloc/chromium/src/google/malloc_extension_c.h +++ b/third_party/tcmalloc/chromium/src/google/malloc_extension_c.h @@ -75,7 +75,6 @@ PERFTOOLS_DLL_DECL int MallocExtension_GetNumericProperty(const char* property, PERFTOOLS_DLL_DECL int MallocExtension_SetNumericProperty(const char* property, size_t value); PERFTOOLS_DLL_DECL void MallocExtension_MarkThreadIdle(void); PERFTOOLS_DLL_DECL void MallocExtension_MarkThreadBusy(void); -PERFTOOLS_DLL_DECL void MallocExtension_ReleaseToSystem(ssize_t num_bytes); PERFTOOLS_DLL_DECL void MallocExtension_ReleaseFreeMemory(void); PERFTOOLS_DLL_DECL size_t MallocExtension_GetEstimatedAllocatedSize(size_t size); PERFTOOLS_DLL_DECL size_t MallocExtension_GetAllocatedSize(void* p); diff --git a/third_party/tcmalloc/chromium/src/heap-checker.cc b/third_party/tcmalloc/chromium/src/heap-checker.cc index 59288e6..fc8973a 100644 --- a/third_party/tcmalloc/chromium/src/heap-checker.cc +++ b/third_party/tcmalloc/chromium/src/heap-checker.cc @@ -47,9 +47,11 @@ #ifdef HAVE_PTHREAD #include <pthread.h> #endif +#ifdef HAVE_POLL_H +#include <poll.h> +#endif #include <sys/stat.h> #include <sys/types.h> -#include <time.h> #include <assert.h> #ifdef HAVE_LINUX_PTRACE_H @@ -2296,8 +2298,7 @@ void HeapLeakChecker_AfterDestructors() { } if (FLAGS_heap_check_after_destructors) { if (HeapLeakChecker::DoMainHeapCheck()) { - const struct timespec sleep_time = { 0, 500000000 }; // 500 ms - nanosleep(&sleep_time, NULL); + poll(0, 0, 500); // Need this hack to wait for other pthreads to exit. // Otherwise tcmalloc find errors // on a free() call from pthreads. diff --git a/third_party/tcmalloc/chromium/src/malloc_extension.cc b/third_party/tcmalloc/chromium/src/malloc_extension.cc index 95fd1c1..068a693 100644 --- a/third_party/tcmalloc/chromium/src/malloc_extension.cc +++ b/third_party/tcmalloc/chromium/src/malloc_extension.cc @@ -143,12 +143,8 @@ void MallocExtension::MarkThreadBusy() { // Default implementation does nothing } -void MallocExtension::ReleaseToSystem(ssize_t num_bytes) { - // Default implementation does nothing -} - void MallocExtension::ReleaseFreeMemory() { - ReleaseToSystem(LONG_MAX); + // Default implementation does nothing } void MallocExtension::SetMemoryReleaseRate(double rate) { @@ -304,10 +300,6 @@ void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter* writer) { DumpAddressMap(writer); } -void MallocExtension::Ranges(void* arg, RangeFunction func) { - // No callbacks by default -} - // These are C shims that work on the current instance. #define C_SHIM(fn, retval, paramlist, arglist) \ @@ -333,6 +325,5 @@ C_SHIM(SetNumericProperty, int, C_SHIM(MarkThreadIdle, void, (void), ()); C_SHIM(MarkThreadBusy, void, (void), ()); C_SHIM(ReleaseFreeMemory, void, (void), ()); -C_SHIM(ReleaseToSystem, void, (ssize_t num_bytes), (num_bytes)); C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size)); C_SHIM(GetAllocatedSize, size_t, (void* p), (p)); diff --git a/third_party/tcmalloc/chromium/src/pagemap.h b/third_party/tcmalloc/chromium/src/pagemap.h index 1786e68..3559932 100644 --- a/third_party/tcmalloc/chromium/src/pagemap.h +++ b/third_party/tcmalloc/chromium/src/pagemap.h @@ -95,20 +95,10 @@ class TCMalloc_PageMap1 { // REQUIRES "k" is in range "[0,2^BITS-1]". // REQUIRES "k" has been ensured before. // - // Sets the value 'v' for key 'k'. + // Sets the value for KEY. void set(Number k, void* v) { array_[k] = v; } - - // Return the first non-NULL pointer found in this map for - // a page number >= k. Returns NULL if no such number is found. - void* Next(Number k) const { - while (k < (1 << BITS)) { - if (array_[k] != NULL) return array_[k]; - k++; - } - return NULL; - } }; // Two-level radix tree @@ -180,24 +170,6 @@ class TCMalloc_PageMap2 { // Allocate enough to keep track of all possible pages Ensure(0, 1 << BITS); } - - void* Next(Number k) const { - while (k < (1 << BITS)) { - const Number i1 = k >> LEAF_BITS; - Leaf* leaf = root_[i1]; - if (leaf != NULL) { - // Scan forward in leaf - for (Number i2 = k & (LEAF_LENGTH - 1); i2 < LEAF_LENGTH; i2++) { - if (leaf->values[i2] != NULL) { - return leaf->values[i2]; - } - } - } - // Skip to next top-level entry - k = (i1 + 1) << LEAF_BITS; - } - return NULL; - } }; // Three-level radix tree @@ -292,29 +264,6 @@ class TCMalloc_PageMap3 { void PreallocateMoreMemory() { } - - void* Next(Number k) const { - while (k < (Number(1) << BITS)) { - const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS); - const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH-1); - if (root_->ptrs[i1] == NULL) { - // Advance to next top-level entry - k = (i1 + 1) << (LEAF_BITS + INTERIOR_BITS); - } else { - Leaf* leaf = reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2]); - if (leaf != NULL) { - for (Number i3 = (k & (LEAF_LENGTH-1)); i3 < LEAF_LENGTH; i3++) { - if (leaf->values[i3] != NULL) { - return leaf->values[i3]; - } - } - } - // Advance to next interior entry - k = ((k >> LEAF_BITS) + 1) << LEAF_BITS; - } - } - return NULL; - } }; #endif // TCMALLOC_PAGEMAP_H_ diff --git a/third_party/tcmalloc/chromium/src/pprof b/third_party/tcmalloc/chromium/src/pprof index 62cce12..88a6041 100644 --- a/third_party/tcmalloc/chromium/src/pprof +++ b/third_party/tcmalloc/chromium/src/pprof @@ -92,7 +92,6 @@ my $GV = "gv"; my $PS2PDF = "ps2pdf"; # These are used for dynamic profiles my $WGET = "wget"; -my $WGET_FLAGS = "--no-http-keep-alive"; # only supported by some wgets my $CURL = "curl"; # These are the web pages that servers need to support for dynamic profiles @@ -118,11 +117,6 @@ my $address_length = 16; # A list of paths to search for shared object files my @prefix_list = (); -# Special routine name that should not have any symbols. -# Used as separator to parse "addr2line -i" output. -my $sep_symbol = '_fini'; -my $sep_address = undef; - ##### Argument parsing ##### sub usage_string { @@ -510,20 +504,6 @@ sub Init() { ConfigureObjTools($main::prog) } - # Check what flags our commandline utilities support - if (open(TFILE, "$WGET $WGET_FLAGS -V 2>&1 |")) { - my @lines = <TFILE>; - if (grep(/unrecognized/, @lines) > 0) { - # grep found 'unrecognized' token from WGET, clear WGET flags - $WGET_FLAGS = ""; - } - close(TFILE); - } - # TODO(csilvers): check all the other binaries and objtools to see - # if they are installed and what flags they support, and store that - # in a data structure here, rather than scattering these tests about. - # Then, ideally, rewrite code to use wget OR curl OR GET or ... - # Break the opt_list_prefix into the prefix_list array @prefix_list = split (',', $main::opt_lib_prefix); @@ -972,31 +952,22 @@ sub PrintSymbolizedProfile { print 'binary=', $prog, "\n"; } while (my ($pc, $name) = each(%{$symbols})) { - my $sep = ' '; - print '0x', $pc; - # We have a list of function names, which include the inlined - # calls. They are separated (and terminated) by --, which is - # illegal in function names. - for (my $j = 2; $j <= $#{$name}; $j += 3) { - print $sep, $name->[$j]; - $sep = '--'; - } - print "\n"; + my $fullname = $name->[2]; + print '0x', $pc, ' ', $fullname, "\n"; } print '---', "\n"; - $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash - my $profile_marker = $&; - print '--- ', $profile_marker, "\n"; if (defined($main::collected_profile)) { # if used with remote fetch, simply dump the collected profile to output. open(SRC, "<$main::collected_profile"); while (<SRC>) { print $_; } - close(SRC); } else { # dump a cpu-format profile to standard out + $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash + my $profile_marker = $&; + print '--- ', $profile_marker, "\n"; PrintProfileData($profile); } } @@ -1098,9 +1069,9 @@ sub PrintDisassembly { } # Return reference to array of tuples of the form: -# [start_address, filename, linenumber, instruction, limit_address] +# [address, filename, linenumber, instruction] # E.g., -# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"] +# ["0x806c43d", "/foo/bar.cc", 131, "ret"] sub Disassemble { my $prog = shift; my $offset = shift; @@ -1115,7 +1086,6 @@ sub Disassemble { my @result = (); my $filename = ""; my $linenumber = -1; - my $last = ["", "", "", ""]; while (<OBJDUMP>) { s/\r//g; # turn windows-looking lines into unix-looking lines chop; @@ -1128,9 +1098,7 @@ sub Disassemble { # Disassembly line -- zero-extend address to full length my $addr = HexExtend($1); my $k = AddressAdd($addr, $offset); - $last->[4] = $k; # Store ending address for previous instruction - $last = [$k, $filename, $linenumber, $2, $end_addr]; - push(@result, $last); + push(@result, [$k, $filename, $linenumber, $2]); } } close(OBJDUMP); @@ -1306,13 +1274,8 @@ sub PrintSource { my $total1 = 0; # Total flat counts my $total2 = 0; # Total cumulative counts foreach my $e (@instructions) { - # Add up counts for all address that fall inside this instruction - my $c1 = 0; - my $c2 = 0; - for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { - $c1 += GetEntry($flat, $a); - $c2 += GetEntry($cumulative, $a); - } + my $c1 = GetEntry($flat, $e->[0]); + my $c2 = GetEntry($cumulative, $e->[0]); $running1 += $c1; $running2 += $c2; $total1 += $c1; @@ -1423,13 +1386,8 @@ sub PrintDisassembledFunction { my $flat_total = 0; my $cum_total = 0; foreach my $e (@instructions) { - # Add up counts for all address that fall inside this instruction - my $c1 = 0; - my $c2 = 0; - for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) { - $c1 += GetEntry($flat, $a); - $c2 += GetEntry($cumulative, $a); - } + my $c1 = GetEntry($flat, $e->[0]); + my $c2 = GetEntry($cumulative, $e->[0]); push(@flat_count, $c1); push(@cum_count, $c2); $flat_total += $c1; @@ -1657,10 +1615,10 @@ sub PrintDot { foreach my $k (keys(%{$raw})) { # TODO: omit low %age edges $n = $raw->{$k}; - my @translated = TranslateStack($symbols, $k); - for (my $i = 1; $i <= $#translated; $i++) { - my $src = $translated[$i]; - my $dst = $translated[$i-1]; + my @addrs = split(/\n/, $k); + for (my $i = 1; $i <= $#addrs; $i++) { + my $src = OutputKey($symbols, $addrs[$i]); + my $dst = OutputKey($symbols, $addrs[$i-1]); #next if ($src eq $dst); # Avoid self-edges? if (exists($node{$src}) && exists($node{$dst})) { my $edge_label = "$src\001$dst"; @@ -1690,18 +1648,14 @@ sub PrintDot { if ($edgeweight > 100000) { $edgeweight = 100000; } $edgeweight = int($edgeweight); - my $style = sprintf("setlinewidth(%f)", $w); - if ($x[1] =~ m/\(inline\)/) { - $style .= ",dashed"; - } - # Use a slightly squashed function of the edge count as the weight - printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n", + printf DOT ("N%s -> N%s [label=%s, weight=%d, " . + "style=\"setlinewidth(%f)\"];\n", $node{$x[0]}, $node{$x[1]}, Unparse($n), $edgeweight, - $style); + $w); } } @@ -1711,74 +1665,42 @@ sub PrintDot { return 1; } -# Translate a stack of addresses into a stack of symbols -sub TranslateStack { +# Generate the key under which a given address should be counted +# based on the user-specified output granularity. +sub OutputKey { my $symbols = shift; - my $k = shift; - - my @addrs = split(/\n/, $k); - my @result = (); - for (my $i = 0; $i <= $#addrs; $i++) { - my $a = $addrs[$i]; - - # Skip large addresses since they sometimes show up as fake entries on RH9 - if (length($a) > 8 && $a gt "7fffffffffffffff") { - next; - } - - if ($main::opt_disasm || $main::opt_list) { - # We want just the address for the key - push(@result, $a); - next; - } - - my $symlist = $symbols->{$a}; - if (!defined($symlist)) { - $symlist = [$a, "", $a]; - } - - # We can have a sequence of symbols for a particular entry - # (more than one symbol in the case of inlining). Callers - # come before callees in symlist, so walk backwards since - # the translated stack should contain callees before callers. - for (my $j = $#{$symlist}; $j >= 2; $j -= 3) { - my $func = $symlist->[$j-2]; - my $fileline = $symlist->[$j-1]; - my $fullfunc = $symlist->[$j]; - if ($j > 2) { - $func = "$func (inline)"; - } - if ($main::opt_addresses) { - push(@result, "$a $func $fileline"); - } elsif ($main::opt_lines) { - if ($func eq '??' && $fileline eq '??:0') { - push(@result, "$a"); - } else { - push(@result, "$func $fileline"); - } - } elsif ($main::opt_functions) { - if ($func eq '??') { - push(@result, "$a"); - } else { - push(@result, $func); - } - } elsif ($main::opt_files) { - if ($fileline eq '??:0' || $fileline eq '') { - push(@result, "$a"); - } else { - my $f = $fileline; - $f =~ s/:\d+$//; - push(@result, $f); - } - } else { - push(@result, $a); - last; # Do not print inlined info - } - } + my $a = shift; + + # Skip large addresses since they sometimes show up as fake entries on RH9 + if (length($a) > 8) { + if ($a gt "7fffffffffffffff") { return ''; } + } + + # Extract symbolic info for address + my $func = $a; + my $fullfunc = $a; + my $fileline = ""; + if (exists($symbols->{$a})) { + $func = $symbols->{$a}->[0]; + $fullfunc = $symbols->{$a}->[2]; + $fileline = $symbols->{$a}->[1]; + } + + if ($main::opt_disasm || $main::opt_list) { + return $a; # We want just the address for the key + } elsif ($main::opt_addresses) { + return "$a $func $fileline"; + } elsif ($main::opt_lines) { + return "$func $fileline"; + } elsif ($main::opt_functions) { + return $func; + } elsif ($main::opt_files) { + my $f = ($fileline eq '') ? $a : $fileline; + $f =~ s/:\d+$//; + return $f; + } else { + return $a; } - - # print join(",", @addrs), " => ", join(",", @result), "\n"; - return @result; } # Generate percent string for a number and a total @@ -2056,16 +1978,17 @@ sub ReduceProfile { my $result = {}; foreach my $k (keys(%{$profile})) { my $count = $profile->{$k}; - my @translated = TranslateStack($symbols, $k); + my @addrs = split(/\n/, $k); my @path = (); my %seen = (); $seen{''} = 1; # So that empty keys are skipped - foreach my $e (@translated) { + foreach my $a (@addrs) { # To avoid double-counting due to recursion, skip a stack-trace # entry if it has already been seen - if (!$seen{$e}) { - $seen{$e} = 1; - push(@path, $e); + my $key = OutputKey($symbols, $a); + if (!$seen{$key}) { + $seen{$key} = 1; + push(@path, $key); } } my $reduced_path = join("\n", @path); @@ -2074,20 +1997,6 @@ sub ReduceProfile { return $result; } -# Does the specified symbol array match the regexp? -sub SymbolMatches { - my $sym = shift; - my $re = shift; - if (defined($sym)) { - for (my $i = 0; $i < $#{$sym}; $i += 3) { - if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) { - return 1; - } - } - } - return 0; -} - # Focus only on paths involving specified regexps sub FocusProfile { my $symbols = shift; @@ -2099,7 +2008,10 @@ sub FocusProfile { my @addrs = split(/\n/, $k); foreach my $a (@addrs) { # Reply if it matches either the address/shortname/fileline - if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) { + if (($a =~ m/$focus/) || + (exists($symbols->{$a}) && + (($symbols->{$a}->[0] =~ m/$focus/) || + ($symbols->{$a}->[1] =~ m/$focus/)))) { AddEntry($result, $k, $count); last; } @@ -2120,7 +2032,10 @@ sub IgnoreProfile { my $matched = 0; foreach my $a (@addrs) { # Reply if it matches either the address/shortname/fileline - if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) { + if (($a =~ m/$ignore/) || + (exists($symbols->{$a}) && + (($symbols->{$a}->[0] =~ m/$ignore/) || + ($symbols->{$a}->[1] =~ m/$ignore/)))) { $matched = 1; last; } @@ -2280,7 +2195,7 @@ sub IsSymbolizedProfileFile { sub CheckSymbolPage { my $url = SymbolPageURL(); - open(SYMBOL, "$WGET $WGET_FLAGS -qO- '$url' |"); + open(SYMBOL, "$WGET -qO- '$url' |"); my $line = <SYMBOL>; $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines close(SYMBOL); @@ -2325,7 +2240,7 @@ sub SymbolPageURL { sub FetchProgramName() { my ($host, $port, $path) = ParseProfileURL($main::pfile_args[0]); my $url = "http://$host:$port$PROGRAM_NAME_PAGE"; - my $command_line = "$WGET $WGET_FLAGS -qO- '$url'"; + my $command_line = "$WGET -qO- '$url'"; open(CMDLINE, "$command_line |") or error($command_line); my $cmdline = <CMDLINE>; $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines @@ -2431,21 +2346,13 @@ sub FetchSymbols { # /symbol, the symbols match and are retrievable from the map. my $shortpc = $pc; $shortpc =~ s/^0*//; - # Each line may have a list of names, which includes the function - # and also other functions it has inlined. They are separated - # (in PrintSymbolizedFile), by --, which is illegal in function names. - my $fullnames; if (defined($symbol_map->{$shortpc})) { - $fullnames = $symbol_map->{$shortpc}; + $fullname = $symbol_map->{$shortpc}; } else { - $fullnames = "0x" . $pc; # Just use addresses - } - my $sym = []; - $symbols->{$pc} = $sym; - foreach my $fullname (split("--", $fullnames)) { - my $name = ShortFunctionName($fullname); - push(@{$sym}, $name, "?", $fullname); + $fullname = "0x" . $pc; # Just use addresses } + my $name = ShortFunctionName($fullname); + $symbols->{$pc} = [$name, "?", $fullname]; } return $symbols; } @@ -2520,7 +2427,7 @@ sub FetchDynamicProfile { return $real_profile; } - my $cmd = "$WGET $WGET_FLAGS $wget_timeout -q -O $tmp_profile '$url'"; + my $cmd = "$WGET $wget_timeout -q -O $tmp_profile '$url'"; if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)){ print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n"; if ($encourage_patience) { @@ -2845,26 +2752,12 @@ sub ReadCPUProfile { # Make key out of the stack entries my @k = (); - for (my $j = 0; $j < $d; $j++) { + for (my $j = $d; $j--; ) { my $pclo = $slots->get($i++); my $pchi = $slots->get($i++); if ($pclo == -1 || $pchi == -1) { error("$fname: Unexpected EOF when reading stack of depth $d\n"); } - - # Subtract one from caller pc so we map back to call instr. - # However, don't do this if we're reading a symbolized profile - # file, in which case the subtract-one was done when the file - # was written. - if ($j > 0 && !$main::use_symbolized_profile) { - if ($pclo == 0) { - $pchi--; - $pclo = 0xffffffff; - } else { - $pclo--; - } - } - my $pc = sprintf("%08x%08x", $pchi, $pclo); $pcs->{$pc} = 1; push @k, $pc; @@ -3623,111 +3516,87 @@ sub MapToSymbols { my $pclist = shift; my $symbols = shift; - my $debug = 0; - # Ignore empty binaries if ($#{$pclist} < 0) { return; } - # Figure out the addr2line command to use - my $addr2line = $obj_tool_map{"addr2line"}; - my $cmd = "$addr2line -f -C -e $image"; - if (exists $obj_tool_map{"addr2line_pdb"}) { - $addr2line = $obj_tool_map{"addr2line_pdb"}; - $cmd = "$addr2line --demangle -f -C -e $image"; - } - - # If "addr2line" isn't installed on the system at all, just use - # nm to get what info we can (function names, but not line numbers). - if (system("$addr2line --help >/dev/null 2>&1") != 0) { - MapSymbolsWithNM($image, $offset, $pclist, $symbols); - return; - } - - # "addr2line -i" can produce a variable number of lines per input - # address, with no separator that allows us to tell when data for - # the next address starts. So we find the address for a special - # symbol (_fini) and interleave this address between all real - # addresses passed to addr2line. The name of this special symbol - # can then be used as a separator. - $sep_address = undef; # May be filled in by MapSymbolsWithNM() - my $nm_symbols = {}; - MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols); - # TODO(csilvers): only add '-i' if addr2line supports it. - if (defined($sep_address)) { - # Only add " -i" to addr2line if the binary supports it. - # addr2line --help returns 0, but not if it sees an unknown flag first. - if (system("$cmd -i --help >/dev/null 2>&1") == 0) { - $cmd .= " -i"; - } else { - $sep_address = undef; # no need for sep_address if we don't support -i - } + 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_callgrind || + !$got_symbols) { + GetLineNumbers($image, $offset, $pclist, $symbols); } +} - # Make file with all PC values with intervening 'sep_address' so - # that we can reliably detect the end of inlined function list - open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n"); - if ($debug) { print("---- $image ---\n"); } - for (my $i = 0; $i <= $#{$pclist}; $i++) { - # addr2line always reads hex addresses, and does not need '0x' prefix. - if ($debug) { printf("%s\n", $pclist->[$i]); } - printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset)); - if (defined($sep_address)) { - printf ADDRESSES ("%s\n", $sep_address); - } - } - close(ADDRESSES); - if ($debug) { - print("----\n"); - system("cat $main::tmpfile_sym"); - print("----\n"); - system("$cmd <$main::tmpfile_sym"); - print("----\n"); - } +# The file $tmpfile_sym must already have been created before calling this. +sub GetLineNumbersViaAddr2Line { + my $addr2line_command = shift; + my $pclist = shift; + my $symbols = shift; - open(SYMBOLS, "$cmd <$main::tmpfile_sym |") || error("$cmd: $!\n"); - my $count = 0; # Index in pclist + open(SYMBOLS, "$addr2line_command <$main::tmpfile_sym |") + || error("$addr2line_command: $!\n"); + my $count = 0; while (<SYMBOLS>) { - # Read fullfunction and filelineinfo from next pair of lines s/\r?\n$//g; my $fullfunction = $_; + $_ = <SYMBOLS>; s/\r?\n$//g; my $filelinenum = $_; - - if (defined($sep_address) && $fullfunction eq $sep_symbol) { - # Terminating marker for data for this address - $count++; - next; + $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths + if (!$main::opt_list) { + $filelinenum =~ s|^.*/([^/]+:\d+)$|$1|; # Remove directory name } - $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths - my $pcstr = $pclist->[$count]; - my $function = ShortFunctionName($fullfunction); - if ($fullfunction eq '??') { - # See if nm found a symbol - my $nms = $nm_symbols->{$pcstr}; - if (defined($nms)) { - $function = $nms->[0]; - $fullfunction = $nms->[2]; + if (defined($symbols->{$pcstr})) { + # Override just the line-number portion. The function name portion + # is less buggy when computed using nm instead of addr2line. But + # don't override if addr2line is giving ??'s and nm didn't. (This + # may be seen mostly/entirely on cygwin's addr2line/nm.) + if (($filelinenum ne "??:0") || ($symbols->{$pcstr}->[1] eq "?")) { + $symbols->{$pcstr}->[1] = $filelinenum; } + } else { + my $function = ShortFunctionName($fullfunction); + $symbols->{$pcstr} = [$function, $filelinenum, $fullfunction]; } + $count++; + } + close(SYMBOLS); + return $count; +} - # Prepend to accumulated symbols for pcstr - # (so that caller comes before callee) - my $sym = $symbols->{$pcstr}; - if (!defined($sym)) { - $sym = []; - $symbols->{$pcstr} = $sym; - } - unshift(@{$sym}, $function, $filelinenum, $fullfunction); - if ($debug) { printf("%s => [%s]\n", $pcstr, join(" ", @{$sym})); } - if (!defined($sep_address)) { - # Inlining is off, se this entry ends immediately - $count++; +sub GetLineNumbers { + my $image = shift; + my $offset = shift; + my $pclist = shift; + my $symbols = shift; + + # Make file with all PC values + open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n"); + for (my $i = 0; $i <= $#{$pclist}; $i++) { + # addr2line always reads hex addresses, and does not need '0x' prefix. + printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset)); + } + close(ADDRESSES); + + # Pass to addr2line + my $addr2line = $obj_tool_map{"addr2line"}; + my @addr2line_commands = ("$addr2line -f -C -e $image"); + if (exists $obj_tool_map{"addr2line_pdb"}) { + my $addr2line_pdb = $obj_tool_map{"addr2line_pdb"}; + push(@addr2line_commands, "$addr2line_pdb --demangle -f -C -e $image"); + } + foreach my $addr2line_command (@addr2line_commands) { + if (GetLineNumbersViaAddr2Line("$addr2line_command", $pclist, $symbols)) { + last; } } - close(SYMBOLS); } # Use nm to map the list of referenced PCs to symbols. Return true iff we @@ -3777,7 +3646,7 @@ sub MapSymbolsWithNM { } return 1; } - + sub ShortFunctionName { my $function = shift; while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types @@ -3944,10 +3813,6 @@ sub GetProcedureBoundariesViaNm { next; } - if ($this_routine eq $sep_symbol) { - $sep_address = HexExtend($start_val); - } - # Tag this routine with the starting address in case the image # has multiple occurrences of this routine. We use a syntax # that resembles template paramters that are automatically diff --git a/third_party/tcmalloc/chromium/src/stacktrace_config.h b/third_party/tcmalloc/chromium/src/stacktrace_config.h index b58ab1d..3bd0fb3 100644 --- a/third_party/tcmalloc/chromium/src/stacktrace_config.h +++ b/third_party/tcmalloc/chromium/src/stacktrace_config.h @@ -46,8 +46,17 @@ #ifndef BASE_STACKTRACE_CONFIG_H_ #define BASE_STACKTRACE_CONFIG_H_ -// First, the i386 and x86_64 case. -#if (defined(__i386__) || defined(__x86_64__)) && __GNUC__ >= 2 +// First, the i386 case. +#if defined(__i386__) && __GNUC__ >= 2 +# if !defined(NO_FRAME_POINTER) +# define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h" +# define STACKTRACE_SKIP_CONTEXT_ROUTINES 1 +# else +# define STACKTRACE_INL_HEADER "stacktrace_generic-inl.h" +# endif + +// Now, the x86_64 case. +#elif defined(__x86_64__) && __GNUC__ >= 2 # if !defined(NO_FRAME_POINTER) # define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h" # define STACKTRACE_SKIP_CONTEXT_ROUTINES 1 diff --git a/third_party/tcmalloc/chromium/src/symbolize.cc b/third_party/tcmalloc/chromium/src/symbolize.cc index 6fe44b9..b7cdf0e 100644 --- a/third_party/tcmalloc/chromium/src/symbolize.cc +++ b/third_party/tcmalloc/chromium/src/symbolize.cc @@ -166,7 +166,7 @@ extern bool Symbolize(char *out, int out_size, return false; // make the symbolization_table values point to the output vector SymbolMap::iterator fill = symbolization_table->begin(); - const char *current_name = out; + char *current_name = out; for (int i = 0; i < total_bytes_read; i++) { if (out[i] == '\n') { fill->second = current_name; diff --git a/third_party/tcmalloc/chromium/src/symbolize.h b/third_party/tcmalloc/chromium/src/symbolize.h index 8fb0366..72196f6 100644 --- a/third_party/tcmalloc/chromium/src/symbolize.h +++ b/third_party/tcmalloc/chromium/src/symbolize.h @@ -33,10 +33,6 @@ #ifndef TCMALLOC_SYMBOLIZE_H_ #define TCMALLOC_SYMBOLIZE_H_ -#include "config.h" -#ifdef HAVE_STDINT_H -#include <stdint.h> // for uintptr_t -#endif #include <map> using std::map; @@ -46,7 +42,7 @@ static const int kSymbolSize = 1024; // TODO(glider): it's better to make SymbolMap a class that encapsulates the // address operations and has the Symbolize() method. -typedef map<uintptr_t, const char*> SymbolMap; +typedef map<uintptr_t, char*> SymbolMap; extern bool Symbolize(char *out, int out_size, SymbolMap *symbolization_table); diff --git a/third_party/tcmalloc/chromium/src/tests/malloc_extension_c_test.c b/third_party/tcmalloc/chromium/src/tests/malloc_extension_c_test.c index b6319a1..aad2d4b 100644 --- a/third_party/tcmalloc/chromium/src/tests/malloc_extension_c_test.c +++ b/third_party/tcmalloc/chromium/src/tests/malloc_extension_c_test.c @@ -108,7 +108,6 @@ void TestMallocExtension(void) { } MallocExtension_MarkThreadIdle(); MallocExtension_MarkThreadBusy(); - MallocExtension_ReleaseToSystem(1); MallocExtension_ReleaseFreeMemory(); if (MallocExtension_GetEstimatedAllocatedSize(10) < 10) { FAIL("GetEstimatedAllocatedSize returned a bad value (too small)"); diff --git a/third_party/tcmalloc/chromium/src/tests/pagemap_unittest.cc b/third_party/tcmalloc/chromium/src/tests/pagemap_unittest.cc index 83e76e2..dcf6c9a 100644 --- a/third_party/tcmalloc/chromium/src/tests/pagemap_unittest.cc +++ b/third_party/tcmalloc/chromium/src/tests/pagemap_unittest.cc @@ -113,53 +113,6 @@ void TestMap(int limit, bool limit_is_below_the_overflow_boundary) { } } -// REQUIRES: BITS==10, i.e., valid range is [0,1023]. -// Representations for different types will end up being: -// PageMap1: array[1024] -// PageMap2: array[32][32] -// PageMap3: array[16][16][4] -template <class Type> -void TestNext(const char* name) { - RAW_LOG(ERROR, "Running NextTest %s\n", name); - Type map(malloc); - char a, b, c, d, e; - - // When map is empty - CHECK(map.Next(0) == NULL); - CHECK(map.Next(5) == NULL); - CHECK(map.Next(1<<30) == NULL); - - // Add a single value - map.Ensure(40, 1); - map.set(40, &a); - CHECK(map.Next(0) == &a); - CHECK(map.Next(39) == &a); - CHECK(map.Next(40) == &a); - CHECK(map.Next(41) == NULL); - CHECK(map.Next(1<<30) == NULL); - - // Add a few values - map.Ensure(41, 1); - map.Ensure(100, 3); - map.set(41, &b); - map.set(100, &c); - map.set(101, &d); - map.set(102, &e); - CHECK(map.Next(0) == &a); - CHECK(map.Next(39) == &a); - CHECK(map.Next(40) == &a); - CHECK(map.Next(41) == &b); - CHECK(map.Next(42) == &c); - CHECK(map.Next(63) == &c); - CHECK(map.Next(64) == &c); - CHECK(map.Next(65) == &c); - CHECK(map.Next(99) == &c); - CHECK(map.Next(100) == &c); - CHECK(map.Next(101) == &d); - CHECK(map.Next(102) == &e); - CHECK(map.Next(103) == NULL); -} - int main(int argc, char** argv) { TestMap< TCMalloc_PageMap1<10> > (100, true); TestMap< TCMalloc_PageMap1<10> > (1 << 10, false); @@ -168,10 +121,6 @@ int main(int argc, char** argv) { TestMap< TCMalloc_PageMap3<20> > (100, true); TestMap< TCMalloc_PageMap3<20> > (1 << 20, false); - TestNext< TCMalloc_PageMap1<10> >("PageMap1"); - TestNext< TCMalloc_PageMap2<10> >("PageMap2"); - TestNext< TCMalloc_PageMap3<10> >("PageMap3"); - printf("PASS\n"); return 0; } diff --git a/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc b/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc index 1e72b2e..4b247c7 100644 --- a/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc +++ b/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc @@ -8,9 +8,8 @@ #include "profile-handler.h" #include <assert.h> -#include <pthread.h> #include <sys/time.h> -#include <time.h> +#include <pthread.h> #include "base/logging.h" #include "base/simple_mutex.h" @@ -47,11 +46,11 @@ class Thread { bool joinable_; }; -// timespec of the sleep interval. To ensure a SIGPROF timer interrupt under -// heavy load, this is set to a 20x of ProfileHandler timer interval (i.e 100Hz) +// Sleep interval in usecs. To ensure a SIGPROF timer interrupt under heavy +// load, this is set to a 20x of ProfileHandler timer interval (i.e 100Hz) // TODO(nabeelmian) Under very heavy loads, the worker thread may not accumulate // enough cpu usage to get a profile tick. -const struct timespec sleep_interval = { 0, 200000000 }; // 200 ms +int kSleepInterval = 200000; // Whether each thread has separate timers. static bool timer_separate_ = false; @@ -214,7 +213,7 @@ class ProfileHandlerTest { busy_worker_->Start(); // Wait for worker to start up and register with the ProfileHandler. // TODO(nabeelmian) This may not work under very heavy load. - nanosleep(&sleep_interval, NULL); + usleep(kSleepInterval); } // Stops the worker thread. @@ -258,7 +257,7 @@ class ProfileHandlerTest { uint64 interrupts_before = GetInterruptCount(); // Sleep for a bit and check that tick counter is making progress. int old_tick_count = tick_counter; - nanosleep(&sleep_interval, NULL); + usleep(kSleepInterval); int new_tick_count = tick_counter; EXPECT_GT(new_tick_count, old_tick_count); uint64 interrupts_after = GetInterruptCount(); @@ -269,7 +268,7 @@ class ProfileHandlerTest { void VerifyUnregistration(const int& tick_counter) { // Sleep for a bit and check that tick counter is not making progress. int old_tick_count = tick_counter; - nanosleep(&sleep_interval, NULL); + usleep(kSleepInterval); int new_tick_count = tick_counter; EXPECT_EQ(new_tick_count, old_tick_count); // If no callbacks, signal handler and shared timer should be disabled. @@ -298,7 +297,7 @@ class ProfileHandlerTest { } // Verify that the ProfileHandler is not accumulating profile ticks. uint64 interrupts_before = GetInterruptCount(); - nanosleep(&sleep_interval, NULL); + usleep(kSleepInterval); uint64 interrupts_after = GetInterruptCount(); EXPECT_EQ(interrupts_after, interrupts_before); } diff --git a/third_party/tcmalloc/chromium/src/tests/tcmalloc_unittest.cc b/third_party/tcmalloc/chromium/src/tests/tcmalloc_unittest.cc index 8eccb18..713fbe1 100644 --- a/third_party/tcmalloc/chromium/src/tests/tcmalloc_unittest.cc +++ b/third_party/tcmalloc/chromium/src/tests/tcmalloc_unittest.cc @@ -124,9 +124,6 @@ using std::vector; using std::string; -DECLARE_double(tcmalloc_release_rate); -DECLARE_int32(max_free_queue_size); // in debugallocation.cc - namespace testing { static const int FLAGS_numtests = 50000; @@ -750,127 +747,6 @@ static void TestHugeThreadCache() { delete[] array; } -namespace { - -struct RangeCallbackState { - uintptr_t ptr; - base::MallocRange::Type expected_type; - size_t min_size; - bool matched; -}; - -static void RangeCallback(void* arg, const base::MallocRange* r) { - RangeCallbackState* state = reinterpret_cast<RangeCallbackState*>(arg); - if (state->ptr >= r->address && - state->ptr < r->address + r->length) { - CHECK_EQ(r->type, state->expected_type); - CHECK_GE(r->length, state->min_size); - state->matched = true; - } -} - -// Check that at least one of the callbacks from Ranges() contains -// the specified address with the specified type, and has size -// >= min_size. -static void CheckRangeCallback(void* ptr, base::MallocRange::Type type, - size_t min_size) { - RangeCallbackState state; - state.ptr = reinterpret_cast<uintptr_t>(ptr); - state.expected_type = type; - state.min_size = min_size; - state.matched = false; - MallocExtension::instance()->Ranges(&state, RangeCallback); - CHECK(state.matched); -} - -} - -static void TestRanges() { - static const int MB = 1048576; - void* a = malloc(MB); - void* b = malloc(MB); - CheckRangeCallback(a, base::MallocRange::INUSE, MB); - CheckRangeCallback(b, base::MallocRange::INUSE, MB); - free(a); - CheckRangeCallback(a, base::MallocRange::FREE, MB); - CheckRangeCallback(b, base::MallocRange::INUSE, MB); - MallocExtension::instance()->ReleaseFreeMemory(); - CheckRangeCallback(a, base::MallocRange::UNMAPPED, MB); - CheckRangeCallback(b, base::MallocRange::INUSE, MB); - free(b); - CheckRangeCallback(a, base::MallocRange::UNMAPPED, MB); - CheckRangeCallback(b, base::MallocRange::FREE, MB); -} - -static size_t GetUnmappedBytes() { - size_t bytes; - CHECK(MallocExtension::instance()->GetNumericProperty( - "tcmalloc.pageheap_unmapped_bytes", &bytes)); - return bytes; -} - -static void TestReleaseToSystem() { - // Debug allocation mode adds overhead to each allocation which - // messes up all the equality tests here. I just disable the - // teset in this mode. TODO(csilvers): get it to work for debugalloc? -#ifndef DEBUGALLOCATION - const double old_tcmalloc_release_rate = FLAGS_tcmalloc_release_rate; - FLAGS_tcmalloc_release_rate = 0; - - static const int MB = 1048576; - void* a = malloc(MB); - void* b = malloc(MB); - MallocExtension::instance()->ReleaseFreeMemory(); - size_t starting_bytes = GetUnmappedBytes(); - - // Calling ReleaseFreeMemory() a second time shouldn't do anything. - MallocExtension::instance()->ReleaseFreeMemory(); - EXPECT_EQ(starting_bytes, GetUnmappedBytes()); - - // ReleaseToSystem shouldn't do anything either. - MallocExtension::instance()->ReleaseToSystem(MB); - EXPECT_EQ(starting_bytes, GetUnmappedBytes()); - - free(a); - - // Negative numbers should be ignored. - MallocExtension::instance()->ReleaseToSystem(-5); - EXPECT_EQ(starting_bytes, GetUnmappedBytes()); - - // The span to release should be 1MB. - MallocExtension::instance()->ReleaseToSystem(MB/2); - EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); - - // Should do nothing since the previous call released too much. - MallocExtension::instance()->ReleaseToSystem(MB/4); - EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); - - free(b); - - // Use up the extra MB/4 bytes from 'a' and also release 'b'. - MallocExtension::instance()->ReleaseToSystem(MB/2); - EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); - - // Should do nothing since the previous call released too much. - MallocExtension::instance()->ReleaseToSystem(MB/2); - EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); - - // Nothing else to release. - MallocExtension::instance()->ReleaseFreeMemory(); - EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); - - a = malloc(MB); - free(a); - EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); - - // Releasing less than a page should still trigger a release. - MallocExtension::instance()->ReleaseToSystem(1); - EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); - - FLAGS_tcmalloc_release_rate = old_tcmalloc_release_rate; -#endif // #ifndef DEBUGALLOCATION -} - static int RunAllTests(int argc, char** argv) { // Optional argv[1] is the seed AllocatorState rnd(argc > 1 ? atoi(argv[1]) : 100); @@ -1147,8 +1023,6 @@ static int RunAllTests(int argc, char** argv) { #endif TestHugeThreadCache(); - TestRanges(); - TestReleaseToSystem(); return 0; } @@ -1158,10 +1032,6 @@ static int RunAllTests(int argc, char** argv) { using testing::RunAllTests; int main(int argc, char** argv) { -#ifdef DEBUGALLOCATION // debug allocation takes forever for huge allocs - FLAGS_max_free_queue_size = 0; // return freed blocks to tcmalloc immediately -#endif - RunAllTests(argc, argv); // Test tc_version() |