1 //===- xray-converter.cc - XRay Trace Conversion --------------------------===//
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 // Implements the trace conversion functions.
12 //===----------------------------------------------------------------------===//
13 #include "xray-converter.h"
15 #include "xray-extract.h"
16 #include "xray-registry.h"
17 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
18 #include "llvm/Support/EndianStream.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/YAMLTraits.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include "llvm/XRay/Trace.h"
23 #include "llvm/XRay/YAMLXRayRecord.h"
29 // ----------------------------------------------------------------------------
30 static cl::SubCommand Convert("convert", "Trace Format Conversion");
31 static cl::opt<std::string> ConvertInput(cl::Positional,
32 cl::desc("<xray log file>"),
33 cl::Required, cl::sub(Convert));
34 enum class ConvertFormats { BINARY, YAML };
35 static cl::opt<ConvertFormats> ConvertOutputFormat(
36 "output-format", cl::desc("output format"),
37 cl::values(clEnumValN(ConvertFormats::BINARY, "raw", "output in binary"),
38 clEnumValN(ConvertFormats::YAML, "yaml", "output in yaml")),
40 static cl::alias ConvertOutputFormat2("f", cl::aliasopt(ConvertOutputFormat),
41 cl::desc("Alias for -output-format"),
43 static cl::opt<std::string>
44 ConvertOutput("output", cl::value_desc("output file"), cl::init("-"),
45 cl::desc("output file; use '-' for stdout"),
47 static cl::alias ConvertOutput2("o", cl::aliasopt(ConvertOutput),
48 cl::desc("Alias for -output"),
52 ConvertSymbolize("symbolize",
53 cl::desc("symbolize function ids from the input log"),
54 cl::init(false), cl::sub(Convert));
55 static cl::alias ConvertSymbolize2("y", cl::aliasopt(ConvertSymbolize),
56 cl::desc("Alias for -symbolize"),
59 static cl::opt<std::string>
60 ConvertInstrMap("instr_map",
61 cl::desc("binary with the instrumentation map, or "
62 "a separate instrumentation map"),
63 cl::value_desc("binary with xray_instr_map"),
64 cl::sub(Convert), cl::init(""));
65 static cl::alias ConvertInstrMap2("m", cl::aliasopt(ConvertInstrMap),
66 cl::desc("Alias for -instr_map"),
68 static cl::opt<bool> ConvertSortInput(
70 cl::desc("determines whether to sort input log records by timestamp"),
71 cl::sub(Convert), cl::init(true));
72 static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput),
73 cl::desc("Alias for -sort"),
75 static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
76 "instr-map-format", cl::desc("format of instrumentation map"),
77 cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
78 "instrumentation map in an ELF header"),
79 clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
80 "yaml", "instrumentation map in YAML")),
81 cl::sub(Convert), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
82 static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
83 cl::desc("Alias for -instr-map-format"),
87 using llvm::yaml::Output;
89 void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
91 const auto &FH = Records.getFileHeader();
92 Trace.Header = {FH.Version, FH.Type, FH.ConstantTSC, FH.NonstopTSC,
94 Trace.Records.reserve(Records.size());
95 for (const auto &R : Records) {
96 Trace.Records.push_back({R.RecordType, R.CPU, R.Type, R.FuncId,
97 Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId)
98 : std::to_string(R.FuncId),
105 void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) {
106 // First write out the file header, in the correct endian-appropriate format
107 // (XRay assumes currently little endian).
108 support::endian::Writer<support::endianness::little> Writer(OS);
109 const auto &FH = Records.getFileHeader();
110 Writer.write(FH.Version);
111 Writer.write(FH.Type);
112 uint32_t Bitfield{0};
116 Bitfield |= 1uL << 1;
117 Writer.write(Bitfield);
118 Writer.write(FH.CycleFrequency);
120 // There's 16 bytes of padding at the end of the file header.
121 static constexpr uint32_t Padding4B = 0;
122 Writer.write(Padding4B);
123 Writer.write(Padding4B);
124 Writer.write(Padding4B);
125 Writer.write(Padding4B);
127 // Then write out the rest of the records, still in an endian-appropriate
129 for (const auto &R : Records) {
130 Writer.write(R.RecordType);
133 case RecordTypes::ENTER:
134 Writer.write(uint8_t{0});
136 case RecordTypes::EXIT:
137 Writer.write(uint8_t{1});
140 Writer.write(R.FuncId);
143 Writer.write(Padding4B);
144 Writer.write(Padding4B);
145 Writer.write(Padding4B);
152 static CommandRegistration Unused(&Convert, []() -> Error {
153 // FIXME: Support conversion to BINARY when upgrading XRay trace versions.
155 auto EC = sys::fs::openFileForRead(ConvertInput, Fd);
157 return make_error<StringError>(
158 Twine("Cannot open file '") + ConvertInput + "'", EC);
160 Error Err = Error::success();
161 xray::InstrumentationMapExtractor Extractor(ConvertInstrMap, InstrMapFormat,
163 handleAllErrors(std::move(Err),
164 [&](const ErrorInfoBase &E) { E.log(errs()); });
166 const auto &FunctionAddresses = Extractor.getFunctionAddresses();
167 symbolize::LLVMSymbolizer::Options Opts(
168 symbolize::FunctionNameKind::LinkageName, true, true, false, "");
169 symbolize::LLVMSymbolizer Symbolizer(Opts);
170 llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer,
172 llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize);
173 raw_fd_ostream OS(ConvertOutput, EC,
174 ConvertOutputFormat == ConvertFormats::BINARY
175 ? sys::fs::OpenFlags::F_None
176 : sys::fs::OpenFlags::F_Text);
178 return make_error<StringError>(
179 Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC);
181 if (auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput)) {
182 auto &T = *TraceOrErr;
183 switch (ConvertOutputFormat) {
184 case ConvertFormats::YAML:
185 TC.exportAsYAML(T, OS);
187 case ConvertFormats::BINARY:
188 TC.exportAsRAWv1(T, OS);
193 make_error<StringError>(
194 Twine("Failed loading input file '") + ConvertInput + "'.",
195 std::make_error_code(std::errc::executable_format_error)),
196 TraceOrErr.takeError());
198 return Error::success();