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)// This file contains a class DeepHeapProfile and its public function 105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)// DeepHeapProfile::DumpOrderedProfile(). The function works like 115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)// HeapProfileTable::FillOrderedProfile(), but dumps directory to files. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 135e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)// DeepHeapProfile::DumpOrderedProfile() dumps more detailed information about 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// heap usage, which includes OS-level information such as memory residency and 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// type information if the type profiler is available. 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 175e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)// DeepHeapProfile::DumpOrderedProfile() uses data stored in HeapProfileTable. 185e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)// Any code in DeepHeapProfile runs only when DumpOrderedProfile() is called. 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It has overhead in dumping, but no overhead in logging. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 215e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)// It currently works only on Linux including Android. It does nothing in 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-Linux environments. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that uint64 is used to represent addresses instead of uintptr_t, and 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// int is used to represent buffer sizes instead of size_t. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It's for consistency with other TCMalloc functions. ProcMapsIterator uses 275e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)// uint64 for addresses, and HeapProfileTable::DumpOrderedProfile uses int 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for buffer sizes. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_DEEP_HEAP_PROFILE_H_ 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_DEEP_HEAP_PROFILE_H_ 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <typeinfo> 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__linux__) 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define USE_DEEP_HEAP_PROFILE 1 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "addressmap-inl.h" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "heap-profile-table.h" 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "memory_region_map.h" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DeepHeapProfile { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch enum PageFrameType { 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DUMP_NO_PAGEFRAME = 0, // Dumps nothing about pageframes 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DUMP_PFN = 1, // Dumps only pageframe numbers (PFNs) 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DUMP_PAGECOUNT = 2, // Dumps PFNs and pagecounts 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constructs a DeepHeapProfile instance. It works as a wrapper of 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HeapProfileTable. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |heap_profile| is a pointer to HeapProfileTable. DeepHeapProfile reads 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data in |heap_profile| and forwards operations to |heap_profile| if 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DeepHeapProfile is not available (non-Linux). 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |prefix| is a prefix of dumped file names. 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // |pageframe_type| means what information is dumped for pageframes. 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DeepHeapProfile(HeapProfileTable* heap_profile, 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const char* prefix, 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch enum PageFrameType pageframe_type); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~DeepHeapProfile(); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) // Dumps a deep profile into |fd| with using |raw_buffer| of |buffer_size|. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In addition, a list of buckets is dumped into a ".buckets" file in 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // descending order of allocated bytes. 725e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) void DumpOrderedProfile(const char* reason, 735e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) char raw_buffer[], 745e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) int buffer_size, 755e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) RawFD fd); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifdef USE_DEEP_HEAP_PROFILE 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef HeapProfileTable::Stats Stats; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef HeapProfileTable::Bucket Bucket; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef HeapProfileTable::AllocValue AllocValue; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef HeapProfileTable::AllocationMap AllocationMap; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum MapsRegionType { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bytes of memory which were not recognized with /proc/<pid>/maps. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This size should be 0. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ABSENT, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bytes of memory which is mapped anonymously. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Regions which contain nothing in the last column of /proc/<pid>/maps. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ANONYMOUS, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bytes of memory which is mapped to a executable/non-executable file. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Regions which contain file paths in the last column of /proc/<pid>/maps. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE_EXEC, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FILE_NONEXEC, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bytes of memory which is labeled [stack] in /proc/<pid>/maps. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STACK, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bytes of memory which is labeled, but not mapped to any file. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Regions which contain non-path strings in the last column of 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // /proc/<pid>/maps. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OTHER, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NUMBER_OF_MAPS_REGION_TYPES 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const char* kMapsRegionTypeDict[NUMBER_OF_MAPS_REGION_TYPES]; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) // Manages a buffer to keep a text to be dumped to a file. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class TextBuffer { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1145e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) TextBuffer(char *raw_buffer, int size, RawFD fd) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : buffer_(raw_buffer), 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_(size), 1175e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) cursor_(0), 1185e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) fd_(fd) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int Size(); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int FilledBytes(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Clear(); 1245e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) void Flush(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool AppendChar(char value); 12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool AppendString(const char* value, int width); 12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool AppendInt(int value, int width, bool leading_zero); 12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool AppendLong(long value, int width); 13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool AppendUnsignedLong(unsigned long value, int width); 13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool AppendInt64(int64 value, int width); 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool AppendBase64(uint64 value, int width); 13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) bool AppendPtr(uint64 value, int width); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ForwardCursor(int appended); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *buffer_; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size_; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int cursor_; 1415e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) RawFD fd_; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(TextBuffer); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Defines an interface for getting info about memory residence. 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch class MemoryResidenceInfoGetterInterface { 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~MemoryResidenceInfoGetterInterface(); 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Initializes the instance. 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void Initialize() = 0; 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns the number of resident (including swapped) bytes of the given 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // memory region from |first_address| to |last_address| inclusive. 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual size_t CommittedSize(uint64 first_address, 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 last_address, 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TextBuffer* buffer) const = 0; 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Creates a new platform specific MemoryResidenceInfoGetterInterface. 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static MemoryResidenceInfoGetterInterface* Create( 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PageFrameType pageframe_type); 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual bool IsPageCountAvailable() const = 0; 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch protected: 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch MemoryResidenceInfoGetterInterface(); 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }; 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(__linux__) 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Implements MemoryResidenceInfoGetterInterface for Linux. 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch class MemoryInfoGetterLinux : public MemoryResidenceInfoGetterInterface { 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch MemoryInfoGetterLinux(PageFrameType pageframe_type) 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch : pageframe_type_(pageframe_type), 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pagemap_fd_(kIllegalRawFD), 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kpagecount_fd_(kIllegalRawFD) {} 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~MemoryInfoGetterLinux() {} 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Opens /proc/<pid>/pagemap and stores its file descriptor. 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // It keeps open while the process is running. 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Note that file descriptors need to be refreshed after fork. 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void Initialize(); 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Returns the number of resident (including swapped) bytes of the given 186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // memory region from |first_address| to |last_address| inclusive. 187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual size_t CommittedSize(uint64 first_address, 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 last_address, 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TextBuffer* buffer) const; 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual bool IsPageCountAvailable() const; 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private: 194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch struct State { 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 pfn; 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_committed; // Currently, we use only this 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_present; 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_swapped; 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_shared; 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_mmap; 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }; 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 ReadPageCount(uint64 pfn) const; 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Seeks to the offset of the open pagemap file. 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // It returns true if succeeded. 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool Seek(uint64 address) const; 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Reads a pagemap state from the current offset. 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // It returns true if succeeded. 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool Read(State* state, bool get_pfn) const; 212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PageFrameType pageframe_type_; 214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RawFD pagemap_fd_; 215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RawFD kpagecount_fd_; 216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }; 217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // defined(__linux__) 218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Contains extended information for HeapProfileTable::Bucket. These objects 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are managed in a hash table (DeepBucketTable) whose key is an address of 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a Bucket and other additional information. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct DeepBucket { 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void UnparseForStats(TextBuffer* buffer); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void UnparseForBucketFile(TextBuffer* buffer); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Bucket* bucket; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::type_info* type; // A type of the object 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t committed_size; // A resident size of this bucket 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_mmap; // True if the bucket represents a mmap region 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int id; // A unique ID of the bucket 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_logged; // True if the stracktrace is logged to a file 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* next; // A reference to the next entry in the hash table 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Manages a hash table for DeepBucket. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class DeepBucketTable { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucketTable(int size, 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::Allocator alloc, 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::DeAllocator dealloc); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~DeepBucketTable(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Finds a DeepBucket instance corresponding to the given |bucket|, or 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // creates a new DeepBucket object if it doesn't exist. 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket* Lookup(Bucket* bucket, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TYPE_PROFILING) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::type_info* type, 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_mmap); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) // Writes stats of the hash table to |buffer| for DumpOrderedProfile. 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void UnparseForStats(TextBuffer* buffer); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Writes all buckets for a bucket file with using |buffer|. 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WriteForBucketFile(const char* prefix, 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int dump_count, 2605e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) char raw_buffer[], 2615e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) int buffer_size); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Resets 'committed_size' members in DeepBucket objects. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ResetCommittedSize(); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Resets all 'is_loggeed' flags in DeepBucket objects. 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ResetIsLogged(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Adds |add| to a |hash_value| for Lookup. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void AddToHashValue(uintptr_t add, uintptr_t* hash_value); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inline static void FinishHashValue(uintptr_t* hash_value); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucket** table_; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t table_size_; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::Allocator alloc_; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable::DeAllocator dealloc_; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bucket_id_; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class RegionStats { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RegionStats(): virtual_bytes_(0), committed_bytes_(0) {} 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~RegionStats() {} 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes 'virtual_bytes_' and 'committed_bytes_'. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Initialize(); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Updates itself to contain the tallies of 'virtual_bytes' and 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 'committed_bytes' in the region from |first_adress| to |last_address| 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // inclusive. 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint64 Record( 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 first_address, 295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint64 last_address, 296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TextBuffer* buffer); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Writes stats of the region into |buffer| with |name|. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Unparse(const char* name, TextBuffer* buffer); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t virtual_bytes() const { return virtual_bytes_; } 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t committed_bytes() const { return committed_bytes_; } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddToVirtualBytes(size_t additional_virtual_bytes) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual_bytes_ += additional_virtual_bytes; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddToCommittedBytes(size_t additional_committed_bytes) { 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) committed_bytes_ += additional_committed_bytes; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AddAnotherRegionStat(const RegionStats& other) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual_bytes_ += other.virtual_bytes_; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) committed_bytes_ += other.committed_bytes_; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t virtual_bytes_; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t committed_bytes_; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(RegionStats); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class GlobalStats { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Snapshots and calculates global stats from /proc/<pid>/maps and pagemap. 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void SnapshotMaps( 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DeepHeapProfile* deep_profile, 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TextBuffer* mmap_dump_buffer); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Snapshots allocations by malloc and mmap. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SnapshotAllocations(DeepHeapProfile* deep_profile); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Writes global stats into |buffer|. 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Unparse(TextBuffer* buffer); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Records both virtual and committed byte counts of malloc and mmap regions 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as callback functions for AllocationMap::Iterate(). 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void RecordAlloc(const void* pointer, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AllocValue* alloc_value, 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepHeapProfile* deep_profile); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepBucket* GetInformationOfMemoryRegion( 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const MemoryRegionMap::RegionIterator& mmap_iter, 343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const MemoryResidenceInfoGetterInterface* memory_residence_info_getter, 344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DeepHeapProfile* deep_profile); 345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All RegionStats members in this class contain the bytes of virtual 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // memory and committed memory. 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmikurube): These regions should be classified more precisely later 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for more detailed analysis. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RegionStats all_[NUMBER_OF_MAPS_REGION_TYPES]; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RegionStats unhooked_[NUMBER_OF_MAPS_REGION_TYPES]; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Total bytes of malloc'ed regions. 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RegionStats profiled_malloc_; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Total bytes of mmap'ed regions. 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RegionStats profiled_mmap_; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Writes reformatted /proc/<pid>/maps into a file "|prefix|.<pid>.maps" 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // with using |raw_buffer| of |buffer_size|. 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void WriteProcMaps(const char* prefix, 3645e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) char raw_buffer[], 3655e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) int buffer_size); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Appends the command line (/proc/pid/cmdline on Linux) into |buffer|. 3687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) bool AppendCommandLine(TextBuffer* buffer); 3697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MemoryResidenceInfoGetterInterface* memory_residence_info_getter_; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Process ID of the last dump. This can change by fork. 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pid_t most_recent_pid_; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GlobalStats stats_; // Stats about total memory. 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int dump_count_; // The number of dumps. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* filename_prefix_; // Output file prefix. 3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch char run_id_[128]; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeepBucketTable deep_table_; 381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch enum PageFrameType pageframe_type_; 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif // USE_DEEP_HEAP_PROFILE 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeapProfileTable* heap_profile_; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DeepHeapProfile); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // BASE_DEEP_HEAP_PROFILE_H_ 391