summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/XRay/InstrumentationMap.h131
-rw-r--r--llvm/lib/XRay/CMakeLists.txt3
-rw-r--r--llvm/lib/XRay/InstrumentationMap.cpp194
-rw-r--r--llvm/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml2
-rw-r--r--llvm/test/tools/llvm-xray/X86/account-keep-going.yaml2
-rw-r--r--llvm/test/tools/llvm-xray/X86/account-simple-case.yaml2
-rw-r--r--llvm/test/tools/llvm-xray/X86/account-simple-sorting.yaml18
-rw-r--r--llvm/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt2
-rw-r--r--llvm/test/tools/llvm-xray/X86/graph-color-simple-case.yaml4
-rw-r--r--llvm/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml16
-rw-r--r--llvm/test/tools/llvm-xray/X86/graph-simple-case.yaml16
-rw-r--r--llvm/tools/llvm-xray/xray-account.cc96
-rw-r--r--llvm/tools/llvm-xray/xray-converter.cc59
-rw-r--r--llvm/tools/llvm-xray/xray-extract.cc244
-rw-r--r--llvm/tools/llvm-xray/xray-extract.h58
-rw-r--r--llvm/tools/llvm-xray/xray-graph.cc73
-rw-r--r--llvm/tools/llvm-xray/xray-sleds.h32
17 files changed, 473 insertions, 479 deletions
diff --git a/llvm/include/llvm/XRay/InstrumentationMap.h b/llvm/include/llvm/XRay/InstrumentationMap.h
new file mode 100644
index 00000000000..1e18d438993
--- /dev/null
+++ b/llvm/include/llvm/XRay/InstrumentationMap.h
@@ -0,0 +1,131 @@
+//===- InstrumentationMap.h - XRay Instrumentation Map --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the interface for extracting the instrumentation map from an
+// XRay-instrumented binary.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_XRAY_INSTRUMENTATION_MAP_H
+#define LLVM_XRAY_INSTRUMENTATION_MAP_H
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace xray {
+
+// Forward declare to make a friend.
+class InstrumentationMap;
+
+/// Loads the instrumentation map from |Filename|. This auto-deduces the type of
+/// the instrumentation map.
+Expected<InstrumentationMap> loadInstrumentationMap(StringRef Filename);
+
+/// Represents an XRay instrumentation sled entry from an object file.
+struct SledEntry {
+
+ /// Each entry here represents the kinds of supported instrumentation map
+ /// entries.
+ enum class FunctionKinds { ENTRY, EXIT, TAIL };
+
+ /// The address of the sled.
+ uint64_t Address;
+
+ /// The address of the function.
+ uint64_t Function;
+
+ /// The kind of sled.
+ FunctionKinds Kind;
+
+ /// Whether the sled was annotated to always be instrumented.
+ bool AlwaysInstrument;
+};
+
+struct YAMLXRaySledEntry {
+ int32_t FuncId;
+ yaml::Hex64 Address;
+ yaml::Hex64 Function;
+ SledEntry::FunctionKinds Kind;
+ bool AlwaysInstrument;
+};
+
+/// The InstrumentationMap represents the computed function id's and indicated
+/// function addresses from an object file (or a YAML file). This provides an
+/// interface to just the mapping between the function id, and the function
+/// address.
+///
+/// We also provide raw access to the actual instrumentation map entries we find
+/// associated with a particular object file.
+///
+class InstrumentationMap {
+public:
+ using FunctionAddressMap = std::unordered_map<int32_t, uint64_t>;
+ using FunctionAddressReverseMap = std::unordered_map<uint64_t, int32_t>;
+ using SledContainer = std::vector<SledEntry>;
+
+private:
+ SledContainer Sleds;
+ FunctionAddressMap FunctionAddresses;
+ FunctionAddressReverseMap FunctionIds;
+
+ friend Expected<InstrumentationMap> loadInstrumentationMap(StringRef);
+
+public:
+ /// Provides a raw accessor to the unordered map of function addresses.
+ const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; }
+
+ /// Returns an XRay computed function id, provided a function address.
+ Optional<int32_t> getFunctionId(uint64_t Addr) const;
+
+ /// Returns the function address for a function id.
+ Optional<uint64_t> getFunctionAddr(int32_t FuncId) const;
+
+ /// Provide read-only access to the entries of the instrumentation map.
+ const SledContainer &sleds() const { return Sleds; };
+};
+
+} // namespace xray
+} // namespace llvm
+
+namespace llvm {
+namespace yaml {
+
+template <> struct ScalarEnumerationTraits<xray::SledEntry::FunctionKinds> {
+ static void enumeration(IO &IO, xray::SledEntry::FunctionKinds &Kind) {
+ IO.enumCase(Kind, "function-enter", xray::SledEntry::FunctionKinds::ENTRY);
+ IO.enumCase(Kind, "function-exit", xray::SledEntry::FunctionKinds::EXIT);
+ IO.enumCase(Kind, "tail-exit", xray::SledEntry::FunctionKinds::TAIL);
+ }
+};
+
+template <> struct MappingTraits<xray::YAMLXRaySledEntry> {
+ static void mapping(IO &IO, xray::YAMLXRaySledEntry &Entry) {
+ IO.mapRequired("id", Entry.FuncId);
+ IO.mapRequired("address", Entry.Address);
+ IO.mapRequired("function", Entry.Function);
+ IO.mapRequired("kind", Entry.Kind);
+ IO.mapRequired("always-instrument", Entry.AlwaysInstrument);
+ }
+
+ static constexpr bool flow = true;
+};
+} // namespace yaml
+} // namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(xray::YAMLXRaySledEntry)
+
+#endif // LLVM_XRAY_INSTRUMENTATION_MAP_H
diff --git a/llvm/lib/XRay/CMakeLists.txt b/llvm/lib/XRay/CMakeLists.txt
index 6c1acba79bf..8d558209d8e 100644
--- a/llvm/lib/XRay/CMakeLists.txt
+++ b/llvm/lib/XRay/CMakeLists.txt
@@ -1,4 +1,5 @@
add_llvm_library(LLVMXRay
+ InstrumentationMap.cpp
Trace.cpp
ADDITIONAL_HEADER_DIRS
@@ -7,7 +8,9 @@ add_llvm_library(LLVMXRay
DEPENDS
LLVMSupport
+ LLVMObject
LINK_LIBS
LLVMSupport
+ LLVMObject
)
diff --git a/llvm/lib/XRay/InstrumentationMap.cpp b/llvm/lib/XRay/InstrumentationMap.cpp
new file mode 100644
index 00000000000..f14ad381578
--- /dev/null
+++ b/llvm/lib/XRay/InstrumentationMap.cpp
@@ -0,0 +1,194 @@
+//===- InstrumentationMap.cpp - XRay Instrumentation Map ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the InstrumentationMap type for XRay sleds.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef XRAY_INSTRUMENTATIONMAP_H
+#define XRAY_INSTRUMENTATIONMAP_H
+
+#include "llvm/XRay/InstrumentationMap.h"
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/XRay/XRayRecord.h"
+#include <system_error>
+
+namespace llvm {
+namespace xray {
+
+Optional<int32_t> InstrumentationMap::getFunctionId(uint64_t Addr) const {
+ auto I = FunctionIds.find(Addr);
+ if (I != FunctionIds.end())
+ return I->second;
+ return None;
+}
+
+Optional<uint64_t> InstrumentationMap::getFunctionAddr(int32_t FuncId) const {
+ auto I = FunctionAddresses.find(FuncId);
+ if (I != FunctionAddresses.end())
+ return I->second;
+ return None;
+}
+
+namespace {
+Error loadELF64(StringRef Filename,
+ object::OwningBinary<object::ObjectFile> &ObjFile,
+ InstrumentationMap::SledContainer &Sleds,
+ InstrumentationMap::FunctionAddressMap &FunctionAddresses,
+ InstrumentationMap::FunctionAddressReverseMap &FunctionIds) {
+ InstrumentationMap Map;
+
+ // Find the section named "xray_instr_map".
+ if (!ObjFile.getBinary()->isELF() ||
+ ObjFile.getBinary()->getArch() != Triple::x86_64)
+ return make_error<StringError>(
+ "File format not supported (only does ELF little endian 64-bit).",
+ std::make_error_code(std::errc::not_supported));
+
+ StringRef Contents = "";
+ const auto &Sections = ObjFile.getBinary()->sections();
+ auto I = find_if(Sections, [&](object::SectionRef Section) {
+ StringRef Name = "";
+ if (Section.getName(Name))
+ return false;
+ return Name == "xray_instr_map";
+ });
+
+ if (I == Sections.end())
+ return make_error<StringError>(
+ "Failed to find XRay instrumentation map.",
+ std::make_error_code(std::errc::executable_format_error));
+
+ if (I->getContents(Contents))
+ return errorCodeToError(
+ std::make_error_code(std::errc::executable_format_error));
+
+ // Copy the instrumentation map data into the Sleds data structure.
+ auto C = Contents.bytes_begin();
+ static constexpr size_t ELF64SledEntrySize = 32;
+
+ if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
+ return make_error<StringError>(
+ Twine("Instrumentation map entries not evenly divisible by size of "
+ "an XRay sled entry in ELF64."),
+ std::make_error_code(std::errc::executable_format_error));
+
+ int32_t FuncId = 1;
+ uint64_t CurFn = 0;
+ for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
+ DataExtractor Extractor(
+ StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
+ 8);
+ Sleds.push_back({});
+ auto &Entry = Sleds.back();
+ uint32_t OffsetPtr = 0;
+ Entry.Address = Extractor.getU64(&OffsetPtr);
+ Entry.Function = Extractor.getU64(&OffsetPtr);
+ auto Kind = Extractor.getU8(&OffsetPtr);
+ static constexpr SledEntry::FunctionKinds Kinds[] = {
+ SledEntry::FunctionKinds::ENTRY, SledEntry::FunctionKinds::EXIT,
+ SledEntry::FunctionKinds::TAIL,
+ };
+ if (Kind >= sizeof(Kinds))
+ return errorCodeToError(
+ std::make_error_code(std::errc::executable_format_error));
+ Entry.Kind = Kinds[Kind];
+ Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
+
+ // We do replicate the function id generation scheme implemented in the
+ // XRay runtime.
+ // FIXME: Figure out how to keep this consistent with the XRay runtime.
+ if (CurFn == 0) {
+ CurFn = Entry.Function;
+ FunctionAddresses[FuncId] = Entry.Function;
+ FunctionIds[Entry.Function] = FuncId;
+ }
+ if (Entry.Function != CurFn) {
+ ++FuncId;
+ CurFn = Entry.Function;
+ FunctionAddresses[FuncId] = Entry.Function;
+ FunctionIds[Entry.Function] = FuncId;
+ }
+ }
+ return Error::success();
+}
+
+Error loadYAML(int Fd, size_t FileSize, StringRef Filename,
+ InstrumentationMap::SledContainer &Sleds,
+ InstrumentationMap::FunctionAddressMap &FunctionAddresses,
+ InstrumentationMap::FunctionAddressReverseMap &FunctionIds) {
+ 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("Failed memory-mapping file '") + Filename + "'.", EC);
+
+ std::vector<YAMLXRaySledEntry> YAMLSleds;
+ yaml::Input In(StringRef(MappedFile.data(), MappedFile.size()));
+ In >> YAMLSleds;
+ if (In.error())
+ return make_error<StringError>(
+ Twine("Failed loading YAML document from '") + Filename + "'.",
+ In.error());
+
+ Sleds.reserve(YAMLSleds.size());
+ for (const auto &Y : YAMLSleds) {
+ FunctionAddresses[Y.FuncId] = Y.Function;
+ FunctionIds[Y.Function] = Y.FuncId;
+ Sleds.push_back(
+ SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
+ }
+ return Error::success();
+}
+} // namespace
+
+// FIXME: Create error types that encapsulate a bit more information than what
+// StringError instances contain.
+Expected<InstrumentationMap> loadInstrumentationMap(StringRef Filename) {
+ // At this point we assume the file is an object file -- and if that doesn't
+ // work, we treat it as YAML.
+ // FIXME: Extend to support non-ELF and non-x86_64 binaries.
+
+ InstrumentationMap Map;
+ auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename);
+ if (!ObjectFileOrError) {
+ auto E = ObjectFileOrError.takeError();
+ // We try to load it as YAML if the ELF load didn't work.
+ int Fd;
+ if (sys::fs::openFileForRead(Filename, Fd))
+ return std::move(E);
+
+ uint64_t FileSize;
+ if (sys::fs::file_size(Filename, FileSize))
+ return std::move(E);
+
+ // If the file is empty, we return the original error.
+ if (FileSize == 0)
+ return std::move(E);
+
+ // From this point on the errors will be only for the YAML parts, so we
+ // consume the errors at this point.
+ consumeError(std::move(E));
+ if (auto E = loadYAML(Fd, FileSize, Filename, Map.Sleds,
+ Map.FunctionAddresses, Map.FunctionIds))
+ return std::move(E);
+ } else if (auto E = loadELF64(Filename, *ObjectFileOrError, Map.Sleds,
+ Map.FunctionAddresses, Map.FunctionIds)) {
+ return std::move(E);
+ }
+ return Map;
+}
+}
+}
+
+#endif // XRAY_INSTRUMENTATIONMAP_H
diff --git a/llvm/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml b/llvm/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml
index 6e926974141..e8b46cbf176 100644
--- a/llvm/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml
+++ b/llvm/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml
@@ -1,4 +1,4 @@
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d | FileCheck %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -d | FileCheck %s
---
header:
version: 1
diff --git a/llvm/test/tools/llvm-xray/X86/account-keep-going.yaml b/llvm/test/tools/llvm-xray/X86/account-keep-going.yaml
index 1b234c0d7e8..76011ee8e6e 100644
--- a/llvm/test/tools/llvm-xray/X86/account-keep-going.yaml
+++ b/llvm/test/tools/llvm-xray/X86/account-keep-going.yaml
@@ -1,4 +1,4 @@
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -k | FileCheck %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -k | FileCheck %s
---
header:
version: 1
diff --git a/llvm/test/tools/llvm-xray/X86/account-simple-case.yaml b/llvm/test/tools/llvm-xray/X86/account-simple-case.yaml
index 82d83aae033..408b52e4465 100644
--- a/llvm/test/tools/llvm-xray/X86/account-simple-case.yaml
+++ b/llvm/test/tools/llvm-xray/X86/account-simple-case.yaml
@@ -1,4 +1,4 @@
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml | FileCheck %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml | FileCheck %s
---
header:
version: 1
diff --git a/llvm/test/tools/llvm-xray/X86/account-simple-sorting.yaml b/llvm/test/tools/llvm-xray/X86/account-simple-sorting.yaml
index d25aef24a27..0196d0a035a 100644
--- a/llvm/test/tools/llvm-xray/X86/account-simple-sorting.yaml
+++ b/llvm/test/tools/llvm-xray/X86/account-simple-sorting.yaml
@@ -1,13 +1,13 @@
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml | FileCheck --check-prefix DEFAULT %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s count | FileCheck --check-prefix COUNT-ASC %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s min | FileCheck --check-prefix MIN-ASC %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s max | FileCheck --check-prefix MAX-ASC %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s sum | FileCheck --check-prefix SUM-ASC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml | FileCheck --check-prefix DEFAULT %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s count | FileCheck --check-prefix COUNT-ASC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s min | FileCheck --check-prefix MIN-ASC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s max | FileCheck --check-prefix MAX-ASC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s sum | FileCheck --check-prefix SUM-ASC %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s count -r dsc | FileCheck --check-prefix COUNT-DSC %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s min -r dsc | FileCheck --check-prefix MIN-DSC %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s max -r dsc | FileCheck --check-prefix MAX-DSC %s
-#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s sum -r dsc | FileCheck --check-prefix SUM-DSC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s count -r dsc | FileCheck --check-prefix COUNT-DSC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s min -r dsc | FileCheck --check-prefix MIN-DSC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s max -r dsc | FileCheck --check-prefix MAX-DSC %s
+#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s sum -r dsc | FileCheck --check-prefix SUM-DSC %s
---
header:
version: 1
diff --git a/llvm/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt b/llvm/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt
index 01191c9c2a3..2b4c35a04f7 100644
--- a/llvm/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt
+++ b/llvm/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt
@@ -1,4 +1,4 @@
-; RUN: llvm-xray convert -m %S/Inputs/simple-xray-instrmap.yaml -t yaml %S/Inputs/naive-log-simple.xray -f=yaml -o - | FileCheck %s
+; RUN: llvm-xray convert -m %S/Inputs/simple-xray-instrmap.yaml %S/Inputs/naive-log-simple.xray -f=yaml -o - | FileCheck %s
; CHECK: ---
; CHECK-NEXT: header:
diff --git a/llvm/test/tools/llvm-xray/X86/graph-color-simple-case.yaml b/llvm/test/tools/llvm-xray/X86/graph-color-simple-case.yaml
index e1d0d9ad52c..1641854d206 100644
--- a/llvm/test/tools/llvm-xray/X86/graph-color-simple-case.yaml
+++ b/llvm/test/tools/llvm-xray/X86/graph-color-simple-case.yaml
@@ -1,6 +1,6 @@
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e sum -c sum \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e sum -c sum \
#RUN: | FileCheck %s -check-prefix=EDGE
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -v sum -b sum \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -v sum -b sum \
#RUN: | FileCheck %s -check-prefix=VERTEX
---
header:
diff --git a/llvm/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml b/llvm/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml
index 1654f672110..6f756bf018f 100644
--- a/llvm/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml
+++ b/llvm/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml
@@ -1,19 +1,19 @@
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d \
#RUN: | FileCheck %s -check-prefix=EMPTY
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e count \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e count \
#RUN: | FileCheck %s -check-prefix=COUNT
#
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e min \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e min \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e med \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e med \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e 90p \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e 90p \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e 99p \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e 99p \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e max \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e max \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e sum \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e sum \
#RUN: | FileCheck %s -check-prefix=TIME
#
---
diff --git a/llvm/test/tools/llvm-xray/X86/graph-simple-case.yaml b/llvm/test/tools/llvm-xray/X86/graph-simple-case.yaml
index 0b465d09134..b43ae465160 100644
--- a/llvm/test/tools/llvm-xray/X86/graph-simple-case.yaml
+++ b/llvm/test/tools/llvm-xray/X86/graph-simple-case.yaml
@@ -1,19 +1,19 @@
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml \
#RUN: | FileCheck %s -check-prefix=EMPTY
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e count \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e count \
#RUN: | FileCheck %s -check-prefix=COUNT
#
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e min \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e min \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e med \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e med \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e 90p \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e 90p \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e 99p \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e 99p \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e max \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e max \
#RUN: | FileCheck %s -check-prefix=TIME
-#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e sum \
+#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e sum \
#RUN: | FileCheck %s -check-prefix=TIME
---
header:
diff --git a/llvm/tools/llvm-xray/xray-account.cc b/llvm/tools/llvm-xray/xray-account.cc
index 671a5a073ee..13654c3911f 100644
--- a/llvm/tools/llvm-xray/xray-account.cc
+++ b/llvm/tools/llvm-xray/xray-account.cc
@@ -18,10 +18,10 @@
#include <utility>
#include "xray-account.h"
-#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
using namespace llvm;
@@ -120,16 +120,6 @@ static cl::opt<std::string>
static cl::alias AccountInstrMap2("m", cl::aliasopt(AccountInstrMap),
cl::desc("Alias for -instr_map"),
cl::sub(Account));
-static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
- "instr-map-format", cl::desc("format of instrumentation map"),
- cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
- "instrumentation map in an ELF header"),
- clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
- "yaml", "instrumentation map in YAML")),
- cl::sub(Account), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
-static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
- cl::desc("Alias for -instr-map-format"),
- cl::sub(Account));
namespace {
@@ -418,67 +408,63 @@ void LatencyAccountant::exportStatsAsCSV(raw_ostream &OS,
using namespace llvm::xray;
static CommandRegistration Unused(&Account, []() -> Error {
- int Fd;
- auto EC = sys::fs::openFileForRead(AccountInput, Fd);
- if (EC)
- return make_error<StringError>(
- Twine("Cannot open file '") + AccountInput + "'", EC);
-
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(AccountInstrMap, InstrMapFormat,
- Err);
- if (auto E = handleErrors(
- std::move(Err), [&](std::unique_ptr<StringError> SE) -> Error {
- if (SE->convertToErrorCode() == std::errc::no_such_file_or_directory)
- return Error::success();
- return Error(std::move(SE));
- }))
- return E;
+ InstrumentationMap Map;
+ if (!AccountInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(AccountInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot open instrumentation map '") +
+ AccountInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
+ std::error_code EC;
raw_fd_ostream OS(AccountOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + AccountOutput + "' for writing.", EC);
- const auto &FunctionAddresses = Extractor.getFunctionAddresses();
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer,
FunctionAddresses);
xray::LatencyAccountant FCA(FuncIdHelper, AccountDeduceSiblingCalls);
- if (auto TraceOrErr = loadTraceFile(AccountInput)) {
- auto &T = *TraceOrErr;
- for (const auto &Record : T) {
- if (FCA.accountRecord(Record))
- continue;
- for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
- errs() << "Thread ID: " << ThreadStack.first << "\n";
- auto Level = ThreadStack.second.size();
- for (const auto &Entry : llvm::reverse(ThreadStack.second))
- errs() << "#" << Level-- << "\t"
- << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
- }
- if (!AccountKeepGoing)
- return make_error<StringError>(
- Twine("Failed accounting function calls in file '") + AccountInput +
- "'.",
- std::make_error_code(std::errc::executable_format_error));
- }
- switch (AccountOutputFormat) {
- case AccountOutputFormats::TEXT:
- FCA.exportStatsAsText(OS, T.getFileHeader());
- break;
- case AccountOutputFormats::CSV:
- FCA.exportStatsAsCSV(OS, T.getFileHeader());
- break;
- }
- } else {
+ auto TraceOrErr = loadTraceFile(AccountInput);
+ if (!TraceOrErr)
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + AccountInput + "'",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
+
+ auto &T = *TraceOrErr;
+ for (const auto &Record : T) {
+ if (FCA.accountRecord(Record))
+ continue;
+ for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
+ errs() << "Thread ID: " << ThreadStack.first << "\n";
+ auto Level = ThreadStack.second.size();
+ for (const auto &Entry : llvm::reverse(ThreadStack.second))
+ errs() << "#" << Level-- << "\t"
+ << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
+ }
+ if (!AccountKeepGoing)
+ return make_error<StringError>(
+ Twine("Failed accounting function calls in file '") + AccountInput +
+ "'.",
+ std::make_error_code(std::errc::executable_format_error));
+ }
+ switch (AccountOutputFormat) {
+ case AccountOutputFormats::TEXT:
+ FCA.exportStatsAsText(OS, T.getFileHeader());
+ break;
+ case AccountOutputFormats::CSV:
+ FCA.exportStatsAsCSV(OS, T.getFileHeader());
+ break;
}
return Error::success();
diff --git a/llvm/tools/llvm-xray/xray-converter.cc b/llvm/tools/llvm-xray/xray-converter.cc
index b1fbc16d205..b9756e4b5bd 100644
--- a/llvm/tools/llvm-xray/xray-converter.cc
+++ b/llvm/tools/llvm-xray/xray-converter.cc
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "xray-converter.h"
-#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Support/EndianStream.h"
@@ -20,6 +19,7 @@
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
#include "llvm/XRay/YAMLXRayRecord.h"
@@ -73,16 +73,6 @@ static cl::opt<bool> ConvertSortInput(
static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput),
cl::desc("Alias for -sort"),
cl::sub(Convert));
-static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
- "instr-map-format", cl::desc("format of instrumentation map"),
- cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
- "instrumentation map in an ELF header"),
- clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
- "yaml", "instrumentation map in YAML")),
- cl::sub(Convert), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
-static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
- cl::desc("Alias for -instr-map-format"),
- cl::sub(Convert));
using llvm::yaml::Output;
@@ -151,25 +141,26 @@ namespace xray {
static CommandRegistration Unused(&Convert, []() -> Error {
// FIXME: Support conversion to BINARY when upgrading XRay trace versions.
- int Fd;
- auto EC = sys::fs::openFileForRead(ConvertInput, Fd);
- if (EC)
- return make_error<StringError>(
- Twine("Cannot open file '") + ConvertInput + "'", EC);
-
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(ConvertInstrMap, InstrMapFormat,
- Err);
- handleAllErrors(std::move(Err),
- [&](const ErrorInfoBase &E) { E.log(errs()); });
+ InstrumentationMap Map;
+ if (!ConvertInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(ConvertInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot open instrumentation map '") +
+ ConvertInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
- const auto &FunctionAddresses = Extractor.getFunctionAddresses();
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer,
FunctionAddresses);
llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize);
+ std::error_code EC;
raw_fd_ostream OS(ConvertOutput, EC,
ConvertOutputFormat == ConvertFormats::BINARY
? sys::fs::OpenFlags::F_None
@@ -178,22 +169,22 @@ static CommandRegistration Unused(&Convert, []() -> Error {
return make_error<StringError>(
Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC);
- 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 {
+ auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput);
+ if (!TraceOrErr)
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + ConvertInput + "'.",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
+
+ auto &T = *TraceOrErr;
+ switch (ConvertOutputFormat) {
+ case ConvertFormats::YAML:
+ TC.exportAsYAML(T, OS);
+ break;
+ case ConvertFormats::BINARY:
+ TC.exportAsRAWv1(T, OS);
+ break;
}
return Error::success();
});
diff --git a/llvm/tools/llvm-xray/xray-extract.cc b/llvm/tools/llvm-xray/xray-extract.cc
index 49ecd742113..bf1f696de55 100644
--- a/llvm/tools/llvm-xray/xray-extract.cc
+++ b/llvm/tools/llvm-xray/xray-extract.cc
@@ -16,10 +16,7 @@
#include <type_traits>
#include <utility>
-#include "xray-extract.h"
-
#include "xray-registry.h"
-#include "xray-sleds.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
@@ -28,8 +25,8 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/InstrumentationMap.h"
using namespace llvm;
using namespace llvm::xray;
@@ -49,243 +46,40 @@ static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput),
cl::desc("Alias for -output"),
cl::sub(Extract));
-struct YAMLXRaySledEntry {
- int32_t FuncId;
- Hex64 Address;
- Hex64 Function;
- SledEntry::FunctionKinds Kind;
- bool AlwaysInstrument;
-};
-
-namespace llvm {
-namespace yaml {
-
-template <> struct ScalarEnumerationTraits<SledEntry::FunctionKinds> {
- static void enumeration(IO &IO, SledEntry::FunctionKinds &Kind) {
- IO.enumCase(Kind, "function-enter", SledEntry::FunctionKinds::ENTRY);
- IO.enumCase(Kind, "function-exit", SledEntry::FunctionKinds::EXIT);
- IO.enumCase(Kind, "tail-exit", SledEntry::FunctionKinds::TAIL);
- }
-};
-
-template <> struct MappingTraits<YAMLXRaySledEntry> {
- static void mapping(IO &IO, YAMLXRaySledEntry &Entry) {
- IO.mapRequired("id", Entry.FuncId);
- IO.mapRequired("address", Entry.Address);
- IO.mapRequired("function", Entry.Function);
- IO.mapRequired("kind", Entry.Kind);
- IO.mapRequired("always-instrument", Entry.AlwaysInstrument);
- }
-
- static constexpr bool flow = true;
-};
-}
-}
-
-LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLXRaySledEntry)
-
namespace {
-llvm::Error LoadBinaryInstrELF(
- StringRef Filename, std::deque<SledEntry> &OutputSleds,
- InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
- InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
- auto ObjectFile = object::ObjectFile::createObjectFile(Filename);
-
- if (!ObjectFile)
- return ObjectFile.takeError();
-
- // FIXME: Maybe support other ELF formats. For now, 64-bit Little Endian only.
- if (!ObjectFile->getBinary()->isELF())
- return make_error<StringError>(
- "File format not supported (only does ELF).",
- std::make_error_code(std::errc::not_supported));
- if (ObjectFile->getBinary()->getArch() != Triple::x86_64)
- return make_error<StringError>(
- "File format not supported (only does ELF little endian 64-bit).",
- std::make_error_code(std::errc::not_supported));
-
- // Find the section named "xray_instr_map".
- StringRef Contents = "";
- const auto &Sections = ObjectFile->getBinary()->sections();
- auto I = find_if(Sections, [&](object::SectionRef Section) {
- StringRef Name = "";
- if (Section.getName(Name))
- return false;
- return Name == "xray_instr_map";
- });
- if (I == Sections.end())
- return make_error<StringError>(
- "Failed to find XRay instrumentation map.",
- std::make_error_code(std::errc::not_supported));
- if (I->getContents(Contents))
- return make_error<StringError>(
- "Failed to get contents of 'xray_instr_map' section.",
- std::make_error_code(std::errc::executable_format_error));
-
- // Copy the instrumentation map data into the Sleds data structure.
- auto C = Contents.bytes_begin();
- static constexpr size_t ELF64SledEntrySize = 32;
-
- if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
- return make_error<StringError>(
- "Instrumentation map entries not evenly divisible by size of an XRay "
- "sled entry in ELF64.",
- std::make_error_code(std::errc::executable_format_error));
-
- int32_t FuncId = 1;
- uint64_t CurFn = 0;
- std::deque<SledEntry> Sleds;
- for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
- DataExtractor Extractor(
- StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
- 8);
- Sleds.push_back({});
- auto &Entry = Sleds.back();
- uint32_t OffsetPtr = 0;
- Entry.Address = Extractor.getU64(&OffsetPtr);
- Entry.Function = Extractor.getU64(&OffsetPtr);
- auto Kind = Extractor.getU8(&OffsetPtr);
- switch (Kind) {
- case 0: // ENTRY
- Entry.Kind = SledEntry::FunctionKinds::ENTRY;
- break;
- case 1: // EXIT
- Entry.Kind = SledEntry::FunctionKinds::EXIT;
- break;
- case 2: // TAIL
- Entry.Kind = SledEntry::FunctionKinds::TAIL;
- break;
- default:
- return make_error<StringError>(
- Twine("Encountered unknown sled type ") + "'" + Twine(int32_t{Kind}) +
- "'.",
- std::make_error_code(std::errc::executable_format_error));
- }
- Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
-
- // We replicate the function id generation scheme implemented in the runtime
- // here. Ideally we should be able to break it out, or output this map from
- // the runtime, but that's a design point we can discuss later on. For now,
- // we replicate the logic and move on.
- if (CurFn == 0) {
- CurFn = Entry.Function;
- InstrMap[FuncId] = Entry.Function;
- FunctionIds[Entry.Function] = FuncId;
- }
- if (Entry.Function != CurFn) {
- ++FuncId;
- CurFn = Entry.Function;
- InstrMap[FuncId] = Entry.Function;
- FunctionIds[Entry.Function] = FuncId;
- }
- }
- OutputSleds = std::move(Sleds);
- return llvm::Error::success();
-}
-
-Error LoadYAMLInstrMap(
- StringRef Filename, std::deque<SledEntry> &Sleds,
- InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
- InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
- int Fd;
- if (auto EC = sys::fs::openFileForRead(Filename, Fd))
- return make_error<StringError>(
- Twine("Failed opening file '") + Filename + "' for reading.", EC);
-
- uint64_t FileSize;
- if (auto EC = sys::fs::file_size(Filename, FileSize))
- return make_error<StringError>(
- Twine("Failed getting size of file '") + Filename + "'.", EC);
-
- 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("Failed memory-mapping file '") + Filename + "'.", EC);
-
- std::vector<YAMLXRaySledEntry> YAMLSleds;
- Input In(StringRef(MappedFile.data(), MappedFile.size()));
- In >> YAMLSleds;
- if (In.error())
- return make_error<StringError>(
- Twine("Failed loading YAML document from '") + Filename + "'.",
- In.error());
-
- for (const auto &Y : YAMLSleds) {
- InstrMap[Y.FuncId] = Y.Function;
- FunctionIds[Y.Function] = Y.FuncId;
- Sleds.push_back(
- SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
- }
- return Error::success();
-}
-
-} // namespace
-
-InstrumentationMapExtractor::InstrumentationMapExtractor(std::string Filename,
- InputFormats Format,
- Error &EC) {
- ErrorAsOutParameter ErrAsOutputParam(&EC);
- if (Filename.empty()) {
- EC = Error::success();
- return;
- }
- switch (Format) {
- case InputFormats::ELF: {
- EC = handleErrors(
- LoadBinaryInstrELF(Filename, Sleds, FunctionAddresses, FunctionIds),
- [&](std::unique_ptr<ErrorInfoBase> E) {
- return joinErrors(
- make_error<StringError>(
- Twine("Cannot extract instrumentation map from '") +
- Filename + "'.",
- std::make_error_code(std::errc::executable_format_error)),
- std::move(E));
- });
- break;
- }
- case InputFormats::YAML: {
- EC = handleErrors(
- LoadYAMLInstrMap(Filename, Sleds, FunctionAddresses, FunctionIds),
- [&](std::unique_ptr<ErrorInfoBase> E) {
- return joinErrors(
- make_error<StringError>(
- Twine("Cannot load YAML instrumentation map from '") +
- Filename + "'.",
- std::make_error_code(std::errc::executable_format_error)),
- std::move(E));
- });
- break;
- }
- }
-}
-
-void InstrumentationMapExtractor::exportAsYAML(raw_ostream &OS) {
+void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS) {
// First we translate the sleds into the YAMLXRaySledEntry objects in a deque.
std::vector<YAMLXRaySledEntry> YAMLSleds;
- YAMLSleds.reserve(Sleds.size());
+ auto Sleds = Map.sleds();
+ YAMLSleds.reserve(std::distance(Sleds.begin(), Sleds.end()));
for (const auto &Sled : Sleds) {
- YAMLSleds.push_back({FunctionIds[Sled.Function], Sled.Address,
- Sled.Function, Sled.Kind, Sled.AlwaysInstrument});
+ auto FuncId = Map.getFunctionId(Sled.Function);
+ if (!FuncId)
+ return;
+ YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind,
+ Sled.AlwaysInstrument});
}
Output Out(OS);
Out << YAMLSleds;
}
+} // namespace
+
static CommandRegistration Unused(&Extract, []() -> Error {
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(
- ExtractInput, InstrumentationMapExtractor::InputFormats::ELF, Err);
- if (Err)
- return Err;
+ auto InstrumentationMapOrError = loadInstrumentationMap(ExtractInput);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot extract instrumentation map from '") +
+ ExtractInput + "'.",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
std::error_code EC;
raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC);
- Extractor.exportAsYAML(OS);
+ exportAsYAML(*InstrumentationMapOrError, OS);
return Error::success();
});
diff --git a/llvm/tools/llvm-xray/xray-extract.h b/llvm/tools/llvm-xray/xray-extract.h
deleted file mode 100644
index 91e4db36805..00000000000
--- a/llvm/tools/llvm-xray/xray-extract.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//===- xray-extract.h - XRay Instrumentation Map Extraction ---------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the interface for extracting the instrumentation map from an
-// XRay-instrumented binary.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_XRAY_EXTRACT_H
-#define LLVM_TOOLS_XRAY_EXTRACT_H
-
-#include <deque>
-#include <map>
-#include <string>
-#include <unordered_map>
-
-#include "xray-sleds.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-namespace xray {
-
-class InstrumentationMapExtractor {
-public:
- typedef std::unordered_map<int32_t, uint64_t> FunctionAddressMap;
- typedef std::unordered_map<uint64_t, int32_t> FunctionAddressReverseMap;
-
- enum class InputFormats { ELF, YAML };
-
-private:
- std::deque<SledEntry> Sleds;
- FunctionAddressMap FunctionAddresses;
- FunctionAddressReverseMap FunctionIds;
-
-public:
- /// Loads the instrumentation map from |Filename|. Updates |EC| in case there
- /// were errors encountered opening the file. |Format| defines what the input
- /// instrumentation map is in.
- InstrumentationMapExtractor(std::string Filename, InputFormats Format,
- Error &EC);
-
- const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; }
-
- /// Exports the loaded function address map as YAML through |OS|.
- void exportAsYAML(raw_ostream &OS);
-};
-
-} // namespace xray
-} // namespace llvm
-
-#endif // LLVM_TOOLS_XRAY_EXTRACT_H
diff --git a/llvm/tools/llvm-xray/xray-graph.cc b/llvm/tools/llvm-xray/xray-graph.cc
index e6ec7aad964..3525b245276 100644
--- a/llvm/tools/llvm-xray/xray-graph.cc
+++ b/llvm/tools/llvm-xray/xray-graph.cc
@@ -17,17 +17,17 @@
#include <system_error>
#include <utility>
-#include "xray-extract.h"
#include "xray-graph.h"
#include "xray-registry.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
#include "llvm/XRay/YAMLXRayRecord.h"
using namespace llvm;
-using namespace xray;
+using namespace llvm::xray;
// Setup llvm-xray graph subcommand and its options.
static cl::SubCommand Graph("graph", "Generate function-call graph");
@@ -48,27 +48,14 @@ static cl::opt<std::string>
static cl::alias GraphOutput2("o", cl::aliasopt(GraphOutput),
cl::desc("Alias for -output"), cl::sub(Graph));
-static cl::opt<std::string>
- GraphInstrMap("instr_map",
- cl::desc("binary with the instrumrntation map, or "
- "a separate instrumentation map"),
- cl::value_desc("binary with xray_instr_map"), cl::sub(Graph),
- cl::init(""));
+static cl::opt<std::string> GraphInstrMap(
+ "instr_map", cl::desc("binary with the instrumrntation map, or "
+ "a separate instrumentation map"),
+ cl::value_desc("binary with xray_instr_map"), cl::sub(Graph), cl::init(""));
static cl::alias GraphInstrMap2("m", cl::aliasopt(GraphInstrMap),
cl::desc("alias for -instr_map"),
cl::sub(Graph));
-static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
- "instr-map-format", cl::desc("format of instrumentation map"),
- cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
- "instrumentation map in an ELF header"),
- clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
- "yaml", "instrumentation map in YAML")),
- cl::sub(Graph), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
-static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
- cl::desc("Alias for -instr-map-format"),
- cl::sub(Graph));
-
static cl::opt<bool> GraphDeduceSiblingCalls(
"deduce-sibling-calls",
cl::desc("Deduce sibling calls when unrolling function call stacks"),
@@ -535,50 +522,44 @@ void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, const XRayFileHeader &H,
// FIXME: include additional filtering and annalysis passes to provide more
// specific useful information.
static CommandRegistration Unused(&Graph, []() -> Error {
- int Fd;
- auto EC = sys::fs::openFileForRead(GraphInput, Fd);
- if (EC)
- return make_error<StringError>(
- Twine("Cannot open file '") + GraphInput + "'", EC);
-
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(GraphInstrMap, InstrMapFormat,
- Err);
- handleAllErrors(std::move(Err),
- [&](const ErrorInfoBase &E) { E.log(errs()); });
-
- const auto &FunctionAddresses = Extractor.getFunctionAddresses();
+ InstrumentationMap Map;
+ if (!GraphInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(GraphInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(
+ make_error<StringError>(
+ Twine("Cannot open instrumentation map '") + GraphInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
-
symbolize::LLVMSymbolizer Symbolizer(Opts);
-
llvm::xray::FuncIdConversionHelper FuncIdHelper(GraphInstrMap, Symbolizer,
FunctionAddresses);
-
xray::GraphRenderer GR(FuncIdHelper, GraphDeduceSiblingCalls);
-
+ std::error_code EC;
raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text);
-
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + GraphOutput + "' for writing.", EC);
auto TraceOrErr = loadTraceFile(GraphInput, true);
-
- if (!TraceOrErr) {
+ if (!TraceOrErr)
return joinErrors(
make_error<StringError>(Twine("Failed loading input file '") +
GraphInput + "'",
make_error_code(llvm::errc::invalid_argument)),
- std::move(Err));
- }
+ TraceOrErr.takeError());
auto &Trace = *TraceOrErr;
const auto &Header = Trace.getFileHeader();
+
+ // Here we generate the call graph from entries we find in the trace.
for (const auto &Record : Trace) {
- // Generate graph.
auto E = GR.accountRecord(Record);
if (!E)
continue;
@@ -592,12 +573,16 @@ static CommandRegistration Unused(&Graph, []() -> Error {
}
if (!GraphKeepGoing)
- return joinErrors(std::move(E), std::move(Err));
+ return joinErrors(make_error<StringError>(
+ "Error encountered generating the call graph.",
+ std::make_error_code(std::errc::bad_message)),
+ std::move(E));
+
handleAllErrors(std::move(E),
[&](const ErrorInfoBase &E) { E.log(errs()); });
}
GR.exportGraphAsDOT(OS, Header, GraphEdgeLabel, GraphEdgeColorType,
GraphVertexLabel, GraphVertexColorType);
- return Err;
+ return Error::success();
});
diff --git a/llvm/tools/llvm-xray/xray-sleds.h b/llvm/tools/llvm-xray/xray-sleds.h
deleted file mode 100644
index 99279579ed4..00000000000
--- a/llvm/tools/llvm-xray/xray-sleds.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===- xray-sleds.h - XRay Sleds Data Structure ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the structure used to represent XRay instrumentation map entries.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
-#define LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
-
-namespace llvm {
-namespace xray {
-
-struct SledEntry {
- enum class FunctionKinds { ENTRY, EXIT, TAIL };
-
- uint64_t Address;
- uint64_t Function;
- FunctionKinds Kind;
- bool AlwaysInstrument;
-};
-
-} // namespace xray
-} // namespace llvm
-
-#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
OpenPOWER on IntegriCloud