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
25namespace llvm {
26namespace xray {
27
28class RecordVisitor;
29class RecordInitializer;
30
31class Record {
32public:
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
52private:
53  const RecordKind T;
54
55public:
56  Record(const Record &) = delete;
57  Record(Record &&) = delete;
58  Record &operator=(const Record &) = delete;
59  Record &operator=(Record &&) = delete;
60  explicit Record(RecordKind T) : T(T) {}
61
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
71class MetadataRecord : public Record {
72public:
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
87protected:
88  static constexpr int kMetadataBodySize = 15;
89  friend class RecordInitializer;
90
91private:
92  const MetadataType MT;
93
94public:
95  explicit MetadataRecord(RecordKind T, MetadataType M) : Record(T), MT(M) {}
96
97  static bool classof(const Record *R) {
98    return R->getRecordType() >= RecordKind::RK_Metadata &&
99           R->getRecordType() <= RecordKind::RK_Metadata_LastMetadata;
100  }
101
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.
110class BufferExtents : public MetadataRecord {
111  uint64_t Size = 0;
112  friend class RecordInitializer;
113
114public:
115  BufferExtents()
116      : MetadataRecord(RecordKind::RK_Metadata_BufferExtents,
117                       MetadataType::BufferExtents) {}
118
119  explicit BufferExtents(uint64_t S)
120      : MetadataRecord(RecordKind::RK_Metadata_BufferExtents,
121                       MetadataType::BufferExtents),
122        Size(S) {}
123
124  uint64_t size() const { return Size; }
125
126  Error apply(RecordVisitor &V) override;
127
128  static bool classof(const Record *R) {
129    return R->getRecordType() == RecordKind::RK_Metadata_BufferExtents;
130  }
131};
132
133class WallclockRecord : public MetadataRecord {
134  uint64_t Seconds = 0;
135  uint32_t Nanos = 0;
136  friend class RecordInitializer;
137
138public:
139  WallclockRecord()
140      : MetadataRecord(RecordKind::RK_Metadata_WallClockTime,
141                       MetadataType::WallClockTime) {}
142
143  explicit WallclockRecord(uint64_t S, uint32_t N)
144      : MetadataRecord(RecordKind::RK_Metadata_WallClockTime,
145                       MetadataType::WallClockTime),
146        Seconds(S), Nanos(N) {}
147
148  uint64_t seconds() const { return Seconds; }
149  uint32_t nanos() const { return Nanos; }
150
151  Error apply(RecordVisitor &V) override;
152
153  static bool classof(const Record *R) {
154    return R->getRecordType() == RecordKind::RK_Metadata_WallClockTime;
155  }
156};
157
158class NewCPUIDRecord : public MetadataRecord {
159  uint16_t CPUId = 0;
160  uint64_t TSC = 0;
161  friend class RecordInitializer;
162
163public:
164  NewCPUIDRecord()
165      : MetadataRecord(RecordKind::RK_Metadata_NewCPUId,
166                       MetadataType::NewCPUId) {}
167
168  NewCPUIDRecord(uint16_t C, uint64_t T)
169      : MetadataRecord(RecordKind::RK_Metadata_NewCPUId,
170                       MetadataType::NewCPUId),
171        CPUId(C), TSC(T) {}
172
173  uint16_t cpuid() const { return CPUId; }
174
175  uint64_t tsc() const { return TSC; }
176
177  Error apply(RecordVisitor &V) override;
178
179  static bool classof(const Record *R) {
180    return R->getRecordType() == RecordKind::RK_Metadata_NewCPUId;
181  }
182};
183
184class TSCWrapRecord : public MetadataRecord {
185  uint64_t BaseTSC = 0;
186  friend class RecordInitializer;
187
188public:
189  TSCWrapRecord()
190      : MetadataRecord(RecordKind::RK_Metadata_TSCWrap, MetadataType::TSCWrap) {
191  }
192
193  explicit TSCWrapRecord(uint64_t B)
194      : MetadataRecord(RecordKind::RK_Metadata_TSCWrap, MetadataType::TSCWrap),
195        BaseTSC(B) {}
196
197  uint64_t tsc() const { return BaseTSC; }
198
199  Error apply(RecordVisitor &V) override;
200
201  static bool classof(const Record *R) {
202    return R->getRecordType() == RecordKind::RK_Metadata_TSCWrap;
203  }
204};
205
206class 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
213public:
214  CustomEventRecord()
215      : MetadataRecord(RecordKind::RK_Metadata_CustomEvent,
216                       MetadataType::CustomEvent) {}
217
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
223  int32_t size() const { return Size; }
224  uint64_t tsc() const { return TSC; }
225  uint16_t cpu() const { return CPU; }
226  StringRef data() const { return Data; }
227
228  Error apply(RecordVisitor &V) override;
229
230  static bool classof(const Record *R) {
231    return R->getRecordType() == RecordKind::RK_Metadata_CustomEvent;
232  }
233};
234
235class CustomEventRecordV5 : public MetadataRecord {
236  int32_t Size = 0;
237  int32_t Delta = 0;
238  std::string Data{};
239  friend class RecordInitializer;
240
241public:
242  CustomEventRecordV5()
243      : MetadataRecord(RecordKind::RK_Metadata_CustomEventV5,
244                       MetadataType::CustomEvent) {}
245
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
251  int32_t size() const { return Size; }
252  int32_t delta() const { return Delta; }
253  StringRef data() const { return Data; }
254
255  Error apply(RecordVisitor &V) override;
256
257  static bool classof(const Record *R) {
258    return R->getRecordType() == RecordKind::RK_Metadata_CustomEventV5;
259  }
260};
261
262class 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
269public:
270  TypedEventRecord()
271      : MetadataRecord(RecordKind::RK_Metadata_TypedEvent,
272                       MetadataType::TypedEvent) {}
273
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
279  int32_t size() const { return Size; }
280  int32_t delta() const { return Delta; }
281  uint16_t eventType() const { return EventType; }
282  StringRef data() const { return Data; }
283
284  Error apply(RecordVisitor &V) override;
285
286  static bool classof(const Record *R) {
287    return R->getRecordType() == RecordKind::RK_Metadata_TypedEvent;
288  }
289};
290
291class CallArgRecord : public MetadataRecord {
292  uint64_t Arg = 0;
293  friend class RecordInitializer;
294
295public:
296  CallArgRecord()
297      : MetadataRecord(RecordKind::RK_Metadata_CallArg, MetadataType::CallArg) {
298  }
299
300  explicit CallArgRecord(uint64_t A)
301      : MetadataRecord(RecordKind::RK_Metadata_CallArg, MetadataType::CallArg),
302        Arg(A) {}
303
304  uint64_t arg() const { return Arg; }
305
306  Error apply(RecordVisitor &V) override;
307
308  static bool classof(const Record *R) {
309    return R->getRecordType() == RecordKind::RK_Metadata_CallArg;
310  }
311};
312
313class PIDRecord : public MetadataRecord {
314  int32_t PID = 0;
315  friend class RecordInitializer;
316
317public:
318  PIDRecord()
319      : MetadataRecord(RecordKind::RK_Metadata_PIDEntry,
320                       MetadataType::PIDEntry) {}
321
322  explicit PIDRecord(int32_t P)
323      : MetadataRecord(RecordKind::RK_Metadata_PIDEntry,
324                       MetadataType::PIDEntry),
325        PID(P) {}
326
327  int32_t pid() const { return PID; }
328
329  Error apply(RecordVisitor &V) override;
330
331  static bool classof(const Record *R) {
332    return R->getRecordType() == RecordKind::RK_Metadata_PIDEntry;
333  }
334};
335
336class NewBufferRecord : public MetadataRecord {
337  int32_t TID = 0;
338  friend class RecordInitializer;
339
340public:
341  NewBufferRecord()
342      : MetadataRecord(RecordKind::RK_Metadata_NewBuffer,
343                       MetadataType::NewBuffer) {}
344
345  explicit NewBufferRecord(int32_t T)
346      : MetadataRecord(RecordKind::RK_Metadata_NewBuffer,
347                       MetadataType::NewBuffer),
348        TID(T) {}
349
350  int32_t tid() const { return TID; }
351
352  Error apply(RecordVisitor &V) override;
353
354  static bool classof(const Record *R) {
355    return R->getRecordType() == RecordKind::RK_Metadata_NewBuffer;
356  }
357};
358
359class EndBufferRecord : public MetadataRecord {
360public:
361  EndBufferRecord()
362      : MetadataRecord(RecordKind::RK_Metadata_EndOfBuffer,
363                       MetadataType::EndOfBuffer) {}
364
365  Error apply(RecordVisitor &V) override;
366
367  static bool classof(const Record *R) {
368    return R->getRecordType() == RecordKind::RK_Metadata_EndOfBuffer;
369  }
370};
371
372class 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
380public:
381  FunctionRecord() : Record(RecordKind::RK_Function) {}
382
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.
388  RecordTypes recordType() const { return Kind; }
389  int32_t functionId() const { return FuncId; }
390  uint32_t delta() const { return Delta; }
391
392  Error apply(RecordVisitor &V) override;
393
394  static bool classof(const Record *R) {
395    return R->getRecordType() == RecordKind::RK_Function;
396  }
397};
398
399class RecordVisitor {
400public:
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
418class RecordInitializer : public RecordVisitor {
419  DataExtractor &E;
420  uint64_t &OffsetPtr;
421  uint16_t Version;
422
423public:
424  static constexpr uint16_t DefaultVersion = 5u;
425
426  explicit RecordInitializer(DataExtractor &DE, uint64_t &OP, uint16_t V)
427      : E(DE), OffsetPtr(OP), Version(V) {}
428
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