blob: b2d8b63e4175c4a71a229b55a287fcedefc184c5 [file] [log] [blame]
ssid83aa5be2015-05-08 12:03:261// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "gin/v8_isolate_memory_dump_provider.h"
6
ssid4205d7b2016-06-15 20:36:037#include <inttypes.h>
avi90e658dd2015-12-21 07:16:198#include <stddef.h>
9
ssid83aa5be2015-05-08 12:03:2610#include "base/strings/stringprintf.h"
gab54909b722016-05-11 18:34:1111#include "base/threading/thread_task_runner_handle.h"
ssid83aa5be2015-05-08 12:03:2612#include "base/trace_event/memory_dump_manager.h"
13#include "base/trace_event/process_memory_dump.h"
14#include "gin/public/isolate_holder.h"
15#include "v8/include/v8.h"
16
17namespace gin {
18
ssid83aa5be2015-05-08 12:03:2619V8IsolateMemoryDumpProvider::V8IsolateMemoryDumpProvider(
20 IsolateHolder* isolate_holder)
21 : isolate_holder_(isolate_holder) {
22 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
primiano186d6bfe2015-10-30 13:21:4023 this, "V8Isolate", base::ThreadTaskRunnerHandle::Get());
ssid83aa5be2015-05-08 12:03:2624}
25
26V8IsolateMemoryDumpProvider::~V8IsolateMemoryDumpProvider() {
27 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
28 this);
29}
30
31// Called at trace dump point time. Creates a snapshot with the memory counters
32// for the current isolate.
33bool V8IsolateMemoryDumpProvider::OnMemoryDump(
ssid90694aeec2015-08-06 13:01:3034 const base::trace_event::MemoryDumpArgs& args,
ssidf51216b02015-06-04 19:46:2335 base::trace_event::ProcessMemoryDump* process_memory_dump) {
ssid90694aeec2015-08-06 13:01:3036 // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
37 // (crbug.com/499731).
38
ssid83aa5be2015-05-08 12:03:2639 if (isolate_holder_->access_mode() == IsolateHolder::kUseLocker) {
40 v8::Locker locked(isolate_holder_->isolate());
ssid2888a242015-08-07 23:08:4241 DumpHeapStatistics(args, process_memory_dump);
ssid83aa5be2015-05-08 12:03:2642 } else {
ssid2888a242015-08-07 23:08:4243 DumpHeapStatistics(args, process_memory_dump);
ssid83aa5be2015-05-08 12:03:2644 }
45 return true;
46}
47
mythria35540662016-06-03 15:02:0548namespace {
49
50// Dump statistics related to code/bytecode when memory-infra.v8.code_stats is
51// enabled.
52void DumpCodeStatistics(
53 base::trace_event::MemoryAllocatorDump* heap_spaces_dump,
54 IsolateHolder* isolate_holder) {
55 // Collecting code statistics is an expensive operation (~10 ms) when
56 // compared to other v8 metrics (< 1 ms). So, dump them only when
57 // memory-infra.v8.code_stats is enabled.
58 // TODO(primiano): This information should be plumbed through TraceConfig.
59 // See crbug.com/616441.
60 bool dump_code_stats = false;
61 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
62 TRACE_DISABLED_BY_DEFAULT("memory-infra.v8.code_stats"),
63 &dump_code_stats);
64 if (!dump_code_stats)
65 return;
66
67 v8::HeapCodeStatistics code_statistics;
68 if (!isolate_holder->isolate()->GetHeapCodeAndMetadataStatistics(
69 &code_statistics)) {
70 return;
71 }
72
73 heap_spaces_dump->AddScalar(
74 "code_and_metadata_size",
75 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
76 code_statistics.code_and_metadata_size());
77 heap_spaces_dump->AddScalar(
78 "bytecode_and_metadata_size",
79 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
80 code_statistics.bytecode_and_metadata_size());
81}
82
83} // namespace anonymous
84
sside36cfaf2015-06-12 16:42:2085void V8IsolateMemoryDumpProvider::DumpHeapStatistics(
ssid2888a242015-08-07 23:08:4286 const base::trace_event::MemoryDumpArgs& args,
sside36cfaf2015-06-12 16:42:2087 base::trace_event::ProcessMemoryDump* process_memory_dump) {
ssid4205d7b2016-06-15 20:36:0388 std::string dump_base_name = base::StringPrintf(
89 "v8/isolate_0x%" PRIXPTR,
90 reinterpret_cast<uintptr_t>(isolate_holder_->isolate()));
sside36cfaf2015-06-12 16:42:2091
92 // Dump statistics of the heap's spaces.
93 std::string space_name_prefix = dump_base_name + "/heap_spaces";
ssid83aa5be2015-05-08 12:03:2694 v8::HeapStatistics heap_statistics;
95 isolate_holder_->isolate()->GetHeapStatistics(&heap_statistics);
96
97 size_t known_spaces_used_size = 0;
98 size_t known_spaces_size = 0;
primiano553bea9a2015-09-09 16:37:3599 size_t known_spaces_physical_size = 0;
ssid83aa5be2015-05-08 12:03:26100 size_t number_of_spaces = isolate_holder_->isolate()->NumberOfHeapSpaces();
101 for (size_t space = 0; space < number_of_spaces; space++) {
102 v8::HeapSpaceStatistics space_statistics;
103 isolate_holder_->isolate()->GetHeapSpaceStatistics(&space_statistics,
104 space);
105 const size_t space_size = space_statistics.space_size();
106 const size_t space_used_size = space_statistics.space_used_size();
primiano553bea9a2015-09-09 16:37:35107 const size_t space_physical_size = space_statistics.physical_space_size();
ssid83aa5be2015-05-08 12:03:26108
109 known_spaces_size += space_size;
110 known_spaces_used_size += space_used_size;
primiano553bea9a2015-09-09 16:37:35111 known_spaces_physical_size += space_physical_size;
ssid83aa5be2015-05-08 12:03:26112
sside36cfaf2015-06-12 16:42:20113 std::string space_dump_name =
114 space_name_prefix + "/" + space_statistics.space_name();
vmpstr1ee03c4c02016-06-30 21:40:56115 auto* space_dump =
116 process_memory_dump->CreateAllocatorDump(space_dump_name);
sside36cfaf2015-06-12 16:42:20117 space_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
ssid83aa5be2015-05-08 12:03:26118 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
primiano553bea9a2015-09-09 16:37:35119 space_physical_size);
120
121 space_dump->AddScalar("virtual_size",
122 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
sside36cfaf2015-06-12 16:42:20123 space_size);
124
primiano553bea9a2015-09-09 16:37:35125 space_dump->AddScalar("allocated_objects_size",
126 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
127 space_used_size);
ssid83aa5be2015-05-08 12:03:26128 }
ssidf51216b02015-06-04 19:46:23129
ssid83aa5be2015-05-08 12:03:26130 // Compute the rest of the memory, not accounted by the spaces above.
sside36cfaf2015-06-12 16:42:20131 std::string other_spaces_name = space_name_prefix + "/other_spaces";
vmpstr1ee03c4c02016-06-30 21:40:56132 auto* other_dump =
133 process_memory_dump->CreateAllocatorDump(other_spaces_name);
sside36cfaf2015-06-12 16:42:20134
primiano553bea9a2015-09-09 16:37:35135 other_dump->AddScalar(
sside36cfaf2015-06-12 16:42:20136 base::trace_event::MemoryAllocatorDump::kNameSize,
ssid83aa5be2015-05-08 12:03:26137 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
primiano553bea9a2015-09-09 16:37:35138 heap_statistics.total_physical_size() - known_spaces_physical_size);
139
140 other_dump->AddScalar(
141 "allocated_objects_size",
142 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
ssid83aa5be2015-05-08 12:03:26143 heap_statistics.used_heap_size() - known_spaces_used_size);
144
primiano553bea9a2015-09-09 16:37:35145 other_dump->AddScalar("virtual_size",
146 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
147 heap_statistics.total_heap_size() - known_spaces_size);
148
ssidbce6ee42015-11-05 02:35:39149 // If V8 zaps garbage, all the memory mapped regions become resident,
150 // so we add an extra dump to avoid mismatches w.r.t. the total
151 // resident values.
152 if (heap_statistics.does_zap_garbage()) {
vmpstr1ee03c4c02016-06-30 21:40:56153 auto* zap_dump = process_memory_dump->CreateAllocatorDump(
ssidbce6ee42015-11-05 02:35:39154 dump_base_name + "/zapped_for_debug");
155 zap_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
156 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
157 heap_statistics.total_heap_size() -
158 heap_statistics.total_physical_size());
159 }
160
jochen07eb75792016-04-09 20:34:02161 // Dump statistics about malloced memory.
162 std::string malloc_name = dump_base_name + "/malloc";
vmpstr1ee03c4c02016-06-30 21:40:56163 auto* malloc_dump = process_memory_dump->CreateAllocatorDump(malloc_name);
jochen07eb75792016-04-09 20:34:02164 malloc_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
165 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
166 heap_statistics.malloced_memory());
jochen077e9d72016-07-19 19:22:38167 malloc_dump->AddScalar("peak_size",
168 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
169 heap_statistics.peak_malloced_memory());
jochen07eb75792016-04-09 20:34:02170 const char* system_allocator_name =
171 base::trace_event::MemoryDumpManager::GetInstance()
172 ->system_allocator_pool_name();
173 if (system_allocator_name) {
174 process_memory_dump->AddSuballocation(malloc_dump->guid(),
175 system_allocator_name);
176 }
177
mythria35540662016-06-03 15:02:05178 // Add an empty row for the heap_spaces. This is to keep the shape of the
179 // dump stable, whether code stats are enabled or not.
vmpstr1ee03c4c02016-06-30 21:40:56180 auto* heap_spaces_dump =
mythria35540662016-06-03 15:02:05181 process_memory_dump->CreateAllocatorDump(space_name_prefix);
182
rmcilroy6b6b89a2016-08-25 15:12:57183 // Dump statistics related to code and bytecode if requested.
184 DumpCodeStatistics(heap_spaces_dump, isolate_holder_);
185
ssid3011f202016-06-01 20:24:26186 // Dump object statistics only for detailed dumps.
187 if (args.level_of_detail !=
188 base::trace_event::MemoryDumpLevelOfDetail::DETAILED) {
ssid2888a242015-08-07 23:08:42189 return;
ssid3011f202016-06-01 20:24:26190 }
ssid2888a242015-08-07 23:08:42191
sside36cfaf2015-06-12 16:42:20192 // Dump statistics of the heap's live objects from last GC.
primiano553bea9a2015-09-09 16:37:35193 // TODO(primiano): these should not be tracked in the same trace event as they
194 // report stats for the last GC (not the current state). See crbug.com/498779.
195 std::string object_name_prefix = dump_base_name + "/heap_objects_at_last_gc";
sside36cfaf2015-06-12 16:42:20196 bool did_dump_object_stats = false;
ssidf51216b02015-06-04 19:46:23197 const size_t object_types =
198 isolate_holder_->isolate()->NumberOfTrackedHeapObjectTypes();
199 for (size_t type_index = 0; type_index < object_types; type_index++) {
200 v8::HeapObjectStatistics object_statistics;
201 if (!isolate_holder_->isolate()->GetHeapObjectStatisticsAtLastGC(
202 &object_statistics, type_index))
203 continue;
204
205 std::string dump_name =
sside36cfaf2015-06-12 16:42:20206 object_name_prefix + "/" + object_statistics.object_type();
ssidf51216b02015-06-04 19:46:23207 if (object_statistics.object_sub_type()[0] != '\0')
208 dump_name += std::string("/") + object_statistics.object_sub_type();
vmpstr1ee03c4c02016-06-30 21:40:56209 auto* object_dump = process_memory_dump->CreateAllocatorDump(dump_name);
ssidf51216b02015-06-04 19:46:23210
211 object_dump->AddScalar(
bratell10f2e3c2015-09-10 16:28:43212 base::trace_event::MemoryAllocatorDump::kNameObjectCount,
ssidf51216b02015-06-04 19:46:23213 base::trace_event::MemoryAllocatorDump::kUnitsObjects,
214 object_statistics.object_count());
sside36cfaf2015-06-12 16:42:20215 object_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
216 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
217 object_statistics.object_size());
218 did_dump_object_stats = true;
ssidf51216b02015-06-04 19:46:23219 }
220
sside36cfaf2015-06-12 16:42:20221 if (process_memory_dump->GetAllocatorDump(object_name_prefix +
222 "/CODE_TYPE")) {
vmpstr1ee03c4c02016-06-30 21:40:56223 auto* code_kind_dump = process_memory_dump->CreateAllocatorDump(
sside36cfaf2015-06-12 16:42:20224 object_name_prefix + "/CODE_TYPE/CODE_KIND");
vmpstr1ee03c4c02016-06-30 21:40:56225 auto* code_age_dump = process_memory_dump->CreateAllocatorDump(
sside36cfaf2015-06-12 16:42:20226 object_name_prefix + "/CODE_TYPE/CODE_AGE");
227 process_memory_dump->AddOwnershipEdge(code_kind_dump->guid(),
228 code_age_dump->guid());
229 }
230
231 if (did_dump_object_stats) {
232 process_memory_dump->AddOwnershipEdge(
233 process_memory_dump->CreateAllocatorDump(object_name_prefix)->guid(),
mythria35540662016-06-03 15:02:05234 heap_spaces_dump->guid());
sside36cfaf2015-06-12 16:42:20235 }
ssidf51216b02015-06-04 19:46:23236}
237
ssid83aa5be2015-05-08 12:03:26238} // namespace gin