//===- FDRRecords.h - XRay Flight Data Recorder Mode Records --------------===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// Define types and operations on these types that represent the different kinds
 
// of records we encounter in XRay flight data recorder mode traces.
 
//
 
//===----------------------------------------------------------------------===//
 
#ifndef LLVM_XRAY_FDRRECORDS_H
 
#define LLVM_XRAY_FDRRECORDS_H
 
 
 
#include <cstdint>
 
#include <string>
 
 
 
#include "llvm/ADT/StringRef.h"
 
#include "llvm/Support/Casting.h"
 
#include "llvm/Support/DataExtractor.h"
 
#include "llvm/Support/Error.h"
 
#include "llvm/XRay/XRayRecord.h"
 
 
 
namespace llvm {
 
namespace xray {
 
 
 
class RecordVisitor;
 
class RecordInitializer;
 
 
 
class Record {
 
public:
 
  enum class RecordKind {
 
    RK_Metadata,
 
    RK_Metadata_BufferExtents,
 
    RK_Metadata_WallClockTime,
 
    RK_Metadata_NewCPUId,
 
    RK_Metadata_TSCWrap,
 
    RK_Metadata_CustomEvent,
 
    RK_Metadata_CustomEventV5,
 
    RK_Metadata_CallArg,
 
    RK_Metadata_PIDEntry,
 
    RK_Metadata_NewBuffer,
 
    RK_Metadata_EndOfBuffer,
 
    RK_Metadata_TypedEvent,
 
    RK_Metadata_LastMetadata,
 
    RK_Function,
 
  };
 
 
 
  static StringRef kindToString(RecordKind K);
 
 
 
private:
 
  const RecordKind T;
 
 
 
public:
 
  Record(const Record &) = delete;
 
  Record(Record &&) = delete;
 
  Record &operator=(const Record &) = delete;
 
  Record &operator=(Record &&) = delete;
 
  explicit Record(RecordKind T) : T(T) {}
 
 
 
  RecordKind getRecordType() const { return T; }
 
 
 
  // Each Record should be able to apply an abstract visitor, and choose the
 
  // appropriate function in the visitor to invoke, given its own type.
 
  virtual Error apply(RecordVisitor &V) = 0;
 
 
 
  virtual ~Record() = default;
 
};
 
 
 
class MetadataRecord : public Record {
 
public:
 
  enum class MetadataType : unsigned {
 
    Unknown,
 
    BufferExtents,
 
    WallClockTime,
 
    NewCPUId,
 
    TSCWrap,
 
    CustomEvent,
 
    CallArg,
 
    PIDEntry,
 
    NewBuffer,
 
    EndOfBuffer,
 
    TypedEvent,
 
  };
 
 
 
protected:
 
  static constexpr int kMetadataBodySize = 15;
 
  friend class RecordInitializer;
 
 
 
private:
 
  const MetadataType MT;
 
 
 
public:
 
  explicit MetadataRecord(RecordKind T, MetadataType M) : Record(T), MT(M) {}
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() >= RecordKind::RK_Metadata &&
 
           R->getRecordType() <= RecordKind::RK_Metadata_LastMetadata;
 
  }
 
 
 
  MetadataType metadataType() const { return MT; }
 
 
 
  virtual ~MetadataRecord() = default;
 
};
 
 
 
// What follows are specific Metadata record types which encapsulate the
 
// information associated with specific metadata record types in an FDR mode
 
// log.
 
class BufferExtents : public MetadataRecord {
 
  uint64_t Size = 0;
 
  friend class RecordInitializer;
 
 
 
public:
 
  BufferExtents()
 
      : MetadataRecord(RecordKind::RK_Metadata_BufferExtents,
 
                       MetadataType::BufferExtents) {}
 
 
 
  explicit BufferExtents(uint64_t S)
 
      : MetadataRecord(RecordKind::RK_Metadata_BufferExtents,
 
                       MetadataType::BufferExtents),
 
        Size(S) {}
 
 
 
  uint64_t size() const { return Size; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_BufferExtents;
 
  }
 
};
 
 
 
class WallclockRecord : public MetadataRecord {
 
  uint64_t Seconds = 0;
 
  uint32_t Nanos = 0;
 
  friend class RecordInitializer;
 
 
 
public:
 
  WallclockRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_WallClockTime,
 
                       MetadataType::WallClockTime) {}
 
 
 
  explicit WallclockRecord(uint64_t S, uint32_t N)
 
      : MetadataRecord(RecordKind::RK_Metadata_WallClockTime,
 
                       MetadataType::WallClockTime),
 
        Seconds(S), Nanos(N) {}
 
 
 
  uint64_t seconds() const { return Seconds; }
 
  uint32_t nanos() const { return Nanos; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_WallClockTime;
 
  }
 
};
 
 
 
