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