summaryrefslogtreecommitdiffstats
path: root/lib/XRay
diff options
context:
space:
mode:
authorDean Michael Berris <dberris@google.com>2017-01-11 06:39:09 +0000
committerDean Michael Berris <dberris@google.com>2017-01-11 06:39:09 +0000
commit14cdbca6b8d17a0757fc5930cc77b542fe7c6445 (patch)
tree38116311132302f1b91ecf031301102f6075ab25 /lib/XRay
parentd27a39a962d108a01145667cfdfc1ff65c338b81 (diff)
[XRay] Define the library for XRay trace logs
Summary: In this change we move the definition of the log reading routines from the tools directory in LLVM to {include/llvm,lib}/XRay. We improve the documentation a little bit for the publicly accessible headers, and adjust the top-matter. This also leads to some refactoring and cleanup in the tooling code. In particular, we do the following: - Rename the class from LogReader to Trace, as it better represents the logical set of records as opposed to a log. - Use file type detection instead of asking the user to say what format the input file is. This allows us to keep the interface simple and encapsulate the logic of loading the data appropriately. In future changes we increase the API surface and write dedicated unit tests for the XRay library. Depends on D24376. Reviewers: dblaikie, echristo Subscribers: mehdi_amini, mgorny, llvm-commits, varno Differential Revision: https://reviews.llvm.org/D28345 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291652 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/XRay')
-rw-r--r--lib/XRay/CMakeLists.txt13
-rw-r--r--lib/XRay/Trace.cpp196
2 files changed, 209 insertions, 0 deletions
diff --git a/lib/XRay/CMakeLists.txt b/lib/XRay/CMakeLists.txt
new file mode 100644
index 000000000000..6c1acba79bfa
--- /dev/null
+++ b/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/lib/XRay/Trace.cpp b/lib/XRay/Trace.cpp
new file mode 100644
index 000000000000..c8d95660431f
--- /dev/null
+++ b/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::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<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);
+}