1 /*
2 * Copyright (C) 2024 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 <unistd.h>
18 #include "test/gtest_and_gmock.h"
19
20 #include <fstream>
21 #include <ostream>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25
26 #include "perfetto/base/logging.h"
27 #include "perfetto/ext/base/file_utils.h"
28 #include "perfetto/ext/base/string_utils.h"
29 #include "src/base/test/utils.h"
30 #include "src/traceconv/pprof_reader.h"
31 #include "src/traceconv/trace_to_profile.h"
32
33 namespace perfetto {
34 namespace {
35
36 using testing::Contains;
37
ConvertTraceToPprof(const std::string & input_file_name)38 pprof::PprofProfileReader ConvertTraceToPprof(
39 const std::string& input_file_name) {
40 const std::string trace_file = base::GetTestDataPath(input_file_name);
41 std::ifstream file_istream;
42 file_istream.open(trace_file, std::ios_base::in | std::ios_base::binary);
43 PERFETTO_CHECK(file_istream.is_open());
44
45 std::stringstream ss;
46 std::ostream os(ss.rdbuf());
47 trace_to_text::TraceToJavaHeapProfile(&file_istream, &os, /*pid=*/0,
48 /*timestamps=*/{},
49 /*annotate_frames=*/false);
50
51 auto conv_stdout = base::SplitString(ss.str(), " ");
52 PERFETTO_CHECK(!conv_stdout.empty());
53 std::string out_dirname = base::TrimWhitespace(conv_stdout.back());
54 std::vector<std::string> filenames;
55 base::ListFilesRecursive(out_dirname, filenames);
56 // assumption: all test inputs contain exactly one profile
57 PERFETTO_CHECK(filenames.size() == 1);
58 std::string profile_path = out_dirname + "/" + filenames[0];
59
60 // read in the profile contents and then clean up the temp files
61 pprof::PprofProfileReader pprof_reader(profile_path);
62 unlink(profile_path.c_str());
63 PERFETTO_CHECK(base::Rmdir(out_dirname));
64 return pprof_reader;
65 }
66
get_samples_function_names(const pprof::PprofProfileReader & pprof,const std::string & last_function_name)67 std::vector<std::vector<std::string>> get_samples_function_names(
68 const pprof::PprofProfileReader& pprof,
69 const std::string& last_function_name) {
70 const auto samples = pprof.get_samples(last_function_name);
71 std::vector<std::vector<std::string>> samples_function_names;
72 for (const auto& sample : samples) {
73 samples_function_names.push_back(pprof.get_sample_function_names(sample));
74 }
75 return samples_function_names;
76 }
77
78 class TraceToPprofTest : public ::testing::Test {
79 public:
80 pprof::PprofProfileReader* pprof = nullptr;
81
SetUp()82 void SetUp() override {
83 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
84 GTEST_SKIP() << "do not run traceconv tests on Android target";
85 #endif
86 }
87
TearDown()88 void TearDown() override { delete pprof; }
89 };
90
TEST_F(TraceToPprofTest,SummaryValues)91 TEST_F(TraceToPprofTest, SummaryValues) {
92 const auto pprof = ConvertTraceToPprof("test/data/heap_graph/heap_graph.pb");
93
94 EXPECT_EQ(pprof.get_samples_value_sum("Foo", "Total allocation count"), 1);
95 EXPECT_EQ(pprof.get_samples_value_sum("Foo", "Total allocation size"), 32);
96 EXPECT_EQ(pprof.get_samples("Foo").size(), 1U);
97 EXPECT_EQ(pprof.get_sample_count(), 3U);
98
99 const std::vector<std::string> expected_function_names = {
100 "Foo", "FactoryProducerDelegateImplActor [ROOT_JAVA_FRAME]"};
101 EXPECT_THAT(get_samples_function_names(pprof, "Foo"),
102 Contains(expected_function_names));
103 }
104
TEST_F(TraceToPprofTest,TreeLocationFunctionNames)105 TEST_F(TraceToPprofTest, TreeLocationFunctionNames) {
106 const auto pprof =
107 ConvertTraceToPprof("test/data/heap_graph/heap_graph_branching.pb");
108
109 EXPECT_THAT(get_samples_function_names(pprof, "LeftChild0"),
110 Contains(std::vector<std::string>{"LeftChild0",
111 "RootNode [ROOT_JAVA_FRAME]"}));
112 EXPECT_THAT(get_samples_function_names(pprof, "LeftChild1"),
113 Contains(std::vector<std::string>{"LeftChild1", "LeftChild0",
114 "RootNode [ROOT_JAVA_FRAME]"}));
115 EXPECT_THAT(get_samples_function_names(pprof, "RightChild0"),
116 Contains(std::vector<std::string>{"RightChild0",
117 "RootNode [ROOT_JAVA_FRAME]"}));
118 EXPECT_THAT(get_samples_function_names(pprof, "RightChild1"),
119 Contains(std::vector<std::string>{"RightChild1", "RightChild0",
120 "RootNode [ROOT_JAVA_FRAME]"}));
121 }
122
TEST_F(TraceToPprofTest,HugeSizes)123 TEST_F(TraceToPprofTest, HugeSizes) {
124 const auto pprof =
125 ConvertTraceToPprof("test/data/heap_graph/heap_graph_huge_size.pb");
126 EXPECT_EQ(pprof.get_samples_value_sum("dev.perfetto.BigStuff",
127 "Total allocation size"),
128 3000000000);
129 }
130
131 class TraceToPprofRealTraceTest : public ::testing::Test {
132 public:
SetUp()133 void SetUp() override {
134 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
135 GTEST_SKIP() << "do not run traceconv tests on Android target";
136 #endif
137 #if defined(LEAK_SANITIZER)
138 GTEST_SKIP() << "trace is too big to be tested in sanitizer builds";
139 #endif
140 }
141 };
142
TEST_F(TraceToPprofRealTraceTest,AllocationCountForClass)143 TEST_F(TraceToPprofRealTraceTest, AllocationCountForClass) {
144 const auto pprof =
145 ConvertTraceToPprof("test/data/system-server-heap-graph-new.pftrace");
146
147 EXPECT_EQ(pprof.get_samples_value_sum(
148 "android.content.pm.parsing.component.ParsedActivity",
149 "Total allocation count"),
150 5108);
151 EXPECT_EQ(pprof.get_samples_value_sum(
152 "android.content.pm.parsing.component.ParsedActivity",
153 "Total allocation size"),
154 817280);
155 EXPECT_EQ(
156 pprof.get_samples("android.content.pm.parsing.component.ParsedActivity")
157 .size(),
158 5U);
159 EXPECT_EQ(pprof.get_sample_count(), 83256U);
160
161 const std::vector<std::string> expected_function_names = {
162 "android.content.pm.parsing.component.ParsedActivity",
163 "java.lang.Object[]",
164 "java.util.ArrayList",
165 "com.android.server.pm.parsing.pkg.PackageImpl",
166 "com.android.server.pm.PackageSetting",
167 "java.lang.Object[]",
168 "android.util.ArrayMap",
169 "com.android.server.pm.Settings",
170 "com.android.server.pm.PackageManagerService [ROOT_JNI_GLOBAL]"};
171
172 EXPECT_THAT(get_samples_function_names(
173 pprof, "android.content.pm.parsing.component.ParsedActivity"),
174 Contains(expected_function_names));
175 }
176
177 } // namespace
178 } // namespace perfetto
179