10b57cec5SDimitry Andric //===- FDRTraceWriter.cpp - XRay FDR Trace Writer ---------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Test a utility that can write out XRay FDR Mode formatted trace files. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric #include "llvm/XRay/FDRTraceWriter.h" 130b57cec5SDimitry Andric #include <tuple> 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric namespace llvm { 160b57cec5SDimitry Andric namespace xray { 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric namespace { 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric template <size_t Index> struct IndexedWriter { 210b57cec5SDimitry Andric template < 220b57cec5SDimitry Andric class Tuple, 235ffd83dbSDimitry Andric std::enable_if_t<(Index < 245ffd83dbSDimitry Andric std::tuple_size<std::remove_reference_t<Tuple>>::value), 255ffd83dbSDimitry Andric int> = 0> 260b57cec5SDimitry Andric static size_t write(support::endian::Writer &OS, Tuple &&T) { 270b57cec5SDimitry Andric OS.write(std::get<Index>(T)); 280b57cec5SDimitry Andric return sizeof(std::get<Index>(T)) + IndexedWriter<Index + 1>::write(OS, T); 290b57cec5SDimitry Andric } 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric template < 320b57cec5SDimitry Andric class Tuple, 335ffd83dbSDimitry Andric std::enable_if_t<(Index >= 345ffd83dbSDimitry Andric std::tuple_size<std::remove_reference_t<Tuple>>::value), 355ffd83dbSDimitry Andric int> = 0> 360b57cec5SDimitry Andric static size_t write(support::endian::Writer &OS, Tuple &&) { 370b57cec5SDimitry Andric return 0; 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric }; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric template <uint8_t Kind, class... Values> 420b57cec5SDimitry Andric Error writeMetadata(support::endian::Writer &OS, Values &&... Ds) { 430b57cec5SDimitry Andric // The first bit in the first byte of metadata records is always set to 1, so 440b57cec5SDimitry Andric // we ensure this is the case when we write out the first byte of the record. 450b57cec5SDimitry Andric uint8_t FirstByte = (static_cast<uint8_t>(Kind) << 1) | uint8_t{0x01u}; 460b57cec5SDimitry Andric auto T = std::make_tuple(std::forward<Values>(std::move(Ds))...); 470b57cec5SDimitry Andric // Write in field order. 480b57cec5SDimitry Andric OS.write(FirstByte); 490b57cec5SDimitry Andric auto Bytes = IndexedWriter<0>::write(OS, T); 500b57cec5SDimitry Andric assert(Bytes <= 15 && "Must only ever write at most 16 byte metadata!"); 510b57cec5SDimitry Andric // Pad out with appropriate numbers of zero's. 520b57cec5SDimitry Andric for (; Bytes < 15; ++Bytes) 530b57cec5SDimitry Andric OS.write('\0'); 540b57cec5SDimitry Andric return Error::success(); 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric } // namespace 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric FDRTraceWriter::FDRTraceWriter(raw_ostream &O, const XRayFileHeader &H) 60*5f757f3fSDimitry Andric : OS(O, llvm::endianness::native) { 610b57cec5SDimitry Andric // We need to re-construct a header, by writing the fields we care about for 620b57cec5SDimitry Andric // traces, in the format that the runtime would have written. 630b57cec5SDimitry Andric uint32_t BitField = 640b57cec5SDimitry Andric (H.ConstantTSC ? 0x01 : 0x0) | (H.NonstopTSC ? 0x02 : 0x0); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric // For endian-correctness, we need to write these fields in the order they 670b57cec5SDimitry Andric // appear and that we expect, instead of blasting bytes of the struct through. 680b57cec5SDimitry Andric OS.write(H.Version); 690b57cec5SDimitry Andric OS.write(H.Type); 700b57cec5SDimitry Andric OS.write(BitField); 710b57cec5SDimitry Andric OS.write(H.CycleFrequency); 720b57cec5SDimitry Andric ArrayRef<char> FreeFormBytes(H.FreeFormData, 730b57cec5SDimitry Andric sizeof(XRayFileHeader::FreeFormData)); 740b57cec5SDimitry Andric OS.write(FreeFormBytes); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 7781ad6265SDimitry Andric FDRTraceWriter::~FDRTraceWriter() = default; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric Error FDRTraceWriter::visit(BufferExtents &R) { 800b57cec5SDimitry Andric return writeMetadata<7u>(OS, R.size()); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric Error FDRTraceWriter::visit(WallclockRecord &R) { 840b57cec5SDimitry Andric return writeMetadata<4u>(OS, R.seconds(), R.nanos()); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric Error FDRTraceWriter::visit(NewCPUIDRecord &R) { 880b57cec5SDimitry Andric return writeMetadata<2u>(OS, R.cpuid(), R.tsc()); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric Error FDRTraceWriter::visit(TSCWrapRecord &R) { 920b57cec5SDimitry Andric return writeMetadata<3u>(OS, R.tsc()); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric Error FDRTraceWriter::visit(CustomEventRecord &R) { 960b57cec5SDimitry Andric if (auto E = writeMetadata<5u>(OS, R.size(), R.tsc(), R.cpu())) 970b57cec5SDimitry Andric return E; 980b57cec5SDimitry Andric auto D = R.data(); 990b57cec5SDimitry Andric ArrayRef<char> Bytes(D.data(), D.size()); 1000b57cec5SDimitry Andric OS.write(Bytes); 1010b57cec5SDimitry Andric return Error::success(); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric Error FDRTraceWriter::visit(CustomEventRecordV5 &R) { 1050b57cec5SDimitry Andric if (auto E = writeMetadata<5u>(OS, R.size(), R.delta())) 1060b57cec5SDimitry Andric return E; 1070b57cec5SDimitry Andric auto D = R.data(); 1080b57cec5SDimitry Andric ArrayRef<char> Bytes(D.data(), D.size()); 1090b57cec5SDimitry Andric OS.write(Bytes); 1100b57cec5SDimitry Andric return Error::success(); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric Error FDRTraceWriter::visit(TypedEventRecord &R) { 1140b57cec5SDimitry Andric if (auto E = writeMetadata<8u>(OS, R.size(), R.delta(), R.eventType())) 1150b57cec5SDimitry Andric return E; 1160b57cec5SDimitry Andric auto D = R.data(); 1170b57cec5SDimitry Andric ArrayRef<char> Bytes(D.data(), D.size()); 1180b57cec5SDimitry Andric OS.write(Bytes); 1190b57cec5SDimitry Andric return Error::success(); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric Error FDRTraceWriter::visit(CallArgRecord &R) { 1230b57cec5SDimitry Andric return writeMetadata<6u>(OS, R.arg()); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric Error FDRTraceWriter::visit(PIDRecord &R) { 1270b57cec5SDimitry Andric return writeMetadata<9u>(OS, R.pid()); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric Error FDRTraceWriter::visit(NewBufferRecord &R) { 1310b57cec5SDimitry Andric return writeMetadata<0u>(OS, R.tid()); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric Error FDRTraceWriter::visit(EndBufferRecord &R) { 1350b57cec5SDimitry Andric return writeMetadata<1u>(OS, 0); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric Error FDRTraceWriter::visit(FunctionRecord &R) { 1390b57cec5SDimitry Andric // Write out the data in "field" order, to be endian-aware. 1400b57cec5SDimitry Andric uint32_t TypeRecordFuncId = uint32_t{R.functionId() & ~uint32_t{0x0Fu << 28}}; 1410b57cec5SDimitry Andric TypeRecordFuncId <<= 3; 1420b57cec5SDimitry Andric TypeRecordFuncId |= static_cast<uint32_t>(R.recordType()); 1430b57cec5SDimitry Andric TypeRecordFuncId <<= 1; 1440b57cec5SDimitry Andric TypeRecordFuncId &= ~uint32_t{0x01}; 1450b57cec5SDimitry Andric OS.write(TypeRecordFuncId); 1460b57cec5SDimitry Andric OS.write(R.delta()); 1470b57cec5SDimitry Andric return Error::success(); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric } // namespace xray 1510b57cec5SDimitry Andric } // namespace llvm 152