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::ExportIncrementally() and returns ListValue |
34 const TypeNameDeduplicator& deduplicator) { | 30 // with exported entries. |
35 std::string json; | 31 std::unique_ptr<ListValue> ExportEntriesIncrementally( |
36 deduplicator.AppendAsTraceFormat(&json); | 32 TypeNameDeduplicator* dedup) { |
37 return JSONReader::Read(json); | 33 TracedValue traced_value; |
| 34 traced_value.BeginArray(""); |
| 35 dedup->ExportIncrementally(&traced_value); |
| 36 traced_value.EndArray(); |
| 37 |
| 38 auto base_value = traced_value.ToBaseValue(); |
| 39 const DictionaryValue* dictionary; |
| 40 const ListValue* entries; |
| 41 if (!base_value->GetAsDictionary(&dictionary) || |
| 42 !dictionary->GetList("", &entries)) { |
| 43 return nullptr; |
| 44 } |
| 45 |
| 46 return WrapUnique(entries->DeepCopy()); |
38 } | 47 } |
39 | 48 |
40 // Inserts a single type name into a new TypeNameDeduplicator instance and | 49 struct TypeNameMapping { |
41 // checks if the value gets inserted and the exported value for |type_name| is | 50 const int id; |
42 // the same as |expected_value|. | 51 const char* const name; |
43 void TestInsertTypeAndReadback(const char* type_name, | 52 }; |
44 const char* expected_value) { | |
45 std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator); | |
46 ASSERT_EQ(1, dedup->Insert(type_name)); | |
47 | 53 |
48 std::unique_ptr<Value> type_names = DumpAndReadBack(*dedup); | 54 std::unique_ptr<ListValue> ConvertMappingsToExportedEntries( |
49 ASSERT_NE(nullptr, type_names); | 55 StringDeduplicator* string_dedup, |
| 56 std::initializer_list<TypeNameMapping> mappings) { |
| 57 auto entries = MakeUnique<ListValue>(); |
| 58 for (const auto& mapping : mappings) { |
| 59 auto entry = MakeUnique<DictionaryValue>(); |
| 60 entry->SetInteger("id", mapping.id); |
| 61 entry->SetInteger("name_sid", string_dedup->Insert(mapping.name)); |
| 62 entries->Append(std::move(entry)); |
| 63 } |
| 64 return entries; |
| 65 } |
50 | 66 |
51 const DictionaryValue* dictionary; | 67 void ExpectIncrementalEntries(TypeNameDeduplicator* dedup, |
52 ASSERT_TRUE(type_names->GetAsDictionary(&dictionary)); | 68 StringDeduplicator* string_dedup, |
| 69 std::initializer_list<TypeNameMapping> mappings) { |
| 70 auto entries = ExportEntriesIncrementally(dedup); |
| 71 ASSERT_TRUE(entries); |
53 | 72 |
54 // When the type name was inserted, it got ID 1. The exported key "1" | 73 auto expected_entries = |
55 // should be equal to |expected_value|. | 74 ConvertMappingsToExportedEntries(string_dedup, mappings); |
56 std::string value; | 75 ASSERT_TRUE(expected_entries->Equals(entries.get())) |
57 ASSERT_TRUE(dictionary->GetString("1", &value)); | 76 << "expected_entries = " << *expected_entries << "entries = " << *entries; |
58 ASSERT_EQ(expected_value, value); | |
59 } | 77 } |
60 | 78 |
61 } // namespace | 79 } // namespace |
62 | 80 |
| 81 TEST(TypeNameDeduplicatorTest, ImplicitId0) { |
| 82 StringDeduplicator string_dedup; |
| 83 TypeNameDeduplicator dedup(&string_dedup); |
| 84 |
| 85 // NULL type name is mapped to an implicitly added ID #0. |
| 86 ExpectIncrementalEntries(&dedup, &string_dedup, {{0, "[unknown]"}}); |
| 87 ASSERT_EQ(0, dedup.Insert(nullptr)); |
| 88 |
| 89 // Even though ID #0 is exported as "[unknown]" string, it's distinct |
| 90 // from "[unknown]" type name. |
| 91 ASSERT_EQ(1, dedup.Insert("[unknown]")); |
| 92 ExpectIncrementalEntries(&dedup, &string_dedup, {{1, "[unknown]"}}); |
| 93 } |
| 94 |
63 TEST(TypeNameDeduplicatorTest, Deduplication) { | 95 TEST(TypeNameDeduplicatorTest, Deduplication) { |
64 // The type IDs should be like this: | 96 // The type IDs should be like this: |
65 // 0: [unknown] | 97 // 0: [unknown] |
66 // 1: int | 98 // 1: int |
67 // 2: bool | 99 // 2: bool |
68 // 3: string | 100 // 3: string |
69 | 101 |
70 std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator); | 102 StringDeduplicator string_dedup; |
71 ASSERT_EQ(1, dedup->Insert(kInt)); | 103 TypeNameDeduplicator dedup(&string_dedup); |
72 ASSERT_EQ(2, dedup->Insert(kBool)); | 104 ASSERT_EQ(1, dedup.Insert("int")); |
73 ASSERT_EQ(3, dedup->Insert(kString)); | 105 ASSERT_EQ(2, dedup.Insert("bool")); |
| 106 ASSERT_EQ(3, dedup.Insert("string")); |
74 | 107 |
75 // Inserting again should return the same IDs. | 108 // Inserting again should return the same IDs. |
76 ASSERT_EQ(2, dedup->Insert(kBool)); | 109 ASSERT_EQ(2, dedup.Insert("bool")); |
77 ASSERT_EQ(1, dedup->Insert(kInt)); | 110 ASSERT_EQ(1, dedup.Insert("int")); |
78 ASSERT_EQ(3, dedup->Insert(kString)); | 111 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 } | 112 } |
89 | 113 |
90 TEST(TypeNameDeduplicatorTest, TestExtractFileName) { | 114 TEST(TypeNameDeduplicatorTest, TestExtractFileName) { |
91 // The exported value for passed file name should be the folders in the path. | 115 StringDeduplicator string_dedup; |
92 TestInsertTypeAndReadback(kTaskFileName, kTaskPath); | 116 TypeNameDeduplicator dedup(&string_dedup); |
| 117 |
| 118 ASSERT_EQ(1, dedup.Insert(kTaskFileName)); |
| 119 |
| 120 ExpectIncrementalEntries(&dedup, &string_dedup, |
| 121 {{0, "[unknown]"}, {1, kTaskPath}}); |
| 122 } |
| 123 |
| 124 TEST(TypeNameDeduplicatorTest, IncrementalExport) { |
| 125 StringDeduplicator string_dedup; |
| 126 TypeNameDeduplicator dedup(&string_dedup); |
| 127 |
| 128 ASSERT_EQ(1, dedup.Insert("int")); |
| 129 ASSERT_EQ(2, dedup.Insert("bool")); |
| 130 |
| 131 ExpectIncrementalEntries(&dedup, &string_dedup, |
| 132 {{0, "[unknown]"}, {1, "int"}, {2, "bool"}}); |
| 133 |
| 134 ASSERT_EQ(2, dedup.Insert("bool")); |
| 135 ASSERT_EQ(3, dedup.Insert("string")); |
| 136 |
| 137 ExpectIncrementalEntries(&dedup, &string_dedup, {{3, "string"}}); |
| 138 |
| 139 ExpectIncrementalEntries(&dedup, &string_dedup, {}); |
93 } | 140 } |
94 | 141 |
95 } // namespace trace_event | 142 } // namespace trace_event |
96 } // namespace base | 143 } // namespace base |
OLD | NEW |