xref: /llvm-project/llvm/lib/XRay/FDRTraceWriter.cpp (revision 7a07a41cbb4c48db19c49bda99479cfdec7d3a0d)
1 //===- FDRTraceWriter.cpp - XRay FDR Trace Writer ---------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Test a utility that can write out XRay FDR Mode formatted trace files.
11 //
12 //===----------------------------------------------------------------------===//
13 #include "llvm/XRay/FDRTraceWriter.h"
14 #include <tuple>
15 
16 namespace llvm {
17 namespace xray {
18 
19 namespace {
20 
21 struct alignas(32) FileHeader {
22   uint16_t Version;
23   uint16_t Type;
24   uint32_t BitField;
25   uint64_t CycleFrequency;
26   char FreeForm[16];
27 };
28 
29 struct MetadataBlob {
30   uint8_t Type : 1;
31   uint8_t RecordKind : 7;
32   char Data[15];
33 };
34 
35 struct FunctionDeltaBlob {
36   uint8_t Type : 1;
37   uint8_t RecordKind : 3;
38   int FuncId : 28;
39   uint32_t TSCDelta;
40 };
41 
42 template <size_t Index> struct IndexedMemcpy {
43   template <
44       class Tuple,
45       typename std::enable_if<
46           (Index <
47            std::tuple_size<typename std::remove_reference<Tuple>::type>::value),
48           int>::type = 0>
49   static void Copy(char *Dest, Tuple &&T) {
50     auto Next = static_cast<char *>(std::memcpy(
51                     Dest, reinterpret_cast<const char *>(&std::get<Index>(T)),
52                     sizeof(std::get<Index>(T)))) +
53                 sizeof(std::get<Index>(T));
54     IndexedMemcpy<Index + 1>::Copy(Next, T);
55   }
56 
57   template <
58       class Tuple,
59       typename std::enable_if<
60           (Index >=
61            std::tuple_size<typename std::remove_reference<Tuple>::type>::value),
62           int>::type = 0>
63   static void Copy(char *, Tuple &&) {}
64 };
65 
66 template <uint8_t Kind, class... Values>
67 Error writeMetadata(raw_ostream &OS, Values &&... Ds) {
68   MetadataBlob B;
69   B.Type = 1;
70   B.RecordKind = Kind;
71   std::memset(B.Data, 0, 15);
72   auto T = std::make_tuple(std::forward<Values>(std::move(Ds))...);
73   IndexedMemcpy<0>::Copy(B.Data, T);
74   OS.write(reinterpret_cast<const char *>(&B), sizeof(MetadataBlob));
75   return Error::success();
76 }
77 
78 } // namespace
79 
80 FDRTraceWriter::FDRTraceWriter(raw_ostream &O, const XRayFileHeader &H)
81     : OS(O) {
82   // We need to re-construct a header, by writing the fields we care about for
83   // traces, in the format that the runtime would have written.
84   FileHeader Raw;
85   Raw.Version = H.Version;
86   Raw.Type = H.Type;
87   Raw.BitField = (H.ConstantTSC ? 0x01 : 0x0) | (H.NonstopTSC ? 0x02 : 0x0);
88   Raw.CycleFrequency = H.CycleFrequency;
89   memcpy(&Raw.FreeForm, H.FreeFormData, 16);
90   OS.write(reinterpret_cast<const char *>(&Raw), sizeof(XRayFileHeader));
91 }
92 
93 FDRTraceWriter::~FDRTraceWriter() {}
94 
95 Error FDRTraceWriter::visit(BufferExtents &R) {
96   return writeMetadata<7u>(OS, R.size());
97 }
98 
99 Error FDRTraceWriter::visit(WallclockRecord &R) {
100   return writeMetadata<4u>(OS, R.seconds(), R.nanos());
101 }
102 
103 Error FDRTraceWriter::visit(NewCPUIDRecord &R) {
104   return writeMetadata<2u>(OS, R.cpuid());
105 }
106 
107 Error FDRTraceWriter::visit(TSCWrapRecord &R) {
108   return writeMetadata<3u>(OS, R.tsc());
109 }
110 
111 Error FDRTraceWriter::visit(CustomEventRecord &R) {
112   if (auto E = writeMetadata<5u>(OS, R.size(), R.tsc()))
113     return E;
114   OS.write(R.data().data(), R.data().size());
115   return Error::success();
116 }
117 
118 Error FDRTraceWriter::visit(CallArgRecord &R) {
119   return writeMetadata<6u>(OS, R.arg());
120 }
121 
122 Error FDRTraceWriter::visit(PIDRecord &R) {
123   return writeMetadata<9u>(OS, R.pid());
124 }
125 
126 Error FDRTraceWriter::visit(NewBufferRecord &R) {
127   return writeMetadata<0u>(OS, R.tid());
128 }
129 
130 Error FDRTraceWriter::visit(EndBufferRecord &R) {
131   return writeMetadata<1u>(OS, 0);
132 }
133 
134 Error FDRTraceWriter::visit(FunctionRecord &R) {
135   FunctionDeltaBlob B;
136   B.Type = 0;
137   B.RecordKind = static_cast<uint8_t>(R.recordType());
138   B.FuncId = R.functionId();
139   B.TSCDelta = R.delta();
140   OS.write(reinterpret_cast<const char *>(&B), sizeof(FunctionDeltaBlob));
141   return Error::success();
142 }
143 
144 } // namespace xray
145 } // namespace llvm
146