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-registry.h"
16 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
17 #include "llvm/Support/EndianStream.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/ScopedPrinter.h"
20 #include "llvm/Support/YAMLTraits.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include "llvm/XRay/InstrumentationMap.h"
23 #include "llvm/XRay/Trace.h"
24 #include "llvm/XRay/YAMLXRayRecord.h"
30 // ----------------------------------------------------------------------------
31 static cl::SubCommand Convert("convert", "Trace Format Conversion");
32 static cl::opt<std::string> ConvertInput(cl::Positional,
33 cl::desc("<xray log file>"),
34 cl::Required, cl::sub(Convert));
35 enum class ConvertFormats { BINARY, YAML };
36 static cl::opt<ConvertFormats> ConvertOutputFormat(
37 "output-format", cl::desc("output format"),
38 cl::values(clEnumValN(ConvertFormats::BINARY, "raw", "output in binary"),
39 clEnumValN(ConvertFormats::YAML, "yaml", "output in yaml")),
41 static cl::alias ConvertOutputFormat2("f", cl::aliasopt(ConvertOutputFormat),
42 cl::desc("Alias for -output-format"),
44 static cl::opt<std::string>
45 ConvertOutput("output", cl::value_desc("output file"), cl::init("-"),
46 cl::desc("output file; use '-' for stdout"),
48 static cl::alias ConvertOutput2("o", cl::aliasopt(ConvertOutput),
49 cl::desc("Alias for -output"),
53 ConvertSymbolize("symbolize",
54 cl::desc("symbolize function ids from the input log"),
55 cl::init(false), cl::sub(Convert));
56 static cl::alias ConvertSymbolize2("y", cl::aliasopt(ConvertSymbolize),
57 cl::desc("Alias for -symbolize"),
60 static cl::opt<std::string>
61 ConvertInstrMap("instr_map",
62 cl::desc("binary with the instrumentation map, or "
63 "a separate instrumentation map"),
64 cl::value_desc("binary with xray_instr_map"),
65 cl::sub(Convert), cl::init(""));
66 static cl::alias ConvertInstrMap2("m", cl::aliasopt(ConvertInstrMap),
67 cl::desc("Alias for -instr_map"),
69 static cl::opt<bool> ConvertSortInput(
71 cl::desc("determines whether to sort input log records by timestamp"),
72 cl::sub(Convert), cl::init(true));
73 static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput),
74 cl::desc("Alias for -sort"),
77 using llvm::yaml::Output;
79 void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
81 const auto &FH = Records.getFileHeader();
82 Trace.Header = {FH.Version, FH.Type, FH.ConstantTSC, FH.NonstopTSC,
84 Trace.Records.reserve(Records.size());
85 for (const auto &R : Records) {
86 Trace.Records.push_back({R.RecordType, R.CPU, R.Type, R.FuncId,
87 Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId)
88 : llvm::to_string(R.FuncId),
91 Output Out(OS, nullptr, 0);
95 void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) {
96 // First write out the file header, in the correct endian-appropriate format
97 // (XRay assumes currently little endian).
98 support::endian::Writer<support::endianness::little> Writer(OS);
99 const auto &FH = Records.getFileHeader();
100 Writer.write(FH.Version);
101 Writer.write(FH.Type);
102 uint32_t Bitfield{0};
106 Bitfield |= 1uL << 1;
107 Writer.write(Bitfield);
108 Writer.write(FH.CycleFrequency);
110 // There's 16 bytes of padding at the end of the file header.
111 static constexpr uint32_t Padding4B = 0;
112 Writer.write(Padding4B);
113 Writer.write(Padding4B);
114 Writer.write(Padding4B);
115 Writer.write(Padding4B);
117 // Then write out the rest of the records, still in an endian-appropriate
119 for (const auto &R : Records) {
120 Writer.write(R.RecordType);
121 // The on disk naive raw format uses 8 bit CPUs, but the record has 16.
122 // There's no choice but truncation.
123 Writer.write(static_cast<uint8_t>(R.CPU));
125 case RecordTypes::ENTER:
126 Writer.write(uint8_t{0});
128 case RecordTypes::EXIT:
129 Writer.write(uint8_t{1});
132 Writer.write(R.FuncId);
135 Writer.write(Padding4B);
136 Writer.write(Padding4B);
137 Writer.write(Padding4B);
144 static CommandRegistration Unused(&Convert, []() -> Error {
145 // FIXME: Support conversion to BINARY when upgrading XRay trace versions.
146 InstrumentationMap Map;
147 if (!ConvertInstrMap.empty()) {
148 auto InstrumentationMapOrError = loadInstrumentationMap(ConvertInstrMap);
149 if (!InstrumentationMapOrError)
150 return joinErrors(make_error<StringError>(
151 Twine("Cannot open instrumentation map '") +
152 ConvertInstrMap + "'",
153 std::make_error_code(std::errc::invalid_argument)),
154 InstrumentationMapOrError.takeError());
155 Map = std::move(*InstrumentationMapOrError);
158 const auto &FunctionAddresses = Map.getFunctionAddresses();
159 symbolize::LLVMSymbolizer::Options Opts(
160 symbolize::FunctionNameKind::LinkageName, true, true, false, "");
161 symbolize::LLVMSymbolizer Symbolizer(Opts);
162 llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer,
164 llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize);
166 raw_fd_ostream OS(ConvertOutput, EC,
167 ConvertOutputFormat == ConvertFormats::BINARY
168 ? sys::fs::OpenFlags::F_None
169 : sys::fs::OpenFlags::F_Text);
171 return make_error<StringError>(
172 Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC);
174 auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput);
177 make_error<StringError>(
178 Twine("Failed loading input file '") + ConvertInput + "'.",
179 std::make_error_code(std::errc::executable_format_error)),
180 TraceOrErr.takeError());
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);
191 return Error::success();