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       : RecordVisitor(), 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