class NewCPUIDRecord : public MetadataRecord {
 
  uint16_t CPUId = 0;
 
  uint64_t TSC = 0;
 
  friend class RecordInitializer;
 
 
 
public:
 
  NewCPUIDRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_NewCPUId,
 
                       MetadataType::NewCPUId) {}
 
 
 
  NewCPUIDRecord(uint16_t C, uint64_t T)
 
      : MetadataRecord(RecordKind::RK_Metadata_NewCPUId,
 
                       MetadataType::NewCPUId),
 
        CPUId(C), TSC(T) {}
 
 
 
  uint16_t cpuid() const { return CPUId; }
 
 
 
  uint64_t tsc() const { return TSC; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_NewCPUId;
 
  }
 
};
 
 
 
class TSCWrapRecord : public MetadataRecord {
 
  uint64_t BaseTSC = 0;
 
  friend class RecordInitializer;
 
 
 
public:
 
  TSCWrapRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_TSCWrap, MetadataType::TSCWrap) {
 
  }
 
 
 
  explicit TSCWrapRecord(uint64_t B)
 
      : MetadataRecord(RecordKind::RK_Metadata_TSCWrap, MetadataType::TSCWrap),
 
        BaseTSC(B) {}
 
 
 
  uint64_t tsc() const { return BaseTSC; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_TSCWrap;
 
  }
 
};
 
 
 
class CustomEventRecord : public MetadataRecord {
 
  int32_t Size = 0;
 
  uint64_t TSC = 0;
 
  uint16_t CPU = 0;
 
  std::string Data{};
 
  friend class RecordInitializer;
 
 
 
public:
 
  CustomEventRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_CustomEvent,
 
                       MetadataType::CustomEvent) {}
 
 
 
  explicit CustomEventRecord(uint64_t S, uint64_t T, uint16_t C, std::string D)
 
      : MetadataRecord(RecordKind::RK_Metadata_CustomEvent,
 
                       MetadataType::CustomEvent),
 
        Size(S), TSC(T), CPU(C), Data(std::move(D)) {}
 
 
 
  int32_t size() const { return Size; }
 
  uint64_t tsc() const { return TSC; }
 
  uint16_t cpu() const { return CPU; }
 
  StringRef data() const { return Data; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_CustomEvent;
 
  }
 
};
 
 
 
class CustomEventRecordV5 : public MetadataRecord {
 
  int32_t Size = 0;
 
  int32_t Delta = 0;
 
  std::string Data{};
 
  friend class RecordInitializer;
 
 
 
public:
 
  CustomEventRecordV5()
 
      : MetadataRecord(RecordKind::RK_Metadata_CustomEventV5,
 
                       MetadataType::CustomEvent) {}
 
 
 
  explicit CustomEventRecordV5(int32_t S, int32_t D, std::string P)
 
      : MetadataRecord(RecordKind::RK_Metadata_CustomEventV5,
 
                       MetadataType::CustomEvent),
 
        Size(S), Delta(D), Data(std::move(P)) {}
 
 
 
  int32_t size() const { return Size; }
 
  int32_t delta() const { return Delta; }
 
  StringRef data() const { return Data; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_CustomEventV5;
 
  }
 
};
 
 
 
class TypedEventRecord : public MetadataRecord {
 
  int32_t Size = 0;
 
  int32_t Delta = 0;
 
  uint16_t EventType = 0;
 
  std::string Data{};
 
  friend class RecordInitializer;
 
 
 
public:
 
  TypedEventRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_TypedEvent,
 
                       MetadataType::TypedEvent) {}
 
 
 
  explicit TypedEventRecord(int32_t S, int32_t D, uint16_t E, std::string P)
 
      : MetadataRecord(RecordKind::RK_Metadata_TypedEvent,
 
                       MetadataType::TypedEvent),
 
        Size(S), Delta(D), Data(std::move(P)) {}
 
 
 
  int32_t size() const { return Size; }
 
  int32_t delta() const { return Delta; }
 
  uint16_t eventType() const { return EventType; }
 
  StringRef data() const { return Data; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_TypedEvent;
 
  }
 
};
 
 
 
class CallArgRecord : public MetadataRecord {
 
  uint64_t Arg = 0;
 
  friend class RecordInitializer;
 
 
 
public:
 
  CallArgRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_CallArg, MetadataType::CallArg) {
 
  }
 
 
 
  explicit CallArgRecord(uint64_t A)
 
      : MetadataRecord(RecordKind::RK_Metadata_CallArg, MetadataType::CallArg),
 
        Arg(A) {}
 
 
 
  uint64_t arg() const { return Arg; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_CallArg;
 
  }
 
};
 
 
 
class PIDRecord : public MetadataRecord {
 
