xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/perf/perf_session.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 "src/trace_processor/importers/perf/perf_session.h"
18 
19 #include <cinttypes>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23 #include <optional>
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 #include "perfetto/base/logging.h"
29 #include "perfetto/base/status.h"
30 #include "perfetto/ext/base/flat_hash_map.h"
31 #include "perfetto/ext/base/status_or.h"
32 #include "perfetto/ext/base/string_utils.h"
33 #include "perfetto/ext/base/string_view.h"
34 #include "perfetto/trace_processor/ref_counted.h"
35 #include "perfetto/trace_processor/trace_blob_view.h"
36 #include "protos/perfetto/common/builtin_clock.pbzero.h"
37 #include "src/trace_processor/importers/perf/perf_event.h"
38 #include "src/trace_processor/importers/perf/perf_event_attr.h"
39 #include "src/trace_processor/importers/perf/reader.h"
40 #include "src/trace_processor/storage/trace_storage.h"  // IWYU pragma: keep
41 #include "src/trace_processor/types/trace_processor_context.h"
42 #include "src/trace_processor/util/build_id.h"
43 
44 namespace perfetto::trace_processor::perf_importer {
45 namespace {
OffsetsMatch(const PerfEventAttr & attr,const PerfEventAttr & other)46 bool OffsetsMatch(const PerfEventAttr& attr, const PerfEventAttr& other) {
47   return attr.id_offset_from_start() == other.id_offset_from_start() &&
48          (!attr.sample_id_all() ||
49           attr.id_offset_from_end() == other.id_offset_from_end());
50 }
51 }  // namespace
52 
Build()53 base::StatusOr<RefPtr<PerfSession>> PerfSession::Builder::Build() {
54   if (attr_with_ids_.empty()) {
55     return base::ErrStatus("No perf_event_attr");
56   }
57 
58   auto perf_session_id =
59       context_->storage->mutable_perf_session_table()->Insert({}).id;
60 
61   RefPtr<PerfEventAttr> first_attr;
62   base::FlatHashMap<uint64_t, RefPtr<PerfEventAttr>> attrs_by_id;
63   for (const auto& entry : attr_with_ids_) {
64     RefPtr<PerfEventAttr> attr(
65         new PerfEventAttr(context_, perf_session_id, entry.attr));
66     if (!first_attr) {
67       first_attr = attr;
68     }
69     if (first_attr->sample_id_all() != attr->sample_id_all()) {
70       return base::ErrStatus(
71           "perf_event_attr with different sample_id_all values");
72     }
73 
74     if (!OffsetsMatch(*first_attr, *attr)) {
75       return base::ErrStatus("perf_event_attr with different id offsets");
76     }
77 
78     for (uint64_t id : entry.ids) {
79       if (!attrs_by_id.Insert(id, attr).second) {
80         return base::ErrStatus(
81             "Same id maps to multiple perf_event_attr: %" PRIu64, id);
82       }
83     }
84   }
85   if (attr_with_ids_.size() > 1 &&
86       (!first_attr->id_offset_from_start().has_value() ||
87        (first_attr->sample_id_all() &&
88         !first_attr->id_offset_from_end().has_value()))) {
89     return base::ErrStatus("No id offsets for multiple perf_event_attr");
90   }
91   return RefPtr<PerfSession>(
92       new PerfSession(context_, perf_session_id, std::move(first_attr),
93                       std::move(attrs_by_id), attr_with_ids_.size() == 1));
94 }
95 
FindAttrForRecord(const perf_event_header & header,const TraceBlobView & payload) const96 base::StatusOr<RefPtr<PerfEventAttr>> PerfSession::FindAttrForRecord(
97     const perf_event_header& header,
98     const TraceBlobView& payload) const {
99   if (header.type >= PERF_RECORD_USER_TYPE_START) {
100     return RefPtr<PerfEventAttr>();
101   }
102 
103   if (has_single_perf_event_attr_) {
104     return first_attr_;
105   }
106 
107   if (header.type != PERF_RECORD_SAMPLE && !first_attr_->sample_id_all()) {
108     return first_attr_;
109   }
110 
111   uint64_t id;
112   if (!ReadEventId(header, payload, id)) {
113     return base::ErrStatus("Failed to read record id");
114   }
115 
116   if (id == 0) {
117     return first_attr_;
118   }
119 
120   auto it = FindAttrForEventId(id);
121   if (!it) {
122     return base::ErrStatus("No perf_event_attr for id %" PRIu64, id);
123   }
124   return it;
125 }
126 
ReadEventId(const perf_event_header & header,const TraceBlobView & payload,uint64_t & id) const127 bool PerfSession::ReadEventId(const perf_event_header& header,
128                               const TraceBlobView& payload,
129                               uint64_t& id) const {
130   const PerfEventAttr& first = *attrs_by_id_.GetIterator().value();
131   Reader reader(payload.copy());
132 
133   if (header.type != PERF_RECORD_SAMPLE) {
134     PERFETTO_CHECK(first.id_offset_from_end().has_value());
135     if (reader.size_left() < *first.id_offset_from_end()) {
136       return false;
137     }
138     const size_t off = reader.size_left() - *first.id_offset_from_end();
139     return reader.Skip(off) && reader.Read(id);
140   }
141   PERFETTO_CHECK(first.id_offset_from_start().has_value());
142   return reader.Skip(*first.id_offset_from_start()) && reader.Read(id);
143 }
144 
FindAttrForEventId(uint64_t id) const145 RefPtr<PerfEventAttr> PerfSession::FindAttrForEventId(uint64_t id) const {
146   auto* it = attrs_by_id_.Find(id);
147   if (!it) {
148     return {};
149   }
150   return RefPtr<PerfEventAttr>(it->get());
151 }
152 
SetEventName(uint64_t event_id,std::string name)153 void PerfSession::SetEventName(uint64_t event_id, std::string name) {
154   auto* it = attrs_by_id_.Find(event_id);
155   if (!it) {
156     return;
157   }
158   (*it)->set_event_name(std::move(name));
159 }
160 
SetEventName(uint32_t type,uint64_t config,const std::string & name)161 void PerfSession::SetEventName(uint32_t type,
162                                uint64_t config,
163                                const std::string& name) {
164   for (auto it = attrs_by_id_.GetIterator(); it; ++it) {
165     if (it.value()->type() == type && it.value()->config() == config) {
166       it.value()->set_event_name(name);
167     }
168   }
169 }
170 
AddBuildId(int32_t pid,std::string filename,BuildId build_id)171 void PerfSession::AddBuildId(int32_t pid,
172                              std::string filename,
173                              BuildId build_id) {
174   build_ids_.Insert({pid, std::move(filename)}, std::move(build_id));
175 }
176 
LookupBuildId(uint32_t pid,const std::string & filename) const177 std::optional<BuildId> PerfSession::LookupBuildId(
178     uint32_t pid,
179     const std::string& filename) const {
180   // -1 is used in BUILD_ID feature to match any pid.
181   static constexpr int32_t kAnyPid = -1;
182   auto* it = build_ids_.Find({static_cast<int32_t>(pid), filename});
183   if (!it) {
184     it = build_ids_.Find({kAnyPid, filename});
185   }
186   return it ? std::make_optional(*it) : std::nullopt;
187 }
188 
SetCmdline(const std::vector<std::string> & args)189 void PerfSession::SetCmdline(const std::vector<std::string>& args) {
190   context_->storage->mutable_perf_session_table()
191       ->FindById(perf_session_id_)
192       ->set_cmdline(context_->storage->InternString(
193           base::StringView(base::Join(args, " "))));
194 }
195 
HasPerfClock() const196 bool PerfSession::HasPerfClock() const {
197   for (auto it = attrs_by_id_.GetIterator(); it; ++it) {
198     if (it.value()->clock_id() == protos::pbzero::BUILTIN_CLOCK_PERF) {
199       return true;
200     }
201   }
202   return false;
203 }
204 
205 }  // namespace perfetto::trace_processor::perf_importer
206