Index: include/llvm/XRay/Trace.h =================================================================== --- /dev/null +++ include/llvm/XRay/Trace.h @@ -0,0 +1,71 @@ +//===- Trace.h - XRay Trace Abstraction -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the XRay Trace class representing records in an XRay trace file. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_XRAY_TRACE_H +#define LLVM_XRAY_TRACE_H + +#include +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/XRay/XRayRecord.h" + +namespace llvm { +namespace xray { + +/// A Trace object represents the records that have been loaded from XRay +/// log files generated by instrumented binaries. We encapsulate the logic of +/// reading the traces in factory functions that populate the Trace object +/// appropriately. +/// +/// Trace objects provide an accessor to an XRayFileHeader which says more about +/// details of the file from which the XRay trace was loaded from. +/// +/// Usage: +/// +/// if (auto TraceOrErr = loadTraceFile("xray-log.something.xray")) { +/// auto& T = *TraceOrErr; +/// // T.getFileHeader() will provide information from the trace header. +/// for (const XRayRecord &R : T) { +/// // ... do something with R here. +/// } +/// } else { +/// // Handle the error here. +/// } +/// +class Trace { + XRayFileHeader FileHeader; + std::vector Records; + + typedef std::vector::const_iterator citerator; + + friend Expected loadTraceFile(StringRef, bool); + +public: + /// Provides access to the loaded XRay trace file header. + const XRayFileHeader &getFileHeader() const { return FileHeader; } + + citerator begin() const { return Records.begin(); } + citerator end() const { return Records.end(); } + size_t size() const { return Records.size(); } +}; + +/// This function will attempt to load XRay trace records from the provided +/// |Filename|. +Expected loadTraceFile(StringRef Filename, bool Sort = false); + +} // namespace xray +} // namespace llvm + +#endif // LLVM_XRAY_TRACE_H Index: include/llvm/XRay/XRayRecord.h =================================================================== --- /dev/null +++ include/llvm/XRay/XRayRecord.h @@ -0,0 +1,76 @@ +//===- XRayRecord.h - XRay Trace Record -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file replicates the record definition for XRay log entries. This should +// follow the evolution of the log record versions supported in the compiler-rt +// xray project. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_XRAY_XRAY_RECORD_H +#define LLVM_XRAY_XRAY_RECORD_H + +#include + +namespace llvm { +namespace xray { + +/// XRay traces all have a header providing some top-matter information useful +/// to help tools determine how to interpret the information available in the +/// trace. +struct XRayFileHeader { + /// Version of the XRay implementation that produced this file. + uint16_t Version = 0; + + /// A numeric identifier for the type of file this is. Best used in + /// combination with Version. + uint16_t Type = 0; + + /// Whether the CPU that produced the timestamp counters (TSC) move at a + /// constant rate. + bool ConstantTSC; + + /// Whether the CPU that produced the timestamp counters (TSC) do not stop. + bool NonstopTSC; + + /// The number of cycles per second for the CPU that produced the timestamp + /// counter (TSC) values. Useful for estimating the amount of time that + /// elapsed between two TSCs on some platforms. + uint64_t CycleFrequency = 0; +}; + +/// Determines the supported types of records that could be seen in XRay traces. +/// This may or may not correspond to actual record types in the raw trace (as +/// the loader implementation may synthesize this information in the process of +/// of loading). +enum class RecordTypes { ENTER, EXIT }; + +struct XRayRecord { + /// The type of record. + uint16_t RecordType; + + /// The CPU where the thread is running. We assume number of CPUs <= 256. + uint8_t CPU; + + /// Identifies the type of record. + RecordTypes Type; + + /// The function ID for the record. + int32_t FuncId; + + /// Get the full 8 bytes of the TSC when we get the log record. + uint64_t TSC; + + /// The thread ID for the currently running thread. + uint32_t TId; +}; + +} // namespace xray +} // namespace llvm + +#endif // LLVM_XRAY_XRAY_RECORD_H Index: include/llvm/XRay/YAMLXRayRecord.h =================================================================== --- include/llvm/XRay/YAMLXRayRecord.h +++ include/llvm/XRay/YAMLXRayRecord.h @@ -1,4 +1,4 @@ -//===- xray-record-yaml.h - XRay Record YAML Support Definitions ----------===// +//===- YAMLXRayRecord.h - XRay Record YAML Support Definitions ------------===// // // The LLVM Compiler Infrastructure // @@ -10,13 +10,13 @@ // Types and traits specialisations for YAML I/O of XRay log entries. // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_RECORD_YAML_H -#define LLVM_TOOLS_LLVM_XRAY_XRAY_RECORD_YAML_H +#ifndef LLVM_XRAY_YAML_XRAY_RECORD_H +#define LLVM_XRAY_YAML_XRAY_RECORD_H #include -#include "xray-record.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/XRay/XRayRecord.h" namespace llvm { namespace xray { @@ -44,9 +44,6 @@ std::vector Records; }; -using XRayRecordStorage = - std::aligned_storage::type; - } // namespace xray namespace yaml { @@ -97,6 +94,6 @@ } // namespace yaml } // namespace llvm -LLVM_YAML_IS_SEQUENCE_VECTOR(xray::YAMLXRayRecord) +LLVM_YAML_IS_SEQUENCE_VECTOR(xray::YAMLXRayRecord) -#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_RECORD_YAML_H +#endif // LLVM_XRAY_YAML_XRAY_RECORD_H Index: lib/CMakeLists.txt =================================================================== --- lib/CMakeLists.txt +++ lib/CMakeLists.txt @@ -22,3 +22,4 @@ add_subdirectory(Fuzzer) add_subdirectory(Passes) add_subdirectory(LibDriver) +add_subdirectory(XRay) Index: lib/XRay/CMakeLists.txt =================================================================== --- /dev/null +++ lib/XRay/CMakeLists.txt @@ -0,0 +1,13 @@ +add_llvm_library(LLVMXRay + Trace.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/ADT + ${LLVM_MAIN_INCLUDE_DIR}/llvm/XRay + + DEPENDS + LLVMSupport + + LINK_LIBS + LLVMSupport + ) Index: lib/XRay/Trace.cpp =================================================================== --- lib/XRay/Trace.cpp +++ lib/XRay/Trace.cpp @@ -1,4 +1,4 @@ -//===- xray-log-reader.cc - XRay Log Reader Implementation ----------------===// +//===- Trace.cpp - XRay Trace Loading implementation. ---------------------===// // // The LLVM Compiler Infrastructure // @@ -10,56 +10,22 @@ // XRay log reader implementation. // //===----------------------------------------------------------------------===// -#include "xray-log-reader.h" -#include "xray-record-yaml.h" +#include "llvm/XRay/Trace.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" +#include "llvm/XRay/YAMLXRayRecord.h" using namespace llvm; using namespace llvm::xray; using llvm::yaml::Input; -LogReader::LogReader( - StringRef Filename, Error &Err, bool Sort, - std::function &)> - Loader) { - ErrorAsOutParameter Guard(&Err); - int Fd; - if (auto EC = sys::fs::openFileForRead(Filename, Fd)) { - Err = make_error( - Twine("Cannot read log from '") + Filename + "'", EC); - return; - } - uint64_t FileSize; - if (auto EC = sys::fs::file_size(Filename, FileSize)) { - Err = make_error( - Twine("Cannot read log from '") + Filename + "'", EC); - return; - } - - std::error_code EC; - sys::fs::mapped_file_region MappedFile( - Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); - if (EC) { - Err = make_error( - Twine("Cannot read log from '") + Filename + "'", EC); - return; - } - - if (auto E = Loader(StringRef(MappedFile.data(), MappedFile.size()), - FileHeader, Records)) { - Err = std::move(E); - return; - } - - if (Sort) - std::sort( - Records.begin(), Records.end(), - [](const XRayRecord &L, const XRayRecord &R) { return L.TSC < R.TSC; }); -} +using XRayRecordStorage = + std::aligned_storage::type; -Error llvm::xray::NaiveLogLoader(StringRef Data, XRayFileHeader &FileHeader, - std::vector &Records) { +Error NaiveLogLoader(StringRef Data, XRayFileHeader &FileHeader, + std::vector &Records) { // FIXME: Maybe deduce whether the data is little or big-endian using some // magic bytes in the beginning of the file? @@ -132,8 +98,8 @@ return Error::success(); } -Error llvm::xray::YAMLLogLoader(StringRef Data, XRayFileHeader &FileHeader, - std::vector &Records) { +Error YAMLLogLoader(StringRef Data, XRayFileHeader &FileHeader, + std::vector &Records) { // Load the documents from the MappedFile. YAMLXRayTrace Trace; @@ -161,3 +127,70 @@ }); return Error::success(); } + +Expected llvm::xray::loadTraceFile(StringRef Filename, bool Sort) { + int Fd; + if (auto EC = sys::fs::openFileForRead(Filename, Fd)) { + return make_error( + Twine("Cannot read log from '") + Filename + "'", EC); + } + + // Attempt to get the filesize. + uint64_t FileSize; + if (auto EC = sys::fs::file_size(Filename, FileSize)) { + return make_error( + Twine("Cannot read log from '") + Filename + "'", EC); + } + if (FileSize < 4) { + return make_error( + Twine("File '") + Filename + "' too small for XRay.", + std::make_error_code(std::errc::protocol_error)); + } + + // Attempt to mmap the file. + std::error_code EC; + sys::fs::mapped_file_region MappedFile( + Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); + if (EC) { + return make_error( + Twine("Cannot read log from '") + Filename + "'", EC); + } + + // Attempt to detect the file type using file magic. We have a slight bias + // towards the binary format, and we do this by making sure that the first 4 + // bytes of the binary file is some combination of the following byte + // patterns: + // + // 0x0001 0x0000 - version 1, "naive" format + // 0x0001 0x0001 - version 1, "flight data recorder" format + // + // YAML files dont' typically have those first four bytes as valid text so we + // try loading assuming YAML if we don't find these bytes. + // + // Only if we can't load either the binary or the YAML format will we yield an + // error. + StringRef Magic(MappedFile.data(), 4); + DataExtractor HeaderExtractor(Magic, true, 8); + uint32_t OffsetPtr = 0; + uint16_t Version = HeaderExtractor.getU16(&OffsetPtr); + uint16_t Type = HeaderExtractor.getU16(&OffsetPtr); + + Trace T; + if (Version == 1 && (Type == 0 || Type == 1)) { + if (auto E = NaiveLogLoader(StringRef(MappedFile.data(), MappedFile.size()), + T.FileHeader, T.Records)) + return std::move(E); + } else { + if (auto E = YAMLLogLoader(StringRef(MappedFile.data(), MappedFile.size()), + T.FileHeader, T.Records)) + return std::move(E); + } + + if (Sort) + std::sort(T.Records.begin(), T.Records.end(), + [&](const XRayRecord &L, const XRayRecord &R) { + return L.TSC < R.TSC; + }); + + return std::move(T); +} Index: test/tools/llvm-xray/X86/convert-roundtrip.yaml =================================================================== --- test/tools/llvm-xray/X86/convert-roundtrip.yaml +++ test/tools/llvm-xray/X86/convert-roundtrip.yaml @@ -1,4 +1,4 @@ -#RUN: llvm-xray convert %s -i=yaml -f=raw -o %t && llvm-xray convert %t -f=yaml -o - | FileCheck %s +#RUN: llvm-xray convert %s -f=raw -o %t && llvm-xray convert %t -f=yaml -o - | FileCheck %s --- header: version: 1 Index: tools/llvm-xray/CMakeLists.txt =================================================================== --- tools/llvm-xray/CMakeLists.txt +++ tools/llvm-xray/CMakeLists.txt @@ -3,14 +3,14 @@ DebugInfoDWARF Object Support - Symbolize) + Symbolize + XRay) set(LLVM_XRAY_TOOLS func-id-helper.cc xray-converter.cc xray-extract.cc xray-extract.cc - xray-log-reader.cc xray-registry.cc) add_llvm_tool(llvm-xray llvm-xray.cc ${LLVM_XRAY_TOOLS}) Index: tools/llvm-xray/xray-converter.h =================================================================== --- tools/llvm-xray/xray-converter.h +++ tools/llvm-xray/xray-converter.h @@ -15,8 +15,8 @@ #define LLVM_TOOLS_LLVM_XRAY_XRAY_CONVERTER_H #include "func-id-helper.h" -#include "xray-log-reader.h" -#include "xray-record.h" +#include "llvm/XRay/XRayRecord.h" +#include "llvm/XRay/Trace.h" namespace llvm { namespace xray { @@ -29,8 +29,8 @@ TraceConverter(FuncIdConversionHelper &FuncIdHelper, bool Symbolize = false) : FuncIdHelper(FuncIdHelper), Symbolize(Symbolize) {} - void exportAsYAML(const LogReader &Records, raw_ostream &OS); - void exportAsRAWv1(const LogReader &Records, raw_ostream &OS); + void exportAsYAML(const Trace &Records, raw_ostream &OS); + void exportAsRAWv1(const Trace &Records, raw_ostream &OS); }; } // namespace xray Index: tools/llvm-xray/xray-converter.cc =================================================================== --- tools/llvm-xray/xray-converter.cc +++ tools/llvm-xray/xray-converter.cc @@ -13,13 +13,14 @@ #include "xray-converter.h" #include "xray-extract.h" -#include "xray-record-yaml.h" #include "xray-registry.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/XRay/Trace.h" +#include "llvm/XRay/YAMLXRayRecord.h" using namespace llvm; using namespace xray; @@ -31,15 +32,6 @@ cl::desc(""), cl::Required, cl::sub(Convert)); enum class ConvertFormats { BINARY, YAML }; -static cl::opt ConvertInputFormat( - "input-format", cl::desc("input format"), - cl::values(clEnumValN(ConvertFormats::BINARY, "raw", - "input is in raw binary"), - clEnumValN(ConvertFormats::YAML, "yaml", "input is in yaml")), - cl::sub(Convert)); -static cl::alias ConvertInputFormat2("i", cl::aliasopt(ConvertInputFormat), - cl::desc("Alias for -input-format"), - cl::sub(Convert)); static cl::opt ConvertOutputFormat( "output-format", cl::desc("output format"), cl::values(clEnumValN(ConvertFormats::BINARY, "raw", "output in binary"), @@ -91,12 +83,10 @@ cl::desc("Alias for -instr-map-format"), cl::sub(Convert)); -using llvm::yaml::MappingTraits; -using llvm::yaml::ScalarEnumerationTraits; using llvm::yaml::IO; using llvm::yaml::Output; -void TraceConverter::exportAsYAML(const LogReader &Records, raw_ostream &OS) { +void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) { YAMLXRayTrace Trace; const auto &FH = Records.getFileHeader(); Trace.Header = {FH.Version, FH.Type, FH.ConstantTSC, FH.NonstopTSC, @@ -112,7 +102,7 @@ Out << Trace; } -void TraceConverter::exportAsRAWv1(const LogReader &Records, raw_ostream &OS) { +void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) { // First write out the file header, in the correct endian-appropriate format // (XRay assumes currently little endian). support::endian::Writer Writer(OS); @@ -180,24 +170,6 @@ llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer, FunctionAddresses); llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize); - LogReader::LoaderFunction Loader; - switch (ConvertInputFormat) { - case ConvertFormats::BINARY: - Loader = NaiveLogLoader; - break; - case ConvertFormats::YAML: - Loader = YAMLLogLoader; - break; - } - - LogReader Reader(ConvertInput, Err, ConvertSortInput, Loader); - if (Err) - return joinErrors( - make_error( - Twine("Failed loading input file '") + ConvertInput + "'.", - std::make_error_code(std::errc::executable_format_error)), - std::move(Err)); - raw_fd_ostream OS(ConvertOutput, EC, ConvertOutputFormat == ConvertFormats::BINARY ? sys::fs::OpenFlags::F_None @@ -206,13 +178,22 @@ return make_error( Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC); - switch (ConvertOutputFormat) { - case ConvertFormats::YAML: - TC.exportAsYAML(Reader, OS); - break; - case ConvertFormats::BINARY: - TC.exportAsRAWv1(Reader, OS); - break; + if (auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput)) { + auto &T = *TraceOrErr; + switch (ConvertOutputFormat) { + case ConvertFormats::YAML: + TC.exportAsYAML(T, OS); + break; + case ConvertFormats::BINARY: + TC.exportAsRAWv1(T, OS); + break; + } + } else { + return joinErrors( + make_error( + Twine("Failed loading input file '") + ConvertInput + "'.", + std::make_error_code(std::errc::protocol_error)), + TraceOrErr.takeError()); } return Error::success(); }); Index: tools/llvm-xray/xray-log-reader.h =================================================================== --- tools/llvm-xray/xray-log-reader.h +++ /dev/null @@ -1,57 +0,0 @@ -//===- xray-log-reader.h - XRay Log Reader Interface ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Define the interface for an XRay log reader. Currently we only support one -// version of the log (naive log) with fixed-sized records. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_LOG_READER_H -#define LLVM_TOOLS_LLVM_XRAY_XRAY_LOG_READER_H - -#include -#include -#include - -#include "xray-record-yaml.h" -#include "xray-record.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" - -namespace llvm { -namespace xray { - -class LogReader { - XRayFileHeader FileHeader; - std::vector Records; - - typedef std::vector::const_iterator citerator; - -public: - typedef std::function &)> - LoaderFunction; - - LogReader(StringRef Filename, Error &Err, bool Sort, LoaderFunction Loader); - - const XRayFileHeader &getFileHeader() const { return FileHeader; } - - citerator begin() const { return Records.begin(); } - citerator end() const { return Records.end(); } - size_t size() const { return Records.size(); } -}; - -Error NaiveLogLoader(StringRef Data, XRayFileHeader &FileHeader, - std::vector &Records); -Error YAMLLogLoader(StringRef Data, XRayFileHeader &FileHeader, - std::vector &Records); - -} // namespace xray -} // namespace llvm - -#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_LOG_READER_H Index: tools/llvm-xray/xray-record.h =================================================================== --- tools/llvm-xray/xray-record.h +++ /dev/null @@ -1,55 +0,0 @@ -//===- xray-record.h - XRay Trace Record ----------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file replicates the record definition for XRay log entries. This should -// follow the evolution of the log record versions supported in the compiler-rt -// xray project. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_RECORD_H -#define LLVM_TOOLS_LLVM_XRAY_XRAY_RECORD_H - -#include - -namespace llvm { -namespace xray { - -struct XRayFileHeader { - uint16_t Version = 0; - uint16_t Type = 0; - bool ConstantTSC; - bool NonstopTSC; - uint64_t CycleFrequency = 0; -}; - -enum class RecordTypes { ENTER, EXIT }; - -struct XRayRecord { - uint16_t RecordType; - - // The CPU where the thread is running. We assume number of CPUs <= 256. - uint8_t CPU; - - // Identifies the type of record. - RecordTypes Type; - - // The function ID for the record. - int32_t FuncId; - - // Get the full 8 bytes of the TSC when we get the log record. - uint64_t TSC; - - // The thread ID for the currently running thread. - uint32_t TId; -}; - -} // namespace xray -} // namespace llvm - -#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_RECORD_H