  int32_t PID = 0;
 
  friend class RecordInitializer;
 
 
 
public:
 
  PIDRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_PIDEntry,
 
                       MetadataType::PIDEntry) {}
 
 
 
  explicit PIDRecord(int32_t P)
 
      : MetadataRecord(RecordKind::RK_Metadata_PIDEntry,
 
                       MetadataType::PIDEntry),
 
        PID(P) {}
 
 
 
  int32_t pid() const { return PID; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_PIDEntry;
 
  }
 
};
 
 
 
class NewBufferRecord : public MetadataRecord {
 
  int32_t TID = 0;
 
  friend class RecordInitializer;
 
 
 
public:
 
  NewBufferRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_NewBuffer,
 
                       MetadataType::NewBuffer) {}
 
 
 
  explicit NewBufferRecord(int32_t T)
 
      : MetadataRecord(RecordKind::RK_Metadata_NewBuffer,
 
                       MetadataType::NewBuffer),
 
        TID(T) {}
 
 
 
  int32_t tid() const { return TID; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_NewBuffer;
 
  }
 
};
 
 
 
class EndBufferRecord : public MetadataRecord {
 
public:
 
  EndBufferRecord()
 
      : MetadataRecord(RecordKind::RK_Metadata_EndOfBuffer,
 
                       MetadataType::EndOfBuffer) {}
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Metadata_EndOfBuffer;
 
  }
 
};
 
 
 
class FunctionRecord : public Record {
 
  RecordTypes Kind;
 
  int32_t FuncId = 0;
 
  uint32_t Delta = 0;
 
  friend class RecordInitializer;
 
 
 
  static constexpr unsigned kFunctionRecordSize = 8;
 
 
 
public:
 
  FunctionRecord() : Record(RecordKind::RK_Function) {}
 
 
 
  explicit FunctionRecord(RecordTypes K, int32_t F, uint32_t D)
 
      : Record(RecordKind::RK_Function), Kind(K), FuncId(F), Delta(D) {}
 
 
 
  // A function record is a concrete record type which has a number of common
 
  // properties.
 
  RecordTypes recordType() const { return Kind; }
 
  int32_t functionId() const { return FuncId; }
 
  uint32_t delta() const { return Delta; }
 
 
 
  Error apply(RecordVisitor &V) override;
 
 
 
  static bool classof(const Record *R) {
 
    return R->getRecordType() == RecordKind::RK_Function;
 
  }
 
};
 
 
 
class RecordVisitor {
 
public:
 
  virtual ~RecordVisitor() = default;
 
 
 
  // Support all specific kinds of records:
 
  virtual Error visit(BufferExtents &) = 0;
 
  virtual Error visit(WallclockRecord &) = 0;
 
  virtual Error visit(NewCPUIDRecord &) = 0;
 
  virtual Error visit(TSCWrapRecord &) = 0;
 
  virtual Error visit(CustomEventRecord &) = 0;
 
  virtual Error visit(CallArgRecord &) = 0;
 
  virtual Error visit(PIDRecord &) = 0;
 
  virtual Error visit(NewBufferRecord &) = 0;
 
  virtual Error visit(EndBufferRecord &) = 0;
 
  virtual Error visit(FunctionRecord &) = 0;
 
  virtual Error visit(CustomEventRecordV5 &) = 0;
 
  virtual Error visit(TypedEventRecord &) = 0;
 
};
 
 
 
class RecordInitializer : public RecordVisitor {
 
  DataExtractor &E;
 
  uint64_t &OffsetPtr;
 
  uint16_t Version;
 
 
 
public:
 
  static constexpr uint16_t DefaultVersion = 5u;
 
 
 
  explicit RecordInitializer(DataExtractor &DE, uint64_t &OP, uint16_t V)
 
      : E(DE), OffsetPtr(OP), Version(V) {}
 
 
 
  explicit RecordInitializer(DataExtractor &DE, uint64_t &OP)
 
      : RecordInitializer(DE, OP, DefaultVersion) {}
 
 
 
  Error visit(BufferExtents &) override;
 
  Error visit(WallclockRecord &) override;
 
  Error visit(NewCPUIDRecord &) override;
 
  Error visit(TSCWrapRecord &) override;
 
  Error visit(CustomEventRecord &) override;
 
  Error visit(CallArgRecord &) override;
 
  Error visit(PIDRecord &) override;
 
  Error visit(NewBufferRecord &) override;
 
  Error visit(EndBufferRecord &) override;
 
  Error visit(FunctionRecord &) override;
 
  Error visit(CustomEventRecordV5 &) override;
 
  Error visit(TypedEventRecord &) override;
 
};
 
 
 
} // namespace xray
 
} // namespace llvm
 
 
 
#endif // LLVM_XRAY_FDRRECORDS_H