1 //===- FDRTraceWriter.cpp - XRay FDR Trace Writer ---------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Test a utility that can write out XRay FDR Mode formatted trace files.
12 //===----------------------------------------------------------------------===//
13 #include "llvm/XRay/FDRTraceWriter.h"
21 template <size_t Index
> struct IndexedWriter
{
24 typename
std::enable_if
<
26 std::tuple_size
<typename
std::remove_reference
<Tuple
>::type
>::value
),
28 static size_t write(support::endian::Writer
&OS
, Tuple
&&T
) {
29 OS
.write(std::get
<Index
>(T
));
30 return sizeof(std::get
<Index
>(T
)) + IndexedWriter
<Index
+ 1>::write(OS
, T
);
35 typename
std::enable_if
<
37 std::tuple_size
<typename
std::remove_reference
<Tuple
>::type
>::value
),
39 static size_t write(support::endian::Writer
&OS
, Tuple
&&) {
44 template <uint8_t Kind
, class... Values
>
45 Error
writeMetadata(support::endian::Writer
&OS
, Values
&&... Ds
) {
46 uint8_t FirstByte
= (Kind
<< 1) | uint8_t{0x01};
47 auto T
= std::make_tuple(std::forward
<Values
>(std::move(Ds
))...);
48 // Write in field order.
50 auto Bytes
= IndexedWriter
<0>::write(OS
, T
);
51 assert(Bytes
<= 15 && "Must only ever write at most 16 byte metadata!");
52 // Pad out with appropriate numbers of zero's.
53 for (; Bytes
< 15; ++Bytes
)
55 return Error::success();
60 FDRTraceWriter::FDRTraceWriter(raw_ostream
&O
, const XRayFileHeader
&H
)
61 : OS(O
, support::endianness::native
) {
62 // We need to re-construct a header, by writing the fields we care about for
63 // traces, in the format that the runtime would have written.
65 (H
.ConstantTSC
? 0x01 : 0x0) | (H
.NonstopTSC
? 0x02 : 0x0);
67 // For endian-correctness, we need to write these fields in the order they
68 // appear and that we expect, instead of blasting bytes of the struct through.
72 OS
.write(H
.CycleFrequency
);
73 ArrayRef
<char> FreeFormBytes(H
.FreeFormData
,
74 sizeof(XRayFileHeader::FreeFormData
));
75 OS
.write(FreeFormBytes
);
78 FDRTraceWriter::~FDRTraceWriter() {}
80 Error
FDRTraceWriter::visit(BufferExtents
&R
) {
81 return writeMetadata
<7u>(OS
, R
.size());
84 Error
FDRTraceWriter::visit(WallclockRecord
&R
) {
85 return writeMetadata
<4u>(OS
, R
.seconds(), R
.nanos());
88 Error
FDRTraceWriter::visit(NewCPUIDRecord
&R
) {
89 return writeMetadata
<2u>(OS
, R
.cpuid(), R
.tsc());
92 Error
FDRTraceWriter::visit(TSCWrapRecord
&R
) {
93 return writeMetadata
<3u>(OS
, R
.tsc());
96 Error
FDRTraceWriter::visit(CustomEventRecord
&R
) {
97 if (auto E
= writeMetadata
<5u>(OS
, R
.size(), R
.tsc()))
99 ArrayRef
<char> Bytes(R
.data().data(), R
.data().size());
101 return Error::success();
104 Error
FDRTraceWriter::visit(CallArgRecord
&R
) {
105 return writeMetadata
<6u>(OS
, R
.arg());
108 Error
FDRTraceWriter::visit(PIDRecord
&R
) {
109 return writeMetadata
<9u>(OS
, R
.pid());
112 Error
FDRTraceWriter::visit(NewBufferRecord
&R
) {
113 return writeMetadata
<0u>(OS
, R
.tid());
116 Error
FDRTraceWriter::visit(EndBufferRecord
&R
) {
117 return writeMetadata
<1u>(OS
, 0);
120 Error
FDRTraceWriter::visit(FunctionRecord
&R
) {
121 // Write out the data in "field" order, to be endian-aware.
122 uint32_t TypeRecordFuncId
= uint32_t{R
.functionId() & ~uint32_t{0x0Fu
<< 28}};
123 TypeRecordFuncId
<<= 3;
124 TypeRecordFuncId
|= static_cast<uint32_t>(R
.recordType());
125 TypeRecordFuncId
<<= 1;
126 TypeRecordFuncId
&= ~uint32_t{0x01};
127 OS
.write(TypeRecordFuncId
);
129 return Error::success();