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