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