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_type_name_deduplicator.h" |
| 6 |
5 #include <memory> | 7 #include <memory> |
6 #include <string> | 8 #include <string> |
7 | 9 |
8 #include "base/json/json_reader.h" | 10 #include "base/memory/ptr_util.h" |
9 #include "base/trace_event/heap_profiler_type_name_deduplicator.h" | 11 #include "base/trace_event/heap_profiler_string_deduplicator.h" |
| 12 #include "base/trace_event/trace_event_argument.h" |
10 #include "base/values.h" | 13 #include "base/values.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
12 | 15 |
13 namespace base { | 16 namespace base { |
14 namespace trace_event { | 17 namespace trace_event { |
15 | 18 |
16 namespace { | 19 namespace { |
17 | 20 |
18 // Define all strings once, because the deduplicator requires pointer equality, | |
19 // and string interning is unreliable. | |
20 const char kInt[] = "int"; | |
21 const char kBool[] = "bool"; | |
22 const char kString[] = "string"; | |
23 const char kNeedsEscape[] = "\"quotes\""; | |
24 | |
25 #if defined(OS_POSIX) | 21 #if defined(OS_POSIX) |
26 const char kTaskFileName[] = "../../base/trace_event/trace_log.cc"; | 22 const char kTaskFileName[] = "../../base/trace_event/trace_log.cc"; |
27 const char kTaskPath[] = "base/trace_event"; | 23 const char kTaskPath[] = "base/trace_event"; |
28 #else | 24 #else |
29 const char kTaskFileName[] = "..\\..\\base\\memory\\memory_win.cc"; | 25 const char kTaskFileName[] = "..\\..\\base\\memory\\memory_win.cc"; |
30 const char kTaskPath[] = "base\\memory"; | 26 const char kTaskPath[] = "base\\memory"; |
31 #endif | 27 #endif |
32 | 28 |
33 std::unique_ptr<Value> DumpAndReadBack( | 29 // Calls TypeNameDeduplicator::SerializeIncrementally() and returns ListValue |
34 const TypeNameDeduplicator& deduplicator) { | 30 // with serialized entries. |
35 std::string json; | 31 std::unique_ptr<ListValue> SerializeEntriesIncrementally( |
36 deduplicator.AppendAsTraceFormat(&json); | 32 TypeNameDeduplicator* dedup) { |
37 return JSONReader::Read(json); | 33 TracedValue traced_value; |
| 34 traced_value.BeginArray(""); |
| 35 dedup->SerializeIncrementally(&traced_value); |
| 36 traced_value.EndArray(); |
| 37 |
| 38 auto base_value = traced_value.ToBaseValue(); |
| 39 DictionaryValue* dictionary; |
| 40 std::unique_ptr<Value> entries; |
| 41 if (!base_value->GetAsDictionary(&dictionary) || |
| 42 !dictionary->Remove("", &entries)) { |
| 43 return nullptr; |
| 44 } |
| 45 return ListValue::From(std::move(entries)); |
38 } | 46 } |
39 | 47 |
40 // Inserts a single type name into a new TypeNameDeduplicator instance and | 48 struct TypeNameMapping { |
41 // checks if the value gets inserted and the exported value for |type_name| is | 49 const int id; |
42 // the same as |expected_value|. | 50 const char* const name; |
43 void TestInsertTypeAndReadback(const char* type_name, | 51 }; |
44 const char* expected_value) { | |
45 std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator); | |
46 ASSERT_EQ(1, dedup->Insert(type_name)); | |
47 | 52 |
48 std::unique_ptr<Value> type_names = DumpAndReadBack(*dedup); | 53 std::unique_ptr<ListValue> SerializeMappingsAsEntries( |
49 ASSERT_NE(nullptr, type_names); | 54 StringDeduplicator* string_dedup, |
| 55 std::initializer_list<TypeNameMapping> mappings) { |
| 56 auto entries = MakeUnique<ListValue>(); |
| 57 for (const auto& mapping : mappings) { |
| 58 auto entry = MakeUnique<DictionaryValue>(); |
| 59 entry->SetInteger("id", mapping.id); |
| 60 entry->SetInteger("name_sid", string_dedup->Insert(mapping.name)); |
| 61 entries->Append(std::move(entry)); |
| 62 } |
| 63 return entries; |
| 64 } |
50 | 65 |
51 const DictionaryValue* dictionary; | 66 void ExpectIncrementalEntries(TypeNameDeduplicator* dedup, |
52 ASSERT_TRUE(type_names->GetAsDictionary(&dictionary)); | 67 StringDeduplicator* string_dedup, |
| 68 std::initializer_list<TypeNameMapping> mappings) { |
| 69 auto entries = SerializeEntriesIncrementally(dedup); |
| 70 ASSERT_TRUE(entries); |
53 | 71 |
54 // When the type name was inserted, it got ID 1. The exported key "1" | 72 auto expected_entries = SerializeMappingsAsEntries(string_dedup, mappings); |
55 // should be equal to |expected_value|. | 73 ASSERT_TRUE(expected_entries->Equals(entries.get())) |
56 std::string value; | 74 << "expected_entries = " << *expected_entries << "entries = " << *entries; |
57 ASSERT_TRUE(dictionary->GetString("1", &value)); | |
58 ASSERT_EQ(expected_value, value); | |
59 } | 75 } |
60 | 76 |
61 } // namespace | 77 } // namespace |
62 | 78 |
63 TEST(TypeNameDeduplicatorTest, Deduplication) { | 79 TEST(TypeNameDeduplicatorTest, ImplicitId0) { |
| 80 StringDeduplicator string_dedup; |
| 81 TypeNameDeduplicator dedup(&string_dedup); |
| 82 |
| 83 // NULL type name is mapped to an implicitly added ID #0. |
| 84 ExpectIncrementalEntries(&dedup, &string_dedup, {{0, "[unknown]"}}); |
| 85 ASSERT_EQ(0, dedup.Insert(nullptr)); |
| 86 |
| 87 // Even though ID #0 is serialized as "[unknown]" string, it's distinct |
| 88 // from "[unknown]" type name. |
| 89 ASSERT_EQ(1, dedup.Insert("[unknown]")); |
| 90 ExpectIncrementalEntries(&dedup, &string_dedup, {{1, "[unknown]"}}); |
| 91 } |
| 92 |
| 93 TEST(TypeNameDeduplicatorTest, Deduplicate) { |
64 // The type IDs should be like this: | 94 // The type IDs should be like this: |
65 // 0: [unknown] | 95 // 0: [unknown] |
66 // 1: int | 96 // 1: int |
67 // 2: bool | 97 // 2: bool |
68 // 3: string | 98 // 3: string |
69 | 99 |
70 std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator); | 100 StringDeduplicator string_dedup; |
71 ASSERT_EQ(1, dedup->Insert(kInt)); | 101 TypeNameDeduplicator dedup(&string_dedup); |
72 ASSERT_EQ(2, dedup->Insert(kBool)); | 102 ASSERT_EQ(1, dedup.Insert("int")); |
73 ASSERT_EQ(3, dedup->Insert(kString)); | 103 ASSERT_EQ(2, dedup.Insert("bool")); |
| 104 ASSERT_EQ(3, dedup.Insert("string")); |
74 | 105 |
75 // Inserting again should return the same IDs. | 106 // Inserting again should return the same IDs. |
76 ASSERT_EQ(2, dedup->Insert(kBool)); | 107 ASSERT_EQ(2, dedup.Insert("bool")); |
77 ASSERT_EQ(1, dedup->Insert(kInt)); | 108 ASSERT_EQ(1, dedup.Insert("int")); |
78 ASSERT_EQ(3, dedup->Insert(kString)); | 109 ASSERT_EQ(3, dedup.Insert("string")); |
79 | |
80 // A null pointer should yield type ID 0. | |
81 ASSERT_EQ(0, dedup->Insert(nullptr)); | |
82 } | |
83 | |
84 TEST(TypeNameDeduplicatorTest, EscapeTypeName) { | |
85 // Reading json should not fail, because the type name should have been | |
86 // escaped properly and exported value should contain quotes. | |
87 TestInsertTypeAndReadback(kNeedsEscape, kNeedsEscape); | |
88 } | 110 } |
89 | 111 |
90 TEST(TypeNameDeduplicatorTest, TestExtractFileName) { | 112 TEST(TypeNameDeduplicatorTest, TestExtractFileName) { |
91 // The exported value for passed file name should be the folders in the path. | 113 StringDeduplicator string_dedup; |
92 TestInsertTypeAndReadback(kTaskFileName, kTaskPath); | 114 TypeNameDeduplicator dedup(&string_dedup); |
| 115 |
| 116 ASSERT_EQ(1, dedup.Insert(kTaskFileName)); |
| 117 |
| 118 ExpectIncrementalEntries(&dedup, &string_dedup, |
| 119 {{0, "[unknown]"}, {1, kTaskPath}}); |
| 120 } |
| 121 |
| 122 TEST(TypeNameDeduplicatorTest, SerializeIncrementally) { |
| 123 StringDeduplicator string_dedup; |
| 124 TypeNameDeduplicator dedup(&string_dedup); |
| 125 |
| 126 ASSERT_EQ(1, dedup.Insert("int")); |
| 127 ASSERT_EQ(2, dedup.Insert("bool")); |
| 128 |
| 129 ExpectIncrementalEntries(&dedup, &string_dedup, |
| 130 {{0, "[unknown]"}, {1, "int"}, {2, "bool"}}); |
| 131 |
| 132 ASSERT_EQ(2, dedup.Insert("bool")); |
| 133 ASSERT_EQ(3, dedup.Insert("string")); |
| 134 |
| 135 ExpectIncrementalEntries(&dedup, &string_dedup, {{3, "string"}}); |
| 136 |
| 137 ExpectIncrementalEntries(&dedup, &string_dedup, {}); |
93 } | 138 } |
94 | 139 |
95 } // namespace trace_event | 140 } // namespace trace_event |
96 } // namespace base | 141 } // namespace base |
OLD | NEW |