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) 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(__linux__) 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <endian.h> 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if !defined(__LITTLE_ENDIAN__) and !defined(__BIG_ENDIAN__) 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if __BYTE_ORDER == __BIG_ENDIAN 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define __BIG_ENDIAN__ 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // __BYTE_ORDER == __BIG_ENDIAN 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // !defined(__LITTLE_ENDIAN__) and !defined(__BIG_ENDIAN__) 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(__BIG_ENDIAN__) 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <byteswap.h> 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // defined(__BIG_ENDIAN__) 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // defined(__linux__) 33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(COMPILER_MSVC) 34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <Winsock2.h> // for gethostname 35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif // defined(COMPILER_MSVC) 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/cycleclock.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sysinfo.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "internal_logging.h" // for ASSERT, etc 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kProfilerBufferSize = 1 << 20; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHashTableSize = 179999; // Same as heap-profile-table.cc. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int PAGEMAP_BYTES = 8; 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic const int KPAGECOUNT_BYTES = 8; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const uint64 MAX_ADDRESS = kuint64max; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tag strings in heap profile dumps. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kProfileHeader[] = "heap profile: "; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char kProfileVersion[] = "DUMP_DEEP_6"; 51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static const char kMetaInformationHeader[] = "META:\n"; 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const char kMMapListHeader[] = "MMAP_LIST:\n"; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kGlobalStatsHeader[] = "GLOBAL_STATS:\n"; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kStacktraceHeader[] = "STACKTRACES:\n"; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kProcSelfMapsHeader[] = "\nMAPPED_LIBRARIES:\n"; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kVirtualLabel[] = "virtual"; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kCommittedLabel[] = "committed"; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(__linux__) 61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#define OS_NAME "linux" 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#elif defined(_WIN32) || defined(_WIN64) 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#define OS_NAME "windows" 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#else 65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#define OS_NAME "unknown-os" 66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif 677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool DeepHeapProfile::AppendCommandLine(TextBuffer* buffer) { 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(__linux__) 707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) RawFD fd; 717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) char filename[100]; 727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) char cmdline[4096]; 737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) snprintf(filename, sizeof(filename), "/proc/%d/cmdline", 747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) static_cast<int>(getpid())); 757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) fd = open(filename, O_RDONLY); 767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (fd == kIllegalRawFD) { 77e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch RAW_VLOG(0, "Failed to open /proc/self/cmdline"); 787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return false; 797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) size_t length = read(fd, cmdline, sizeof(cmdline) - 1); 827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) close(fd); 837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for (int i = 0; i < length; ++i) 857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (cmdline[i] == '\0') 867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cmdline[i] = ' '; 877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cmdline[length] = '\0'; 887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) buffer->AppendString("CommandLine: ", 0); 907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) buffer->AppendString(cmdline, 0); 917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) buffer->AppendChar('\n'); 927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return true; 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#else 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif 977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(_WIN32) || defined(_WIN64) 1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// TODO(peria): Implement this function. 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void DeepHeapProfile::MemoryInfoGetterWindows::Initialize() { 103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// TODO(peria): Implement this function. 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)size_t DeepHeapProfile::MemoryInfoGetterWindows::CommittedSize( 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) uint64 first_address, 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) uint64 last_address, 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) TextBuffer* buffer) const { 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return 0; 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// TODO(peria): Implement this function. 114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool DeepHeapProfile::MemoryInfoGetterWindows::IsPageCountAvailable() const { 1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return false; 1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif // defined(_WIN32) || defined(_WIN64) 1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid DeepHeapProfile::MemoryInfoGetterLinux::Initialize() { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char filename[100]; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(filename, sizeof(filename), "/proc/%d/pagemap", 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int>(getpid())); 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pagemap_fd_ = open(filename, O_RDONLY); 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RAW_CHECK(pagemap_fd_ != -1, "Failed to open /proc/self/pagemap"); 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pageframe_type_ == DUMP_PAGECOUNT) { 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snprintf(filename, sizeof(filename), "/proc/kpagecount"); 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kpagecount_fd_ = open(filename, O_RDONLY); 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (kpagecount_fd_ == -1) 133e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch RAW_VLOG(0, "Failed to open /proc/kpagecount"); 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochsize_t DeepHeapProfile::MemoryInfoGetterLinux::CommittedSize( 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 first_address, 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 last_address, 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DeepHeapProfile::TextBuffer* buffer) const { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int page_size = getpagesize(); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 page_address = (first_address / page_size) * page_size; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t committed_size = 0; 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch size_t pageframe_list_length = 0; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Seek(first_address); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check every page on which the allocation resides. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (page_address <= last_address) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read corresponding physical page. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) State state; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmikurube): Read pagemap in bulk for speed. 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dmikurube): Consider using mincore(2). 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (Read(&state, pageframe_type_ != DUMP_NO_PAGEFRAME) == false) { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can't read the last region (e.g vsyscall). 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 157e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch RAW_VLOG(0, "pagemap read failed @ %#llx %" PRId64 " bytes", 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first_address, last_address - first_address + 1); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Dump pageframes of resident pages. Non-resident pages are just skipped. 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pageframe_type_ != DUMP_NO_PAGEFRAME && 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer != NULL && state.pfn != 0) { 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pageframe_list_length == 0) { 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendString(" PF:", 0); 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pageframe_list_length = 5; 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendChar(' '); 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (page_address < first_address) 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendChar('<'); 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendBase64(state.pfn, 4); 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pageframe_list_length += 5; 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pageframe_type_ == DUMP_PAGECOUNT && IsPageCountAvailable()) { 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 pagecount = ReadPageCount(state.pfn); 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Assume pagecount == 63 if the pageframe is mapped more than 63 times. 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pagecount > 63) 179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pagecount = 63; 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendChar('#'); 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendBase64(pagecount, 1); 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pageframe_list_length += 2; 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (last_address < page_address - 1 + page_size) 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendChar('>'); 186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Begins a new line every 94 characters. 187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pageframe_list_length > 94) { 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendChar('\n'); 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pageframe_list_length = 0; 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state.is_committed) { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate the size of the allocation part in this page. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t bytes = page_size; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If looking at the last page in a given region. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_address <= page_address - 1 + page_size) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes = last_address - page_address + 1; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If looking at the first page in a given region. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_address < first_address) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes -= first_address - page_address; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) committed_size += bytes; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (page_address > MAX_ADDRESS - page_size) { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_address += page_size; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pageframe_type_ != DUMP_NO_PAGEFRAME && 216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer != NULL && pageframe_list_length != 0) { 217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->AppendChar('\n'); 218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return committed_size; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochuint64 DeepHeapProfile::MemoryInfoGetterLinux::ReadPageCount(uint64 pfn) const { 224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int64 index = pfn * KPAGECOUNT_BYTES; 225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int64 offset = lseek64(kpagecount_fd_, index, SEEK_SET); 226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RAW_DCHECK(offset == index, "Failed in seeking in kpagecount."); 227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 kpagecount_value; 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int result = read(kpagecount_fd_, &kpagecount_value, KPAGECOUNT_BYTES); 230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (result != KPAGECOUNT_BYTES) 231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return 0; 232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return kpagecount_value; 234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DeepHeapProfile::MemoryInfoGetterLinux::Seek(uint64 address) const { 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 index = (address / getpagesize()) * PAGEMAP_BYTES; 238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RAW_DCHECK(pagemap_fd_ != -1, "Failed to seek in /proc/self/pagemap"); 239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int64 offset = lseek64(pagemap_fd_, index, SEEK_SET); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(offset == index, "Failed in seeking."); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return offset >= 0; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DeepHeapProfile::MemoryInfoGetterLinux::Read( 245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch State* state, bool get_pfn) const { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 U64_1 = 1; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PFN_FILTER = (U64_1 << 55) - U64_1; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PAGE_PRESENT = U64_1 << 63; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PAGE_SWAP = U64_1 << 62; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 PAGE_RESERVED = U64_1 << 61; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 FLAG_NOPAGE = U64_1 << 20; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 FLAG_KSM = U64_1 << 21; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const uint64 FLAG_MMAP = U64_1 << 11; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 pagemap_value; 256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RAW_DCHECK(pagemap_fd_ != -1, "Failed to read from /proc/self/pagemap"); 257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int result = read(pagemap_fd_, &pagemap_value, PAGEMAP_BYTES); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != PAGEMAP_BYTES) { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the page is committed. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_committed = (pagemap_value & (PAGE_PRESENT | PAGE_SWAP)); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_present = (pagemap_value & PAGE_PRESENT); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_swapped = (pagemap_value & PAGE_SWAP); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->is_shared = false; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (get_pfn && state->is_present && !state->is_swapped) 270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch state->pfn = (pagemap_value & PFN_FILTER); 271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else 272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch state->pfn = 0; 273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DeepHeapProfile::MemoryInfoGetterLinux::IsPageCountAvailable() const { 278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return kpagecount_fd_ != -1; 279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // defined(__linux__) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::MemoryResidenceInfoGetterInterface:: 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryResidenceInfoGetterInterface() {} 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::MemoryResidenceInfoGetterInterface:: 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MemoryResidenceInfoGetterInterface() {} 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::MemoryResidenceInfoGetterInterface* 290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DeepHeapProfile::MemoryResidenceInfoGetterInterface::Create( 291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PageFrameType pageframe_type) { 292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(_WIN32) || defined(_WIN64) 293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return new MemoryInfoGetterWindows(pageframe_type); 294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#elif defined(__linux__) 295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return new MemoryInfoGetterLinux(pageframe_type); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, 302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const char* prefix, 303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch enum PageFrameType pageframe_type) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : memory_residence_info_getter_( 305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch MemoryResidenceInfoGetterInterface::Create(pageframe_type)), 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) most_recent_pid_(-1), 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats_(), 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dump_count_(0), 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_prefix_(NULL), 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_(kHashTableSize, heap_profile->alloc_, heap_profile->dealloc_), 311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pageframe_type_(pageframe_type), 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_profile_(heap_profile) { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy filename prefix. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int prefix_length = strlen(prefix); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_prefix_ = 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<char*>(heap_profile_->alloc_(prefix_length + 1)); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(filename_prefix_, prefix, prefix_length); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_prefix_[prefix_length] = '\0'; 3197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 3207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch strncpy(run_id_, "undetermined-run-id", sizeof(run_id_)); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::~DeepHeapProfile() { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) heap_profile_->dealloc_(filename_prefix_); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete memory_residence_info_getter_; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Global malloc() should not be used in this function. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use LowLevelAlloc if required. 3305e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)void DeepHeapProfile::DumpOrderedProfile(const char* reason, 3315e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) char raw_buffer[], 3325e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) int buffer_size, 3335e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) RawFD fd) { 3345e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) TextBuffer buffer(raw_buffer, buffer_size, fd); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 starting_cycles = CycleClock::Now(); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 339b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Get the time before starting snapshot. 34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // TODO(dmikurube): Consider gettimeofday if available. 342b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) time_t time_value = time(NULL); 343b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++dump_count_; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Re-open files in /proc/pid/ if the process is newly forked one. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (most_recent_pid_ != getpid()) { 3487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch char hostname[64]; 3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (0 == gethostname(hostname, sizeof(hostname))) { 3507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch char* dot = strchr(hostname, '.'); 3517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (dot != NULL) 3527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch *dot = '\0'; 3537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } else { 3547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch strcpy(hostname, "unknown"); 3557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 3567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) most_recent_pid_ = getpid(); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) snprintf(run_id_, sizeof(run_id_), "%s-" OS_NAME "-%d-%lu", 3607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch hostname, most_recent_pid_, time(NULL)); 3617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 362a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (memory_residence_info_getter_) 363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) memory_residence_info_getter_->Initialize(); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_.ResetIsLogged(); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write maps into "|filename_prefix_|.<pid>.maps". 3675e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) WriteProcMaps(filename_prefix_, raw_buffer, buffer_size); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset committed sizes of buckets. 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_.ResetCommittedSize(); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Record committed sizes. 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stats_.SnapshotAllocations(this); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // glibc's snprintf internally allocates memory by alloca normally, but it 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocates memory by malloc if large memory is required. 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kProfileHeader, 0); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kProfileVersion, 0); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString("\n", 0); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 384b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Fill buffer with meta information. 385b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer.AppendString(kMetaInformationHeader, 0); 386b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 387b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer.AppendString("Time: ", 0); 38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendUnsignedLong(time_value, 0); 389b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer.AppendChar('\n'); 390b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (reason != NULL) { 39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendString("Reason: ", 0); 39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendString(reason, 0); 39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer.AppendChar('\n'); 39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AppendCommandLine(&buffer); 3987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch buffer.AppendString("RunID: ", 0); 4007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch buffer.AppendString(run_id_, 0); 4017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch buffer.AppendChar('\n'); 4027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 4037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) buffer.AppendString("PageSize: ", 0); 4047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) buffer.AppendInt(getpagesize(), 0, 0); 4057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) buffer.AppendChar('\n'); 4067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Assumes the physical memory <= 64GB (PFN < 2^24). 408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (pageframe_type_ == DUMP_PAGECOUNT && memory_residence_info_getter_ && 409eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch memory_residence_info_getter_->IsPageCountAvailable()) { 410eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer.AppendString("PageFrame: 24,Base64,PageCount", 0); 411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer.AppendChar('\n'); 412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (pageframe_type_ != DUMP_NO_PAGEFRAME) { 413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer.AppendString("PageFrame: 24,Base64", 0); 414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer.AppendChar('\n'); 415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 416eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fill buffer with the global stats. 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer.AppendString(kMMapListHeader, 0); 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stats_.SnapshotMaps(memory_residence_info_getter_, this, &buffer); 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Fill buffer with the global stats. 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kGlobalStatsHeader, 0); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats_.Unparse(&buffer); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kStacktraceHeader, 0); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kVirtualLabel, 10); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendChar(' '); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString(kCommittedLabel, 10); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.AppendString("\n", 0); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fill buffer. 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_table_.UnparseForStats(&buffer); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) buffer.Flush(); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write the bucket listing into a .bucket file. 4395e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) deep_table_.WriteForBucketFile( 4405e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) filename_prefix_, dump_count_, raw_buffer, buffer_size); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 elapsed_cycles = CycleClock::Now() - starting_cycles; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double elapsed_seconds = elapsed_cycles / CyclesPerSecond(); 445e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch RAW_VLOG(0, "Time spent on DeepProfiler: %.3f sec\n", elapsed_seconds); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DeepHeapProfile::TextBuffer::Size() { 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return size_; 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DeepHeapProfile::TextBuffer::FilledBytes() { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cursor_; 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::TextBuffer::Clear() { 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cursor_ = 0; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)void DeepHeapProfile::TextBuffer::Flush() { 4625e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) RawWrite(fd_, buffer_, cursor_); 4635e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) cursor_ = 0; 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dmikurube): These Append* functions should not use snprintf. 46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendChar(char value) { 46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return ForwardCursor(snprintf(buffer_ + cursor_, size_ - cursor_, 46990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "%c", value)); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 47290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendString(const char* value, int width) { 47390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 47490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 47690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 47790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%s", value); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 47990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*s", 48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) width, value); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 48490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendInt(int value, int width, 48590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool leading_zero) { 48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 48790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 48990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 49090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%d", value); 491b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) else if (leading_zero) 49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%0*d", width, value); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*d", width, value); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 49890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendLong(long value, int width) { 49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 50090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%ld", value); 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*ld", width, value); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 50990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendUnsignedLong(unsigned long value, 51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int width) { 51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 51290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%lu", value); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) appended = snprintf(position, available, "%*lu", width, value); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendInt64(int64 value, int width) { 52290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 526558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch appended = snprintf(position, available, "%" PRId64, value); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 528558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch appended = snprintf(position, available, "%*" PRId64, width, value); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool DeepHeapProfile::TextBuffer::AppendPtr(uint64 value, int width) { 53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) char* position = buffer_ + cursor_; 53490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int available = size_ - cursor_; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int appended; 53690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (width == 0) 537558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch appended = snprintf(position, available, "%" PRIx64, value); 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 539558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch appended = snprintf(position, available, "%0*" PRIx64, width, value); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ForwardCursor(appended); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 543eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DeepHeapProfile::TextBuffer::AppendBase64(uint64 value, int width) { 544eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static const char base64[65] = 545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(__BIG_ENDIAN__) 547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch value = bswap_64(value); 548eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif 549eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (int shift = (width - 1) * 6; shift >= 0; shift -= 6) { 550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!AppendChar(base64[(value >> shift) & 0x3f])) 551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 555eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DeepHeapProfile::TextBuffer::ForwardCursor(int appended) { 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (appended < 0 || appended >= size_ - cursor_) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cursor_ += appended; 5605e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) if (cursor_ > size_ * 4 / 5) 5615e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) Flush(); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucket::UnparseForStats(TextBuffer* buffer) { 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendInt64(bucket->alloc_size - bucket->free_size, 10); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendInt64(committed_size, 10); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 570b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(bucket->allocs, 6, false); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 572b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(bucket->frees, 6, false); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" @ ", 0); 574b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(id, 0, false); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucket::UnparseForBucketFile(TextBuffer* buffer) { 579b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) buffer->AppendInt(id, 0, false); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(is_mmap ? "mmap" : "malloc", 0); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" t0x", 0); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendPtr(reinterpret_cast<uintptr_t>(type), 0); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == NULL) { 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" nno_typeinfo", 0); 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" n", 0); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(type->name(), 0); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int depth = 0; depth < bucket->depth; depth++) { 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(" 0x", 0); 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendPtr(reinterpret_cast<uintptr_t>(bucket->stack[depth]), 8); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepBucketTable::DeepBucketTable( 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int table_size, 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::Allocator alloc, 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::DeAllocator dealloc) 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : table_(NULL), 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_size_(table_size), 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alloc_(alloc), 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(dealloc), 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bucket_id_(0) { 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int bytes = table_size * sizeof(DeepBucket*); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_ = reinterpret_cast<DeepBucket**>(alloc(bytes)); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(table_, 0, bytes); 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepBucketTable::~DeepBucketTable() { 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(table_ != NULL); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int db = 0; db < table_size_; db++) { 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* x = table_[db]; x != 0; /**/) { 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* db = x; 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x = x->next; 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(db); 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dealloc_(table_); 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepBucket* DeepHeapProfile::DeepBucketTable::Lookup( 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket, 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::type_info* type, 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_mmap) { 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make hash-value 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t h = 0; 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(reinterpret_cast<uintptr_t>(bucket), &h); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_mmap) { 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(1, &h); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(0, &h); 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type == NULL) { 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(0, &h); 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddToHashValue(reinterpret_cast<uintptr_t>(type->name()), &h); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FinishHashValue(&h); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lookup stack trace in table 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int buck = ((unsigned int) h) % table_size_; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* db = table_[buck]; db != 0; db = db->next) { 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (db->bucket == bucket) { 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return db; 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a new bucket 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* db = reinterpret_cast<DeepBucket*>(alloc_(sizeof(DeepBucket))); 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(db, 0, sizeof(*db)); 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->bucket = bucket; 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->type = type; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->committed_size = 0; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->is_mmap = is_mmap; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->id = (bucket_id_++); 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->is_logged = false; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db->next = table_[buck]; 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_[buck] = db; 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return db; 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::UnparseForStats(TextBuffer* buffer) { 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket = deep_bucket->bucket; 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bucket->alloc_size - bucket->free_size == 0) { 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Skip empty buckets. 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->UnparseForStats(buffer); 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::WriteForBucketFile( 6935e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) const char* prefix, int dump_count, char raw_buffer[], int buffer_size) { 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char filename[100]; 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snprintf(filename, sizeof(filename), 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "%s.%05d.%04d.buckets", prefix, getpid(), dump_count); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd = RawOpenForWriting(filename); 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(fd != kIllegalRawFD, ""); 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7005e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) TextBuffer buffer(raw_buffer, buffer_size, fd); 7015e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket = deep_bucket->bucket; 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (deep_bucket->is_logged) { 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Skip the bucket if it is already logged. 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!deep_bucket->is_mmap && 7117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) bucket->alloc_size - bucket->free_size <= 64) { 7127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) continue; // Skip small malloc buckets. 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) deep_bucket->UnparseForBucketFile(&buffer); 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->is_logged = true; 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7205e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) buffer.Flush(); 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawClose(fd); 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::ResetCommittedSize() { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->committed_size = 0; 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::ResetIsLogged() { 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < table_size_; i++) { 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (DeepBucket* deep_bucket = table_[i]; 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket != NULL; 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket = deep_bucket->next) { 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->is_logged = false; 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This hash function is from HeapProfileTable::GetBucket. 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::AddToHashValue( 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t add, uintptr_t* hash_value) { 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value += add; 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value += *hash_value << 10; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value ^= *hash_value >> 6; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This hash function is from HeapProfileTable::GetBucket. 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::DeepBucketTable::FinishHashValue(uintptr_t* hash_value) { 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value += *hash_value << 3; 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *hash_value ^= *hash_value >> 11; 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::RegionStats::Initialize() { 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual_bytes_ = 0; 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) committed_bytes_ = 0; 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)uint64 DeepHeapProfile::RegionStats::Record( 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 first_address, 768eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 last_address, 769eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TextBuffer* buffer) { 770a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) uint64 committed = 0; 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual_bytes_ += static_cast<size_t>(last_address - first_address + 1); 772a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (memory_residence_info_getter) 773a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) committed = memory_residence_info_getter->CommittedSize(first_address, 774a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) last_address, 775a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) buffer); 7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) committed_bytes_ += committed; 7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return committed; 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::RegionStats::Unparse(const char* name, 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextBuffer* buffer) { 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(name, 25); 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendLong(virtual_bytes_, 12); 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendLong(committed_bytes_, 12); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 790a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Snapshots all virtual memory mapping stats by merging mmap(2) records from 791c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// MemoryRegionMap and /proc/maps, the OS-level memory mapping information. 792c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Memory regions described in /proc/maps, but which are not created by mmap, 793c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// are accounted as "unhooked" memory regions. 794c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 795c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This function assumes that every memory region created by mmap is covered 796c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// by VMA(s) described in /proc/maps except for http://crbug.com/189114. 797c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Note that memory regions created with mmap don't align with borders of VMAs 798c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// in /proc/maps. In other words, a memory region by mmap can cut across many 799c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// VMAs. Also, of course a VMA can include many memory regions by mmap. 800c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// It means that the following situation happens: 801c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 802c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// => Virtual address 803c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// <----- VMA #1 -----><----- VMA #2 ----->...<----- VMA #3 -----><- VMA #4 -> 804c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ..< mmap #1 >.<- mmap #2 -><- mmap #3 ->...<- mmap #4 ->..<-- mmap #5 -->.. 805c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 806c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// It can happen easily as permission can be changed by mprotect(2) for a part 807c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// of a memory region. A change in permission splits VMA(s). 808c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 809c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// To deal with the situation, this function iterates over MemoryRegionMap and 810c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// /proc/maps independently. The iterator for MemoryRegionMap is initialized 811c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// at the top outside the loop for /proc/maps, and it goes forward inside the 812c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// loop while comparing their addresses. 813c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dmikurube): Eliminate dynamic memory allocation caused by snprintf. 8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DeepHeapProfile::GlobalStats::SnapshotMaps( 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DeepHeapProfile* deep_profile, 8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TextBuffer* mmap_dump_buffer) { 8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MemoryRegionMap::LockHolder lock_holder; 8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcMapsIterator::Buffer procmaps_iter_buffer; 8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcMapsIterator procmaps_iter(0, &procmaps_iter_buffer); 822c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint64 vma_start_addr, vma_last_addr, offset; 8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int64 inode; 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* flags; 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* filename; 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum MapsRegionType type; 827a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[i].Initialize(); 8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[i].Initialize(); 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profiled_mmap_.Initialize(); 8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MemoryRegionMap::RegionIterator mmap_iter = 8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MemoryRegionMap::BeginRegionLocked(); 836b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DeepBucket* deep_bucket = NULL; 837b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (mmap_iter != MemoryRegionMap::EndRegionLocked()) { 838b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) deep_bucket = GetInformationOfMemoryRegion( 839b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) mmap_iter, memory_residence_info_getter, deep_profile); 840b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 842c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) while (procmaps_iter.Next(&vma_start_addr, &vma_last_addr, 8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &flags, &offset, &inode, &filename)) { 8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_dump_buffer) { 8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char buffer[1024]; 8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int written = procmaps_iter.FormatLine(buffer, sizeof(buffer), 847c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) vma_start_addr, vma_last_addr, 848c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) flags, offset, inode, filename, 0); 8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(buffer, 0); 8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 852c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // 'vma_last_addr' should be the last inclusive address of the region. 853c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) vma_last_addr -= 1; 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strcmp("[vsyscall]", filename) == 0) { 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // Reading pagemap will fail in [vsyscall]. 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 858868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // TODO(dmikurube): |type| will be deprecated in the dump. 859868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // See http://crbug.com/245603. 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = ABSENT; 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename[0] == '/') { 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags[2] == 'x') 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = FILE_EXEC; 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = FILE_NONEXEC; 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (filename[0] == '\0' || filename[0] == '\n') { 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = ANONYMOUS; 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (strcmp(filename, "[stack]") == 0) { 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = STACK; 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = OTHER; 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 873868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // TODO(dmikurube): This |all_| count should be removed in future soon. 874868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // See http://crbug.com/245603. 875868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint64 vma_total = all_[type].Record( 876eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch memory_residence_info_getter, vma_start_addr, vma_last_addr, NULL); 877868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint64 vma_subtotal = 0; 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmikurube): Stop double-counting pagemap. 880868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // It will be fixed when http://crbug.com/245603 finishes. 8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (MemoryRegionMap::IsRecordingLocked()) { 882c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) uint64 cursor = vma_start_addr; 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool first = true; 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Iterates over MemoryRegionMap until the iterator moves out of the VMA. 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!first) { 8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cursor = mmap_iter->end_addr; 8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++mmap_iter; 8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't break here even if mmap_iter == EndRegionLocked(). 891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (mmap_iter != MemoryRegionMap::EndRegionLocked()) { 893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deep_bucket = GetInformationOfMemoryRegion( 894c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter, memory_residence_info_getter, deep_profile); 895c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first = false; 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64 last_address_of_unhooked; 900c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If the next mmap entry is away from the current VMA. 9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_iter == MemoryRegionMap::EndRegionLocked() || 902c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->start_addr > vma_last_addr) { 903c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) last_address_of_unhooked = vma_last_addr; 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_address_of_unhooked = mmap_iter->start_addr - 1; 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (last_address_of_unhooked + 1 > cursor) { 909c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RAW_CHECK(cursor >= vma_start_addr, 9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Wrong calculation for unhooked"); 911c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RAW_CHECK(last_address_of_unhooked <= vma_last_addr, 9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Wrong calculation for unhooked"); 9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64 committed_size = unhooked_[type].Record( 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memory_residence_info_getter, 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cursor, 916eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_address_of_unhooked, 917eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mmap_dump_buffer); 918868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) vma_subtotal += committed_size; 9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_dump_buffer) { 9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" ", 0); 9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(cursor, 0); 9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" - ", 0); 9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(last_address_of_unhooked + 1, 0); 9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" unhooked ", 0); 9252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendInt64(committed_size, 0); 92690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendString(" / ", 0); 92790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendInt64( 92890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) last_address_of_unhooked - cursor + 1, 0); 9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString("\n", 0); 9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cursor = last_address_of_unhooked + 1; 9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mmap_iter != MemoryRegionMap::EndRegionLocked() && 935c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->start_addr <= vma_last_addr && 9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer) { 937c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool trailing = mmap_iter->start_addr < vma_start_addr; 938c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool continued = mmap_iter->end_addr - 1 > vma_last_addr; 93990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) uint64 partial_first_address, partial_last_address; 94090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (trailing) 94190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_first_address = vma_start_addr; 94290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) else 94390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_first_address = mmap_iter->start_addr; 94490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (continued) 94590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_last_address = vma_last_addr; 94690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) else 94790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_last_address = mmap_iter->end_addr - 1; 948a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) uint64 committed_size = 0; 949a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (memory_residence_info_getter) 950a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) committed_size = memory_residence_info_getter->CommittedSize( 951a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) partial_first_address, partial_last_address, mmap_dump_buffer); 952868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) vma_subtotal += committed_size; 9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(trailing ? " (" : " ", 0); 9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(mmap_iter->start_addr, 0); 9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(trailing ? ")" : " ", 0); 9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString("-", 0); 9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(continued ? "(" : " ", 0); 9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendPtr(mmap_iter->end_addr, 0); 9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(continued ? ")" : " ", 0); 9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" hooked ", 0); 96190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendInt64(committed_size, 0); 96290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendString(" / ", 0); 96390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) mmap_dump_buffer->AppendInt64( 96490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) partial_last_address - partial_first_address + 1, 0); 9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString(" @ ", 0); 9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (deep_bucket != NULL) { 967b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) mmap_dump_buffer->AppendInt(deep_bucket->id, 0, false); 9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 969b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) mmap_dump_buffer->AppendInt(0, 0, false); 9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_dump_buffer->AppendString("\n", 0); 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (mmap_iter != MemoryRegionMap::EndRegionLocked() && 974c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->end_addr - 1 <= vma_last_addr); 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 976868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 977868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (vma_total != vma_subtotal) { 978868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) char buffer[1024]; 979868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int written = procmaps_iter.FormatLine(buffer, sizeof(buffer), 980868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) vma_start_addr, vma_last_addr, 981868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) flags, offset, inode, filename, 0); 982e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch RAW_VLOG(0, "[%d] Mismatched total in VMA %" PRId64 ":" 983558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch "%" PRId64 " (%" PRId64 ")", 984868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) getpid(), vma_total, vma_subtotal, vma_total - vma_subtotal); 985e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch RAW_VLOG(0, "[%d] in %s", getpid(), buffer); 986868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dmikurube): Investigate and fix http://crbug.com/189114. 9902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 9912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The total committed memory usage in all_ (from /proc/<pid>/maps) is 9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // sometimes smaller than the sum of the committed mmap'ed addresses and 9932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // unhooked regions. Within our observation, the difference was only 4KB 9942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in committed usage, zero in reserved virtual addresses 9952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 9962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // A guess is that an uncommitted (but reserved) page may become committed 9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // during counting memory usage in the loop above. 9982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 9992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The difference is accounted as "ABSENT" to investigate such cases. 1000868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // 1001868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // It will be fixed when http://crbug.com/245603 finishes (no double count). 10022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegionStats all_total; 10042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegionStats unhooked_total; 10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { 10062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_total.AddAnotherRegionStat(all_[i]); 10072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.AddAnotherRegionStat(unhooked_[i]); 10082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 10092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t absent_virtual = profiled_mmap_.virtual_bytes() + 10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.virtual_bytes() - 10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_total.virtual_bytes(); 10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (absent_virtual > 0) 10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_[ABSENT].AddToVirtualBytes(absent_virtual); 10152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t absent_committed = profiled_mmap_.committed_bytes() + 10172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.committed_bytes() - 10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_total.committed_bytes(); 10192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (absent_committed > 0) 10202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_[ABSENT].AddToCommittedBytes(absent_committed); 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::GlobalStats::SnapshotAllocations( 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepHeapProfile* deep_profile) { 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_malloc_.Initialize(); 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) deep_profile->heap_profile_->address_map_->Iterate(RecordAlloc, deep_profile); 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::GlobalStats::Unparse(TextBuffer* buffer) { 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RegionStats all_total; 10322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegionStats unhooked_total; 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < NUMBER_OF_MAPS_REGION_TYPES; ++i) { 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_total.AddAnotherRegionStat(all_[i]); 10352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.AddAnotherRegionStat(unhooked_[i]); 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "# total (%lu) %c= profiled-mmap (%lu) + nonprofiled-* (%lu)\n" 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("# total (", 0); 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendUnsignedLong(all_total.committed_bytes(), 0); 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(") ", 0); 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(all_total.committed_bytes() == 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_mmap_.committed_bytes() + 10442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.committed_bytes() ? '=' : '!'); 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("= profiled-mmap (", 0); 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendUnsignedLong(profiled_mmap_.committed_bytes(), 0); 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(") + nonprofiled-* (", 0); 10482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer->AppendUnsignedLong(unhooked_total.committed_bytes(), 0); 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(")\n", 0); 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // " virtual committed" 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("", 26); 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(kVirtualLabel, 12); 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendChar(' '); 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString(kCommittedLabel, 12); 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer->AppendString("\n", 0); 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_total.Unparse("total", buffer); 10592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) all_[ABSENT].Unparse("absent", buffer); 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[FILE_EXEC].Unparse("file-exec", buffer); 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[FILE_NONEXEC].Unparse("file-nonexec", buffer); 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[ANONYMOUS].Unparse("anonymous", buffer); 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[STACK].Unparse("stack", buffer); 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_[OTHER].Unparse("other", buffer); 10652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_total.Unparse("nonprofiled-total", buffer); 10662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[ABSENT].Unparse("nonprofiled-absent", buffer); 10672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[ANONYMOUS].Unparse("nonprofiled-anonymous", buffer); 10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[FILE_EXEC].Unparse("nonprofiled-file-exec", buffer); 10692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[FILE_NONEXEC].Unparse("nonprofiled-file-nonexec", buffer); 10702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[STACK].Unparse("nonprofiled-stack", buffer); 10712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unhooked_[OTHER].Unparse("nonprofiled-other", buffer); 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_mmap_.Unparse("profiled-mmap", buffer); 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiled_malloc_.Unparse("profiled-malloc", buffer); 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::GlobalStats::RecordAlloc(const void* pointer, 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* alloc_value, 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepHeapProfile* deep_profile) { 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 address = reinterpret_cast<uintptr_t>(pointer); 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t committed = deep_profile->memory_residence_info_getter_->CommittedSize( 1082eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch address, address + alloc_value->bytes - 1, NULL); 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* deep_bucket = deep_profile->deep_table_.Lookup( 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alloc_value->bucket(), 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LookupType(pointer), 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* is_mmap */ false); 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_bucket->committed_size += committed; 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_profile->stats_.profiled_malloc_.AddToVirtualBytes(alloc_value->bytes); 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) deep_profile->stats_.profiled_malloc_.AddToCommittedBytes(committed); 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)DeepHeapProfile::DeepBucket* 1096c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepHeapProfile::GlobalStats::GetInformationOfMemoryRegion( 1097c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const MemoryRegionMap::RegionIterator& mmap_iter, 1098c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 1099c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepHeapProfile* deep_profile) { 1100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) size_t committed = deep_profile->memory_residence_info_getter_-> 1101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CommittedSize(mmap_iter->start_addr, mmap_iter->end_addr - 1, NULL); 1102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(dmikurube): Store a reference to the bucket in region. 1104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Bucket* bucket = MemoryRegionMap::GetBucket( 1105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->call_stack_depth, mmap_iter->call_stack); 1106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepBucket* deep_bucket = NULL; 1107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (bucket != NULL) { 1108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deep_bucket = deep_profile->deep_table_.Lookup( 1109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bucket, 1110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(TYPE_PROFILING) 1111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NULL, // No type information for memory regions by mmap. 1112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 1113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /* is_mmap */ true); 1114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (deep_bucket != NULL) 1115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deep_bucket->committed_size += committed; 1116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profiled_mmap_.AddToVirtualBytes( 1119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mmap_iter->end_addr - mmap_iter->start_addr); 1120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profiled_mmap_.AddToCommittedBytes(committed); 1121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return deep_bucket; 1123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 1124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeepHeapProfile::WriteProcMaps(const char* prefix, 11275e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) char raw_buffer[], 11285e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) int buffer_size) { 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char filename[100]; 11302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) snprintf(filename, sizeof(filename), 11312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "%s.%05d.maps", prefix, static_cast<int>(getpid())); 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawFD fd = RawOpenForWriting(filename); 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(fd != kIllegalRawFD, ""); 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int length; 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool wrote_all; 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length = tcmalloc::FillProcSelfMaps(raw_buffer, buffer_size, &wrote_all); 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(wrote_all, ""); 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_DCHECK(length <= buffer_size, ""); 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawWrite(fd, raw_buffer, length); 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RawClose(fd); 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else // USE_DEEP_HEAP_PROFILE 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::DeepHeapProfile(HeapProfileTable* heap_profile, 1147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char* prefix, 1148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) enum PageFrameType pageframe_type) 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : heap_profile_(heap_profile) { 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeepHeapProfile::~DeepHeapProfile() { 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DeepHeapProfile::DumpOrderedProfile(const char* reason, 1156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) char raw_buffer[], 1157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int buffer_size, 1158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RawFD fd) { 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif // USE_DEEP_HEAP_PROFILE 1162