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 // Collection of constant and utilities to parse SPE data.
18 // SPE packet spec can be found here:
19 // Arm Architecture Reference Manual for A-profile architecture
20 // https://developer.arm.com/documentation/ddi0487/latest/
21
22 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PERF_SPE_H_
23 #define SRC_TRACE_PROCESSOR_IMPORTERS_PERF_SPE_H_
24
25 #include <cstddef>
26 #include <cstdint>
27 #include "perfetto/base/logging.h"
28 #include "perfetto/public/compiler.h"
29
30 namespace perfetto::trace_processor::perf_importer::spe {
31
32 // Test whether a given bit is set. e.g.
33 // IsBitSet<1>(0b0010) == true
34 // IsBitSet<0>(0b0010) == false
35 template <int bit, typename T>
IsBitSet(T value)36 inline constexpr bool IsBitSet(T value) {
37 static_assert(std::is_unsigned_v<T>);
38 static_assert(bit < sizeof(T) * 8);
39 return value & (T(1) << bit);
40 }
41
42 // Index value in Address packets
43 enum class AddressIndex : uint8_t {
44 kInstruction,
45 kBranchTarget,
46 kDataVirtual,
47 kDataPhysical,
48 kPrevBranchTarget,
49 kUnknown,
50 kMax = kUnknown,
51 };
52
53 // Index value in Counter packets
54 enum class CounterIndex : uint8_t {
55 kTotalLatency,
56 kIssueLatency,
57 kTranslationLatency,
58 kUnknown,
59 kMax = kUnknown,
60 };
61
62 enum class ContextIndex : uint8_t {
63 kEl1,
64 kEl2,
65 kUnknown,
66 kMax = kUnknown,
67 };
68
69 // Operation class for OperationType packets
70 enum class OperationClass : uint8_t {
71 kOther,
72 kLoadOrStoreOrAtomic,
73 kBranchOrExceptionReturn,
74 kUnknown,
75 kMax = kUnknown,
76 };
77
78 // Data source types for a payload of a DataSource packet
79 enum class DataSource : uint8_t {
80 kL1D,
81 kL2,
82 kPeerCore,
83 kLocalCluster,
84 kSysCache,
85 kPeerCluster,
86 kRemote,
87 kDram,
88 kUnknown,
89 kMax = kUnknown,
90 };
91
92 // Exception levels instructions can execute in.
93 enum class ExceptionLevel { kEl0, kEl1, kEl2, kEl3, kMax = kEl3 };
94
95 // Common constants to both short and extended headers
96 constexpr uint8_t COMMON_HEADER_MASK = 0b1111'1000;
97 constexpr uint8_t COMMON_HEADER_ADDRESS_PACKET = 0b1011'0000;
98 constexpr uint8_t COMMON_HEADER_COUNTER_PACKET = 0b1001'1000;
99
100 constexpr uint8_t COMMON_HEADER_SIZE_MASK = 0b0011'0000;
101 constexpr uint8_t COMMON_HEADER_SIZE_MASK_RSHIFT = 4;
102
103 constexpr uint8_t COMMON_HEADER_NO_PAYLOAD_MASK = 0b1110'0000;
104 constexpr uint8_t COMMON_HEADER_NO_PAYLOAD = 0b0000'0000;
105
106 // Constants for short headers
107 constexpr uint8_t SHORT_HEADER_PADDING = 0b0000'0000;
108 constexpr uint8_t SHORT_HEADER_END_PACKET = 0b0000'0001;
109 constexpr uint8_t SHORT_HEADER_TIMESTAMP_PACKET = 0b0111'0001;
110
111 constexpr uint8_t SHORT_HEADER_MASK_1 = 0b1100'1111;
112 constexpr uint8_t SHORT_HEADER_EVENTS_PACKET = 0b0100'0010;
113 constexpr uint8_t SHORT_HEADER_DATA_SOURCE_PACKET = 0b0100'0011;
114
115 constexpr uint8_t SHORT_HEADER_MASK_2 = 0b1111'1100;
116 constexpr uint8_t SHORT_HEADER_CONTEXT_PACKET = 0b0110'0100;
117 constexpr uint8_t SHORT_HEADER_OPERATION_TYPE_PACKET = 0b0100'1000;
118
119 constexpr uint8_t SHORT_HEADER_INDEX_MASK = 0b0000'0111;
120
121 // Constants for extended headers
122 constexpr uint8_t EXTENDED_HEADER_MASK = 0b1110'0000;
123 constexpr uint8_t EXTENDED_HEADER = 0b0010'0000;
124
125 constexpr uint8_t EXTENDED_HEADER_INDEX_MASK = 0b0000'0011;
126 constexpr uint8_t EXTENDED_HEADER_INDEX_LSHIFT = 3;
127
128 // OperationType packet constants
129 constexpr uint8_t PKT_OP_TYPE_HEADER_CLASS_MASK = 0b0000'0011;
130 constexpr uint8_t PKT_OP_TYPE_HEADER_CLASS_OTHER = 0b0000'0000;
131 constexpr uint8_t PKT_OP_TYPE_HEADER_CLASS_LD_ST_ATOMIC = 0b0000'0001;
132 constexpr uint8_t PKT_OP_TYPE_HEADER_CLASS_BR_ERET = 0b0000'0010;
133
134 constexpr uint8_t PKT_OP_TYPE_PAYLOAD_SUBCLASS_OTHER_MASK = 0b1111'1110;
135 constexpr uint8_t PKT_OP_TYPE_PAYLOAD_SUBCLASS_OTHER = 0b0000'0000;
136
137 constexpr uint8_t PKT_OP_TYPE_PAYLOAD_SUBCLASS_SVE_OTHER_MASK = 0b1000'1001;
138 constexpr uint8_t PKT_OP_TYPE_PAYLOAD_SUBCLASS_SVE_OTHER = 0b0000'1000;
139
140 // DataSource packet constants
141 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_L1D = 0b0000'0000;
142 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_L2 = 0b0000'1000;
143 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_PEER_CORE = 0b0000'1001;
144 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_LOCAL_CLUSTER = 0b0000'1010;
145 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_SYS_CACHE = 0b0000'1011;
146 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_PEER_CLUSTER = 0b0000'1100;
147 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_REMOTE = 0b0000'1101;
148 constexpr uint16_t PKT_DATA_SOURCE_PAYLOAD_DRAM = 0b0000'1110;
149
150 // Helper to cast a value into a typed enum. Takes care of invalid inputs by
151 // returning the `kUnknown` value.
152 template <typename T>
ToEnum(uint8_t val)153 T ToEnum(uint8_t val) {
154 if (PERFETTO_LIKELY(val < static_cast<uint8_t>(T::kMax))) {
155 return static_cast<T>(val);
156 }
157 return T::kUnknown;
158 }
159
160 // An SPE record is a collection of packets. An End or Timestamp packet signals
161 // the end of a record. Each record consists of a 1 or 2 byte header followed by
162 // 0 - 4 bytes of payload. The `ShortHeader`, and `ExtendedHeader` hide all the
163 // low level bit fiddling details of handling packets. When parsing a stream of
164 // SPE records you can just check the first byte in the stream to determine if
165 // it belongs to a short or extended header and then use the appropiate class to
166 // determine packet type, payload length and packet details. There are other
167 // helper classes to parse payloads for the different packets.
168
169 // Checks if a header bytes is a padding packet. (no payload)
170 inline bool IsPadding(uint8_t byte) {
171 return byte == SHORT_HEADER_PADDING;
172 }
173
174 // Checks if a header byte corresponds to an extended header.
175 inline bool IsExtendedHeader(uint8_t byte) {
176 return (byte & EXTENDED_HEADER_MASK) == EXTENDED_HEADER;
177 }
178
179 class ShortHeader {
180 public:
181 explicit ShortHeader(uint8_t byte) : byte_0_(byte) {
182 PERFETTO_DCHECK(!IsExtendedHeader(byte));
183 }
184
185 inline bool IsPadding() { return byte_0_ == SHORT_HEADER_PADDING; }
186
187 inline bool IsEndPacket() { return byte_0_ == SHORT_HEADER_END_PACKET; }
188
189 inline bool IsTimestampPacket() {
190 return byte_0_ == SHORT_HEADER_TIMESTAMP_PACKET;
191 }
192
193 bool IsAddressPacket() const {
194 return (byte_0_ & COMMON_HEADER_MASK) == COMMON_HEADER_ADDRESS_PACKET;
195 }
196
197 AddressIndex GetAddressIndex() const {
198 PERFETTO_DCHECK(IsAddressPacket());
199 return ToEnum<AddressIndex>(index());
200 }
201
202 bool IsCounterPacket() const {
203 return (byte_0_ & COMMON_HEADER_MASK) == COMMON_HEADER_COUNTER_PACKET;
204 }
205
206 CounterIndex GetCounterIndex() const {
207 PERFETTO_DCHECK(IsCounterPacket());
208 return ToEnum<CounterIndex>(index());
209 }
210
211 bool IsEventsPacket() const {
212 return (byte_0_ & SHORT_HEADER_MASK_1) == SHORT_HEADER_EVENTS_PACKET;
213 }
214
215 bool IsContextPacket() const {
216 return (byte_0_ & SHORT_HEADER_MASK_2) == SHORT_HEADER_CONTEXT_PACKET;
217 }
218
219 ContextIndex GetContextIndex() const { return ToEnum<ContextIndex>(index()); }
220
221 bool IsDataSourcePacket() const {
222 return (byte_0_ & SHORT_HEADER_MASK_1) == SHORT_HEADER_DATA_SOURCE_PACKET;
223 }
224
225 DataSource GetDataSource(uint64_t payload) {
226 PERFETTO_DCHECK(IsDataSourcePacket());
227 switch (payload) {
228 case PKT_DATA_SOURCE_PAYLOAD_L1D:
229 return DataSource::kL1D;
230 case PKT_DATA_SOURCE_PAYLOAD_L2:
231 return DataSource::kL2;
232 case PKT_DATA_SOURCE_PAYLOAD_PEER_CORE:
233 return DataSource::kPeerCore;
234 case PKT_DATA_SOURCE_PAYLOAD_LOCAL_CLUSTER:
235 return DataSource::kLocalCluster;
236 case PKT_DATA_SOURCE_PAYLOAD_SYS_CACHE:
237 return DataSource::kSysCache;
238 case PKT_DATA_SOURCE_PAYLOAD_PEER_CLUSTER:
239 return DataSource::kPeerCluster;
240 case PKT_DATA_SOURCE_PAYLOAD_REMOTE:
241 return DataSource::kRemote;
242 case PKT_DATA_SOURCE_PAYLOAD_DRAM:
243 return DataSource::kDram;
244 default:
245 break;
246 }
247 return DataSource::kUnknown;
248 }
249
250 bool IsOperationTypePacket() const {
251 return (byte_0_ & SHORT_HEADER_MASK_2) ==
252 SHORT_HEADER_OPERATION_TYPE_PACKET;
253 }
254
255 OperationClass GetOperationClass() const {
256 PERFETTO_DCHECK(IsOperationTypePacket());
257 switch (byte_0_ & PKT_OP_TYPE_HEADER_CLASS_MASK) {
258 case PKT_OP_TYPE_HEADER_CLASS_OTHER:
259 return OperationClass::kOther;
260
261 case PKT_OP_TYPE_HEADER_CLASS_LD_ST_ATOMIC:
262 return OperationClass::kLoadOrStoreOrAtomic;
263
264 case PKT_OP_TYPE_HEADER_CLASS_BR_ERET:
265 return OperationClass::kBranchOrExceptionReturn;
266
267 default:
268 break;
269 }
270 return OperationClass::kUnknown;
271 }
272
273 bool HasPayload() const {
274 return (byte_0_ & COMMON_HEADER_NO_PAYLOAD_MASK) !=
275 COMMON_HEADER_NO_PAYLOAD;
276 }
277
278 uint8_t GetPayloadSize() const {
279 PERFETTO_DCHECK(!IsExtendedHeader(byte_0_));
280 if (!HasPayload()) {
281 return 0;
282 }
283 return static_cast<uint8_t>(1 << ((byte_0_ & COMMON_HEADER_SIZE_MASK) >>
284 COMMON_HEADER_SIZE_MASK_RSHIFT));
285 }
286
287 private:
288 friend class ExtendedHeader;
289
290 uint8_t index() const { return byte_0_ & SHORT_HEADER_INDEX_MASK; }
291
292 uint8_t byte_0_;
293 };
294
295 class ExtendedHeader {
296 public:
297 ExtendedHeader(uint8_t byte_0, uint8_t byte_1)
298 : byte_0_(byte_0), short_header_(byte_1) {
299 PERFETTO_DCHECK(IsExtendedHeader(byte_0));
300 }
301
302 bool IsAddressPacket() const { return short_header_.IsAddressPacket(); }
303
304 AddressIndex GetAddressIndex() const { return ToEnum<AddressIndex>(index()); }
305
306 bool IsCounterPacket() const { return short_header_.IsCounterPacket(); }
307
308 CounterIndex GetCounterIndex() const { return ToEnum<CounterIndex>(index()); }
309
310 inline uint8_t GetPayloadSize() { return short_header_.GetPayloadSize(); }
311
312 private:
313 uint8_t byte_1() const { return short_header_.byte_0_; }
314
315 uint8_t index() const {
316 return static_cast<uint8_t>((byte_0_ & EXTENDED_HEADER_INDEX_MASK)
317 << EXTENDED_HEADER_INDEX_LSHIFT) +
318 short_header_.index();
319 }
320
321 uint8_t byte_0_;
322 ShortHeader short_header_;
323 };
324
325 enum class OperationOtherSubclass : uint8_t {
326 kOther,
327 kSveVecOp,
328 kUnknown,
329 kMax = kUnknown
330 };
331 class OperationTypeOtherPayload {
332 public:
333 explicit OperationTypeOtherPayload(uint8_t payload) : payload_(payload) {}
334
335 OperationOtherSubclass subclass() const {
336 if ((payload_ & PKT_OP_TYPE_PAYLOAD_SUBCLASS_OTHER_MASK) ==
337 PKT_OP_TYPE_PAYLOAD_SUBCLASS_OTHER) {
338 return OperationOtherSubclass::kOther;
339 }
340 if ((payload_ & PKT_OP_TYPE_PAYLOAD_SUBCLASS_SVE_OTHER_MASK) ==
341 PKT_OP_TYPE_PAYLOAD_SUBCLASS_SVE_OTHER) {
342 return OperationOtherSubclass::kSveVecOp;
343 }
344 return OperationOtherSubclass::kUnknown;
345 }
346
347 private:
348 uint8_t payload_;
349 };
350
351 class OperationTypeLdStAtPayload {
352 public:
353 explicit OperationTypeLdStAtPayload(uint8_t payload) : payload_(payload) {}
354
355 bool IsStore() const { return IsBitSet<0>(payload_); }
356
357 private:
358 uint8_t payload_;
359 };
360
361 namespace internal {
362 inline uint64_t GetPacketAddressAddress(uint64_t payload) {
363 return payload & 0x0FFFFFFFFFFFFFFF;
364 }
365
366 inline bool GetPacketAddressNs(uint64_t payload) {
367 return IsBitSet<63>(payload);
368 }
369
370 inline ExceptionLevel GetPacketAddressEl(uint64_t payload) {
371 return static_cast<ExceptionLevel>((payload >> 61) & 0x03);
372 }
373
374 inline bool GetPacketAddressNse(uint64_t payload) {
375 return IsBitSet<60>(payload);
376 }
377 } // namespace internal
378
379 struct InstructionVirtualAddress {
380 explicit InstructionVirtualAddress(uint64_t payload)
381 : address(internal::GetPacketAddressAddress(payload)),
382 el(internal::GetPacketAddressEl(payload)),
383 ns(internal::GetPacketAddressNs(payload)),
384 nse(internal::GetPacketAddressNse(payload)) {}
385 uint64_t address;
386 ExceptionLevel el;
387 bool ns;
388 bool nse;
389 };
390
391 struct DataVirtualAddress {
392 explicit DataVirtualAddress(uint64_t payload)
393 : address(internal::GetPacketAddressAddress(payload)) {}
394 uint64_t address;
395 };
396
397 struct DataPhysicalAddress {
398 explicit DataPhysicalAddress(uint64_t payload)
399 : address(internal::GetPacketAddressAddress(payload)) {}
400 uint64_t address;
401 };
402
403 } // namespace perfetto::trace_processor::perf_importer::spe
404
405 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PERF_SPE_H_
406