1*0b57cec5SDimitry Andric //===- FDRTraceWriter.cpp - XRay FDR Trace Writer ---------------*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // Test a utility that can write out XRay FDR Mode formatted trace files. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric #include "llvm/XRay/FDRTraceWriter.h" 13*0b57cec5SDimitry Andric #include <tuple> 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric namespace llvm { 16*0b57cec5SDimitry Andric namespace xray { 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric namespace { 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric template <size_t Index> struct IndexedWriter { 21*0b57cec5SDimitry Andric template < 22*0b57cec5SDimitry Andric class Tuple, 23*0b57cec5SDimitry Andric typename std::enable_if< 24*0b57cec5SDimitry Andric (Index < 25*0b57cec5SDimitry Andric std::tuple_size<typename std::remove_reference<Tuple>::type>::value), 26*0b57cec5SDimitry Andric int>::type = 0> 27*0b57cec5SDimitry Andric static size_t write(support::endian::Writer &OS, Tuple &&T) { 28*0b57cec5SDimitry Andric OS.write(std::get<Index>(T)); 29*0b57cec5SDimitry Andric return sizeof(std::get<Index>(T)) + IndexedWriter<Index + 1>::write(OS, T); 30*0b57cec5SDimitry Andric } 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric template < 33*0b57cec5SDimitry Andric class Tuple, 34*0b57cec5SDimitry Andric typename std::enable_if< 35*0b57cec5SDimitry Andric (Index >= 36*0b57cec5SDimitry Andric std::tuple_size<typename std::remove_reference<Tuple>::type>::value), 37*0b57cec5SDimitry Andric int>::type = 0> 38*0b57cec5SDimitry Andric static size_t write(support::endian::Writer &OS, Tuple &&) { 39*0b57cec5SDimitry Andric return 0; 40*0b57cec5SDimitry Andric } 41*0b57cec5SDimitry Andric }; 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric template <uint8_t Kind, class... Values> 44*0b57cec5SDimitry Andric Error writeMetadata(support::endian::Writer &OS, Values &&... Ds) { 45*0b57cec5SDimitry Andric // The first bit in the first byte of metadata records is always set to 1, so 46*0b57cec5SDimitry Andric // we ensure this is the case when we write out the first byte of the record. 47*0b57cec5SDimitry Andric uint8_t FirstByte = (static_cast<uint8_t>(Kind) << 1) | uint8_t{0x01u}; 48*0b57cec5SDimitry Andric auto T = std::make_tuple(std::forward<Values>(std::move(Ds))...); 49*0b57cec5SDimitry Andric // Write in field order. 50*0b57cec5SDimitry Andric OS.write(FirstByte); 51*0b57cec5SDimitry Andric auto Bytes = IndexedWriter<0>::write(OS, T); 52*0b57cec5SDimitry Andric assert(Bytes <= 15 && "Must only ever write at most 16 byte metadata!"); 53*0b57cec5SDimitry Andric // Pad out with appropriate numbers of zero's. 54*0b57cec5SDimitry Andric for (; Bytes < 15; ++Bytes) 55*0b57cec5SDimitry Andric OS.write('\0'); 56*0b57cec5SDimitry Andric return Error::success(); 57*0b57cec5SDimitry Andric } 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric } // namespace 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric FDRTraceWriter::FDRTraceWriter(raw_ostream &O, const XRayFileHeader &H) 62*0b57cec5SDimitry Andric : OS(O, support::endianness::native) { 63*0b57cec5SDimitry Andric // We need to re-construct a header, by writing the fields we care about for 64*0b57cec5SDimitry Andric // traces, in the format that the runtime would have written. 65*0b57cec5SDimitry Andric uint32_t BitField = 66*0b57cec5SDimitry Andric (H.ConstantTSC ? 0x01 : 0x0) | (H.NonstopTSC ? 0x02 : 0x0); 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric // For endian-correctness, we need to write these fields in the order they 69*0b57cec5SDimitry Andric // appear and that we expect, instead of blasting bytes of the struct through. 70*0b57cec5SDimitry Andric OS.write(H.Version); 71*0b57cec5SDimitry Andric OS.write(H.Type); 72*0b57cec5SDimitry Andric OS.write(BitField); 73*0b57cec5SDimitry Andric OS.write(H.CycleFrequency); 74*0b57cec5SDimitry Andric ArrayRef<char> FreeFormBytes(H.FreeFormData, 75*0b57cec5SDimitry Andric sizeof(XRayFileHeader::FreeFormData)); 76*0b57cec5SDimitry Andric OS.write(FreeFormBytes); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric FDRTraceWriter::~FDRTraceWriter() {} 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(BufferExtents &R) { 82*0b57cec5SDimitry Andric return writeMetadata<7u>(OS, R.size()); 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(WallclockRecord &R) { 86*0b57cec5SDimitry Andric return writeMetadata<4u>(OS, R.seconds(), R.nanos()); 87*0b57cec5SDimitry Andric } 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(NewCPUIDRecord &R) { 90*0b57cec5SDimitry Andric return writeMetadata<2u>(OS, R.cpuid(), R.tsc()); 91*0b57cec5SDimitry Andric } 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(TSCWrapRecord &R) { 94*0b57cec5SDimitry Andric return writeMetadata<3u>(OS, R.tsc()); 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(CustomEventRecord &R) { 98*0b57cec5SDimitry Andric if (auto E = writeMetadata<5u>(OS, R.size(), R.tsc(), R.cpu())) 99*0b57cec5SDimitry Andric return E; 100*0b57cec5SDimitry Andric auto D = R.data(); 101*0b57cec5SDimitry Andric ArrayRef<char> Bytes(D.data(), D.size()); 102*0b57cec5SDimitry Andric OS.write(Bytes); 103*0b57cec5SDimitry Andric return Error::success(); 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(CustomEventRecordV5 &R) { 107*0b57cec5SDimitry Andric if (auto E = writeMetadata<5u>(OS, R.size(), R.delta())) 108*0b57cec5SDimitry Andric return E; 109*0b57cec5SDimitry Andric auto D = R.data(); 110*0b57cec5SDimitry Andric ArrayRef<char> Bytes(D.data(), D.size()); 111*0b57cec5SDimitry Andric OS.write(Bytes); 112*0b57cec5SDimitry Andric return Error::success(); 113*0b57cec5SDimitry Andric } 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(TypedEventRecord &R) { 116*0b57cec5SDimitry Andric if (auto E = writeMetadata<8u>(OS, R.size(), R.delta(), R.eventType())) 117*0b57cec5SDimitry Andric return E; 118*0b57cec5SDimitry Andric auto D = R.data(); 119*0b57cec5SDimitry Andric ArrayRef<char> Bytes(D.data(), D.size()); 120*0b57cec5SDimitry Andric OS.write(Bytes); 121*0b57cec5SDimitry Andric return Error::success(); 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(CallArgRecord &R) { 125*0b57cec5SDimitry Andric return writeMetadata<6u>(OS, R.arg()); 126*0b57cec5SDimitry Andric } 127*0b57cec5SDimitry Andric 128*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(PIDRecord &R) { 129*0b57cec5SDimitry Andric return writeMetadata<9u>(OS, R.pid()); 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric 132*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(NewBufferRecord &R) { 133*0b57cec5SDimitry Andric return writeMetadata<0u>(OS, R.tid()); 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(EndBufferRecord &R) { 137*0b57cec5SDimitry Andric return writeMetadata<1u>(OS, 0); 138*0b57cec5SDimitry Andric } 139*0b57cec5SDimitry Andric 140*0b57cec5SDimitry Andric Error FDRTraceWriter::visit(FunctionRecord &R) { 141*0b57cec5SDimitry Andric // Write out the data in "field" order, to be endian-aware. 142*0b57cec5SDimitry Andric uint32_t TypeRecordFuncId = uint32_t{R.functionId() & ~uint32_t{0x0Fu << 28}}; 143*0b57cec5SDimitry Andric TypeRecordFuncId <<= 3; 144*0b57cec5SDimitry Andric TypeRecordFuncId |= static_cast<uint32_t>(R.recordType()); 145*0b57cec5SDimitry Andric TypeRecordFuncId <<= 1; 146*0b57cec5SDimitry Andric TypeRecordFuncId &= ~uint32_t{0x01}; 147*0b57cec5SDimitry Andric OS.write(TypeRecordFuncId); 148*0b57cec5SDimitry Andric OS.write(R.delta()); 149*0b57cec5SDimitry Andric return Error::success(); 150*0b57cec5SDimitry Andric } 151*0b57cec5SDimitry Andric 152*0b57cec5SDimitry Andric } // namespace xray 153*0b57cec5SDimitry Andric } // namespace llvm 154