1 //===- FDRTraceWriter.cpp - XRay FDR Trace Writer ---------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Test a utility that can write out XRay FDR Mode formatted trace files.
11 //===----------------------------------------------------------------------===//
12 #include "llvm/XRay/FDRTraceWriter.h"
20 template <size_t Index
> struct IndexedWriter
{
23 typename
std::enable_if
<
25 std::tuple_size
<typename
std::remove_reference
<Tuple
>::type
>::value
),
27 static size_t write(support::endian::Writer
&OS
, Tuple
&&T
) {
28 OS
.write(std::get
<Index
>(T
));
29 return sizeof(std::get
<Index
>(T
)) + IndexedWriter
<Index
+ 1>::write(OS
, T
);
34 typename
std::enable_if
<
36 std::tuple_size
<typename
std::remove_reference
<Tuple
>::type
>::value
),
38 static size_t write(support::endian::Writer
&OS
, Tuple
&&) {
43 template <uint8_t Kind
, class... Values
>
44 Error
writeMetadata(support::endian::Writer
&OS
, Values
&&... Ds
) {
45 // The first bit in the first byte of metadata records is always set to 1, so
46 // we ensure this is the case when we write out the first byte of the record.
47 uint8_t FirstByte
= (static_cast<uint8_t>(Kind
) << 1) | uint8_t{0x01u
};
48 auto T
= std::make_tuple(std::forward
<Values
>(std::move(Ds
))...);
49 // Write in field order.
51 auto Bytes
= IndexedWriter
<0>::write(OS
, T
);
52 assert(Bytes
<= 15 && "Must only ever write at most 16 byte metadata!");
53 // Pad out with appropriate numbers of zero's.
54 for (; Bytes
< 15; ++Bytes
)
56 return Error::success();
61 FDRTraceWriter::FDRTraceWriter(raw_ostream
&O
, const XRayFileHeader
&H
)
62 : OS(O
, support::endianness::native
) {
63 // We need to re-construct a header, by writing the fields we care about for
64 // traces, in the format that the runtime would have written.
66 (H
.ConstantTSC
? 0x01 : 0x0) | (H
.NonstopTSC
? 0x02 : 0x0);
68 // For endian-correctness, we need to write these fields in the order they
69 // appear and that we expect, instead of blasting bytes of the struct through.
73 OS
.write(H
.CycleFrequency
);
74 ArrayRef
<char> FreeFormBytes(H
.FreeFormData
,
75 sizeof(XRayFileHeader::FreeFormData
));
76 OS
.write(FreeFormBytes
);
79 FDRTraceWriter::~FDRTraceWriter() {}
81 Error
FDRTraceWriter::visit(BufferExtents
&R
) {
82 return writeMetadata
<7u>(OS
, R
.size());
85 Error
FDRTraceWriter::visit(WallclockRecord
&R
) {
86 return writeMetadata
<4u>(OS
, R
.seconds(), R
.nanos());
89 Error
FDRTraceWriter::visit(NewCPUIDRecord
&R
) {
90 return writeMetadata
<2u>(OS
, R
.cpuid(), R
.tsc());
93 Error
FDRTraceWriter::visit(TSCWrapRecord
&R
) {
94 return writeMetadata
<3u>(OS
, R
.tsc());
97 Error
FDRTraceWriter::visit(CustomEventRecord
&R
) {
98 if (auto E
= writeMetadata
<5u>(OS
, R
.size(), R
.tsc(), R
.cpu()))
101 ArrayRef
<char> Bytes(D
.data(), D
.size());
103 return Error::success();
106 Error
FDRTraceWriter::visit(CustomEventRecordV5
&R
) {
107 if (auto E
= writeMetadata
<5u>(OS
, R
.size(), R
.delta()))
110 ArrayRef
<char> Bytes(D
.data(), D
.size());
112 return Error::success();
115 Error
FDRTraceWriter::visit(TypedEventRecord
&R
) {
116 if (auto E
= writeMetadata
<8u>(OS
, R
.size(), R
.delta(), R
.eventType()))
119 ArrayRef
<char> Bytes(D
.data(), D
.size());
121 return Error::success();
124 Error
FDRTraceWriter::visit(CallArgRecord
&R
) {
125 return writeMetadata
<6u>(OS
, R
.arg());
128 Error
FDRTraceWriter::visit(PIDRecord
&R
) {
129 return writeMetadata
<9u>(OS
, R
.pid());
132 Error
FDRTraceWriter::visit(NewBufferRecord
&R
) {
133 return writeMetadata
<0u>(OS
, R
.tid());
136 Error
FDRTraceWriter::visit(EndBufferRecord
&R
) {
137 return writeMetadata
<1u>(OS
, 0);
140 Error
FDRTraceWriter::visit(FunctionRecord
&R
) {
141 // Write out the data in "field" order, to be endian-aware.
142 uint32_t TypeRecordFuncId
= uint32_t{R
.functionId() & ~uint32_t{0x0Fu
<< 28}};
143 TypeRecordFuncId
<<= 3;
144 TypeRecordFuncId
|= static_cast<uint32_t>(R
.recordType());
145 TypeRecordFuncId
<<= 1;
146 TypeRecordFuncId
&= ~uint32_t{0x01};
147 OS
.write(TypeRecordFuncId
);
149 return Error::success();