1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/proto/heap_graph_tracker.h"
18 
19 #include "src/trace_processor/importers/proto/profiler_util.h"
20 
21 #include "perfetto/base/logging.h"
22 #include "test/gtest_and_gmock.h"
23 
24 namespace perfetto {
25 namespace trace_processor {
26 namespace {
27 
28 using ::testing::UnorderedElementsAre;
29 
TEST(HeapGraphTrackerTest,PackageFromLocationApp)30 TEST(HeapGraphTrackerTest, PackageFromLocationApp) {
31   TraceStorage storage;
32   EXPECT_EQ(
33       PackageFromLocation(&storage,
34                           "/data/app/~~ASDFGH1234QWerT==/"
35                           "com.twitter.android-MNBVCX7890SDTst6==/test.apk"),
36       "com.twitter.android");
37   EXPECT_EQ(PackageFromLocation(
38                 &storage,
39                 "/data/app/com.google.android.webview-6XfQhnaSkFwGK0sYL9is0G==/"
40                 "base.apk"),
41             "com.google.android.webview");
42   EXPECT_EQ(PackageFromLocation(&storage,
43                                 "/data/app/"
44                                 "com.google.android.apps.wellbeing-"
45                                 "qfQCaB4uJ7P0OPpZQqOu0Q==/oat/arm64/base.odex"),
46             "com.google.android.apps.wellbeing");
47 }
48 
TEST(HeapGraphTrackerTest,BuildFlamegraph)49 TEST(HeapGraphTrackerTest, BuildFlamegraph) {
50   //           4@A 5@B
51   //             \ /
52   //         2@Y 3@Y
53   //           \ /
54   //           1@X
55 
56   constexpr uint64_t kSeqId = 1;
57   constexpr UniquePid kPid = 1;
58   constexpr int64_t kTimestamp = 1;
59 
60   TraceProcessorContext context;
61   context.storage.reset(new TraceStorage());
62 
63   HeapGraphTracker tracker(&context);
64 
65   constexpr uint64_t kField = 1;
66   constexpr uint64_t kLocation = 0;
67 
68   constexpr uint64_t kX = 1;
69   constexpr uint64_t kY = 2;
70   constexpr uint64_t kA = 3;
71   constexpr uint64_t kB = 4;
72   constexpr uint64_t kWeakRef = 5;
73 
74   base::StringView field = base::StringView("foo");
75   StringPool::Id x = context.storage->InternString("X");
76   StringPool::Id y = context.storage->InternString("Y");
77   StringPool::Id a = context.storage->InternString("A");
78   StringPool::Id b = context.storage->InternString("B");
79   StringPool::Id weak_ref = context.storage->InternString("WeakReference");
80 
81   StringPool::Id normal_kind = context.storage->InternString("KIND_NORMAL");
82   StringPool::Id weak_ref_kind =
83       context.storage->InternString("KIND_WEAK_REFERENCE");
84   tracker.AddInternedFieldName(kSeqId, kField, field);
85 
86   tracker.AddInternedLocationName(kSeqId, kLocation,
87                                   context.storage->InternString("location"));
88   tracker.AddInternedType(kSeqId, kX, x, kLocation, /*object_size=*/0,
89                           /*field_name_ids=*/{}, /*superclass_id=*/0,
90                           /*classloader_id=*/0, /*no_fields=*/false,
91                           /*kind=*/normal_kind);
92   tracker.AddInternedType(kSeqId, kY, y, kLocation, /*object_size=*/0,
93                           /*field_name_ids=*/{}, /*superclass_id=*/0,
94                           /*classloader_id=*/0, /*no_fields=*/false,
95                           /*kind=*/normal_kind);
96   tracker.AddInternedType(kSeqId, kA, a, kLocation, /*object_size=*/0,
97                           /*field_name_ids=*/{}, /*superclass_id=*/0,
98                           /*classloader_id=*/0, /*no_fields=*/false,
99                           /*kind=*/normal_kind);
100   tracker.AddInternedType(kSeqId, kB, b, kLocation, /*object_size=*/0,
101                           /*field_name_ids=*/{}, /*superclass_id=*/0,
102                           /*classloader_id=*/0, /*no_fields=*/false,
103                           /*kind=*/normal_kind);
104   tracker.AddInternedType(kSeqId, kWeakRef, weak_ref, kLocation,
105                           /*object_size=*/0,
106                           /*field_name_ids=*/{}, /*superclass_id=*/0,
107                           /*classloader_id=*/0, /*no_fields=*/false,
108                           /*kind=*/weak_ref_kind);
109   {
110     HeapGraphTracker::SourceObject obj;
111     obj.object_id = 999;
112     obj.self_size = 999;
113     obj.type_id = kWeakRef;
114     obj.field_name_ids = {kField};
115     obj.referred_objects = {5};
116 
117     tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
118   }
119 
120   {
121     HeapGraphTracker::SourceObject obj;
122     obj.object_id = 1;
123     obj.self_size = 1;
124     obj.type_id = kX;
125     obj.field_name_ids = {kField, kField};
126     obj.referred_objects = {2, 3};
127 
128     tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
129   }
130 
131   {
132     HeapGraphTracker::SourceObject obj;
133     obj.object_id = 2;
134     obj.self_size = 2;
135     obj.type_id = kY;
136     tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
137   }
138 
139   {
140     HeapGraphTracker::SourceObject obj;
141     obj.object_id = 3;
142     obj.self_size = 3;
143     obj.type_id = kY;
144     obj.field_name_ids = {kField, kField};
145     obj.referred_objects = {4, 5};
146 
147     tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
148   }
149 
150   {
151     HeapGraphTracker::SourceObject obj;
152     obj.object_id = 4;
153     obj.self_size = 4;
154     obj.type_id = kA;
155     tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
156   }
157 
158   {
159     HeapGraphTracker::SourceObject obj;
160     obj.object_id = 5;
161     obj.self_size = 5;
162     obj.type_id = kB;
163     tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
164   }
165 
166   HeapGraphTracker::SourceRoot root;
167   root.root_type = context.storage->InternString("ROOT");
168   root.object_ids.emplace_back(1);
169   root.object_ids.emplace_back(999);
170   tracker.AddRoot(kSeqId, kPid, kTimestamp, root);
171 
172   tracker.FinalizeProfile(kSeqId);
173   std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> flame =
174       tracker.BuildFlamegraph(kPid, kTimestamp);
175   ASSERT_NE(flame, nullptr);
176 
177   auto cumulative_sizes = flame->cumulative_size().ToVectorForTesting();
178   EXPECT_THAT(cumulative_sizes, UnorderedElementsAre(15, 4, 14, 5, 999));
179 
180   auto cumulative_counts = flame->cumulative_count().ToVectorForTesting();
181   EXPECT_THAT(cumulative_counts, UnorderedElementsAre(5, 4, 1, 1, 1));
182 
183   auto sizes = flame->size().ToVectorForTesting();
184   EXPECT_THAT(sizes, UnorderedElementsAre(1, 5, 4, 5, 999));
185 
186   auto counts = flame->count().ToVectorForTesting();
187   EXPECT_THAT(counts, UnorderedElementsAre(1, 2, 1, 1, 1));
188 }
189 
190 static const char kArray[] = "X[]";
191 static const char kDoubleArray[] = "X[][]";
192 static const char kNoArray[] = "X";
193 static const char kLongNoArray[] = "ABCDE";
194 static const char kStaticClassNoArray[] = "java.lang.Class<abc>";
195 static const char kStaticClassArray[] = "java.lang.Class<abc[]>";
196 
TEST(HeapGraphTrackerTest,NormalizeTypeName)197 TEST(HeapGraphTrackerTest, NormalizeTypeName) {
198   // sizeof(...) - 1 below to get rid of the null-byte.
199   EXPECT_EQ(NormalizeTypeName(base::StringView(kArray, sizeof(kArray) - 1))
200                 .ToStdString(),
201             "X");
202   EXPECT_EQ(NormalizeTypeName(
203                 base::StringView(kDoubleArray, sizeof(kDoubleArray) - 1))
204                 .ToStdString(),
205             "X");
206   EXPECT_EQ(NormalizeTypeName(base::StringView(kNoArray, sizeof(kNoArray) - 1))
207                 .ToStdString(),
208             "X");
209   EXPECT_EQ(NormalizeTypeName(
210                 base::StringView(kLongNoArray, sizeof(kLongNoArray) - 1))
211                 .ToStdString(),
212             "ABCDE");
213   EXPECT_EQ(NormalizeTypeName(base::StringView(kStaticClassNoArray,
214                                                sizeof(kStaticClassNoArray) - 1))
215                 .ToStdString(),
216             "abc");
217   EXPECT_EQ(NormalizeTypeName(base::StringView(kStaticClassArray,
218                                                sizeof(kStaticClassArray) - 1))
219                 .ToStdString(),
220             "abc");
221 }
222 
TEST(HeapGraphTrackerTest,NumberOfArray)223 TEST(HeapGraphTrackerTest, NumberOfArray) {
224   // sizeof(...) - 1 below to get rid of the null-byte.
225   EXPECT_EQ(NumberOfArrays(base::StringView(kArray, sizeof(kArray) - 1)), 1u);
226   EXPECT_EQ(
227       NumberOfArrays(base::StringView(kDoubleArray, sizeof(kDoubleArray) - 1)),
228       2u);
229   EXPECT_EQ(NumberOfArrays(base::StringView(kNoArray, sizeof(kNoArray) - 1)),
230             0u);
231   EXPECT_EQ(
232       NumberOfArrays(base::StringView(kLongNoArray, sizeof(kLongNoArray) - 1)),
233       0u);
234 }
235 
236 }  // namespace
237 }  // namespace trace_processor
238 }  // namespace perfetto
239