1 // 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 "third_party/blink/renderer/platform/heap/blink_gc_memory_dump_provider.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/trace_event/memory_allocator_dump.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "base/trace_event/process_memory_dump.h"
12 #include "third_party/blink/public/platform/platform.h"
13 #include "third_party/blink/renderer/platform/heap/handle.h"
14 #include "third_party/blink/renderer/platform/heap/impl/thread_state_statistics.h"
15 #include "third_party/blink/renderer/platform/heap/thread_state.h"
16 #include "third_party/blink/renderer/platform/instrumentation/tracing/web_memory_allocator_dump.h"
17 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
18 #include "third_party/blink/renderer/platform/wtf/threading.h"
19
20 namespace blink {
21 namespace {
22
HeapTypeString(BlinkGCMemoryDumpProvider::HeapType heap_type)23 constexpr const char* HeapTypeString(
24 BlinkGCMemoryDumpProvider::HeapType heap_type) {
25 switch (heap_type) {
26 case BlinkGCMemoryDumpProvider::HeapType::kBlinkMainThread:
27 return "main";
28 case BlinkGCMemoryDumpProvider::HeapType::kBlinkWorkerThread:
29 return "workers";
30 }
31 }
32
33 } // namespace
34
BlinkGCMemoryDumpProvider(ThreadState * thread_state,scoped_refptr<base::SingleThreadTaskRunner> task_runner,BlinkGCMemoryDumpProvider::HeapType heap_type)35 BlinkGCMemoryDumpProvider::BlinkGCMemoryDumpProvider(
36 ThreadState* thread_state,
37 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
38 BlinkGCMemoryDumpProvider::HeapType heap_type)
39 : thread_state_(thread_state),
40 heap_type_(heap_type),
41 dump_base_name_(
42 "blink_gc/" + std::string(HeapTypeString(heap_type_)) + "/heap" +
43 (heap_type_ == HeapType::kBlinkWorkerThread
44 ? "/" + base::StringPrintf(
45 "worker_0x%" PRIXPTR,
46 reinterpret_cast<uintptr_t>(thread_state_))
47 : "")) {
48 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
49 this, "BlinkGC", task_runner);
50 }
51
~BlinkGCMemoryDumpProvider()52 BlinkGCMemoryDumpProvider::~BlinkGCMemoryDumpProvider() {
53 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
54 this);
55 }
56
OnMemoryDump(const base::trace_event::MemoryDumpArgs & args,base::trace_event::ProcessMemoryDump * process_memory_dump)57 bool BlinkGCMemoryDumpProvider::OnMemoryDump(
58 const base::trace_event::MemoryDumpArgs& args,
59 base::trace_event::ProcessMemoryDump* process_memory_dump) {
60 ThreadState::Statistics::DetailLevel detail_level =
61 args.level_of_detail ==
62 base::trace_event::MemoryDumpLevelOfDetail::DETAILED
63 ? ThreadState::Statistics::kDetailed
64 : ThreadState::Statistics::kBrief;
65
66 ThreadState::Statistics stats =
67 ThreadState::StatisticsCollector(thread_state_)
68 .CollectStatistics(detail_level);
69
70 auto* heap_dump = process_memory_dump->CreateAllocatorDump(dump_base_name_);
71 heap_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
72 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
73 stats.committed_size_bytes);
74 heap_dump->AddScalar("allocated_objects_size",
75 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
76 stats.used_size_bytes);
77
78 if (detail_level == ThreadState::Statistics::kBrief) {
79 return true;
80 }
81
82 // Detailed statistics.
83 for (const ThreadState::Statistics::ArenaStatistics& arena_stats :
84 stats.arena_stats) {
85 std::string arena_dump_name = dump_base_name_ + "/" + arena_stats.name;
86 auto* arena_dump =
87 process_memory_dump->CreateAllocatorDump(arena_dump_name);
88 arena_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
89 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
90 arena_stats.committed_size_bytes);
91 arena_dump->AddScalar("allocated_objects_size",
92 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
93 arena_stats.used_size_bytes);
94
95 size_t page_count = 0;
96 for (const ThreadState::Statistics::PageStatistics& page_stats :
97 arena_stats.page_stats) {
98 auto* page_dump = process_memory_dump->CreateAllocatorDump(
99 arena_dump_name + "/pages/page_" +
100 base::NumberToString(page_count++));
101 page_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
102 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
103 page_stats.committed_size_bytes);
104 page_dump->AddScalar("allocated_objects_size",
105 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
106 page_stats.used_size_bytes);
107 }
108
109 const ThreadState::Statistics::FreeListStatistics& free_list_stats =
110 arena_stats.free_list_stats;
111 for (wtf_size_t i = 0; i < free_list_stats.bucket_size.size(); ++i) {
112 constexpr size_t kDigits = 8;
113 std::string original_bucket_size =
114 base::NumberToString(free_list_stats.bucket_size[i]);
115 std::string padded_bucket_size =
116 std::string(kDigits - original_bucket_size.length(), '0') +
117 original_bucket_size;
118 auto* free_list_bucket_dump = process_memory_dump->CreateAllocatorDump(
119 arena_dump_name + "/freelist/bucket_" + padded_bucket_size);
120 free_list_bucket_dump->AddScalar(
121 "free_size", base::trace_event::MemoryAllocatorDump::kUnitsBytes,
122 free_list_stats.free_size[i]);
123 }
124
125 const ThreadState::Statistics::ObjectStatistics& object_stats =
126 arena_stats.object_stats;
127 for (wtf_size_t i = 1; i < object_stats.num_types; i++) {
128 if (object_stats.type_name[i].empty())
129 continue;
130
131 auto* class_dump = process_memory_dump->CreateAllocatorDump(
132 arena_dump_name + "/classes/" + object_stats.type_name[i]);
133 class_dump->AddScalar(
134 "object_count", base::trace_event::MemoryAllocatorDump::kUnitsObjects,
135 object_stats.type_count[i]);
136 class_dump->AddScalar("object_size",
137 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
138 object_stats.type_bytes[i]);
139 }
140 }
141 return true;
142 }
143
144 } // namespace blink
145