Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: base/trace_event/heap_profiler_heap_dump_writer_unittest.cc

Issue 1467453003: [Tracing] Make heap profiler type info a string (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <stdlib.h> 5 #include <stdlib.h>
6 #include <string> 6 #include <string>
7 7
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/memory/ref_counted.h" 9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "base/trace_event/heap_profiler_allocation_context.h" 11 #include "base/trace_event/heap_profiler_allocation_context.h"
12 #include "base/trace_event/heap_profiler_heap_dump_writer.h" 12 #include "base/trace_event/heap_profiler_heap_dump_writer.h"
13 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h" 13 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
14 #include "base/trace_event/heap_profiler_type_name_deduplicator.h"
14 #include "base/trace_event/trace_event_argument.h" 15 #include "base/trace_event/trace_event_argument.h"
15 #include "base/values.h" 16 #include "base/values.h"
16 #include "testing/gtest/include/gtest/gtest.h" 17 #include "testing/gtest/include/gtest/gtest.h"
17 18
18 namespace { 19 namespace {
19 20
20 // Define all strings once, because the deduplicator requires pointer equality, 21 // Define all strings once, because the deduplicator requires pointer equality,
21 // and string interning is unreliable. 22 // and string interning is unreliable.
22 const char kBrowserMain[] = "BrowserMain"; 23 const char kBrowserMain[] = "BrowserMain";
23 const char kRendererMain[] = "RendererMain"; 24 const char kRendererMain[] = "RendererMain";
24 const char kCreateWidget[] = "CreateWidget"; 25 const char kCreateWidget[] = "CreateWidget";
25 const char kInitialize[] = "Initialize"; 26 const char kInitialize[] = "Initialize";
26 27
28 const char kInt[] = "int";
29 const char kBool[] = "bool";
30 const char kString[] = "string";
31
27 } // namespace 32 } // namespace
28 33
29 namespace base { 34 namespace base {
30 namespace trace_event { 35 namespace trace_event {
31 36
32 void AssertStringEq(const DictionaryValue* entry,
33 const char* key,
34 const char* expected_value) {
35 std::string str;
36 ASSERT_TRUE(entry->GetString(key, &str));
37 ASSERT_EQ(expected_value, str);
38 }
39
40 // Asserts that an integer stored in the json as a string has the correct value. 37 // Asserts that an integer stored in the json as a string has the correct value.
41 void AssertIntEq(const DictionaryValue* entry, 38 void AssertIntEq(const DictionaryValue* entry,
42 const char* key, 39 const char* key,
43 int expected_value) { 40 int expected_value) {
44 std::string str; 41 std::string str;
45 ASSERT_TRUE(entry->GetString(key, &str)); 42 ASSERT_TRUE(entry->GetString(key, &str));
46 ASSERT_EQ(expected_value, atoi(str.c_str())); 43 ASSERT_EQ(expected_value, atoi(str.c_str()));
47 } 44 }
48 45
49 scoped_ptr<Value> DumpAndReadBack(HeapDumpWriter* writer) { 46 scoped_ptr<Value> DumpAndReadBack(HeapDumpWriter* writer) {
50 scoped_refptr<TracedValue> traced_value = writer->WriteHeapDump(); 47 scoped_refptr<TracedValue> traced_value = writer->WriteHeapDump();
51 std::string json; 48 std::string json;
52 traced_value->AppendAsTraceFormat(&json); 49 traced_value->AppendAsTraceFormat(&json);
53 return JSONReader::Read(json); 50 return JSONReader::Read(json);
54 } 51 }
55 52
56 TEST(HeapDumpWriterTest, BacktraceTypeIdTable) { 53 TEST(HeapDumpWriterTest, BacktraceTypeNameTable) {
57 auto deduplicator = make_scoped_refptr(new StackFrameDeduplicator); 54 auto sf_deduplicator = make_scoped_refptr(new StackFrameDeduplicator);
58 HeapDumpWriter writer(deduplicator.get()); 55 auto tn_deduplicator = make_scoped_refptr(new TypeNameDeduplicator);
56 HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get());
59 57
60 AllocationContext ctx = AllocationContext::Empty(); 58 AllocationContext ctx = AllocationContext::Empty();
61 ctx.backtrace.frames[0] = kBrowserMain; 59 ctx.backtrace.frames[0] = kBrowserMain;
62 ctx.backtrace.frames[1] = kCreateWidget; 60 ctx.backtrace.frames[1] = kCreateWidget;
63 ctx.type_id = 1; 61 ctx.type_name = kInt;
64 62
65 // 10 bytes with context { type: 1, bt: [BrowserMain, CreateWidget] }. 63 // 10 bytes with context { type: int, bt: [BrowserMain, CreateWidget] }.
66 writer.InsertAllocation(ctx, 2); 64 writer.InsertAllocation(ctx, 2);
67 writer.InsertAllocation(ctx, 3); 65 writer.InsertAllocation(ctx, 3);
68 writer.InsertAllocation(ctx, 5); 66 writer.InsertAllocation(ctx, 5);
69 67
70 ctx.type_id = 2; 68 ctx.type_name = kBool;
71 69
72 // 18 bytes with context { type: 2, bt: [BrowserMain, CreateWidget] }. 70 // 18 bytes with context { type: bool, bt: [BrowserMain, CreateWidget] }.
73 writer.InsertAllocation(ctx, 7); 71 writer.InsertAllocation(ctx, 7);
74 writer.InsertAllocation(ctx, 11); 72 writer.InsertAllocation(ctx, 11);
75 73
76 ctx.backtrace.frames[0] = kRendererMain; 74 ctx.backtrace.frames[0] = kRendererMain;
77 ctx.backtrace.frames[1] = kInitialize; 75 ctx.backtrace.frames[1] = kInitialize;
78 76
79 // 30 bytes with context { type: 2, bt: [RendererMain, Initialize] }. 77 // 30 bytes with context { type: bool, bt: [RendererMain, Initialize] }.
80 writer.InsertAllocation(ctx, 13); 78 writer.InsertAllocation(ctx, 13);
81 writer.InsertAllocation(ctx, 17); 79 writer.InsertAllocation(ctx, 17);
82 80
83 ctx.type_id = 3; 81 ctx.type_name = kString;
84 82
85 // 19 bytes with context { type: 3, bt: [RendererMain, Initialize] }. 83 // 19 bytes with context { type: string, bt: [RendererMain, Initialize] }.
86 writer.InsertAllocation(ctx, 19); 84 writer.InsertAllocation(ctx, 19);
87 85
88 // At this point the heap looks like this: 86 // At this point the heap looks like this:
89 // 87 //
90 // | | CrWidget <- BrMain | Init <- RenMain | Sum | 88 // | | CrWidget <- BrMain | Init <- RenMain | Sum |
91 // +--------+--------------------+-----------------+-----+ 89 // +--------+--------------------+-----------------+-----+
92 // | Type 1 | 10 | 0 | 10 | 90 // | int | 10 | 0 | 10 |
93 // | Type 2 | 18 | 30 | 48 | 91 // | bool | 18 | 30 | 48 |
94 // | Type 3 | 0 | 19 | 19 | 92 // | string | 0 | 19 | 19 |
95 // +--------+--------------------+-----------------+-----+ 93 // +--------+--------------------+-----------------+-----+
96 // | Sum | 28 | 49 | 77 | 94 // | Sum | 28 | 49 | 77 |
97 95
98 scoped_ptr<Value> heap_dump = DumpAndReadBack(&writer); 96 scoped_ptr<Value> heap_dump = DumpAndReadBack(&writer);
99 97
100 // The json heap dump should at least include this: 98 // The json heap dump should at least include this:
101 // { 99 // {
102 // "entries": [ 100 // "entries": [
103 // { "size": "4d" }, // 77 = 0x4d. 101 // { "size": "4d" }, // 77 = 0x4d.
104 // { "size": "31", "bt": "id_of(Init <- RenMain)" }, // 49 = 0x31. 102 // { "size": "31", "bt": "id_of(Init <- RenMain)" }, // 49 = 0x31.
105 // { "size": "1c", "bt": "id_of(CrWidget <- BrMain)" }, // 28 = 0x1c. 103 // { "size": "1c", "bt": "id_of(CrWidget <- BrMain)" }, // 28 = 0x1c.
106 // { "size": "30", "type": "2" }, // 48 = 0x30. 104 // { "size": "30", "type": "id_of(bool)" }, // 48 = 0x30.
107 // { "size": "13", "type": "3" }, // 19 = 0x13. 105 // { "size": "13", "type": "id_of(string)" }, // 19 = 0x13.
108 // { "size": "a", "type": "1" } // 10 = 0xa. 106 // { "size": "a", "type": "id_of(int)" } // 10 = 0xa.
109 // ] 107 // ]
110 // } 108 // }
111 109
112 // Get the indices of the backtraces by adding them again to the deduplicator. 110 // Get the indices of the backtraces and types by adding them again to the
113 // Because they were added before, the same number is returned. 111 // deduplicator. Because they were added before, the same number is returned.
114 int bt_renderer_main_initialize = 112 int bt_renderer_main_initialize =
115 deduplicator->Insert({{kRendererMain, kInitialize}}); 113 sf_deduplicator->Insert({{kRendererMain, kInitialize}});
116 int bt_browser_main_create_widget = 114 int bt_browser_main_create_widget =
117 deduplicator->Insert({{kBrowserMain, kCreateWidget}}); 115 sf_deduplicator->Insert({{kBrowserMain, kCreateWidget}});
116 int type_id_int = tn_deduplicator->Insert(kInt);
117 int type_id_bool = tn_deduplicator->Insert(kBool);
118 int type_id_string = tn_deduplicator->Insert(kString);
118 119
119 const DictionaryValue* dictionary; 120 const DictionaryValue* dictionary;
120 ASSERT_TRUE(heap_dump->GetAsDictionary(&dictionary)); 121 ASSERT_TRUE(heap_dump->GetAsDictionary(&dictionary));
121 122
122 const ListValue* entries; 123 const ListValue* entries;
123 ASSERT_TRUE(dictionary->GetList("entries", &entries)); 124 ASSERT_TRUE(dictionary->GetList("entries", &entries));
124 125
125 // Keep counters to verify that every entry is present exactly once. 126 // Keep counters to verify that every entry is present exactly once.
126 int x4d_seen = 0; 127 int x4d_seen = 0;
127 int x31_seen = 0; 128 int x31_seen = 0;
(...skipping 19 matching lines...) Expand all
147 // Entry for backtrace "Initialize <- RendererMain". 148 // Entry for backtrace "Initialize <- RendererMain".
148 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements. 149 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements.
149 AssertIntEq(entry, "bt", bt_renderer_main_initialize); 150 AssertIntEq(entry, "bt", bt_renderer_main_initialize);
150 x31_seen++; 151 x31_seen++;
151 } else if (size == "1c") { 152 } else if (size == "1c") {
152 // Entry for backtrace "CreateWidget <- BrowserMain". 153 // Entry for backtrace "CreateWidget <- BrowserMain".
153 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements. 154 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements.
154 AssertIntEq(entry, "bt", bt_browser_main_create_widget); 155 AssertIntEq(entry, "bt", bt_browser_main_create_widget);
155 x1c_seen++; 156 x1c_seen++;
156 } else if (size == "30") { 157 } else if (size == "30") {
157 // Entry for type ID 2. 158 // Entry for type bool.
158 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements. 159 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements.
159 AssertStringEq(entry, "type", "2"); 160 AssertIntEq(entry, "type", type_id_bool);
160 x30_seen++; 161 x30_seen++;
161 } else if (size == "13") { 162 } else if (size == "13") {
162 // Entry for type ID 3. 163 // Entry for type string.
163 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements. 164 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements.
164 AssertStringEq(entry, "type", "3"); 165 AssertIntEq(entry, "type", type_id_string);
165 x13_seen++; 166 x13_seen++;
166 } else if (size == "a") { 167 } else if (size == "a") {
167 // Entry for type ID 1. 168 // Entry for type int.
168 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements. 169 ASSERT_EQ(2u, entry->size()); // Dictionary must have two elements.
169 AssertStringEq(entry, "type", "1"); 170 AssertIntEq(entry, "type", type_id_int);
170 xa_seen++; 171 xa_seen++;
171 } 172 }
172 } 173 }
173 174
174 ASSERT_EQ(1, x4d_seen); 175 ASSERT_EQ(1, x4d_seen);
175 ASSERT_EQ(1, x31_seen); 176 ASSERT_EQ(1, x31_seen);
176 ASSERT_EQ(1, x1c_seen); 177 ASSERT_EQ(1, x1c_seen);
177 ASSERT_EQ(1, x30_seen); 178 ASSERT_EQ(1, x30_seen);
178 ASSERT_EQ(1, x13_seen); 179 ASSERT_EQ(1, x13_seen);
179 ASSERT_EQ(1, xa_seen); 180 ASSERT_EQ(1, xa_seen);
180 } 181 }
181 182
182 // Test that the entry for the empty backtrace ends up in the json with the 183 // Test that the entry for the empty backtrace ends up in the json with the
183 // "bt" field set to the empty string. Also test that the entry for "unknown 184 // "bt" field set to the empty string. Also test that an entry for "unknown
184 // type" (type ID 0) ends up in the json with the "type" field set to the empty 185 // type" (nullptr type name) does not dereference the null pointer when writing
185 // string. 186 // the type names, and that the type ID is 0.
186 TEST(HeapDumpWriterTest, EmptyBacktraceIndexAndUnknownTypeIdAreEmptyString) { 187 TEST(HeapDumpWriterTest, EmptyBacktraceIndexIsEmptyString) {
187 auto deduplicator = make_scoped_refptr(new StackFrameDeduplicator); 188 auto sf_deduplicator = make_scoped_refptr(new StackFrameDeduplicator);
188 HeapDumpWriter writer(deduplicator.get()); 189 auto tn_deduplicator = make_scoped_refptr(new TypeNameDeduplicator);
190 HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get());
189 191
190 // A context with empty backtrace and type ID 0 (unknown type). 192 // A context with empty backtrace and unknown type (nullptr).
191 AllocationContext ctx = AllocationContext::Empty(); 193 AllocationContext ctx = AllocationContext::Empty();
192 194
193 writer.InsertAllocation(ctx, 1); 195 writer.InsertAllocation(ctx, 1);
194 196
195 scoped_ptr<Value> heap_dump = DumpAndReadBack(&writer); 197 scoped_ptr<Value> heap_dump = DumpAndReadBack(&writer);
196 198
197 const DictionaryValue* dictionary; 199 const DictionaryValue* dictionary;
198 ASSERT_TRUE(heap_dump->GetAsDictionary(&dictionary)); 200 ASSERT_TRUE(heap_dump->GetAsDictionary(&dictionary));
199 201
200 const ListValue* entries; 202 const ListValue* entries;
(...skipping 10 matching lines...) Expand all
211 if (entry->HasKey("bt") && entry->size() == 2) { 213 if (entry->HasKey("bt") && entry->size() == 2) {
212 std::string backtrace; 214 std::string backtrace;
213 ASSERT_TRUE(entry->GetString("bt", &backtrace)); 215 ASSERT_TRUE(entry->GetString("bt", &backtrace));
214 ASSERT_EQ("", backtrace); 216 ASSERT_EQ("", backtrace);
215 empty_backtrace_seen++; 217 empty_backtrace_seen++;
216 } 218 }
217 219
218 if (entry->HasKey("type") && entry->size() == 2) { 220 if (entry->HasKey("type") && entry->size() == 2) {
219 std::string type_id; 221 std::string type_id;
220 ASSERT_TRUE(entry->GetString("type", &type_id)); 222 ASSERT_TRUE(entry->GetString("type", &type_id));
221 ASSERT_EQ("", type_id); 223 ASSERT_EQ("0", type_id);
222 unknown_type_seen++; 224 unknown_type_seen++;
223 } 225 }
224 } 226 }
225 227
226 ASSERT_EQ(1, unknown_type_seen); 228 ASSERT_EQ(1, unknown_type_seen);
227 ASSERT_EQ(1, empty_backtrace_seen); 229 ASSERT_EQ(1, empty_backtrace_seen);
228 } 230 }
229 231
230 } // namespace trace_event 232 } // namespace trace_event
231 } // namespace base 233 } // namespace base
OLDNEW
« no previous file with comments | « base/trace_event/heap_profiler_heap_dump_writer.cc ('k') | base/trace_event/heap_profiler_type_name_deduplicator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698