xref: /aosp_15_r20/external/perfetto/src/traceconv/trace_to_pprof_integrationtest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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