xref: /aosp_15_r20/external/perfetto/src/traceconv/pprof_reader.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/traceconv/pprof_reader.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
20*6dbdd20aSAndroid Build Coastguard Worker #include <fstream>
21*6dbdd20aSAndroid Build Coastguard Worker 
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
23*6dbdd20aSAndroid Build Coastguard Worker 
24*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto::pprof {
25*6dbdd20aSAndroid Build Coastguard Worker 
26*6dbdd20aSAndroid Build Coastguard Worker using namespace third_party::perftools::profiles::gen;
27*6dbdd20aSAndroid Build Coastguard Worker 
PprofProfileReader(const std::string & path)28*6dbdd20aSAndroid Build Coastguard Worker PprofProfileReader::PprofProfileReader(const std::string& path) {
29*6dbdd20aSAndroid Build Coastguard Worker   std::string pprof_contents;
30*6dbdd20aSAndroid Build Coastguard Worker   base::ReadFile(path, &pprof_contents);
31*6dbdd20aSAndroid Build Coastguard Worker   profile_.ParseFromString(pprof_contents);
32*6dbdd20aSAndroid Build Coastguard Worker }
33*6dbdd20aSAndroid Build Coastguard Worker 
get_sample_count() const34*6dbdd20aSAndroid Build Coastguard Worker uint64_t PprofProfileReader::get_sample_count() const {
35*6dbdd20aSAndroid Build Coastguard Worker   return static_cast<uint64_t>(profile_.sample_size());
36*6dbdd20aSAndroid Build Coastguard Worker }
37*6dbdd20aSAndroid Build Coastguard Worker 
get_string_index(const std::string & str) const38*6dbdd20aSAndroid Build Coastguard Worker int64_t PprofProfileReader::get_string_index(const std::string& str) const {
39*6dbdd20aSAndroid Build Coastguard Worker   const auto it = std::find(profile_.string_table().begin(),
40*6dbdd20aSAndroid Build Coastguard Worker                             profile_.string_table().end(), str);
41*6dbdd20aSAndroid Build Coastguard Worker 
42*6dbdd20aSAndroid Build Coastguard Worker   if (it == profile_.string_table().end()) {
43*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_FATAL("String %s not found in string table", str.c_str());
44*6dbdd20aSAndroid Build Coastguard Worker   }
45*6dbdd20aSAndroid Build Coastguard Worker 
46*6dbdd20aSAndroid Build Coastguard Worker   return std::distance(profile_.string_table().begin(), it);
47*6dbdd20aSAndroid Build Coastguard Worker }
48*6dbdd20aSAndroid Build Coastguard Worker 
get_string_by_index(const uint64_t string_index) const49*6dbdd20aSAndroid Build Coastguard Worker std::string PprofProfileReader::get_string_by_index(
50*6dbdd20aSAndroid Build Coastguard Worker     const uint64_t string_index) const {
51*6dbdd20aSAndroid Build Coastguard Worker   if (string_index >= profile_.string_table().size()) {
52*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_FATAL("String %" PRIu64 " is out of range in string table",
53*6dbdd20aSAndroid Build Coastguard Worker                    string_index);
54*6dbdd20aSAndroid Build Coastguard Worker   }
55*6dbdd20aSAndroid Build Coastguard Worker 
56*6dbdd20aSAndroid Build Coastguard Worker   return profile_.string_table()[string_index];
57*6dbdd20aSAndroid Build Coastguard Worker }
58*6dbdd20aSAndroid Build Coastguard Worker 
find_location_id(const std::string & function_name) const59*6dbdd20aSAndroid Build Coastguard Worker uint64_t PprofProfileReader::find_location_id(
60*6dbdd20aSAndroid Build Coastguard Worker     const std::string& function_name) const {
61*6dbdd20aSAndroid Build Coastguard Worker   const int64_t function_string_id = get_string_index(function_name);
62*6dbdd20aSAndroid Build Coastguard Worker 
63*6dbdd20aSAndroid Build Coastguard Worker   // Find a function based on function_name
64*6dbdd20aSAndroid Build Coastguard Worker   uint64_t function_id = 0;
65*6dbdd20aSAndroid Build Coastguard Worker   bool found_function_id = false;
66*6dbdd20aSAndroid Build Coastguard Worker 
67*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& function : profile_.function()) {
68*6dbdd20aSAndroid Build Coastguard Worker     if (function.name() == function_string_id) {
69*6dbdd20aSAndroid Build Coastguard Worker       function_id = function.id();
70*6dbdd20aSAndroid Build Coastguard Worker       found_function_id = true;
71*6dbdd20aSAndroid Build Coastguard Worker     }
72*6dbdd20aSAndroid Build Coastguard Worker   }
73*6dbdd20aSAndroid Build Coastguard Worker 
74*6dbdd20aSAndroid Build Coastguard Worker   if (!found_function_id) {
75*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_FATAL("Function %s not found", function_name.c_str());
76*6dbdd20aSAndroid Build Coastguard Worker   }
77*6dbdd20aSAndroid Build Coastguard Worker 
78*6dbdd20aSAndroid Build Coastguard Worker   // Find a location for the function
79*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& location : profile_.location()) {
80*6dbdd20aSAndroid Build Coastguard Worker     for (const auto& line : location.line()) {
81*6dbdd20aSAndroid Build Coastguard Worker       if (line.function_id() == function_id) {
82*6dbdd20aSAndroid Build Coastguard Worker         return location.id();
83*6dbdd20aSAndroid Build Coastguard Worker       }
84*6dbdd20aSAndroid Build Coastguard Worker     }
85*6dbdd20aSAndroid Build Coastguard Worker   }
86*6dbdd20aSAndroid Build Coastguard Worker 
87*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_FATAL("Location for function %s not found", function_name.c_str());
88*6dbdd20aSAndroid Build Coastguard Worker }
89*6dbdd20aSAndroid Build Coastguard Worker 
find_location(const uint64_t location_id) const90*6dbdd20aSAndroid Build Coastguard Worker Location PprofProfileReader::find_location(const uint64_t location_id) const {
91*6dbdd20aSAndroid Build Coastguard Worker   const auto it = std::find_if(
92*6dbdd20aSAndroid Build Coastguard Worker       profile_.location().begin(), profile_.location().end(),
93*6dbdd20aSAndroid Build Coastguard Worker       [location_id](const Location& loc) { return loc.id() == location_id; });
94*6dbdd20aSAndroid Build Coastguard Worker 
95*6dbdd20aSAndroid Build Coastguard Worker   if (it != profile_.location().end()) {
96*6dbdd20aSAndroid Build Coastguard Worker     return *it;
97*6dbdd20aSAndroid Build Coastguard Worker   }
98*6dbdd20aSAndroid Build Coastguard Worker 
99*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_FATAL("Location with id %" PRIu64 " not found", location_id);
100*6dbdd20aSAndroid Build Coastguard Worker }
101*6dbdd20aSAndroid Build Coastguard Worker 
find_function(const uint64_t function_id) const102*6dbdd20aSAndroid Build Coastguard Worker Function PprofProfileReader::find_function(const uint64_t function_id) const {
103*6dbdd20aSAndroid Build Coastguard Worker   const auto it = std::find_if(
104*6dbdd20aSAndroid Build Coastguard Worker       profile_.function().begin(), profile_.function().end(),
105*6dbdd20aSAndroid Build Coastguard Worker       [function_id](const Function& fun) { return fun.id() == function_id; });
106*6dbdd20aSAndroid Build Coastguard Worker 
107*6dbdd20aSAndroid Build Coastguard Worker   if (it != profile_.function().end()) {
108*6dbdd20aSAndroid Build Coastguard Worker     return *it;
109*6dbdd20aSAndroid Build Coastguard Worker   }
110*6dbdd20aSAndroid Build Coastguard Worker 
111*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_FATAL("Function with id %" PRIu64 " not found", function_id);
112*6dbdd20aSAndroid Build Coastguard Worker }
113*6dbdd20aSAndroid Build Coastguard Worker 
get_sample_function_names(const Sample & sample) const114*6dbdd20aSAndroid Build Coastguard Worker std::vector<std::string> PprofProfileReader::get_sample_function_names(
115*6dbdd20aSAndroid Build Coastguard Worker     const Sample& sample) const {
116*6dbdd20aSAndroid Build Coastguard Worker   std::vector<std::string> function_names;
117*6dbdd20aSAndroid Build Coastguard Worker   for (const auto location_id : sample.location_id()) {
118*6dbdd20aSAndroid Build Coastguard Worker     const auto location = find_location(location_id);
119*6dbdd20aSAndroid Build Coastguard Worker 
120*6dbdd20aSAndroid Build Coastguard Worker     for (const auto& line : location.line()) {
121*6dbdd20aSAndroid Build Coastguard Worker       Function function = find_function(line.function_id());
122*6dbdd20aSAndroid Build Coastguard Worker       std::string function_name =
123*6dbdd20aSAndroid Build Coastguard Worker           get_string_by_index(static_cast<uint64_t>(function.name()));
124*6dbdd20aSAndroid Build Coastguard Worker       function_names.push_back(function_name);
125*6dbdd20aSAndroid Build Coastguard Worker     }
126*6dbdd20aSAndroid Build Coastguard Worker   }
127*6dbdd20aSAndroid Build Coastguard Worker 
128*6dbdd20aSAndroid Build Coastguard Worker   return function_names;
129*6dbdd20aSAndroid Build Coastguard Worker }
130*6dbdd20aSAndroid Build Coastguard Worker 
get_samples(const std::string & last_function_name) const131*6dbdd20aSAndroid Build Coastguard Worker std::vector<Sample> PprofProfileReader::get_samples(
132*6dbdd20aSAndroid Build Coastguard Worker     const std::string& last_function_name) const {
133*6dbdd20aSAndroid Build Coastguard Worker   const uint64_t location_id = find_location_id(last_function_name);
134*6dbdd20aSAndroid Build Coastguard Worker 
135*6dbdd20aSAndroid Build Coastguard Worker   std::vector<Sample> samples;
136*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& sample : profile_.sample()) {
137*6dbdd20aSAndroid Build Coastguard Worker     if (sample.location_id_size() == 0) {
138*6dbdd20aSAndroid Build Coastguard Worker       continue;
139*6dbdd20aSAndroid Build Coastguard Worker     }
140*6dbdd20aSAndroid Build Coastguard Worker 
141*6dbdd20aSAndroid Build Coastguard Worker     // Get the first location id from the iterator as they are stored inverted
142*6dbdd20aSAndroid Build Coastguard Worker     const uint64_t last_location_id = sample.location_id()[0];
143*6dbdd20aSAndroid Build Coastguard Worker 
144*6dbdd20aSAndroid Build Coastguard Worker     if (last_location_id == location_id) {
145*6dbdd20aSAndroid Build Coastguard Worker       samples.push_back(sample);
146*6dbdd20aSAndroid Build Coastguard Worker     }
147*6dbdd20aSAndroid Build Coastguard Worker   }
148*6dbdd20aSAndroid Build Coastguard Worker 
149*6dbdd20aSAndroid Build Coastguard Worker   return samples;
150*6dbdd20aSAndroid Build Coastguard Worker }
151*6dbdd20aSAndroid Build Coastguard Worker 
get_sample_value_index(const std::string & value_name) const152*6dbdd20aSAndroid Build Coastguard Worker uint64_t PprofProfileReader::get_sample_value_index(
153*6dbdd20aSAndroid Build Coastguard Worker     const std::string& value_name) const {
154*6dbdd20aSAndroid Build Coastguard Worker   const int64_t value_name_string_index = get_string_index(value_name);
155*6dbdd20aSAndroid Build Coastguard Worker 
156*6dbdd20aSAndroid Build Coastguard Worker   const auto it =
157*6dbdd20aSAndroid Build Coastguard Worker       std::find_if(profile_.sample_type().begin(), profile_.sample_type().end(),
158*6dbdd20aSAndroid Build Coastguard Worker                    [value_name_string_index](const auto& sample_type) {
159*6dbdd20aSAndroid Build Coastguard Worker                      return sample_type.type() == value_name_string_index;
160*6dbdd20aSAndroid Build Coastguard Worker                    });
161*6dbdd20aSAndroid Build Coastguard Worker 
162*6dbdd20aSAndroid Build Coastguard Worker   if (it != profile_.sample_type().end()) {
163*6dbdd20aSAndroid Build Coastguard Worker     return static_cast<uint64_t>(
164*6dbdd20aSAndroid Build Coastguard Worker         std::distance(profile_.sample_type().begin(), it));
165*6dbdd20aSAndroid Build Coastguard Worker   }
166*6dbdd20aSAndroid Build Coastguard Worker 
167*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_FATAL("Can't find value type with name \"%s\"", value_name.c_str());
168*6dbdd20aSAndroid Build Coastguard Worker }
169*6dbdd20aSAndroid Build Coastguard Worker 
get_samples_value_sum(const std::string & last_function_name,const std::string & value_name) const170*6dbdd20aSAndroid Build Coastguard Worker int64_t PprofProfileReader::get_samples_value_sum(
171*6dbdd20aSAndroid Build Coastguard Worker     const std::string& last_function_name,
172*6dbdd20aSAndroid Build Coastguard Worker     const std::string& value_name) const {
173*6dbdd20aSAndroid Build Coastguard Worker   int64_t total = 0;
174*6dbdd20aSAndroid Build Coastguard Worker   const auto samples = get_samples(last_function_name);
175*6dbdd20aSAndroid Build Coastguard Worker   const auto value_index = get_sample_value_index(value_name);
176*6dbdd20aSAndroid Build Coastguard Worker   for (const auto& sample : samples) {
177*6dbdd20aSAndroid Build Coastguard Worker     total += sample.value()[value_index];
178*6dbdd20aSAndroid Build Coastguard Worker   }
179*6dbdd20aSAndroid Build Coastguard Worker   return total;
180*6dbdd20aSAndroid Build Coastguard Worker }
181*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto::pprof
182