OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "base/trace_event/heap_profiler_heap_dump_writer.h" |
| 6 |
5 #include <stddef.h> | 7 #include <stddef.h> |
6 | 8 |
| 9 #include <memory> |
7 #include <set> | 10 #include <set> |
8 #include <string> | 11 #include <string> |
9 | 12 |
10 #include "base/json/json_reader.h" | 13 #include "base/json/json_reader.h" |
11 #include "base/macros.h" | 14 #include "base/macros.h" |
12 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/ptr_util.h" |
13 #include "base/trace_event/heap_profiler_allocation_context.h" | 16 #include "base/trace_event/heap_profiler_allocation_context.h" |
14 #include "base/trace_event/heap_profiler_heap_dump_writer.h" | |
15 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h" | 17 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h" |
16 #include "base/trace_event/heap_profiler_type_name_deduplicator.h" | 18 #include "base/trace_event/heap_profiler_type_name_deduplicator.h" |
17 #include "base/trace_event/trace_event_argument.h" | 19 #include "base/trace_event/trace_event_argument.h" |
18 #include "base/values.h" | 20 #include "base/values.h" |
19 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
20 | 22 |
21 namespace { | 23 namespace { |
22 | 24 |
23 // Define all strings once, because the deduplicator requires pointer equality, | 25 // Define all strings once, because the deduplicator requires pointer equality, |
24 // and string interning is unreliable. | 26 // and string interning is unreliable. |
25 const char kBrowserMain[] = "BrowserMain"; | 27 const char kBrowserMain[] = "BrowserMain"; |
26 const char kRendererMain[] = "RendererMain"; | 28 const char kRendererMain[] = "RendererMain"; |
27 const char kCreateWidget[] = "CreateWidget"; | 29 const char kCreateWidget[] = "CreateWidget"; |
28 const char kInitialize[] = "Initialize"; | 30 const char kInitialize[] = "Initialize"; |
29 const char kGetBitmap[] = "GetBitmap"; | 31 const char kGetBitmap[] = "GetBitmap"; |
30 | 32 |
31 const char kInt[] = "int"; | 33 const char kInt[] = "int"; |
32 const char kBool[] = "bool"; | 34 const char kBool[] = "bool"; |
33 const char kString[] = "string"; | 35 const char kString[] = "string"; |
34 | 36 |
35 } // namespace | 37 } // namespace |
36 | 38 |
37 namespace base { | 39 namespace base { |
38 namespace trace_event { | 40 namespace trace_event { |
39 namespace internal { | 41 namespace internal { |
40 | 42 |
41 scoped_ptr<const Value> WriteAndReadBack(const std::set<Entry>& entries) { | 43 std::unique_ptr<const Value> WriteAndReadBack(const std::set<Entry>& entries) { |
42 scoped_ptr<TracedValue> traced_value = Serialize(entries); | 44 std::unique_ptr<TracedValue> traced_value = Serialize(entries); |
43 std::string json; | 45 std::string json; |
44 traced_value->AppendAsTraceFormat(&json); | 46 traced_value->AppendAsTraceFormat(&json); |
45 return JSONReader::Read(json); | 47 return JSONReader::Read(json); |
46 } | 48 } |
47 | 49 |
48 scoped_ptr<const DictionaryValue> WriteAndReadBackEntry(Entry entry) { | 50 std::unique_ptr<const DictionaryValue> WriteAndReadBackEntry(Entry entry) { |
49 std::set<Entry> input_entries; | 51 std::set<Entry> input_entries; |
50 input_entries.insert(entry); | 52 input_entries.insert(entry); |
51 | 53 |
52 scoped_ptr<const Value> json_dict = WriteAndReadBack(input_entries); | 54 std::unique_ptr<const Value> json_dict = WriteAndReadBack(input_entries); |
53 | 55 |
54 // Note: Ideally these should use |ASSERT_TRUE| instead of |EXPECT_TRUE|, but | 56 // Note: Ideally these should use |ASSERT_TRUE| instead of |EXPECT_TRUE|, but |
55 // |ASSERT_TRUE| can only be used in void functions. | 57 // |ASSERT_TRUE| can only be used in void functions. |
56 const DictionaryValue* dictionary; | 58 const DictionaryValue* dictionary; |
57 EXPECT_TRUE(json_dict->GetAsDictionary(&dictionary)); | 59 EXPECT_TRUE(json_dict->GetAsDictionary(&dictionary)); |
58 | 60 |
59 const ListValue* json_entries; | 61 const ListValue* json_entries; |
60 EXPECT_TRUE(dictionary->GetList("entries", &json_entries)); | 62 EXPECT_TRUE(dictionary->GetList("entries", &json_entries)); |
61 | 63 |
62 const DictionaryValue* json_entry; | 64 const DictionaryValue* json_entry; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 << "Entry should not be present for sf = " << stack_frame_id | 101 << "Entry should not be present for sf = " << stack_frame_id |
100 << ", type = " << type_id << "."; | 102 << ", type = " << type_id << "."; |
101 } | 103 } |
102 | 104 |
103 TEST(HeapDumpWriterTest, BacktraceIndex) { | 105 TEST(HeapDumpWriterTest, BacktraceIndex) { |
104 Entry entry; | 106 Entry entry; |
105 entry.stack_frame_id = -1; // -1 means empty backtrace. | 107 entry.stack_frame_id = -1; // -1 means empty backtrace. |
106 entry.type_id = 0; | 108 entry.type_id = 0; |
107 entry.size = 1; | 109 entry.size = 1; |
108 | 110 |
109 scoped_ptr<const DictionaryValue> json_entry = WriteAndReadBackEntry(entry); | 111 std::unique_ptr<const DictionaryValue> json_entry = |
| 112 WriteAndReadBackEntry(entry); |
110 | 113 |
111 // For an empty backtrace, the "bt" key cannot reference a stack frame. | 114 // For an empty backtrace, the "bt" key cannot reference a stack frame. |
112 // Instead it should be set to the empty string. | 115 // Instead it should be set to the empty string. |
113 std::string backtrace_index; | 116 std::string backtrace_index; |
114 ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index)); | 117 ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index)); |
115 ASSERT_EQ("", backtrace_index); | 118 ASSERT_EQ("", backtrace_index); |
116 | 119 |
117 // Also verify that a non-negative backtrace index is dumped properly. | 120 // Also verify that a non-negative backtrace index is dumped properly. |
118 entry.stack_frame_id = 2; | 121 entry.stack_frame_id = 2; |
119 json_entry = WriteAndReadBackEntry(entry); | 122 json_entry = WriteAndReadBackEntry(entry); |
120 ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index)); | 123 ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index)); |
121 ASSERT_EQ("2", backtrace_index); | 124 ASSERT_EQ("2", backtrace_index); |
122 } | 125 } |
123 | 126 |
124 TEST(HeapDumpWriterTest, TypeId) { | 127 TEST(HeapDumpWriterTest, TypeId) { |
125 Entry entry; | 128 Entry entry; |
126 entry.type_id = -1; // -1 means sum over all types. | 129 entry.type_id = -1; // -1 means sum over all types. |
127 entry.stack_frame_id = 0; | 130 entry.stack_frame_id = 0; |
128 entry.size = 1; | 131 entry.size = 1; |
129 | 132 |
130 scoped_ptr<const DictionaryValue> json_entry = WriteAndReadBackEntry(entry); | 133 std::unique_ptr<const DictionaryValue> json_entry = |
| 134 WriteAndReadBackEntry(entry); |
131 | 135 |
132 // Entries for the cumulative size of all types should not have the "type" | 136 // Entries for the cumulative size of all types should not have the "type" |
133 // key set. | 137 // key set. |
134 ASSERT_FALSE(json_entry->HasKey("type")); | 138 ASSERT_FALSE(json_entry->HasKey("type")); |
135 | 139 |
136 // Also verify that a non-negative type ID is dumped properly. | 140 // Also verify that a non-negative type ID is dumped properly. |
137 entry.type_id = 2; | 141 entry.type_id = 2; |
138 json_entry = WriteAndReadBackEntry(entry); | 142 json_entry = WriteAndReadBackEntry(entry); |
139 std::string type_id; | 143 std::string type_id; |
140 ASSERT_TRUE(json_entry->GetString("type", &type_id)); | 144 ASSERT_TRUE(json_entry->GetString("type", &type_id)); |
141 ASSERT_EQ("2", type_id); | 145 ASSERT_EQ("2", type_id); |
142 } | 146 } |
143 | 147 |
144 TEST(HeapDumpWriterTest, SizeIsHexadecimalString) { | 148 TEST(HeapDumpWriterTest, SizeIsHexadecimalString) { |
145 // Take a number between 2^63 and 2^64 (or between 2^31 and 2^32 if |size_t| | 149 // Take a number between 2^63 and 2^64 (or between 2^31 and 2^32 if |size_t| |
146 // is not 64 bits). | 150 // is not 64 bits). |
147 const size_t large_value = | 151 const size_t large_value = |
148 sizeof(size_t) == 8 ? 0xffffffffffffffc5 : 0xffffff9d; | 152 sizeof(size_t) == 8 ? 0xffffffffffffffc5 : 0xffffff9d; |
149 const char* large_value_str = | 153 const char* large_value_str = |
150 sizeof(size_t) == 8 ? "ffffffffffffffc5" : "ffffff9d"; | 154 sizeof(size_t) == 8 ? "ffffffffffffffc5" : "ffffff9d"; |
151 Entry entry; | 155 Entry entry; |
152 entry.type_id = 0; | 156 entry.type_id = 0; |
153 entry.stack_frame_id = 0; | 157 entry.stack_frame_id = 0; |
154 entry.size = large_value; | 158 entry.size = large_value; |
155 | 159 |
156 scoped_ptr<const DictionaryValue> json_entry = WriteAndReadBackEntry(entry); | 160 std::unique_ptr<const DictionaryValue> json_entry = |
| 161 WriteAndReadBackEntry(entry); |
157 | 162 |
158 std::string size; | 163 std::string size; |
159 ASSERT_TRUE(json_entry->GetString("size", &size)); | 164 ASSERT_TRUE(json_entry->GetString("size", &size)); |
160 ASSERT_EQ(large_value_str, size); | 165 ASSERT_EQ(large_value_str, size); |
161 } | 166 } |
162 | 167 |
163 TEST(HeapDumpWriterTest, BacktraceTypeNameTable) { | 168 TEST(HeapDumpWriterTest, BacktraceTypeNameTable) { |
164 hash_map<AllocationContext, size_t> bytes_by_context; | 169 hash_map<AllocationContext, size_t> bytes_by_context; |
165 | 170 |
166 AllocationContext ctx = AllocationContext::Empty(); | 171 AllocationContext ctx = AllocationContext::Empty(); |
(...skipping 23 matching lines...) Expand all Loading... |
190 // At this point the heap looks like this: | 195 // At this point the heap looks like this: |
191 // | 196 // |
192 // | | CrWidget <- BrMain | Init <- RenMain | Sum | | 197 // | | CrWidget <- BrMain | Init <- RenMain | Sum | |
193 // +--------+--------------------+-----------------+-----+ | 198 // +--------+--------------------+-----------------+-----+ |
194 // | int | 10 | 0 | 10 | | 199 // | int | 10 | 0 | 10 | |
195 // | bool | 18 | 30 | 48 | | 200 // | bool | 18 | 30 | 48 | |
196 // | string | 0 | 19 | 19 | | 201 // | string | 0 | 19 | 19 | |
197 // +--------+--------------------+-----------------+-----+ | 202 // +--------+--------------------+-----------------+-----+ |
198 // | Sum | 28 | 49 | 77 | | 203 // | Sum | 28 | 49 | 77 | |
199 | 204 |
200 auto sf_deduplicator = make_scoped_ptr(new StackFrameDeduplicator); | 205 auto sf_deduplicator = WrapUnique(new StackFrameDeduplicator); |
201 auto tn_deduplicator = make_scoped_ptr(new TypeNameDeduplicator); | 206 auto tn_deduplicator = WrapUnique(new TypeNameDeduplicator); |
202 HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get()); | 207 HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get()); |
203 const std::set<Entry>& dump = writer.Summarize(bytes_by_context); | 208 const std::set<Entry>& dump = writer.Summarize(bytes_by_context); |
204 | 209 |
205 // Get the indices of the backtraces and types by adding them again to the | 210 // Get the indices of the backtraces and types by adding them again to the |
206 // deduplicator. Because they were added before, the same number is returned. | 211 // deduplicator. Because they were added before, the same number is returned. |
207 StackFrame bt0[] = {kRendererMain, kInitialize}; | 212 StackFrame bt0[] = {kRendererMain, kInitialize}; |
208 StackFrame bt1[] = {kBrowserMain, kCreateWidget}; | 213 StackFrame bt1[] = {kBrowserMain, kCreateWidget}; |
209 int bt_renderer_main = sf_deduplicator->Insert(bt0, bt0 + 1); | 214 int bt_renderer_main = sf_deduplicator->Insert(bt0, bt0 + 1); |
210 int bt_browser_main = sf_deduplicator->Insert(bt1, bt1 + 1); | 215 int bt_browser_main = sf_deduplicator->Insert(bt1, bt1 + 1); |
211 int bt_renderer_main_initialize = sf_deduplicator->Insert(bt0, bt0 + 2); | 216 int bt_renderer_main_initialize = sf_deduplicator->Insert(bt0, bt0 + 2); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 bytes_by_context[ctx] = 512; | 260 bytes_by_context[ctx] = 512; |
256 | 261 |
257 // 1 MiB in BrowserMain -> CreateWidget -> GetBitmap. | 262 // 1 MiB in BrowserMain -> CreateWidget -> GetBitmap. |
258 ctx.backtrace.frames[2] = kGetBitmap; | 263 ctx.backtrace.frames[2] = kGetBitmap; |
259 bytes_by_context[ctx] = 1024 * 1024; | 264 bytes_by_context[ctx] = 1024 * 1024; |
260 | 265 |
261 // 0.5 KiB in BrowserMain -> CreateWidget -> Initialize. | 266 // 0.5 KiB in BrowserMain -> CreateWidget -> Initialize. |
262 ctx.backtrace.frames[2] = kInitialize; | 267 ctx.backtrace.frames[2] = kInitialize; |
263 bytes_by_context[ctx] = 512; | 268 bytes_by_context[ctx] = 512; |
264 | 269 |
265 auto sf_deduplicator = make_scoped_ptr(new StackFrameDeduplicator); | 270 auto sf_deduplicator = WrapUnique(new StackFrameDeduplicator); |
266 auto tn_deduplicator = make_scoped_ptr(new TypeNameDeduplicator); | 271 auto tn_deduplicator = WrapUnique(new TypeNameDeduplicator); |
267 HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get()); | 272 HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get()); |
268 const std::set<Entry>& dump = writer.Summarize(bytes_by_context); | 273 const std::set<Entry>& dump = writer.Summarize(bytes_by_context); |
269 | 274 |
270 // Get the indices of the backtraces and types by adding them again to the | 275 // Get the indices of the backtraces and types by adding them again to the |
271 // deduplicator. Because they were added before, the same number is returned. | 276 // deduplicator. Because they were added before, the same number is returned. |
272 StackFrame bt0[] = {kBrowserMain, kCreateWidget, kGetBitmap}; | 277 StackFrame bt0[] = {kBrowserMain, kCreateWidget, kGetBitmap}; |
273 StackFrame bt1[] = {kBrowserMain, kCreateWidget, kInitialize}; | 278 StackFrame bt1[] = {kBrowserMain, kCreateWidget, kInitialize}; |
274 int bt_browser_main = sf_deduplicator->Insert(bt0, bt0 + 1); | 279 int bt_browser_main = sf_deduplicator->Insert(bt0, bt0 + 1); |
275 int bt_create_widget = sf_deduplicator->Insert(bt0, bt0 + 2); | 280 int bt_create_widget = sf_deduplicator->Insert(bt0, bt0 + 2); |
276 int bt_get_bitmap = sf_deduplicator->Insert(bt0, bt0 + 3); | 281 int bt_get_bitmap = sf_deduplicator->Insert(bt0, bt0 + 3); |
(...skipping 11 matching lines...) Expand all Loading... |
288 AssertSizeEq(dump, bt_create_widget, -1, 1024 * 1024 + 512 + 512); | 293 AssertSizeEq(dump, bt_create_widget, -1, 1024 * 1024 + 512 + 512); |
289 AssertSizeEq(dump, bt_browser_main, -1, 1024 * 1024 + 512 + 512); | 294 AssertSizeEq(dump, bt_browser_main, -1, 1024 * 1024 + 512 + 512); |
290 | 295 |
291 // Initialize was not significant, it should not have been dumped. | 296 // Initialize was not significant, it should not have been dumped. |
292 AssertNotDumped(dump, bt_initialize, -1); | 297 AssertNotDumped(dump, bt_initialize, -1); |
293 } | 298 } |
294 | 299 |
295 } // namespace internal | 300 } // namespace internal |
296 } // namespace trace_event | 301 } // namespace trace_event |
297 } // namespace base | 302 } // namespace base |
OLD | NEW |