deep-heap-profile.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --- 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Sainbayar Sukhbaatar 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Dai Mikurube 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "deep-heap-profile.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifdef USE_DEEP_HEAP_PROFILE 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h> 17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include <time.h> 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_UNISTD_H 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> // for getpagesize and getpid 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // HAVE_UNISTD_H 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/cycleclock.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sysinfo.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "internal_logging.h" // for ASSERT, etc 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kProfilerBufferSize = 1 << 20; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHashTableSize = 179999; // Same as heap-profile-table.cc. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int PAGEMAP_BYTES = 8; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const uint64 MAX_ADDRESS = kuint64max; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tag strings in heap profile dumps. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kProfileHeader[] = "heap profile: "; 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char kProfileVersion[] = "DUMP_DEEP_6"; 35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static const char kMetaInformationHeader[] = "META:\n"; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char kMMapListHeader[] = "MMAP_LIST:\n"; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kGlobalStatsHeader[] = "GLOBAL_STATS:\n"; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kStacktraceHeader[] = "STACKTRACES:\n"; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n"; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kVirtualLabel[] = "virtual"; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kCommittedLabel[] = "committed"; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implements MemoryResidenceInfoGetterInterface for Linux. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemoryInfoGetterLinux : 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public DeepHeapProfile::MemoryResidenceInfoGetterInterface { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryInfoGetterLinux(): fd_(kIllegalRawFD) {} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~MemoryInfoGetterLinux() {} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Opens /proc/<pid>/pagemap and stores its file descriptor. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It keeps open while the process is running. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that file descriptors need to be refreshed after fork. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Initialize(); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns the number of resident (including swapped) bytes of the given 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // memory region from |first_address| to |last_address| inclusive. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual size_t CommittedSize(uint64 first_address, uint64 last_address) const; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct State { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_committed; // Currently, we use only this 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_present; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_swapped; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_shared; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_mmap; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Seeks to the offset of the open pagemap file. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It returns true if succeeded. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Seek(uint64 address) const; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reads a pagemap state from the current offset. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It returns true if succeeded. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool Read(State* state) const; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd_; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryInfoGetterLinux::Initialize() { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char filename[100]; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(filename, sizeof(filename), "/proc/%d/pagemap", 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(getpid())); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd_ = open(filename, O_RDONLY); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(fd_ != -1, "Failed to open /proc/self/pagemap"); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t MemoryInfoGetterLinux::CommittedSize( 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 first_address, uint64 last_address) const { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int page_size = getpagesize(); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 page_address = (first_address / page_size) * page_size; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t committed_size = 0; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Seek(first_address); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check every page on which the allocation resides. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (page_address <= last_address) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read corresponding physical page. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) State state; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmikurube): Read pagemap in bulk for speed. 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dmikurube): Consider using mincore(2). 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Read(&state) == false) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can't read the last region (e.g vsyscall). 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(0, "pagemap read failed @ %#llx %"PRId64" bytes", 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first_address, last_address - first_address + 1); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.is_committed) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate the size of the allocation part in this page. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t bytes = page_size; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If looking at the last page in a given region. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_address <= page_address - 1 + page_size) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes = last_address - page_address + 1; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If looking at the first page in a given region. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_address < first_address) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes -= first_address - page_address; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) committed_size += bytes; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_address > MAX_ADDRESS - page_size) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_address += page_size; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return committed_size; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryInfoGetterLinux::Seek(uint64 address) const { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 index = (address / getpagesize()) * PAGEMAP_BYTES; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 offset = lseek64(fd_, index, SEEK_SET); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(offset == index, "Failed in seeking."); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return offset >= 0; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryInfoGetterLinux::Read(State* state) const { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 U64_1 = 1; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PFN_FILTER = (U64_1 << 55) - U64_1; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PAGE_PRESENT = U64_1 << 63; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PAGE_SWAP = U64_1 << 62; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PAGE_RESERVED = U64_1 << 61; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 FLAG_NOPAGE = U64_1 << 20; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 FLAG_KSM = U64_1 << 21; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 FLAG_MMAP = U64_1 << 11; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 pagemap_value; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int result = read(fd_, &pagemap_value, PAGEMAP_BYTES); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != PAGEMAP_BYTES) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the page is committed. 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_committed = (pagemap_value & (PAGE_PRESENT | PAGE_SWAP)); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_present = (pagemap_value & PAGE_PRESENT); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_swapped = (pagemap_value & PAGE_SWAP); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_shared = false; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(__linux__) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // anonymous namespace 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::MemoryResidenceInfoGetterInterface:: 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryResidenceInfoGetterInterface() {} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::MemoryResidenceInfoGetterInterface:: 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MemoryResidenceInfoGetterInterface() {} 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::MemoryResidenceInfoGetterInterface* 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepHeapProfile::MemoryResidenceInfoGetterInterface::Create() { 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new MemoryInfoGetterLinux(); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* prefix) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : memory_residence_info_getter_( 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryResidenceInfoGetterInterface::Create()), 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) most_recent_pid_(-1), 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats_(), 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dump_count_(0), 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_prefix_(NULL), 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiler_buffer_(NULL), 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_(kHashTableSize, heap_profile->alloc_, heap_profile->dealloc_), 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_profile_(heap_profile) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy filename prefix. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int prefix_length = strlen(prefix); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_prefix_ = 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<char*>(heap_profile_->alloc_(prefix_length + 1)); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(filename_prefix_, prefix, prefix_length); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_prefix_[prefix_length] = '\0'; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiler_buffer_ = 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<char*>(heap_profile_->alloc_(kProfilerBufferSize)); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::~DeepHeapProfile() { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_profile_->dealloc_(profiler_buffer_); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_profile_->dealloc_(filename_prefix_); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete memory_residence_info_getter_; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Global malloc() should not be used in this function. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use LowLevelAlloc if required. 22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int DeepHeapProfile::FillOrderedProfile(const char* reason, 22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char raw_buffer[], 22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int buffer_size) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextBuffer buffer(raw_buffer, buffer_size); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextBuffer global_buffer(profiler_buffer_, kProfilerBufferSize); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 starting_cycles = CycleClock::Now(); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 232b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 23390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Get the time before starting snapshot. 23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // TODO(dmikurube): Consider gettimeofday if available. 235b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) time_t time_value = time(NULL); 236b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++dump_count_; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Re-open files in /proc/pid/ if the process is newly forked one. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (most_recent_pid_ != getpid()) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) most_recent_pid_ = getpid(); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memory_residence_info_getter_->Initialize(); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_.ResetIsLogged(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write maps into "|filename_prefix_|.<pid>.maps". 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WriteProcMaps(filename_prefix_, kProfilerBufferSize, profiler_buffer_); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset committed sizes of buckets. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_.ResetCommittedSize(); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Record committed sizes. 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stats_.SnapshotAllocations(this); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // glibc's snprintf internally allocates memory by alloca normally, but it 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocates memory by malloc if large memory is required. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kProfileHeader, 0); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kProfileVersion, 0); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString("\n", 0); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 264b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Fill buffer with meta information. 265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer.AppendString(kMetaInformationHeader, 0); 266b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 267b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer.AppendString("Time: ", 0); 26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendUnsignedLong(time_value, 0); 269b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer.AppendChar('\n'); 270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (reason != NULL) { 27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendString("Reason: ", 0); 27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendString(reason, 0); 27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendChar('\n'); 27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fill buffer with the global stats. 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer.AppendString(kMMapListHeader, 0); 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stats_.SnapshotMaps(memory_residence_info_getter_, this, &buffer); 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Fill buffer with the global stats. 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kGlobalStatsHeader, 0); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats_.Unparse(&buffer); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kStacktraceHeader, 0); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kVirtualLabel, 10); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendChar(' '); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kCommittedLabel, 10); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString("\n", 0); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fill buffer. 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_.UnparseForStats(&buffer); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(buffer.FilledBytes() < buffer_size, ""); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write the bucket listing into a .bucket file. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_.WriteForBucketFile(filename_prefix_, dump_count_, &global_buffer); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 elapsed_cycles = CycleClock::Now() - starting_cycles; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double elapsed_seconds = elapsed_cycles / CyclesPerSecond(); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(0, "Time spent on DeepProfiler: %.3f sec\n", elapsed_seconds); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return buffer.FilledBytes(); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DeepHeapProfile::TextBuffer::Size() { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return size_; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DeepHeapProfile::TextBuffer::FilledBytes() { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cursor_; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::TextBuffer::Clear() { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cursor_ = 0; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::TextBuffer::Write(RawFD fd) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, buffer_, cursor_); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dmikurube): These Append* functions should not use snprintf. 32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendChar(char value) { 32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return ForwardCursor(snprintf(buffer_ + cursor_, size_ - cursor_, 32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "%c", value)); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendString(const char* value, int width) { 33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%s", value); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*s", 34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) width, value); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendInt(int value, int width, 34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool leading_zero) { 34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%d", value); 351b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else if (leading_zero) 35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%0*d", width, value); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*d", width, value); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendLong(long value, int width) { 35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 36090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%ld", value); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*ld", width, value); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendUnsignedLong(unsigned long value, 37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int width) { 37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%lu", value); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*lu", width, value); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendInt64(int64 value, int width) { 38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 38390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 38590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%"PRId64, value); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*"PRId64, width, value); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendPtr(uint64 value, int width) { 39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%"PRIx64, value); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%0*"PRIx64, width, value); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DeepHeapProfile::TextBuffer::ForwardCursor(int appended) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (appended < 0 || appended >= size_ - cursor_) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cursor_ += appended; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucket::UnparseForStats(TextBuffer* buffer) { 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendInt64(bucket->alloc_size - bucket->free_size, 10); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendInt64(committed_size, 10); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 415b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(bucket->allocs, 6, false); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 417b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(bucket->frees, 6, false); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" @ ", 0); 419b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(id, 0, false); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucket::UnparseForBucketFile(TextBuffer* buffer) { 424b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(id, 0, false); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(is_mmap ? "mmap" : "malloc", 0); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" t0x", 0); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendPtr(reinterpret_cast<uintptr_t>(type), 0); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == NULL) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" nno_typeinfo", 0); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" n", 0); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(type->name(), 0); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int depth = 0; depth < bucket->depth; depth++) { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" 0x", 0); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendPtr(reinterpret_cast<uintptr_t>(bucket->stack[depth]), 8); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepBucketTable::DeepBucketTable( 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int table_size, 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::Allocator alloc, 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::DeAllocator dealloc) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : table_(NULL), 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_size_(table_size), 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alloc_(alloc), 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(dealloc), 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bucket_id_(0) { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int bytes = table_size * sizeof(DeepBucket*); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_ = reinterpret_cast<DeepBucket**>(alloc(bytes)); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(table_, 0, bytes); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepBucketTable::~DeepBucketTable() { 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(table_ != NULL); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int db = 0; db < table_size_; db++) { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* x = table_[db]; x != 0; /**/) { 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* db = x; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x = x->next; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(db); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(table_); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepBucket* DeepHeapProfile::DeepBucketTable::Lookup( 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket, 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::type_info* type, 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_mmap) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make hash-value 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t h = 0; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(reinterpret_cast<uintptr_t>(bucket), &h); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_mmap) { 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(1, &h); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(0, &h); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == NULL) { 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(0, &h); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(reinterpret_cast<uintptr_t>(type->name()), &h); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FinishHashValue(&h); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lookup stack trace in table 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int buck = ((unsigned int) h) % table_size_; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* db = table_[buck]; db != 0; db = db->next) { 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (db->bucket == bucket) { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return db; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a new bucket 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* db = reinterpret_cast<DeepBucket*>(alloc_(sizeof(DeepBucket))); 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(db, 0, sizeof(*db)); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->bucket = bucket; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->type = type; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->committed_size = 0; 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->is_mmap = is_mmap; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->id = (bucket_id_++); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->is_logged = false; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->next = table_[buck]; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_[buck] = db; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return db; 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::UnparseForStats(TextBuffer* buffer) { 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket = deep_bucket->bucket; 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bucket->alloc_size - bucket->free_size == 0) { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Skip empty buckets. 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->UnparseForStats(buffer); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::WriteForBucketFile( 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* prefix, int dump_count, TextBuffer* buffer) { 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char filename[100]; 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(filename, sizeof(filename), 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%s.%05d.%04d.buckets", prefix, getpid(), dump_count); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd = RawOpenForWriting(filename); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(fd != kIllegalRawFD, ""); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket = deep_bucket->bucket; 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (deep_bucket->is_logged) { 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Skip the bucket if it is already logged. 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bucket->alloc_size - bucket->free_size <= 64) { 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Skip small buckets. 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->UnparseForBucketFile(buffer); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->is_logged = true; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write to file if buffer 80% full. 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buffer->FilledBytes() > buffer->Size() * 0.8) { 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->Write(fd); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->Clear(); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->Write(fd); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawClose(fd); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::ResetCommittedSize() { 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->committed_size = 0; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::ResetIsLogged() { 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->is_logged = false; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This hash function is from HeapProfileTable::GetBucket. 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::AddToHashValue( 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t add, uintptr_t* hash_value) { 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value += add; 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value += *hash_value << 10; 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value ^= *hash_value >> 6; 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This hash function is from HeapProfileTable::GetBucket. 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::FinishHashValue(uintptr_t* hash_value) { 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value += *hash_value << 3; 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value ^= *hash_value >> 11; 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::RegionStats::Initialize() { 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual_bytes_ = 0; 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) committed_bytes_ = 0; 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)uint64 DeepHeapProfile::RegionStats::Record( 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 first_address, 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 last_address) { 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64 committed; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual_bytes_ += static_cast<size_t>(last_address - first_address + 1); 6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) committed = memory_residence_info_getter->CommittedSize(first_address, 6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_address); 6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) committed_bytes_ += committed; 6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return committed; 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::RegionStats::Unparse(const char* name, 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextBuffer* buffer) { 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(name, 25); 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendLong(virtual_bytes_, 12); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendLong(committed_bytes_, 12); 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Snapshots all virtual memory mappging stats by merging mmap(2) records from 636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// MemoryRegionMap and /proc/maps, the OS-level memory mapping information. 637c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Memory regions described in /proc/maps, but which are not created by mmap, 638c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// are accounted as "unhooked" memory regions. 639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This function assumes that every memory region created by mmap is covered 641c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// by VMA(s) described in /proc/maps except for http://crbug.com/189114. 642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Note that memory regions created with mmap don't align with borders of VMAs 643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// in /proc/maps. In other words, a memory region by mmap can cut across many 644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// VMAs. Also, of course a VMA can include many memory regions by mmap. 645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// It means that the following situation happens: 646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// => Virtual address 648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// <----- VMA #1 -----><----- VMA #2 ----->...<----- VMA #3 -----><- VMA #4 -> 649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ..< mmap #1 >.<- mmap #2 -><- mmap #3 ->...<- mmap #4 ->..<-- mmap #5 -->.. 650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// It can happen easily as permission can be changed by mprotect(2) for a part 652c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// of a memory region. A change in permission splits VMA(s). 653c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 654c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// To deal with the situation, this function iterates over MemoryRegionMap and 655c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// /proc/maps independently. The iterator for MemoryRegionMap is initialized 656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// at the top outside the loop for /proc/maps, and it goes forward inside the 657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// loop while comparing their addresses. 658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. 6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DeepHeapProfile::GlobalStats::SnapshotMaps( 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DeepHeapProfile* deep_profile, 6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TextBuffer* mmap_dump_buffer) { 6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MemoryRegionMap::LockHolder lock_holder; 6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcMapsIterator::Buffer procmaps_iter_buffer; 6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcMapsIterator procmaps_iter(0, &procmaps_iter_buffer); 667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint64 vma_start_addr, vma_last_addr, offset; 6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int64 inode; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* flags; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* filename; 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum MapsRegionType type; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[i].Initialize(); 6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[i].Initialize(); 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profiled_mmap_.Initialize(); 6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MemoryRegionMap::RegionIterator mmap_iter = 6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MemoryRegionMap::BeginRegionLocked(); 680b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DeepBucket* deep_bucket = NULL; 681b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (mmap_iter != MemoryRegionMap::EndRegionLocked()) { 682b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) deep_bucket = GetInformationOfMemoryRegion( 683b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) mmap_iter, memory_residence_info_getter, deep_profile); 684b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) while (procmaps_iter.Next(&vma_start_addr, &vma_last_addr, 6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &flags, &offset, &inode, &filename)) { 6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_dump_buffer) { 6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char buffer[1024]; 6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int written = procmaps_iter.FormatLine(buffer, sizeof(buffer), 691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) vma_start_addr, vma_last_addr, 692c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) flags, offset, inode, filename, 0); 6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(buffer, 0); 6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 696c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // 'vma_last_addr' should be the last inclusive address of the region. 697c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) vma_last_addr -= 1; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strcmp("[vsyscall]", filename) == 0) { 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Reading pagemap will fail in [vsyscall]. 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = ABSENT; 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename[0] == '/') { 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags[2] == 'x') 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = FILE_EXEC; 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = FILE_NONEXEC; 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (filename[0] == '\0' || filename[0] == '\n') { 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = ANONYMOUS; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (strcmp(filename, "[stack]") == 0) { 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = STACK; 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = OTHER; 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[type].Record( 716c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) memory_residence_info_getter, vma_start_addr, vma_last_addr); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmikurube): Stop double-counting pagemap. 7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (MemoryRegionMap::IsRecordingLocked()) { 720c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint64 cursor = vma_start_addr; 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool first = true; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 723c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Iterates over MemoryRegionMap until the iterator moves out of the VMA. 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!first) { 7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cursor = mmap_iter->end_addr; 7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++mmap_iter; 7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't break here even if mmap_iter == EndRegionLocked(). 729c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 730c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (mmap_iter != MemoryRegionMap::EndRegionLocked()) { 731c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deep_bucket = GetInformationOfMemoryRegion( 732c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter, memory_residence_info_getter, deep_profile); 733c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first = false; 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64 last_address_of_unhooked; 738c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If the next mmap entry is away from the current VMA. 7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_iter == MemoryRegionMap::EndRegionLocked() || 740c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->start_addr > vma_last_addr) { 741c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) last_address_of_unhooked = vma_last_addr; 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_address_of_unhooked = mmap_iter->start_addr - 1; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (last_address_of_unhooked + 1 > cursor) { 747c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RAW_CHECK(cursor >= vma_start_addr, 7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Wrong calculation for unhooked"); 749c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RAW_CHECK(last_address_of_unhooked <= vma_last_addr, 7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Wrong calculation for unhooked"); 7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64 committed_size = unhooked_[type].Record( 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memory_residence_info_getter, 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cursor, 7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_address_of_unhooked); 7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_dump_buffer) { 7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" ", 0); 7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(cursor, 0); 7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" - ", 0); 7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(last_address_of_unhooked + 1, 0); 7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" unhooked ", 0); 7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendInt64(committed_size, 0); 76290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendString(" / ", 0); 76390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendInt64( 76490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) last_address_of_unhooked - cursor + 1, 0); 7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString("\n", 0); 7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cursor = last_address_of_unhooked + 1; 7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_iter != MemoryRegionMap::EndRegionLocked() && 771c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->start_addr <= vma_last_addr && 7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer) { 773c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool trailing = mmap_iter->start_addr < vma_start_addr; 774c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool continued = mmap_iter->end_addr - 1 > vma_last_addr; 77590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) uint64 partial_first_address, partial_last_address; 77690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (trailing) 77790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_first_address = vma_start_addr; 77890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) else 77990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_first_address = mmap_iter->start_addr; 78090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (continued) 78190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_last_address = vma_last_addr; 78290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) else 78390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_last_address = mmap_iter->end_addr - 1; 78490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) uint64 committed_size = memory_residence_info_getter->CommittedSize( 78590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_first_address, partial_last_address); 7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(trailing ? " (" : " ", 0); 7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(mmap_iter->start_addr, 0); 7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(trailing ? ")" : " ", 0); 7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString("-", 0); 7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(continued ? "(" : " ", 0); 7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(mmap_iter->end_addr, 0); 7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(continued ? ")" : " ", 0); 7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" hooked ", 0); 79490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendInt64(committed_size, 0); 79590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendString(" / ", 0); 79690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendInt64( 79790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_last_address - partial_first_address + 1, 0); 7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" @ ", 0); 7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (deep_bucket != NULL) { 800b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) mmap_dump_buffer->AppendInt(deep_bucket->id, 0, false); 8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 802b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) mmap_dump_buffer->AppendInt(0, 0, false); 8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString("\n", 0); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (mmap_iter != MemoryRegionMap::EndRegionLocked() && 807c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->end_addr - 1 <= vma_last_addr); 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dmikurube): Investigate and fix http://crbug.com/189114. 8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The total committed memory usage in all_ (from /proc/<pid>/maps) is 8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // sometimes smaller than the sum of the committed mmap'ed addresses and 8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // unhooked regions. Within our observation, the difference was only 4KB 8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in committed usage, zero in reserved virtual addresses 8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // A guess is that an uncommitted (but reserved) page may become committed 8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // during counting memory usage in the loop above. 8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The difference is accounted as "ABSENT" to investigate such cases. 8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegionStats all_total; 8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegionStats unhooked_total; 8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { 8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_total.AddAnotherRegionStat(all_[i]); 8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.AddAnotherRegionStat(unhooked_[i]); 8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t absent_virtual = profiled_mmap_.virtual_bytes() + 8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.virtual_bytes() - 8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_total.virtual_bytes(); 8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (absent_virtual > 0) 8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_[ABSENT].AddToVirtualBytes(absent_virtual); 8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t absent_committed = profiled_mmap_.committed_bytes() + 8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.committed_bytes() - 8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_total.committed_bytes(); 8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (absent_committed > 0) 8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_[ABSENT].AddToCommittedBytes(absent_committed); 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::GlobalStats::SnapshotAllocations( 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepHeapProfile* deep_profile) { 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_malloc_.Initialize(); 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) deep_profile->heap_profile_->address_map_->Iterate(RecordAlloc, deep_profile); 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::GlobalStats::Unparse(TextBuffer* buffer) { 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RegionStats all_total; 8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegionStats unhooked_total; 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_total.AddAnotherRegionStat(all_[i]); 8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.AddAnotherRegionStat(unhooked_[i]); 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "# total (%lu) %c= profiled-mmap (%lu) + nonprofiled-* (%lu)\n" 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("# total (", 0); 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendUnsignedLong(all_total.committed_bytes(), 0); 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(") ", 0); 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(all_total.committed_bytes() == 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_mmap_.committed_bytes() + 8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.committed_bytes() ? '=' : '!'); 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("= profiled-mmap (", 0); 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendUnsignedLong(profiled_mmap_.committed_bytes(), 0); 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(") + nonprofiled-* (", 0); 8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer->AppendUnsignedLong(unhooked_total.committed_bytes(), 0); 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(")\n", 0); 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // " virtual committed" 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("", 26); 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(kVirtualLabel, 12); 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(kCommittedLabel, 12); 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_total.Unparse("total", buffer); 8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_[ABSENT].Unparse("absent", buffer); 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[FILE_EXEC].Unparse("file-exec", buffer); 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[FILE_NONEXEC].Unparse("file-nonexec", buffer); 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[ANONYMOUS].Unparse("anonymous", buffer); 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[STACK].Unparse("stack", buffer); 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[OTHER].Unparse("other", buffer); 8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.Unparse("nonprofiled-total", buffer); 8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[ABSENT].Unparse("nonprofiled-absent", buffer); 8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[ANONYMOUS].Unparse("nonprofiled-anonymous", buffer); 8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[FILE_EXEC].Unparse("nonprofiled-file-exec", buffer); 8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[FILE_NONEXEC].Unparse("nonprofiled-file-nonexec", buffer); 8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[STACK].Unparse("nonprofiled-stack", buffer); 8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[OTHER].Unparse("nonprofiled-other", buffer); 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_mmap_.Unparse("profiled-mmap", buffer); 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_malloc_.Unparse("profiled-malloc", buffer); 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::GlobalStats::RecordAlloc(const void* pointer, 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* alloc_value, 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepHeapProfile* deep_profile) { 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 address = reinterpret_cast<uintptr_t>(pointer); 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t committed = deep_profile->memory_residence_info_getter_->CommittedSize( 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) address, address + alloc_value->bytes - 1); 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* deep_bucket = deep_profile->deep_table_.Lookup( 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alloc_value->bucket(), 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LookupType(pointer), 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* is_mmap */ false); 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->committed_size += committed; 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_profile->stats_.profiled_malloc_.AddToVirtualBytes(alloc_value->bytes); 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_profile->stats_.profiled_malloc_.AddToCommittedBytes(committed); 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)DeepHeapProfile::DeepBucket* 916c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepHeapProfile::GlobalStats::GetInformationOfMemoryRegion( 917c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const MemoryRegionMap::RegionIterator& mmap_iter, 918c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 919c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepHeapProfile* deep_profile) { 920c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t committed = deep_profile->memory_residence_info_getter_-> 921c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CommittedSize(mmap_iter->start_addr, mmap_iter->end_addr - 1); 922c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 923c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(dmikurube): Store a reference to the bucket in region. 924c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Bucket* bucket = MemoryRegionMap::GetBucket( 925c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->call_stack_depth, mmap_iter->call_stack); 926c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepBucket* deep_bucket = NULL; 927c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (bucket != NULL) { 928c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deep_bucket = deep_profile->deep_table_.Lookup( 929c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bucket, 930c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(TYPE_PROFILING) 931c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NULL, // No type information for memory regions by mmap. 932c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 933c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /* is_mmap */ true); 934c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (deep_bucket != NULL) 935c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deep_bucket->committed_size += committed; 936c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 937c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 938c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profiled_mmap_.AddToVirtualBytes( 939c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->end_addr - mmap_iter->start_addr); 940c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profiled_mmap_.AddToCommittedBytes(committed); 941c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 942c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return deep_bucket; 943c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 944c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::WriteProcMaps(const char* prefix, 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int buffer_size, 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char raw_buffer[]) { 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char filename[100]; 9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) snprintf(filename, sizeof(filename), 9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "%s.%05d.maps", prefix, static_cast<int>(getpid())); 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd = RawOpenForWriting(filename); 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(fd != kIllegalRawFD, ""); 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int length; 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool wrote_all; 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = tcmalloc::FillProcSelfMaps(raw_buffer, buffer_size, &wrote_all); 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(wrote_all, ""); 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(length <= buffer_size, ""); 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, raw_buffer, length); 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawClose(fd); 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 964c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else // USE_DEEP_HEAP_PROFILE 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* prefix) 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : heap_profile_(heap_profile) { 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::~DeepHeapProfile() { 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DeepHeapProfile::FillOrderedProfile(char raw_buffer[], int buffer_size) { 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return heap_profile_->FillOrderedProfile(raw_buffer, buffer_size); 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 978c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif // USE_DEEP_HEAP_PROFILE 979