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