15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Sanjay Ghemawat 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maxim Lifantsev (refactoring) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h> 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_UNISTD_H 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> // for write() 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> // for open() 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_GLOB_H 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <glob.h> 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef GLOB_NOMATCH // true on some old cygwins 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define GLOB_NOMATCH 0 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_INTTYPES_H 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <inttypes.h> // for PRIxPTR 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_POLL_H 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <poll.h> 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h> 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map> 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> // for sort(), equal(), and copy() 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "heap-profile-table.h" 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "raw_printer.h" 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "symbolize.h" 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/stacktrace.h> 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gperftools/malloc_hook.h> 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "memory_region_map.h" 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/commandlineflags.h" 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" // for the RawFD I/O commands 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sysinfo.h" 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::sort; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::equal; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::copy; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::map; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tcmalloc::FillProcSelfMaps; // from sysinfo.h 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using tcmalloc::DumpProcSelfMaps; // from sysinfo.h 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//---------------------------------------------------------------------- 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DEFINE_bool(cleanup_old_heap_profiles, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnvToBool("HEAP_PROFILE_CLEANUP", true), 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "At initialization time, delete old heap profiles."); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DEFINE_int32(heap_check_max_leaks, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnvToInt("HEAP_CHECK_MAX_LEAKS", 20), 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "The maximum number of leak reports to print."); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//---------------------------------------------------------------------- 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// header of the dumped heap profile 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kProfileHeader[] = "heap profile: "; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n"; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kTypeProfileStatsHeader[] = "type statistics:\n"; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(TYPE_PROFILING) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//---------------------------------------------------------------------- 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char HeapProfileTable::kFileExt[] = ".heap"; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//---------------------------------------------------------------------- 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kHashTableSize = 179999; // Size for bucket_table_. 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// GCC requires this declaration, but MSVC does not allow it. 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if !defined(COMPILER_MSVC) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*static*/ const int HeapProfileTable::kMaxStackDepth; 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//---------------------------------------------------------------------- 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We strip out different number of stack frames in debug mode 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// because less inlining happens in that case 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NDEBUG 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kStripFrames = 2; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kStripFrames = 3; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For sorting Stats or Buckets by in-use space 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool ByAllocatedSpace(HeapProfileTable::Stats* a, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::Stats* b) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return true iff "a" has more allocated space than "b" 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (a->alloc_size - a->free_size) > (b->alloc_size - b->free_size); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//---------------------------------------------------------------------- 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HeapProfileTable::HeapProfileTable(Allocator alloc, 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DeAllocator dealloc, 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool profile_mmap) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : alloc_(alloc), 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(dealloc), 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket_table_(NULL), 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile_mmap_(profile_mmap), 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_buckets_(0), 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_(NULL) { 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make a hash table for buckets. 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int table_bytes = kHashTableSize * sizeof(*bucket_table_); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket_table_ = static_cast<Bucket**>(alloc_(table_bytes)); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memset(bucket_table_, 0, table_bytes); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make an allocation map. 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_ = 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new(alloc_(sizeof(AllocationMap))) AllocationMap(alloc_, dealloc_); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Initialize. 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memset(&total_, 0, sizeof(total_)); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_buckets_ = 0; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HeapProfileTable::~HeapProfileTable() { 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Free the allocation map. 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->~AllocationMap(); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dealloc_(address_map_); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_ = NULL; 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Free the hash table. 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < kHashTableSize; i++) { 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (Bucket* curr = bucket_table_[i]; curr != 0; /**/) { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bucket* bucket = curr; 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) curr = curr->next; 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dealloc_(bucket->stack); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dealloc_(bucket); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) dealloc_(bucket_table_); 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket_table_ = NULL; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HeapProfileTable::Bucket* HeapProfileTable::GetBucket(int depth, 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const void* const key[]) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make hash-value 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t h = 0; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < depth; i++) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) h += reinterpret_cast<uintptr_t>(key[i]); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) h += h << 10; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) h ^= h >> 6; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) h += h << 3; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) h ^= h >> 11; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lookup stack trace in table 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int buck = ((unsigned int) h) % kHashTableSize; 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (Bucket* b = bucket_table_[buck]; b != 0; b = b->next) { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((b->hash == h) && 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (b->depth == depth) && 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) equal(key, key + depth, b->stack)) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return b; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create new bucket 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t key_size = sizeof(key[0]) * depth; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void** kcopy = reinterpret_cast<const void**>(alloc_(key_size)); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copy(key, key + depth, kcopy); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* b = reinterpret_cast<Bucket*>(alloc_(sizeof(Bucket))); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(b, 0, sizeof(*b)); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b->hash = h; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b->depth = depth; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b->stack = kcopy; 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) b->next = bucket_table_[buck]; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket_table_[buck] = b; 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_buckets_++; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return b; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HeapProfileTable::GetCallerStackTrace( 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int skip_count, void* stack[kMaxStackDepth]) { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MallocHook::GetCallerStackTrace( 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stack, kMaxStackDepth, kStripFrames + skip_count + 1); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::RecordAlloc( 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* ptr, size_t bytes, int stack_depth, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* const call_stack[]) { 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bucket* b = GetBucket(stack_depth, call_stack); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b->allocs++; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b->alloc_size += bytes; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_.allocs++; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_.alloc_size += bytes; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue v; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) v.set_bucket(b); // also did set_live(false); set_ignore(false) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) v.bytes = bytes; 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Insert(ptr, v); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::RecordFree(const void* ptr) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue v; 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (address_map_->FindAndRemove(ptr, &v)) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* b = v.bucket(); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b->frees++; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b->free_size += v.bytes; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_.frees++; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_.free_size += v.bytes; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HeapProfileTable::FindAlloc(const void* ptr, size_t* object_size) const { 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AllocValue* alloc_value = address_map_->Find(ptr); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (alloc_value != NULL) *object_size = alloc_value->bytes; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return alloc_value != NULL; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HeapProfileTable::FindAllocDetails(const void* ptr, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocInfo* info) const { 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AllocValue* alloc_value = address_map_->Find(ptr); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (alloc_value != NULL) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->object_size = alloc_value->bytes; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->call_stack = alloc_value->bucket()->stack; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->stack_depth = alloc_value->bucket()->depth; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return alloc_value != NULL; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HeapProfileTable::FindInsideAlloc(const void* ptr, 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t max_size, 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void** object_ptr, 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t* object_size) const { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AllocValue* alloc_value = 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->FindInside(&AllocValueSize, max_size, ptr, object_ptr); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (alloc_value != NULL) *object_size = alloc_value->bytes; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return alloc_value != NULL; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HeapProfileTable::MarkAsLive(const void* ptr) { 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AllocValue* alloc = address_map_->FindMutable(ptr); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (alloc && !alloc->live()) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alloc->set_live(true); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::MarkAsIgnored(const void* ptr) { 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AllocValue* alloc = address_map_->FindMutable(ptr); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (alloc) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alloc->set_ignore(true); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::IterateAllocationAddresses(AddressIterator f, 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* data) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AllocationAddressIteratorArgs args(f, data); 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate<const AllocationAddressIteratorArgs&>( 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocationAddressesIterator, args); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::MarkCurrentAllocations(AllocationMark mark) { 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MarkArgs args(mark, true); 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate<const MarkArgs&>(MarkIterator, args); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::MarkUnmarkedAllocations(AllocationMark mark) { 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const MarkArgs args(mark, false); 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate<const MarkArgs&>(MarkIterator, args); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We'd be happier using snprintfer, but we don't to reduce dependencies. 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HeapProfileTable::UnparseBucket(const Bucket& b, 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* buf, int buflen, int bufsize, 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* extra, 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stats* profile_stats) { 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile_stats != NULL) { 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_stats->allocs += b.allocs; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_stats->alloc_size += b.alloc_size; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_stats->frees += b.frees; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_stats->free_size += b.free_size; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int printed = 313558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch snprintf(buf + buflen, bufsize - buflen, 314558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "%6d: %8" PRId64 " [%6d: %8" PRId64 "] @%s", 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.allocs - b.frees, 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.alloc_size - b.free_size, 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.allocs, 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.alloc_size, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it looks like the snprintf failed, ignore the fact we printed anything 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (printed < 0 || printed >= bufsize - buflen) return buflen; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buflen += printed; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int d = 0; d < b.depth; d++) { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printed = snprintf(buf + buflen, bufsize - buflen, " 0x%08" PRIxPTR, 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<uintptr_t>(b.stack[d])); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (printed < 0 || printed >= bufsize - buflen) return buflen; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buflen += printed; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printed = snprintf(buf + buflen, bufsize - buflen, "\n"); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (printed < 0 || printed >= bufsize - buflen) return buflen; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buflen += printed; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return buflen; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HeapProfileTable::Bucket** 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HeapProfileTable::MakeSortedBucketList() const { 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bucket** list = static_cast<Bucket**>(alloc_(sizeof(Bucket) * num_buckets_)); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bucket_count = 0; 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < kHashTableSize; i++) { 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (Bucket* curr = bucket_table_[i]; curr != 0; curr = curr->next) { 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) list[bucket_count++] = curr; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RAW_DCHECK(bucket_count == num_buckets_, ""); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort(list, list + num_buckets_, ByAllocatedSpace); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return list; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::DumpMarkedObjects(AllocationMark mark, 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* file_name) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd = RawOpenForWriting(file_name); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd == kIllegalRawFD) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "Failed dumping live objects to %s", file_name); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpMarkedArgs args(fd, mark); 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate<const DumpMarkedArgs&>(DumpMarkedIterator, args); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawClose(fd); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::DumpTypeStatistics(const char* file_name) const { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd = RawOpenForWriting(file_name); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd == kIllegalRawFD) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "Failed dumping type statistics to %s", file_name); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddressMap<TypeCount>* type_size_map; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_size_map = new(alloc_(sizeof(AddressMap<TypeCount>))) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddressMap<TypeCount>(alloc_, dealloc_); 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate(TallyTypesItererator, type_size_map); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, kTypeProfileStatsHeader, strlen(kTypeProfileStatsHeader)); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpArgs args(fd, NULL); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_size_map->Iterate<const DumpArgs&>(DumpTypesIterator, args); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawClose(fd); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_size_map->~AddressMap<TypeCount>(); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(type_size_map); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(TYPE_PROFILING) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::IterateOrderedAllocContexts( 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocContextIterator callback) const { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket** list = MakeSortedBucketList(); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocContextInfo info; 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < num_buckets_; ++i) { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *static_cast<Stats*>(&info) = *static_cast<Stats*>(list[i]); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.stack_depth = list[i]->depth; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.call_stack = list[i]->stack; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback(info); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(list); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HeapProfileTable::FillOrderedProfile(char buf[], int size) const { 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket** list = MakeSortedBucketList(); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Our file format is "bucket, bucket, ..., bucket, proc_self_maps_info". 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In the cases buf is too small, we'd rather leave out the last 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // buckets than leave out the /proc/self/maps info. To ensure that, 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we actually print the /proc/self/maps info first, then move it to 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the end of the buffer, then write the bucket info into whatever 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is remaining, and then move the maps info one last time to close 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // any gaps. Whew! 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int map_length = snprintf(buf, size, "%s", kProcSelfMapsHeader); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (map_length < 0 || map_length >= size) return 0; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool dummy; // "wrote_all" -- did /proc/self/maps fit in its entirety? 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map_length += FillProcSelfMaps(buf + map_length, size - map_length, &dummy); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(map_length <= size, ""); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* const map_start = buf + size - map_length; // move to end 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memmove(map_start, buf, map_length); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size -= map_length; 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stats stats; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&stats, 0, sizeof(stats)); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bucket_length = snprintf(buf, size, "%s", kProfileHeader); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bucket_length < 0 || bucket_length >= size) return 0; 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket_length = UnparseBucket(total_, buf, bucket_length, size, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " heapprofile", &stats); 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Dump the mmap list first. 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (profile_mmap_) { 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BufferArgs buffer(buf, bucket_length, size); 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MemoryRegionMap::IterateBuckets<BufferArgs*>(DumpBucketIterator, &buffer); 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bucket_length = buffer.buflen; 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < num_buckets_; i++) { 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bucket_length = UnparseBucket(*list[i], buf, bucket_length, size, "", 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &stats); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(bucket_length < size, ""); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(list); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(buf + bucket_length <= map_start, ""); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memmove(buf + bucket_length, map_start, map_length); // close the gap 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bucket_length + map_length; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HeapProfileTable::DumpBucketIterator(const Bucket* bucket, 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BufferArgs* args) { 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args->buflen = UnparseBucket(*bucket, args->buf, args->buflen, args->bufsize, 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "", NULL); 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::TallyTypesItererator( 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* ptr, 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* value, 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddressMap<TypeCount>* type_size_map) { 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::type_info* type = LookupType(ptr); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* key = NULL; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = type->name(); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeCount* count = type_size_map->FindMutable(key); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (count) { 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count->bytes += value->bytes; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++count->objects; 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_size_map->Insert(key, TypeCount(value->bytes, 1)); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::DumpTypesIterator(const void* ptr, 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeCount* count, 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpArgs& args) { 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[1024]; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len; 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* mangled_type_name = static_cast<const char*>(ptr); 482558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch len = snprintf(buf, sizeof(buf), "%6d: %8" PRId64 " @ %s\n", 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count->objects, count->bytes, 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mangled_type_name ? mangled_type_name : "(no_typeinfo)"); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(args.fd, buf, len); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(TYPE_PROFILING) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::DumpNonLiveIterator(const void* ptr, AllocValue* v, 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpArgs& args) { 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (v->live()) { 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) v->set_live(false); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (v->ignore()) { 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket b; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&b, 0, sizeof(b)); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.allocs = 1; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.alloc_size = v->bytes; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.depth = v->bucket()->depth; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.stack = v->bucket()->stack; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[1024]; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = UnparseBucket(b, buf, 0, sizeof(buf), "", args.profile_stats); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(args.fd, buf, len); 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::DumpMarkedIterator(const void* ptr, AllocValue* v, 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpMarkedArgs& args) { 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (v->mark() != args.mark) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket b; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&b, 0, sizeof(b)); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.allocs = 1; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.alloc_size = v->bytes; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.depth = v->bucket()->depth; 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b.stack = v->bucket()->stack; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char addr[16]; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(addr, 16, "0x%08" PRIxPTR, ptr); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[1024]; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = UnparseBucket(b, buf, 0, sizeof(buf), addr, NULL); 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(args.fd, buf, len); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::AllocationAddressesIterator( 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* ptr, 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* v, 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AllocationAddressIteratorArgs& args) { 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args.callback(args.data, ptr); 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::MarkIterator(const void* ptr, AllocValue* v, 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MarkArgs& args) { 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!args.mark_all && v->mark() != UNMARKED) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) v->set_mark(args.mark); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback from NonLiveSnapshot; adds entry to arg->dest 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if not the entry is not live and is not present in arg->base. 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::AddIfNonLive(const void* ptr, AllocValue* v, 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddNonLiveArgs* arg) { 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (v->live()) { 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) v->set_live(false); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (arg->base != NULL && arg->base->map_.Find(ptr) != NULL) { 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Present in arg->base, so do not save 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arg->dest->Add(ptr, *v); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HeapProfileTable::WriteProfile(const char* file_name, 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Bucket& total, 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocationMap* allocations) { 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_VLOG(1, "Dumping non-live heap profile to %s", file_name); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd = RawOpenForWriting(file_name); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd == kIllegalRawFD) { 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "Failed dumping filtered heap profile to %s", file_name); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, kProfileHeader, strlen(kProfileHeader)); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[512]; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int len = UnparseBucket(total, buf, 0, sizeof(buf), " heapprofile", 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, buf, len); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DumpArgs args(fd, NULL); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocations->Iterate<const DumpArgs&>(DumpNonLiveIterator, args); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, kProcSelfMapsHeader, strlen(kProcSelfMapsHeader)); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DumpProcSelfMaps(fd); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawClose(fd); 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::CleanupOldProfiles(const char* prefix) { 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!FLAGS_cleanup_old_heap_profiles) 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf[1000]; 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(buf, 1000,"%s.%05d.", prefix, getpid()); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string pattern = string(buf) + ".*" + kFileExt; 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(HAVE_GLOB_H) 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) glob_t g; 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int r = glob(pattern.c_str(), GLOB_ERR, NULL, &g); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (r == 0 || r == GLOB_NOMATCH) { 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int prefix_length = strlen(prefix); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < g.gl_pathc; i++) { 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* fname = g.gl_pathv[i]; 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((strlen(fname) >= prefix_length) && 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (memcmp(fname, prefix, prefix_length) == 0)) { 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_VLOG(1, "Removing old heap profile %s", fname); 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unlink(fname); 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) globfree(&g); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else /* HAVE_GLOB_H */ 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(WARNING, "Unable to remove old heap profiles (can't run glob())"); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HeapProfileTable::Snapshot* HeapProfileTable::TakeSnapshot() { 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* s = new (alloc_(sizeof(Snapshot))) Snapshot(alloc_, dealloc_); 6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate(AddToSnapshot, s); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return s; 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::ReleaseSnapshot(Snapshot* s) { 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s->~Snapshot(); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(s); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback from TakeSnapshot; adds a single entry to snapshot 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::AddToSnapshot(const void* ptr, AllocValue* v, 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* snapshot) { 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snapshot->Add(ptr, *v); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HeapProfileTable::Snapshot* HeapProfileTable::NonLiveSnapshot( 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* base) { 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_VLOG(2, "NonLiveSnapshot input: %d %d\n", 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(total_.allocs - total_.frees), 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(total_.alloc_size - total_.free_size)); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Snapshot* s = new (alloc_(sizeof(Snapshot))) Snapshot(alloc_, dealloc_); 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddNonLiveArgs args; 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args.dest = s; 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) args.base = base; 6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) address_map_->Iterate<AddNonLiveArgs*>(AddIfNonLive, &args); 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_VLOG(2, "NonLiveSnapshot output: %d %d\n", 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(s->total_.allocs - s->total_.frees), 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int(s->total_.alloc_size - s->total_.free_size)); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return s; 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Information kept per unique bucket seen 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct HeapProfileTable::Snapshot::Entry { 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bytes; 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Entry() : count(0), bytes(0) { } 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Order by decreasing bytes 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool operator<(const Entry& x) const { 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this->bytes > x.bytes; 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// State used to generate leak report. We keep a mapping from Bucket pointer 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the collected stats for that bucket. 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct HeapProfileTable::Snapshot::ReportState { 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map<Bucket*, Entry> buckets_; 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback from ReportLeaks; updates ReportState. 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::Snapshot::ReportCallback(const void* ptr, 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* v, 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReportState* state) { 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Entry* e = &state->buckets_[v->bucket()]; // Creates empty Entry first time 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e->bucket = v->bucket(); 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e->count++; 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e->bytes += v->bytes; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::Snapshot::ReportLeaks(const char* checker_name, 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* filename, 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_symbolize) { 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is only used by the heap leak checker, but is intimately 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tied to the allocation map that belongs in this module and is 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // therefore placed here. 677558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch RAW_LOG(ERROR, "Leak check %s detected leaks of %" PRIuS " bytes " 678558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "in %" PRIuS " objects", 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) checker_name, 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t(total_.alloc_size), 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t(total_.allocs)); 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Group objects by Bucket 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReportState state; 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map_.Iterate(&ReportCallback, &state); 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sort buckets by decreasing leaked size 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int n = state.buckets_.size(); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Entry* entries = new Entry[n]; 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int dst = 0; 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (map<Bucket*,Entry>::const_iterator iter = state.buckets_.begin(); 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter != state.buckets_.end(); 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++iter) { 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entries[dst++] = iter->second; 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sort(entries, entries + n); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Report a bounded number of leaks to keep the leak report from 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // growing too long. 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int to_report = 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (FLAGS_heap_check_max_leaks > 0 && 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) n > FLAGS_heap_check_max_leaks) ? FLAGS_heap_check_max_leaks : n; 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "The %d largest leaks:", to_report); 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Print 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SymbolTable symbolization_table; 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < to_report; i++) { 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Entry& e = entries[i]; 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int j = 0; j < e.bucket->depth; j++) { 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) symbolization_table.Add(e.bucket->stack[j]); 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kBufSize = 2<<10; 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buffer[kBufSize]; 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (should_symbolize) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) symbolization_table.Symbolize(); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < to_report; i++) { 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Entry& e = entries[i]; 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::RawPrinter printer(buffer, kBufSize); 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printer.Printf("Leak of %d bytes in %d objects allocated from:\n", 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e.bytes, e.count); 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int j = 0; j < e.bucket->depth; j++) { 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* pc = e.bucket->stack[j]; 724558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch printer.Printf("\t@ %" PRIxPTR " %s\n", 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<uintptr_t>(pc), symbolization_table.GetSymbol(pc)); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "%s", buffer); 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (to_report < n) { 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "Skipping leaks numbered %d..%d", 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_report, n-1); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete[] entries; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO: Dump the sorted Entry list instead of dumping raw data? 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (should be much shorter) 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HeapProfileTable::WriteProfile(filename, total_, &map_)) { 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(ERROR, "Could not write pprof profile to %s", filename); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::Snapshot::ReportObject(const void* ptr, 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* v, 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* unused) { 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Perhaps also log the allocation stack trace (unsymbolized) 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on this line in case somebody finds it useful. 748558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch RAW_LOG(ERROR, "leaked %" PRIuS " byte object %p", v->bytes, ptr); 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HeapProfileTable::Snapshot::ReportIndividualObjects() { 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char unused; 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map_.Iterate(ReportObject, &unused); 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755