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