summaryrefslogtreecommitdiff
path: root/gnu/llvm/lib/XRay
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2017-01-24 08:33:39 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2017-01-24 08:33:39 +0000
commit191f5aec14fa2cfaf2f023580df9ac81db321223 (patch)
tree54650dd8fc4a937b4efa5c479f29f9bd9f218975 /gnu/llvm/lib/XRay
parentc5c5d71a3c51a145ba9d0a7d2f3ca2be4d6a2131 (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.txt13
-rw-r--r--gnu/llvm/lib/XRay/Trace.cpp196
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);
+}