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