1 //===- FDRRecords.h - XRay Flight Data Recorder Mode Records --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Define types and operations on these types that represent the different kinds 10 // of records we encounter in XRay flight data recorder mode traces. 11 // 12 //===----------------------------------------------------------------------===// 13 #ifndef LLVM_XRAY_FDRRECORDS_H 14 #define LLVM_XRAY_FDRRECORDS_H 15 16 #include <cstdint> 17 #include <string> 18 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Support/DataExtractor.h" 22 #include "llvm/Support/Error.h" 23 #include "llvm/XRay/XRayRecord.h" 24 25 namespace llvm { 26 namespace xray { 27 28 class RecordVisitor; 29 class RecordInitializer; 30 31 class Record { 32 public: 33 enum class RecordKind { 34 RK_Metadata, 35 RK_Metadata_BufferExtents, 36 RK_Metadata_WallClockTime, 37 RK_Metadata_NewCPUId, 38 RK_Metadata_TSCWrap, 39 RK_Metadata_CustomEvent, 40 RK_Metadata_CustomEventV5, 41 RK_Metadata_CallArg, 42 RK_Metadata_PIDEntry, 43 RK_Metadata_NewBuffer, 44 RK_Metadata_EndOfBuffer, 45 RK_Metadata_TypedEvent, 46 RK_Metadata_LastMetadata, 47 RK_Function, 48 }; 49 50 static StringRef kindToString(RecordKind K); 51 52 private: 53 const RecordKind T; 54 55 public: 56 Record(const Record &) = delete; 57 Record(Record &&) = delete; 58 Record &operator=(const Record &) = delete; 59 Record &operator=(Record &&) = delete; Record(RecordKind T)60 explicit Record(RecordKind T) : T(T) {} 61 getRecordType()62 RecordKind getRecordType() const { return T; } 63 64 // Each Record should be able to apply an abstract visitor, and choose the 65 // appropriate function in the visitor to invoke, given its own type. 66 virtual Error apply(RecordVisitor &V) = 0; 67 68 virtual ~Record() = default; 69 }; 70 71 class MetadataRecord : public Record { 72 public: 73 enum class MetadataType : unsigned { 74 Unknown, 75 BufferExtents, 76 WallClockTime, 77 NewCPUId, 78 TSCWrap, 79 CustomEvent, 80 CallArg, 81 PIDEntry, 82 NewBuffer, 83 EndOfBuffer, 84 TypedEvent, 85 }; 86 87 protected: 88 static constexpr int kMetadataBodySize = 15; 89 friend class RecordInitializer; 90 91 private: 92 const MetadataType MT; 93 94 public: MetadataRecord(RecordKind T,MetadataType M)95 explicit MetadataRecord(RecordKind T, MetadataType M) : Record(T), MT(M) {} 96 classof(const Record * R)97 static bool classof(const Record *R) { 98 return R->getRecordType() >= RecordKind::RK_Metadata && 99 R->getRecordType() <= RecordKind::RK_Metadata_LastMetadata; 100 } 101 metadataType()102 MetadataType metadataType() const { return MT; } 103 104 virtual ~MetadataRecord() = default; 105 }; 106 107 // What follows are specific Metadata record types which encapsulate the 108 // information associated with specific metadata record types in an FDR mode 109 // log. 110 class BufferExtents : public MetadataRecord { 111 uint64_t Size = 0; 112 friend class RecordInitializer; 113 114 public: BufferExtents()115 BufferExtents() 116 : MetadataRecord(RecordKind::RK_Metadata_BufferExtents, 117 MetadataType::BufferExtents) {} 118 BufferExtents(uint64_t S)119 explicit BufferExtents(uint64_t S) 120 : MetadataRecord(RecordKind::RK_Metadata_BufferExtents, 121 MetadataType::BufferExtents), 122 Size(S) {} 123 size()124 uint64_t size() const { return Size; } 125 126 Error apply(RecordVisitor &V) override; 127 classof(const Record * R)128 static bool classof(const Record *R) { 129 return R->getRecordType() == RecordKind::RK_Metadata_BufferExtents; 130 } 131 }; 132 133 class WallclockRecord : public MetadataRecord { 134 uint64_t Seconds = 0; 135 uint32_t Nanos = 0; 136 friend class RecordInitializer; 137 138 public: WallclockRecord()139 WallclockRecord() 140 : MetadataRecord(RecordKind::RK_Metadata_WallClockTime, 141 MetadataType::WallClockTime) {} 142 WallclockRecord(uint64_t S,uint32_t N)143 explicit WallclockRecord(uint64_t S, uint32_t N) 144 : MetadataRecord(RecordKind::RK_Metadata_WallClockTime, 145 MetadataType::WallClockTime), 146 Seconds(S), Nanos(N) {} 147 seconds()148 uint64_t seconds() const { return Seconds; } nanos()149 uint32_t nanos() const { return Nanos; } 150 151 Error apply(RecordVisitor &V) override; 152 classof(const Record * R)153 static bool classof(const Record *R) { 154 return R->getRecordType() == RecordKind::RK_Metadata_WallClockTime; 155 } 156 }; 157 158 class NewCPUIDRecord : public MetadataRecord { 159 uint16_t CPUId = 0; 160 uint64_t TSC = 0; 161 friend class RecordInitializer; 162 163 public: NewCPUIDRecord()164 NewCPUIDRecord() 165 : MetadataRecord(RecordKind::RK_Metadata_NewCPUId, 166 MetadataType::NewCPUId) {} 167 NewCPUIDRecord(uint16_t C,uint64_t T)168 NewCPUIDRecord(uint16_t C, uint64_t T) 169 : MetadataRecord(RecordKind::RK_Metadata_NewCPUId, 170 MetadataType::NewCPUId), 171 CPUId(C), TSC(T) {} 172 cpuid()173 uint16_t cpuid() const { return CPUId; } 174 tsc()175 uint64_t tsc() const { return TSC; } 176 177 Error apply(RecordVisitor &V) override; 178 classof(const Record * R)179 static bool classof(const Record *R) { 180 return R->getRecordType() == RecordKind::RK_Metadata_NewCPUId; 181 } 182 }; 183 184 class TSCWrapRecord : public MetadataRecord { 185 uint64_t BaseTSC = 0; 186 friend class RecordInitializer; 187 188 public: TSCWrapRecord()189 TSCWrapRecord() 190 : MetadataRecord(RecordKind::RK_Metadata_TSCWrap, MetadataType::TSCWrap) { 191 } 192 TSCWrapRecord(uint64_t B)193 explicit TSCWrapRecord(uint64_t B) 194 : MetadataRecord(RecordKind::RK_Metadata_TSCWrap, MetadataType::TSCWrap), 195 BaseTSC(B) {} 196 tsc()197 uint64_t tsc() const { return BaseTSC; } 198 199 Error apply(RecordVisitor &V) override; 200 classof(const Record * R)201 static bool classof(const Record *R) { 202 return R->getRecordType() == RecordKind::RK_Metadata_TSCWrap; 203 } 204 }; 205 206 class CustomEventRecord : public MetadataRecord { 207 int32_t Size = 0; 208 uint64_t TSC = 0; 209 uint16_t CPU = 0; 210 std::string Data{}; 211 friend class RecordInitializer; 212 213 public: CustomEventRecord()214 CustomEventRecord() 215 : MetadataRecord(RecordKind::RK_Metadata_CustomEvent, 216 MetadataType::CustomEvent) {} 217 CustomEventRecord(uint64_t S,uint64_t T,uint16_t C,std::string D)218 explicit CustomEventRecord(uint64_t S, uint64_t T, uint16_t C, std::string D) 219 : MetadataRecord(RecordKind::RK_Metadata_CustomEvent, 220 MetadataType::CustomEvent), 221 Size(S), TSC(T), CPU(C), Data(std::move(D)) {} 222 size()223 int32_t size() const { return Size; } tsc()224 uint64_t tsc() const { return TSC; } cpu()225 uint16_t cpu() const { return CPU; } data()226 StringRef data() const { return Data; } 227 228 Error apply(RecordVisitor &V) override; 229 classof(const Record * R)230 static bool classof(const Record *R) { 231 return R->getRecordType() == RecordKind::RK_Metadata_CustomEvent; 232 } 233 }; 234 235 class CustomEventRecordV5 : public MetadataRecord { 236 int32_t Size = 0; 237 int32_t Delta = 0; 238 std::string Data{}; 239 friend class RecordInitializer; 240 241 public: CustomEventRecordV5()242 CustomEventRecordV5() 243 : MetadataRecord(RecordKind::RK_Metadata_CustomEventV5, 244 MetadataType::CustomEvent) {} 245 CustomEventRecordV5(int32_t S,int32_t D,std::string P)246 explicit CustomEventRecordV5(int32_t S, int32_t D, std::string P) 247 : MetadataRecord(RecordKind::RK_Metadata_CustomEventV5, 248 MetadataType::CustomEvent), 249 Size(S), Delta(D), Data(std::move(P)) {} 250 size()251 int32_t size() const { return Size; } delta()252 int32_t delta() const { return Delta; } data()253 StringRef data() const { return Data; } 254 255 Error apply(RecordVisitor &V) override; 256 classof(const Record * R)257 static bool classof(const Record *R) { 258 return R->getRecordType() == RecordKind::RK_Metadata_CustomEventV5; 259 } 260 }; 261 262 class TypedEventRecord : public MetadataRecord { 263 int32_t Size = 0; 264 int32_t Delta = 0; 265 uint16_t EventType = 0; 266 std::string Data{}; 267 friend class RecordInitializer; 268 269 public: TypedEventRecord()270 TypedEventRecord() 271 : MetadataRecord(RecordKind::RK_Metadata_TypedEvent, 272 MetadataType::TypedEvent) {} 273 TypedEventRecord(int32_t S,int32_t D,uint16_t E,std::string P)274 explicit TypedEventRecord(int32_t S, int32_t D, uint16_t E, std::string P) 275 : MetadataRecord(RecordKind::RK_Metadata_TypedEvent, 276 MetadataType::TypedEvent), 277 Size(S), Delta(D), Data(std::move(P)) {} 278 size()279 int32_t size() const { return Size; } delta()280 int32_t delta() const { return Delta; } eventType()281 uint16_t eventType() const { return EventType; } data()282 StringRef data() const { return Data; } 283 284 Error apply(RecordVisitor &V) override; 285 classof(const Record * R)286 static bool classof(const Record *R) { 287 return R->getRecordType() == RecordKind::RK_Metadata_TypedEvent; 288 } 289 }; 290 291 class CallArgRecord : public MetadataRecord { 292 uint64_t Arg = 0; 293 friend class RecordInitializer; 294 295 public: CallArgRecord()296 CallArgRecord() 297 : MetadataRecord(RecordKind::RK_Metadata_CallArg, MetadataType::CallArg) { 298 } 299 CallArgRecord(uint64_t A)300 explicit CallArgRecord(uint64_t A) 301 : MetadataRecord(RecordKind::RK_Metadata_CallArg, MetadataType::CallArg), 302 Arg(A) {} 303 arg()304 uint64_t arg() const { return Arg; } 305 306 Error apply(RecordVisitor &V) override; 307 classof(const Record * R)308 static bool classof(const Record *R) { 309 return R->getRecordType() == RecordKind::RK_Metadata_CallArg; 310 } 311 }; 312 313 class PIDRecord : public MetadataRecord { 314 int32_t PID = 0; 315 friend class RecordInitializer; 316 317 public: PIDRecord()318 PIDRecord() 319 : MetadataRecord(RecordKind::RK_Metadata_PIDEntry, 320 MetadataType::PIDEntry) {} 321 PIDRecord(int32_t P)322 explicit PIDRecord(int32_t P) 323 : MetadataRecord(RecordKind::RK_Metadata_PIDEntry, 324 MetadataType::PIDEntry), 325 PID(P) {} 326 pid()327 int32_t pid() const { return PID; } 328 329 Error apply(RecordVisitor &V) override; 330 classof(const Record * R)331 static bool classof(const Record *R) { 332 return R->getRecordType() == RecordKind::RK_Metadata_PIDEntry; 333 } 334 }; 335 336 class NewBufferRecord : public MetadataRecord { 337 int32_t TID = 0; 338 friend class RecordInitializer; 339 340 public: NewBufferRecord()341 NewBufferRecord() 342 : MetadataRecord(RecordKind::RK_Metadata_NewBuffer, 343 MetadataType::NewBuffer) {} 344 NewBufferRecord(int32_t T)345 explicit NewBufferRecord(int32_t T) 346 : MetadataRecord(RecordKind::RK_Metadata_NewBuffer, 347 MetadataType::NewBuffer), 348 TID(T) {} 349 tid()350 int32_t tid() const { return TID; } 351 352 Error apply(RecordVisitor &V) override; 353 classof(const Record * R)354 static bool classof(const Record *R) { 355 return R->getRecordType() == RecordKind::RK_Metadata_NewBuffer; 356 } 357 }; 358 359 class EndBufferRecord : public MetadataRecord { 360 public: EndBufferRecord()361 EndBufferRecord() 362 : MetadataRecord(RecordKind::RK_Metadata_EndOfBuffer, 363 MetadataType::EndOfBuffer) {} 364 365 Error apply(RecordVisitor &V) override; 366 classof(const Record * R)367 static bool classof(const Record *R) { 368 return R->getRecordType() == RecordKind::RK_Metadata_EndOfBuffer; 369 } 370 }; 371 372 class FunctionRecord : public Record { 373 RecordTypes Kind; 374 int32_t FuncId = 0; 375 uint32_t Delta = 0; 376 friend class RecordInitializer; 377 378 static constexpr unsigned kFunctionRecordSize = 8; 379 380 public: FunctionRecord()381 FunctionRecord() : Record(RecordKind::RK_Function) {} 382 FunctionRecord(RecordTypes K,int32_t F,uint32_t D)383 explicit FunctionRecord(RecordTypes K, int32_t F, uint32_t D) 384 : Record(RecordKind::RK_Function), Kind(K), FuncId(F), Delta(D) {} 385 386 // A function record is a concrete record type which has a number of common 387 // properties. recordType()388 RecordTypes recordType() const { return Kind; } functionId()389 int32_t functionId() const { return FuncId; } delta()390 uint32_t delta() const { return Delta; } 391 392 Error apply(RecordVisitor &V) override; 393 classof(const Record * R)394 static bool classof(const Record *R) { 395 return R->getRecordType() == RecordKind::RK_Function; 396 } 397 }; 398 399 class RecordVisitor { 400 public: 401 virtual ~RecordVisitor() = default; 402 403 // Support all specific kinds of records: 404 virtual Error visit(BufferExtents &) = 0; 405 virtual Error visit(WallclockRecord &) = 0; 406 virtual Error visit(NewCPUIDRecord &) = 0; 407 virtual Error visit(TSCWrapRecord &) = 0; 408 virtual Error visit(CustomEventRecord &) = 0; 409 virtual Error visit(CallArgRecord &) = 0; 410 virtual Error visit(PIDRecord &) = 0; 411 virtual Error visit(NewBufferRecord &) = 0; 412 virtual Error visit(EndBufferRecord &) = 0; 413 virtual Error visit(FunctionRecord &) = 0; 414 virtual Error visit(CustomEventRecordV5 &) = 0; 415 virtual Error visit(TypedEventRecord &) = 0; 416 }; 417 418 class RecordInitializer : public RecordVisitor { 419 DataExtractor &E; 420 uint64_t &OffsetPtr; 421 uint16_t Version; 422 423 public: 424 static constexpr uint16_t DefaultVersion = 5u; 425 RecordInitializer(DataExtractor & DE,uint64_t & OP,uint16_t V)426 explicit RecordInitializer(DataExtractor &DE, uint64_t &OP, uint16_t V) 427 : E(DE), OffsetPtr(OP), Version(V) {} 428 RecordInitializer(DataExtractor & DE,uint64_t & OP)429 explicit RecordInitializer(DataExtractor &DE, uint64_t &OP) 430 : RecordInitializer(DE, OP, DefaultVersion) {} 431 432 Error visit(BufferExtents &) override; 433 Error visit(WallclockRecord &) override; 434 Error visit(NewCPUIDRecord &) override; 435 Error visit(TSCWrapRecord &) override; 436 Error visit(CustomEventRecord &) override; 437 Error visit(CallArgRecord &) override; 438 Error visit(PIDRecord &) override; 439 Error visit(NewBufferRecord &) override; 440 Error visit(EndBufferRecord &) override; 441 Error visit(FunctionRecord &) override; 442 Error visit(CustomEventRecordV5 &) override; 443 Error visit(TypedEventRecord &) override; 444 }; 445 446 } // namespace xray 447 } // namespace llvm 448 449 #endif // LLVM_XRAY_FDRRECORDS_H 450