xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/perf/spe_record_parser.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/spe_record_parser.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <optional>
22 
23 #include "perfetto/base/logging.h"
24 #include "perfetto/trace_processor/trace_blob_view.h"
25 #include "src/trace_processor/importers/common/mapping_tracker.h"
26 #include "src/trace_processor/importers/common/process_tracker.h"
27 #include "src/trace_processor/importers/common/virtual_memory_mapping.h"
28 #include "src/trace_processor/importers/perf/reader.h"
29 #include "src/trace_processor/importers/perf/spe.h"
30 #include "src/trace_processor/storage/trace_storage.h"
31 #include "src/trace_processor/tables/metadata_tables_py.h"
32 #include "src/trace_processor/tables/perf_tables_py.h"
33 #include "src/trace_processor/types/trace_processor_context.h"
34 
35 namespace perfetto::trace_processor::perf_importer {
36 
37 // static
ToString(spe::DataSource ds)38 const char* SpeRecordParserImpl::ToString(spe::DataSource ds) {
39   switch (ds) {
40     case spe::DataSource::kUnknown:
41       return "UNKNOWN";
42     case spe::DataSource::kL1D:
43       return "L1D";
44     case spe::DataSource::kL2:
45       return "L2";
46     case spe::DataSource::kPeerCore:
47       return "PEER_CORE";
48     case spe::DataSource::kLocalCluster:
49       return "LOCAL_CLUSTER";
50     case spe::DataSource::kSysCache:
51       return "SYS_CACHE";
52     case spe::DataSource::kPeerCluster:
53       return "PEER_CLUSTER";
54     case spe::DataSource::kRemote:
55       return "REMOTE";
56     case spe::DataSource::kDram:
57       return "DRAM";
58   }
59   PERFETTO_FATAL("For GCC");
60 }
61 
62 // static
ToString(spe::ExceptionLevel el)63 const char* SpeRecordParserImpl::ToString(spe::ExceptionLevel el) {
64   switch (el) {
65     case spe::ExceptionLevel::kEl0:
66       return "EL0";
67     case spe::ExceptionLevel::kEl1:
68       return "EL1";
69     case spe::ExceptionLevel::kEl2:
70       return "EL2";
71     case spe::ExceptionLevel::kEl3:
72       return "EL3";
73   }
74   PERFETTO_FATAL("For GCC");
75 }
76 
77 // static
ToString(OperationName name)78 const char* SpeRecordParserImpl::ToString(OperationName name) {
79   switch (name) {
80     case OperationName::kOther:
81       return "OTHER";
82     case OperationName::kSveVecOp:
83       return "SVE_VEC_OP";
84     case OperationName::kLoad:
85       return "LOAD";
86     case OperationName::kStore:
87       return "STORE";
88     case OperationName::kBranch:
89       return "BRANCH";
90     case OperationName::kUnknown:
91       return "UNKNOWN";
92   }
93   PERFETTO_FATAL("For GCC");
94 }
95 
ToStringId(OperationName name)96 StringId SpeRecordParserImpl::ToStringId(OperationName name) {
97   if (operation_name_strings_[name] == kNullStringId) {
98     operation_name_strings_[name] =
99         context_->storage->InternString(ToString(name));
100   }
101   return operation_name_strings_[name];
102 }
103 
ToStringId(spe::ExceptionLevel el)104 StringId SpeRecordParserImpl::ToStringId(spe::ExceptionLevel el) {
105   if (exception_level_strings_[el] == kNullStringId) {
106     exception_level_strings_[el] =
107         context_->storage->InternString(ToString(el));
108   }
109   return exception_level_strings_[el];
110 }
111 
ToStringId(spe::DataSource ds)112 StringId SpeRecordParserImpl::ToStringId(spe::DataSource ds) {
113   if (data_source_strings_[ds] == kNullStringId) {
114     data_source_strings_[ds] = context_->storage->InternString(ToString(ds));
115   }
116   return data_source_strings_[ds];
117 }
118 
SpeRecordParserImpl(TraceProcessorContext * context)119 SpeRecordParserImpl::SpeRecordParserImpl(TraceProcessorContext* context)
120     : context_(context), reader_(TraceBlobView()) {}
121 
ParseSpeRecord(int64_t ts,TraceBlobView data)122 void SpeRecordParserImpl::ParseSpeRecord(int64_t ts, TraceBlobView data) {
123   reader_ = Reader(std::move(data));
124   inflight_row_ = {};
125   inflight_row_.ts = ts;
126   inflight_record_ = {};
127 
128   // No need to check that there is enough data as this has been validated by
129   // the tokenization step.
130   while (reader_.size_left() != 0) {
131     uint8_t byte_0;
132     reader_.Read(byte_0);
133 
134     if (spe::IsExtendedHeader(byte_0)) {
135       uint8_t byte_1;
136       reader_.Read(byte_1);
137       spe::ExtendedHeader extended_header(byte_0, byte_1);
138       ReadExtendedPacket(extended_header);
139     } else {
140       ReadShortPacket(spe::ShortHeader(byte_0));
141     }
142   }
143   if (!inflight_record_.instruction_address) {
144     context_->storage->mutable_spe_record_table()->Insert(inflight_row_);
145     return;
146   }
147 
148   const auto& inst = *inflight_record_.instruction_address;
149 
150   inflight_row_.exception_level = ToStringId(inst.el);
151 
152   if (inst.el == spe::ExceptionLevel::kEl0 && inflight_row_.utid) {
153     const auto upid =
154         *context_->storage->thread_table()
155              .FindById(tables::ThreadTable::Id(*inflight_row_.utid))
156              ->upid();
157 
158     VirtualMemoryMapping* mapping =
159         context_->mapping_tracker->FindUserMappingForAddress(upid,
160                                                              inst.address);
161     if (mapping) {
162       inflight_row_.instruction_frame_id =
163           mapping->InternFrame(mapping->ToRelativePc(inst.address), "");
164     }
165   } else if (inst.el == spe::ExceptionLevel::kEl1) {
166     VirtualMemoryMapping* mapping =
167         context_->mapping_tracker->FindKernelMappingForAddress(inst.address);
168     if (mapping) {
169       inflight_row_.instruction_frame_id =
170           mapping->InternFrame(mapping->ToRelativePc(inst.address), "");
171     }
172   }
173 
174   if (!inflight_row_.instruction_frame_id.has_value()) {
175     inflight_row_.instruction_frame_id = GetDummyMapping()->InternFrame(
176         GetDummyMapping()->ToRelativePc(inst.address), "");
177   }
178 
179   context_->storage->mutable_spe_record_table()->Insert(inflight_row_);
180 }
181 
ReadShortPacket(spe::ShortHeader short_header)182 void SpeRecordParserImpl::ReadShortPacket(spe::ShortHeader short_header) {
183   if (short_header.IsAddressPacket()) {
184     ReadAddressPacket(short_header.GetAddressIndex());
185 
186   } else if (short_header.IsCounterPacket()) {
187     ReadCounterPacket(short_header.GetCounterIndex());
188 
189   } else if (short_header.IsEventsPacket()) {
190     ReadEventsPacket(short_header);
191 
192   } else if (short_header.IsContextPacket()) {
193     ReadContextPacket(short_header);
194 
195   } else if (short_header.IsOperationTypePacket()) {
196     ReadOperationTypePacket(short_header);
197 
198   } else if (short_header.IsDataSourcePacket()) {
199     ReadDataSourcePacket(short_header);
200 
201   } else {
202     reader_.Skip(short_header.GetPayloadSize());
203   }
204 }
205 
ReadExtendedPacket(spe::ExtendedHeader extended_header)206 void SpeRecordParserImpl::ReadExtendedPacket(
207     spe::ExtendedHeader extended_header) {
208   if (extended_header.IsAddressPacket()) {
209     ReadAddressPacket(extended_header.GetAddressIndex());
210 
211   } else if (extended_header.IsCounterPacket()) {
212     ReadCounterPacket(extended_header.GetCounterIndex());
213 
214   } else {
215     reader_.Skip(extended_header.GetPayloadSize());
216   }
217 }
218 
ReadAddressPacket(spe::AddressIndex index)219 void SpeRecordParserImpl::ReadAddressPacket(spe::AddressIndex index) {
220   uint64_t payload;
221   reader_.Read(payload);
222 
223   switch (index) {
224     case spe::AddressIndex::kInstruction:
225       inflight_record_.instruction_address =
226           spe::InstructionVirtualAddress(payload);
227       break;
228 
229     case spe::AddressIndex::kDataVirtual:
230       inflight_row_.data_virtual_address =
231           static_cast<int64_t>(spe::DataVirtualAddress(payload).address);
232       break;
233 
234     case spe::AddressIndex::kDataPhysical:
235       inflight_row_.data_physical_address =
236           static_cast<int64_t>(spe::DataPhysicalAddress(payload).address);
237       break;
238 
239     case spe::AddressIndex::kBranchTarget:
240     case spe::AddressIndex::kPrevBranchTarget:
241     case spe::AddressIndex::kUnknown:
242       break;
243   }
244 }
245 
ReadCounterPacket(spe::CounterIndex index)246 void SpeRecordParserImpl::ReadCounterPacket(spe::CounterIndex index) {
247   uint16_t value;
248   reader_.Read(value);
249   switch (index) {
250     case spe::CounterIndex::kTotalLatency:
251       inflight_row_.total_latency = value;
252       break;
253 
254     case spe::CounterIndex::kIssueLatency:
255       inflight_row_.issue_latency = value;
256       break;
257 
258     case spe::CounterIndex::kTranslationLatency:
259       inflight_row_.translation_latency = value;
260       break;
261 
262     case spe::CounterIndex::kUnknown:
263       break;
264   }
265 }
266 
ReadEventsPacket(spe::ShortHeader short_header)267 void SpeRecordParserImpl::ReadEventsPacket(spe::ShortHeader short_header) {
268   inflight_row_.events_bitmask =
269       static_cast<int64_t>(ReadPayload(short_header));
270 }
271 
ReadContextPacket(spe::ShortHeader short_header)272 void SpeRecordParserImpl::ReadContextPacket(spe::ShortHeader short_header) {
273   uint32_t tid;
274   reader_.Read(tid);
275   inflight_row_.utid = context_->process_tracker->GetOrCreateThread(tid);
276   switch (short_header.GetContextIndex()) {
277     case spe::ContextIndex::kEl1:
278     case spe::ContextIndex::kEl2:
279     case spe::ContextIndex::kUnknown:
280       break;
281   }
282 }
283 
ReadOperationTypePacket(spe::ShortHeader short_header)284 void SpeRecordParserImpl::ReadOperationTypePacket(
285     spe::ShortHeader short_header) {
286   uint8_t payload;
287   reader_.Read(payload);
288   inflight_row_.operation = ToStringId(GetOperationName(short_header, payload));
289 }
290 
GetOperationName(spe::ShortHeader short_header,uint8_t payload) const291 SpeRecordParserImpl::OperationName SpeRecordParserImpl::GetOperationName(
292     spe::ShortHeader short_header,
293     uint8_t payload) const {
294   switch (short_header.GetOperationClass()) {
295     case spe::OperationClass::kOther:
296       switch (spe::OperationTypeOtherPayload(payload).subclass()) {
297         case spe::OperationOtherSubclass::kOther:
298           return OperationName::kOther;
299         case spe::OperationOtherSubclass::kSveVecOp:
300           return OperationName::kSveVecOp;
301         case spe::OperationOtherSubclass::kUnknown:
302           return OperationName::kUnknown;
303       }
304       PERFETTO_FATAL("For GCC");
305 
306     case spe::OperationClass::kLoadOrStoreOrAtomic:
307       if (spe::OperationTypeLdStAtPayload(payload).IsStore()) {
308         return OperationName::kStore;
309       }
310       return OperationName::kLoad;
311 
312     case spe::OperationClass::kBranchOrExceptionReturn:
313       return OperationName::kBranch;
314 
315     case spe::OperationClass::kUnknown:
316       return OperationName::kUnknown;
317   }
318   PERFETTO_FATAL("For GCC");
319 }
320 
GetDummyMapping()321 VirtualMemoryMapping* SpeRecordParserImpl::GetDummyMapping() {
322   if (!dummy_mapping_) {
323     dummy_mapping_ =
324         &context_->mapping_tracker->CreateDummyMapping("spe_dummy");
325   }
326   return dummy_mapping_;
327 }
328 
ReadDataSourcePacket(spe::ShortHeader short_header)329 void SpeRecordParserImpl::ReadDataSourcePacket(spe::ShortHeader short_header) {
330   inflight_row_.data_source =
331       ToStringId(short_header.GetDataSource(ReadPayload(short_header)));
332 }
333 
ReadPayload(spe::ShortHeader short_header)334 uint64_t SpeRecordParserImpl::ReadPayload(spe::ShortHeader short_header) {
335   switch (short_header.GetPayloadSize()) {
336     case 1: {
337       uint8_t data;
338       reader_.Read(data);
339       return data;
340     }
341     case 2: {
342       uint16_t data;
343       reader_.Read(data);
344       return data;
345     }
346     case 4: {
347       uint32_t data;
348       reader_.Read(data);
349       return data;
350     }
351     case 8: {
352       uint64_t data;
353       reader_.Read(data);
354       return data;
355     }
356     default:
357       break;
358   }
359   PERFETTO_FATAL("Unreachable");
360 }
361 
362 }  // namespace perfetto::trace_processor::perf_importer
363