• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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