diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-01-24 08:33:39 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2017-01-24 08:33:39 +0000 |
commit | 191f5aec14fa2cfaf2f023580df9ac81db321223 (patch) | |
tree | 54650dd8fc4a937b4efa5c479f29f9bd9f218975 /gnu/llvm/lib/XRay | |
parent | c5c5d71a3c51a145ba9d0a7d2f3ca2be4d6a2131 (diff) |
Import LLVM 4.0.0 rc1 including clang and lld to help the current
development effort on OpenBSD/arm64.
Diffstat (limited to 'gnu/llvm/lib/XRay')
-rw-r--r-- | gnu/llvm/lib/XRay/CMakeLists.txt | 13 | ||||
-rw-r--r-- | gnu/llvm/lib/XRay/Trace.cpp | 196 |
2 files changed, 209 insertions, 0 deletions
diff --git a/gnu/llvm/lib/XRay/CMakeLists.txt b/gnu/llvm/lib/XRay/CMakeLists.txt new file mode 100644 index 00000000000..6c1acba79bf --- /dev/null +++ b/gnu/llvm/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 + ) diff --git a/gnu/llvm/lib/XRay/Trace.cpp b/gnu/llvm/lib/XRay/Trace.cpp new file mode 100644 index 00000000000..51000c777de --- /dev/null +++ b/gnu/llvm/lib/XRay/Trace.cpp @@ -0,0 +1,196 @@ +//===- Trace.cpp - XRay Trace Loading implementation. ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// XRay log reader implementation. +// +//===----------------------------------------------------------------------===// +#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; + +using XRayRecordStorage = + std::aligned_storage<sizeof(XRayRecord), alignof(XRayRecord)>::type; + +Error NaiveLogLoader(StringRef Data, XRayFileHeader &FileHeader, + std::vector<XRayRecord> &Records) { + // FIXME: Maybe deduce whether the data is little or big-endian using some + // magic bytes in the beginning of the file? + + // First 32 bytes of the file will always be the header. We assume a certain + // format here: + // + // (2) uint16 : version + // (2) uint16 : type + // (4) uint32 : bitfield + // (8) uint64 : cycle frequency + // (16) - : padding + // + if (Data.size() < 32) + return make_error<StringError>( + "Not enough bytes for an XRay log.", + std::make_error_code(std::errc::invalid_argument)); + + if (Data.size() - 32 == 0 || Data.size() % 32 != 0) + return make_error<StringError>( + "Invalid-sized XRay data.", + std::make_error_code(std::errc::invalid_argument)); + + DataExtractor HeaderExtractor(Data, true, 8); + uint32_t OffsetPtr = 0; + FileHeader.Version = HeaderExtractor.getU16(&OffsetPtr); + FileHeader.Type = HeaderExtractor.getU16(&OffsetPtr); + uint32_t Bitfield = HeaderExtractor.getU32(&OffsetPtr); + FileHeader.ConstantTSC = Bitfield & 1uL; + FileHeader.NonstopTSC = Bitfield & 1uL << 1; + FileHeader.CycleFrequency = HeaderExtractor.getU64(&OffsetPtr); + + if (FileHeader.Version != 1) + return make_error<StringError>( + Twine("Unsupported XRay file version: ") + Twine(FileHeader.Version), + std::make_error_code(std::errc::invalid_argument)); + + // Each record after the header will be 32 bytes, in the following format: + // + // (2) uint16 : record type + // (1) uint8 : cpu id + // (1) uint8 : type + // (4) sint32 : function id + // (8) uint64 : tsc + // (4) uint32 : thread id + // (12) - : padding + for (auto S = Data.drop_front(32); !S.empty(); S = S.drop_front(32)) { + DataExtractor RecordExtractor(S, true, 8); + uint32_t OffsetPtr = 0; + Records.emplace_back(); + auto &Record = Records.back(); + Record.RecordType = RecordExtractor.getU16(&OffsetPtr); + Record.CPU = RecordExtractor.getU8(&OffsetPtr); + auto Type = RecordExtractor.getU8(&OffsetPtr); + switch (Type) { + case 0: + Record.Type = RecordTypes::ENTER; + break; + case 1: + Record.Type = RecordTypes::EXIT; + break; + default: + return make_error<StringError>( + Twine("Unknown record type '") + Twine(int{Type}) + "'", + std::make_error_code(std::errc::executable_format_error)); + } + Record.FuncId = RecordExtractor.getSigned(&OffsetPtr, sizeof(int32_t)); + Record.TSC = RecordExtractor.getU64(&OffsetPtr); + Record.TId = RecordExtractor.getU32(&OffsetPtr); + } + return Error::success(); +} + +Error YAMLLogLoader(StringRef Data, XRayFileHeader &FileHeader, + std::vector<XRayRecord> &Records) { + + // Load the documents from the MappedFile. + YAMLXRayTrace Trace; + Input In(Data); + In >> Trace; + if (In.error()) + return make_error<StringError>("Failed loading YAML Data.", In.error()); + + FileHeader.Version = Trace.Header.Version; + FileHeader.Type = Trace.Header.Type; + FileHeader.ConstantTSC = Trace.Header.ConstantTSC; + FileHeader.NonstopTSC = Trace.Header.NonstopTSC; + FileHeader.CycleFrequency = Trace.Header.CycleFrequency; + + if (FileHeader.Version != 1) + return make_error<StringError>( + Twine("Unsupported XRay file version: ") + Twine(FileHeader.Version), + std::make_error_code(std::errc::invalid_argument)); + + Records.clear(); + std::transform(Trace.Records.begin(), Trace.Records.end(), + std::back_inserter(Records), [&](const YAMLXRayRecord &R) { + return XRayRecord{R.RecordType, R.CPU, R.Type, + R.FuncId, R.TSC, R.TId}; + }); + return Error::success(); +} + +Expected<Trace> llvm::xray::loadTraceFile(StringRef Filename, bool Sort) { + int Fd; + if (auto EC = sys::fs::openFileForRead(Filename, Fd)) { + return make_error<StringError>( + 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<StringError>( + Twine("Cannot read log from '") + Filename + "'", EC); + } + if (FileSize < 4) { + return make_error<StringError>( + Twine("File '") + Filename + "' too small for XRay.", + std::make_error_code(std::errc::executable_format_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<StringError>( + 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); +} |