You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.207
Former-commit-id: 3b152f462918d427ce18620a2cbe4f8b79650449
This commit is contained in:
parent
8e12397d70
commit
eb85e2fc17
21
external/llvm/tools/llvm-xray/CMakeLists.txt
vendored
21
external/llvm/tools/llvm-xray/CMakeLists.txt
vendored
@ -1,21 +0,0 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
DebugInfoDWARF
|
||||
Object
|
||||
Support
|
||||
Symbolize
|
||||
XRay)
|
||||
|
||||
set(LLVM_XRAY_TOOLS
|
||||
func-id-helper.cc
|
||||
xray-account.cc
|
||||
xray-color-helper.cc
|
||||
xray-converter.cc
|
||||
xray-extract.cc
|
||||
xray-extract.cc
|
||||
xray-graph.cc
|
||||
xray-graph-diff.cc
|
||||
xray-stacks.cc
|
||||
xray-registry.cc)
|
||||
|
||||
add_llvm_tool(llvm-xray llvm-xray.cc ${LLVM_XRAY_TOOLS})
|
60
external/llvm/tools/llvm-xray/func-id-helper.cc
vendored
60
external/llvm/tools/llvm-xray/func-id-helper.cc
vendored
@ -1,60 +0,0 @@
|
||||
//===- xray-fc-account.cc - XRay Function Call Accounting Tool ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implementation of the helper tools dealing with XRay-generated function ids.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "func-id-helper.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xray;
|
||||
|
||||
std::string FuncIdConversionHelper::SymbolOrNumber(int32_t FuncId) const {
|
||||
std::ostringstream F;
|
||||
auto It = FunctionAddresses.find(FuncId);
|
||||
if (It == FunctionAddresses.end()) {
|
||||
F << "#" << FuncId;
|
||||
return F.str();
|
||||
}
|
||||
|
||||
if (auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, It->second)) {
|
||||
auto &DI = *ResOrErr;
|
||||
if (DI.FunctionName == "<invalid>")
|
||||
F << "@(" << std::hex << It->second << ")";
|
||||
else
|
||||
F << DI.FunctionName;
|
||||
} else
|
||||
handleAllErrors(ResOrErr.takeError(), [&](const ErrorInfoBase &) {
|
||||
F << "@(" << std::hex << It->second << ")";
|
||||
});
|
||||
|
||||
return F.str();
|
||||
}
|
||||
|
||||
std::string FuncIdConversionHelper::FileLineAndColumn(int32_t FuncId) const {
|
||||
auto It = FunctionAddresses.find(FuncId);
|
||||
if (It == FunctionAddresses.end())
|
||||
return "(unknown)";
|
||||
|
||||
std::ostringstream F;
|
||||
auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, It->second);
|
||||
if (!ResOrErr) {
|
||||
consumeError(ResOrErr.takeError());
|
||||
return "(unknown)";
|
||||
}
|
||||
|
||||
auto &DI = *ResOrErr;
|
||||
F << sys::path::filename(DI.FileName).str() << ":" << DI.Line << ":"
|
||||
<< DI.Column;
|
||||
|
||||
return F.str();
|
||||
}
|
49
external/llvm/tools/llvm-xray/func-id-helper.h
vendored
49
external/llvm/tools/llvm-xray/func-id-helper.h
vendored
@ -1,49 +0,0 @@
|
||||
//===- func-id-helper.h - XRay Function ID Conversion Helpers -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines helper tools dealing with XRay-generated function ids.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_TOOLS_LLVM_XRAY_FUNC_ID_HELPER_H
|
||||
#define LLVM_TOOLS_LLVM_XRAY_FUNC_ID_HELPER_H
|
||||
|
||||
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
// This class consolidates common operations related to Function IDs.
|
||||
class FuncIdConversionHelper {
|
||||
public:
|
||||
using FunctionAddressMap = std::unordered_map<int32_t, uint64_t>;
|
||||
|
||||
private:
|
||||
std::string BinaryInstrMap;
|
||||
symbolize::LLVMSymbolizer &Symbolizer;
|
||||
const FunctionAddressMap &FunctionAddresses;
|
||||
|
||||
public:
|
||||
FuncIdConversionHelper(std::string BinaryInstrMap,
|
||||
symbolize::LLVMSymbolizer &Symbolizer,
|
||||
const FunctionAddressMap &FunctionAddresses)
|
||||
: BinaryInstrMap(std::move(BinaryInstrMap)), Symbolizer(Symbolizer),
|
||||
FunctionAddresses(FunctionAddresses) {}
|
||||
|
||||
// Returns the symbol or a string representation of the function id.
|
||||
std::string SymbolOrNumber(int32_t FuncId) const;
|
||||
|
||||
// Returns the file and column from debug info for the given function id.
|
||||
std::string FileLineAndColumn(int32_t FuncId) const;
|
||||
};
|
||||
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_TOOLS_LLVM_XRAY_FUNC_ID_HELPER_H
|
49
external/llvm/tools/llvm-xray/llvm-xray.cc
vendored
49
external/llvm/tools/llvm-xray/llvm-xray.cc
vendored
@ -1,49 +0,0 @@
|
||||
//===- llvm-xray.cc - XRay Tool Main Program ------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the main entry point for the suite of XRay tools. All
|
||||
// additional functionality are implemented as subcommands.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Basic usage:
|
||||
//
|
||||
// llvm-xray [options] <subcommand> [subcommand-specific options]
|
||||
//
|
||||
#include "xray-registry.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::xray;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
"XRay Tools\n\n"
|
||||
" This program consolidates multiple XRay trace "
|
||||
"processing tools for convenient access.\n");
|
||||
for (auto *SC : cl::getRegisteredSubcommands()) {
|
||||
if (*SC) {
|
||||
// If no subcommand was provided, we need to explicitly check if this is
|
||||
// the top-level subcommand.
|
||||
if (SC == &*cl::TopLevelSubCommand) {
|
||||
cl::PrintHelpMessage(false, true);
|
||||
return 0;
|
||||
}
|
||||
if (auto C = dispatch(SC)) {
|
||||
ExitOnError("llvm-xray: ")(C());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all else fails, we still print the usage message.
|
||||
cl::PrintHelpMessage(false, true);
|
||||
return 0;
|
||||
}
|
92
external/llvm/tools/llvm-xray/trie-node.h
vendored
92
external/llvm/tools/llvm-xray/trie-node.h
vendored
@ -1,92 +0,0 @@
|
||||
//===- trie-node.h - XRay Call Stack Data Structure -----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides a data structure and routines for working with call stacks
|
||||
// of instrumented functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H
|
||||
#define LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H
|
||||
|
||||
#include <forward_list>
|
||||
#include <numeric>
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
/// A type to represent a trie of invocations. It is useful to construct a
|
||||
/// graph of these nodes from reading an XRay trace, such that each function
|
||||
/// call can be placed in a larger context.
|
||||
///
|
||||
/// The template parameter allows users of the template to attach their own
|
||||
/// data elements to each node in the invocation graph.
|
||||
template <typename AssociatedData> struct TrieNode {
|
||||
/// The function ID.
|
||||
int32_t FuncId;
|
||||
|
||||
/// The caller of this function.
|
||||
TrieNode<AssociatedData> *Parent;
|
||||
|
||||
/// The callees from this function.
|
||||
llvm::SmallVector<TrieNode<AssociatedData> *, 4> Callees;
|
||||
|
||||
/// Additional parameterized data on each node.
|
||||
AssociatedData ExtraData;
|
||||
};
|
||||
|
||||
/// Merges together two TrieNodes with like function ids, aggregating their
|
||||
/// callee lists and durations. The caller must provide storage where new merged
|
||||
/// nodes can be allocated in the form of a linked list.
|
||||
template <typename T, typename Callable>
|
||||
TrieNode<T> *
|
||||
mergeTrieNodes(const TrieNode<T> &Left, const TrieNode<T> &Right,
|
||||
/*Non-deduced pointer type for nullptr compatibility*/
|
||||
typename std::remove_reference<TrieNode<T> *>::type NewParent,
|
||||
std::forward_list<TrieNode<T>> &NodeStore,
|
||||
Callable &&MergeCallable) {
|
||||
llvm::function_ref<T(const T &, const T &)> MergeFn(
|
||||
std::forward<Callable>(MergeCallable));
|
||||
assert(Left.FuncId == Right.FuncId);
|
||||
NodeStore.push_front(TrieNode<T>{
|
||||
Left.FuncId, NewParent, {}, MergeFn(Left.ExtraData, Right.ExtraData)});
|
||||
auto I = NodeStore.begin();
|
||||
auto *Node = &*I;
|
||||
|
||||
// Build a map of callees from the left side.
|
||||
llvm::DenseMap<int32_t, TrieNode<T> *> LeftCalleesByFuncId;
|
||||
for (auto *Callee : Left.Callees) {
|
||||
LeftCalleesByFuncId[Callee->FuncId] = Callee;
|
||||
}
|
||||
|
||||
// Iterate through the right side, either merging with the map values or
|
||||
// directly adding to the Callees vector. The iteration also removes any
|
||||
// merged values from the left side map.
|
||||
// TODO: Unroll into iterative and explicit stack for efficiency.
|
||||
for (auto *Callee : Right.Callees) {
|
||||
auto iter = LeftCalleesByFuncId.find(Callee->FuncId);
|
||||
if (iter != LeftCalleesByFuncId.end()) {
|
||||
Node->Callees.push_back(
|
||||
mergeTrieNodes(*(iter->second), *Callee, Node, NodeStore, MergeFn));
|
||||
LeftCalleesByFuncId.erase(iter);
|
||||
} else {
|
||||
Node->Callees.push_back(Callee);
|
||||
}
|
||||
}
|
||||
|
||||
// Add any callees that weren't found in the right side.
|
||||
for (auto MapPairIter : LeftCalleesByFuncId) {
|
||||
Node->Callees.push_back(MapPairIter.second);
|
||||
}
|
||||
|
||||
return Node;
|
||||
}
|
||||
|
||||
#endif // LLVM_TOOLS_LLVM_XRAY_STACK_TRIE_H
|
507
external/llvm/tools/llvm-xray/xray-account.cc
vendored
507
external/llvm/tools/llvm-xray/xray-account.cc
vendored
File diff suppressed because it is too large
Load Diff
109
external/llvm/tools/llvm-xray/xray-account.h
vendored
109
external/llvm/tools/llvm-xray/xray-account.h
vendored
@ -1,109 +0,0 @@
|
||||
//===- xray-account.h - XRay Function Call Accounting ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface for performing some basic function call
|
||||
// accounting from an XRay trace.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
|
||||
#define LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "func-id-helper.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/XRay/XRayRecord.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
class LatencyAccountant {
|
||||
public:
|
||||
typedef std::map<int32_t, std::vector<uint64_t>> FunctionLatencyMap;
|
||||
typedef std::map<llvm::sys::ProcessInfo::ProcessId,
|
||||
std::pair<uint64_t, uint64_t>>
|
||||
PerThreadMinMaxTSCMap;
|
||||
typedef std::map<uint8_t, std::pair<uint64_t, uint64_t>> PerCPUMinMaxTSCMap;
|
||||
typedef std::vector<std::pair<int32_t, uint64_t>> FunctionStack;
|
||||
typedef std::map<llvm::sys::ProcessInfo::ProcessId, FunctionStack>
|
||||
PerThreadFunctionStackMap;
|
||||
|
||||
private:
|
||||
PerThreadFunctionStackMap PerThreadFunctionStack;
|
||||
FunctionLatencyMap FunctionLatencies;
|
||||
PerThreadMinMaxTSCMap PerThreadMinMaxTSC;
|
||||
PerCPUMinMaxTSCMap PerCPUMinMaxTSC;
|
||||
FuncIdConversionHelper &FuncIdHelper;
|
||||
|
||||
bool DeduceSiblingCalls = false;
|
||||
uint64_t CurrentMaxTSC = 0;
|
||||
|
||||
void recordLatency(int32_t FuncId, uint64_t Latency) {
|
||||
FunctionLatencies[FuncId].push_back(Latency);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit LatencyAccountant(FuncIdConversionHelper &FuncIdHelper,
|
||||
bool DeduceSiblingCalls)
|
||||
: FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DeduceSiblingCalls) {}
|
||||
|
||||
const FunctionLatencyMap &getFunctionLatencies() const {
|
||||
return FunctionLatencies;
|
||||
}
|
||||
|
||||
const PerThreadMinMaxTSCMap &getPerThreadMinMaxTSC() const {
|
||||
return PerThreadMinMaxTSC;
|
||||
}
|
||||
|
||||
const PerCPUMinMaxTSCMap &getPerCPUMinMaxTSC() const {
|
||||
return PerCPUMinMaxTSC;
|
||||
}
|
||||
|
||||
/// Returns false in case we fail to account the provided record. This happens
|
||||
/// in the following cases:
|
||||
///
|
||||
/// - An exit record does not match any entry records for the same function.
|
||||
/// If we've been set to deduce sibling calls, we try walking up the stack
|
||||
/// and recording times for the higher level functions.
|
||||
/// - A record has a TSC that's before the latest TSC that has been
|
||||
/// recorded. We still record the TSC for the min-max.
|
||||
///
|
||||
bool accountRecord(const XRayRecord &Record);
|
||||
|
||||
const FunctionStack *
|
||||
getThreadFunctionStack(llvm::sys::ProcessInfo::ProcessId TId) const {
|
||||
auto I = PerThreadFunctionStack.find(TId);
|
||||
if (I == PerThreadFunctionStack.end())
|
||||
return nullptr;
|
||||
return &I->second;
|
||||
}
|
||||
|
||||
const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
|
||||
return PerThreadFunctionStack;
|
||||
}
|
||||
|
||||
// Output Functions
|
||||
// ================
|
||||
|
||||
void exportStatsAsText(raw_ostream &OS, const XRayFileHeader &Header) const;
|
||||
void exportStatsAsCSV(raw_ostream &OS, const XRayFileHeader &Header) const;
|
||||
|
||||
private:
|
||||
// Internal helper to implement common parts of the exportStatsAs...
|
||||
// functions.
|
||||
template <class F> void exportStats(const XRayFileHeader &Header, F fn) const;
|
||||
};
|
||||
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
|
222
external/llvm/tools/llvm-xray/xray-color-helper.cc
vendored
222
external/llvm/tools/llvm-xray/xray-color-helper.cc
vendored
@ -1,222 +0,0 @@
|
||||
//===-- xray-graph.cc - XRay Function Call Graph Renderer -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// A class to get a color from a specified gradient.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "xray-color-helper.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xray;
|
||||
|
||||
// Sequential ColorMaps, which are used to represent information
|
||||
// from some minimum to some maximum.
|
||||
|
||||
static const std::tuple<uint8_t, uint8_t, uint8_t> SequentialMaps[][9] = {
|
||||
{// The greys color scheme from http://colorbrewer2.org/
|
||||
std::make_tuple(255, 255, 255), std::make_tuple(240, 240, 240),
|
||||
std::make_tuple(217, 217, 217), std::make_tuple(189, 189, 189),
|
||||
std::make_tuple(150, 150, 150), std::make_tuple(115, 115, 115),
|
||||
std::make_tuple(82, 82, 82), std::make_tuple(37, 37, 37),
|
||||
std::make_tuple(0, 0, 0)},
|
||||
{// The OrRd color scheme from http://colorbrewer2.org/
|
||||
std::make_tuple(255, 247, 236), std::make_tuple(254, 232, 200),
|
||||
std::make_tuple(253, 212, 158), std::make_tuple(253, 187, 132),
|
||||
std::make_tuple(252, 141, 89), std::make_tuple(239, 101, 72),
|
||||
std::make_tuple(215, 48, 31), std::make_tuple(179, 0, 0),
|
||||
std::make_tuple(127, 0, 0)},
|
||||
{// The PuBu color scheme from http://colorbrewer2.org/
|
||||
std::make_tuple(255, 247, 251), std::make_tuple(236, 231, 242),
|
||||
std::make_tuple(208, 209, 230), std::make_tuple(166, 189, 219),
|
||||
std::make_tuple(116, 169, 207), std::make_tuple(54, 144, 192),
|
||||
std::make_tuple(5, 112, 176), std::make_tuple(4, 90, 141),
|
||||
std::make_tuple(2, 56, 88)}};
|
||||
|
||||
// Sequential Maps extend the last colors given out of range inputs.
|
||||
static const std::tuple<uint8_t, uint8_t, uint8_t> SequentialBounds[][2] = {
|
||||
{// The Bounds for the greys color scheme
|
||||
std::make_tuple(255, 255, 255), std::make_tuple(0, 0, 0)},
|
||||
{// The Bounds for the OrRd color Scheme
|
||||
std::make_tuple(255, 247, 236), std::make_tuple(127, 0, 0)},
|
||||
{// The Bounds for the PuBu color Scheme
|
||||
std::make_tuple(255, 247, 251), std::make_tuple(2, 56, 88)}};
|
||||
|
||||
ColorHelper::ColorHelper(ColorHelper::SequentialScheme S)
|
||||
: MinIn(0.0), MaxIn(1.0), ColorMap(SequentialMaps[static_cast<int>(S)]),
|
||||
BoundMap(SequentialBounds[static_cast<int>(S)]) {}
|
||||
|
||||
// Diverging ColorMaps, which are used to represent information
|
||||
// representing differenes, or a range that goes from negative to positive.
|
||||
// These take an input in the range [-1,1].
|
||||
|
||||
static const std::tuple<uint8_t, uint8_t, uint8_t> DivergingCoeffs[][11] = {
|
||||
{// The PiYG color scheme from http://colorbrewer2.org/
|
||||
std::make_tuple(142, 1, 82), std::make_tuple(197, 27, 125),
|
||||
std::make_tuple(222, 119, 174), std::make_tuple(241, 182, 218),
|
||||
std::make_tuple(253, 224, 239), std::make_tuple(247, 247, 247),
|
||||
std::make_tuple(230, 245, 208), std::make_tuple(184, 225, 134),
|
||||
std::make_tuple(127, 188, 65), std::make_tuple(77, 146, 33),
|
||||
std::make_tuple(39, 100, 25)}};
|
||||
|
||||
// Diverging maps use out of bounds ranges to show missing data. Missing Right
|
||||
// Being below min, and missing left being above max.
|
||||
static const std::tuple<uint8_t, uint8_t, uint8_t> DivergingBounds[][2] = {
|
||||
{// The PiYG color scheme has green and red for missing right and left
|
||||
// respectively.
|
||||
std::make_tuple(255, 0, 0), std::make_tuple(0, 255, 0)}};
|
||||
|
||||
ColorHelper::ColorHelper(ColorHelper::DivergingScheme S)
|
||||
: MinIn(-1.0), MaxIn(1.0), ColorMap(DivergingCoeffs[static_cast<int>(S)]),
|
||||
BoundMap(DivergingBounds[static_cast<int>(S)]) {}
|
||||
|
||||
// Takes a tuple of uint8_ts representing a color in RGB and converts them to
|
||||
// HSV represented by a tuple of doubles
|
||||
static std::tuple<double, double, double>
|
||||
convertToHSV(const std::tuple<uint8_t, uint8_t, uint8_t> &Color) {
|
||||
double Scaled[3] = {std::get<0>(Color) / 255.0, std::get<1>(Color) / 255.0,
|
||||
std::get<2>(Color) / 255.0};
|
||||
int Min = 0;
|
||||
int Max = 0;
|
||||
for (int i = 1; i < 3; ++i) {
|
||||
if (Scaled[i] < Scaled[Min])
|
||||
Min = i;
|
||||
if (Scaled[i] > Scaled[Max])
|
||||
Max = i;
|
||||
}
|
||||
|
||||
double C = Scaled[Max] - Scaled[Min];
|
||||
|
||||
double HPrime =
|
||||
(C == 0) ? 0 : (Scaled[(Max + 1) % 3] - Scaled[(Max + 2) % 3]) / C;
|
||||
HPrime = HPrime + 2.0 * Max;
|
||||
|
||||
double H = (HPrime < 0) ? (HPrime + 6.0) * 60
|
||||
: HPrime * 60; // Scale to between 0 and 360
|
||||
double V = Scaled[Max];
|
||||
|
||||
double S = (V == 0.0) ? 0.0 : C / V;
|
||||
|
||||
return std::make_tuple(H, S, V);
|
||||
}
|
||||
|
||||
// Takes a double precision number, clips it between 0 and 1 and then converts
|
||||
// that to an integer between 0x00 and 0xFF with proxpper rounding.
|
||||
static uint8_t unitIntervalTo8BitChar(double B) {
|
||||
double n = std::max(std::min(B, 1.0), 0.0);
|
||||
return static_cast<uint8_t>(255 * n + 0.5);
|
||||
}
|
||||
|
||||
// Takes a typle of doubles representing a color in HSV and converts them to
|
||||
// RGB represented as a tuple of uint8_ts
|
||||
static std::tuple<uint8_t, uint8_t, uint8_t>
|
||||
convertToRGB(const std::tuple<double, double, double> &Color) {
|
||||
const double &H = std::get<0>(Color);
|
||||
const double &S = std::get<1>(Color);
|
||||
const double &V = std::get<2>(Color);
|
||||
|
||||
double C = V * S;
|
||||
|
||||
double HPrime = H / 60;
|
||||
double X = C * (1 - std::abs(std::fmod(HPrime, 2.0) - 1));
|
||||
|
||||
double RGB1[3];
|
||||
int HPrimeInt = static_cast<int>(HPrime);
|
||||
if (HPrimeInt % 2 == 0) {
|
||||
RGB1[(HPrimeInt / 2) % 3] = C;
|
||||
RGB1[(HPrimeInt / 2 + 1) % 3] = X;
|
||||
RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
|
||||
} else {
|
||||
RGB1[(HPrimeInt / 2) % 3] = X;
|
||||
RGB1[(HPrimeInt / 2 + 1) % 3] = C;
|
||||
RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
|
||||
}
|
||||
|
||||
double Min = V - C;
|
||||
double RGB2[3] = {RGB1[0] + Min, RGB1[1] + Min, RGB1[2] + Min};
|
||||
|
||||
return std::make_tuple(unitIntervalTo8BitChar(RGB2[0]),
|
||||
unitIntervalTo8BitChar(RGB2[1]),
|
||||
unitIntervalTo8BitChar(RGB2[2]));
|
||||
}
|
||||
|
||||
// The Hue component of the HSV interpolation Routine
|
||||
static double interpolateHue(double H0, double H1, double T) {
|
||||
double D = H1 - H0;
|
||||
if (H0 > H1) {
|
||||
std::swap(H0, H1);
|
||||
|
||||
D = -D;
|
||||
T = 1 - T;
|
||||
}
|
||||
|
||||
if (D <= 180) {
|
||||
return H0 + T * (H1 - H0);
|
||||
} else {
|
||||
H0 = H0 + 360;
|
||||
return std::fmod(H0 + T * (H1 - H0) + 720, 360);
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolates between two HSV Colors both represented as a tuple of doubles
|
||||
// Returns an HSV Color represented as a tuple of doubles
|
||||
static std::tuple<double, double, double>
|
||||
interpolateHSV(const std::tuple<double, double, double> &C0,
|
||||
const std::tuple<double, double, double> &C1, double T) {
|
||||
double H = interpolateHue(std::get<0>(C0), std::get<0>(C1), T);
|
||||
double S = std::get<1>(C0) + T * (std::get<1>(C1) - std::get<1>(C0));
|
||||
double V = std::get<2>(C0) + T * (std::get<2>(C1) - std::get<2>(C0));
|
||||
return std::make_tuple(H, S, V);
|
||||
}
|
||||
|
||||
// Get the Color as a tuple of uint8_ts
|
||||
std::tuple<uint8_t, uint8_t, uint8_t>
|
||||
ColorHelper::getColorTuple(double Point) const {
|
||||
assert(!ColorMap.empty() && "ColorMap must not be empty!");
|
||||
assert(!BoundMap.empty() && "BoundMap must not be empty!");
|
||||
|
||||
if (Point < MinIn)
|
||||
return BoundMap[0];
|
||||
if (Point > MaxIn)
|
||||
return BoundMap[1];
|
||||
|
||||
size_t MaxIndex = ColorMap.size() - 1;
|
||||
double IntervalWidth = MaxIn - MinIn;
|
||||
double OffsetP = Point - MinIn;
|
||||
double SectionWidth = IntervalWidth / static_cast<double>(MaxIndex);
|
||||
size_t SectionNo = std::floor(OffsetP / SectionWidth);
|
||||
double T = (OffsetP - SectionNo * SectionWidth) / SectionWidth;
|
||||
|
||||
auto &RGBColor0 = ColorMap[SectionNo];
|
||||
auto &RGBColor1 = ColorMap[std::min(SectionNo + 1, MaxIndex)];
|
||||
|
||||
auto HSVColor0 = convertToHSV(RGBColor0);
|
||||
auto HSVColor1 = convertToHSV(RGBColor1);
|
||||
|
||||
auto InterpolatedHSVColor = interpolateHSV(HSVColor0, HSVColor1, T);
|
||||
return convertToRGB(InterpolatedHSVColor);
|
||||
}
|
||||
|
||||
// A helper method to convert a color represented as tuple of uint8s to a hex
|
||||
// string.
|
||||
std::string
|
||||
ColorHelper::getColorString(std::tuple<uint8_t, uint8_t, uint8_t> t) {
|
||||
return llvm::formatv("#{0:X-2}{1:X-2}{2:X-2}", std::get<0>(t), std::get<1>(t),
|
||||
std::get<2>(t));
|
||||
}
|
||||
|
||||
// Gets a color in a gradient given a number in the interval [0,1], it does this
|
||||
// by evaluating a polynomial which maps [0, 1] -> [0, 1] for each of the R G
|
||||
// and B values in the color. It then converts this [0,1] colors to a 24 bit
|
||||
// color as a hex string.
|
||||
std::string ColorHelper::getColorString(double Point) const {
|
||||
return getColorString(getColorTuple(Point));
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// A class to get a color from a specified gradient.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef XRAY_COLOR_HELPER_H
|
||||
#define XRAY_COLOR_HELPER_H
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
/// The color helper class it a healper class which allows you to easily get a
|
||||
/// color in a gradient. This is used to color-code edges in XRay-Graph tools.
|
||||
///
|
||||
/// There are two types of color schemes in this class:
|
||||
/// - Sequential schemes, which are used to represent information from some
|
||||
/// minimum to some maximum. These take an input in the range [0,1]
|
||||
/// - Diverging schemes, which are used to represent information representing
|
||||
/// differenes, or a range that goes from negative to positive. These take
|
||||
/// an input in the range [-1,1].
|
||||
/// Usage;
|
||||
/// ColorHelper S(ColorHelper::SequentialScheme::OrRd); //Chose a color scheme.
|
||||
/// for (double p = 0.0; p <= 1; p += 0.1){
|
||||
/// cout() << S.getColor(p) << " \n"; // Sample the gradient at 0.1 intervals
|
||||
/// }
|
||||
///
|
||||
/// ColorHelper D(ColorHelper::DivergingScheme::Spectral); // Choose a color
|
||||
/// // scheme.
|
||||
/// for (double p= -1; p <= 1 ; p += 0.1){
|
||||
/// cout() << D.getColor(p) << " \n"; // sample the gradient at 0.1 intervals
|
||||
/// }
|
||||
class ColorHelper {
|
||||
double MinIn;
|
||||
double MaxIn;
|
||||
|
||||
ArrayRef<std::tuple<uint8_t, uint8_t, uint8_t>> ColorMap;
|
||||
ArrayRef<std::tuple<uint8_t, uint8_t, uint8_t>> BoundMap;
|
||||
|
||||
public:
|
||||
/// Enum of the availible Sequential Color Schemes
|
||||
enum class SequentialScheme {
|
||||
// Schemes based on the ColorBrewer Color schemes of the same name from
|
||||
// http://www.colorbrewer.org/ by Cynthis A Brewer Penn State University.
|
||||
Greys,
|
||||
OrRd,
|
||||
PuBu
|
||||
};
|
||||
|
||||
ColorHelper(SequentialScheme S);
|
||||
|
||||
/// Enum of the availible Diverging Color Schemes
|
||||
enum class DivergingScheme {
|
||||
// Schemes based on the ColorBrewer Color schemes of the same name from
|
||||
// http://www.colorbrewer.org/ by Cynthis A Brewer Penn State University.
|
||||
PiYG
|
||||
};
|
||||
|
||||
ColorHelper(DivergingScheme S);
|
||||
|
||||
// Sample the gradient at the input point.
|
||||
std::tuple<uint8_t, uint8_t, uint8_t> getColorTuple(double Point) const;
|
||||
|
||||
std::string getColorString(double Point) const;
|
||||
|
||||
// Get the Default color, at the moment allways black.
|
||||
std::tuple<uint8_t, uint8_t, uint8_t> getDefaultColorTuple() const {
|
||||
return std::make_tuple(0, 0, 0);
|
||||
}
|
||||
|
||||
std::string getDefaultColorString() const { return "black"; }
|
||||
|
||||
// Convert a tuple to a string
|
||||
static std::string getColorString(std::tuple<uint8_t, uint8_t, uint8_t> t);
|
||||
};
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
||||
#endif
|
393
external/llvm/tools/llvm-xray/xray-converter.cc
vendored
393
external/llvm/tools/llvm-xray/xray-converter.cc
vendored
@ -1,393 +0,0 @@
|
||||
//===- xray-converter.cc - XRay Trace Conversion --------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements the trace conversion functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "xray-converter.h"
|
||||
|
||||
#include "trie-node.h"
|
||||
#include "xray-registry.h"
|
||||
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
|
||||
#include "llvm/Support/EndianStream.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#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"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xray;
|
||||
|
||||
// llvm-xray convert
|
||||
// ----------------------------------------------------------------------------
|
||||
static cl::SubCommand Convert("convert", "Trace Format Conversion");
|
||||
static cl::opt<std::string> ConvertInput(cl::Positional,
|
||||
cl::desc("<xray log file>"),
|
||||
cl::Required, cl::sub(Convert));
|
||||
enum class ConvertFormats { BINARY, YAML, CHROME_TRACE_EVENT };
|
||||
static cl::opt<ConvertFormats> ConvertOutputFormat(
|
||||
"output-format", cl::desc("output format"),
|
||||
cl::values(clEnumValN(ConvertFormats::BINARY, "raw", "output in binary"),
|
||||
clEnumValN(ConvertFormats::YAML, "yaml", "output in yaml"),
|
||||
clEnumValN(ConvertFormats::CHROME_TRACE_EVENT, "trace_event",
|
||||
"Output in chrome's trace event format. "
|
||||
"May be visualized with the Catapult trace viewer.")),
|
||||
cl::sub(Convert));
|
||||
static cl::alias ConvertOutputFormat2("f", cl::aliasopt(ConvertOutputFormat),
|
||||
cl::desc("Alias for -output-format"),
|
||||
cl::sub(Convert));
|
||||
static cl::opt<std::string>
|
||||
ConvertOutput("output", cl::value_desc("output file"), cl::init("-"),
|
||||
cl::desc("output file; use '-' for stdout"),
|
||||
cl::sub(Convert));
|
||||
static cl::alias ConvertOutput2("o", cl::aliasopt(ConvertOutput),
|
||||
cl::desc("Alias for -output"),
|
||||
cl::sub(Convert));
|
||||
|
||||
static cl::opt<bool>
|
||||
ConvertSymbolize("symbolize",
|
||||
cl::desc("symbolize function ids from the input log"),
|
||||
cl::init(false), cl::sub(Convert));
|
||||
static cl::alias ConvertSymbolize2("y", cl::aliasopt(ConvertSymbolize),
|
||||
cl::desc("Alias for -symbolize"),
|
||||
cl::sub(Convert));
|
||||
|
||||
static cl::opt<std::string>
|
||||
ConvertInstrMap("instr_map",
|
||||
cl::desc("binary with the instrumentation map, or "
|
||||
"a separate instrumentation map"),
|
||||
cl::value_desc("binary with xray_instr_map"),
|
||||
cl::sub(Convert), cl::init(""));
|
||||
static cl::alias ConvertInstrMap2("m", cl::aliasopt(ConvertInstrMap),
|
||||
cl::desc("Alias for -instr_map"),
|
||||
cl::sub(Convert));
|
||||
static cl::opt<bool> ConvertSortInput(
|
||||
"sort",
|
||||
cl::desc("determines whether to sort input log records by timestamp"),
|
||||
cl::sub(Convert), cl::init(true));
|
||||
static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput),
|
||||
cl::desc("Alias for -sort"),
|
||||
cl::sub(Convert));
|
||||
|
||||
using llvm::yaml::Output;
|
||||
|
||||
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,
|
||||
FH.CycleFrequency};
|
||||
Trace.Records.reserve(Records.size());
|
||||
for (const auto &R : Records) {
|
||||
Trace.Records.push_back({R.RecordType, R.CPU, R.Type, R.FuncId,
|
||||
Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId)
|
||||
: llvm::to_string(R.FuncId),
|
||||
R.TSC, R.TId, R.CallArgs});
|
||||
}
|
||||
Output Out(OS, nullptr, 0);
|
||||
Out << Trace;
|
||||
}
|
||||
|
||||
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<support::endianness::little> Writer(OS);
|
||||
const auto &FH = Records.getFileHeader();
|
||||
Writer.write(FH.Version);
|
||||
Writer.write(FH.Type);
|
||||
uint32_t Bitfield{0};
|
||||
if (FH.ConstantTSC)
|
||||
Bitfield |= 1uL;
|
||||
if (FH.NonstopTSC)
|
||||
Bitfield |= 1uL << 1;
|
||||
Writer.write(Bitfield);
|
||||
Writer.write(FH.CycleFrequency);
|
||||
|
||||
// There's 16 bytes of padding at the end of the file header.
|
||||
static constexpr uint32_t Padding4B = 0;
|
||||
Writer.write(Padding4B);
|
||||
Writer.write(Padding4B);
|
||||
Writer.write(Padding4B);
|
||||
Writer.write(Padding4B);
|
||||
|
||||
// Then write out the rest of the records, still in an endian-appropriate
|
||||
// format.
|
||||
for (const auto &R : Records) {
|
||||
Writer.write(R.RecordType);
|
||||
// The on disk naive raw format uses 8 bit CPUs, but the record has 16.
|
||||
// There's no choice but truncation.
|
||||
Writer.write(static_cast<uint8_t>(R.CPU));
|
||||
switch (R.Type) {
|
||||
case RecordTypes::ENTER:
|
||||
case RecordTypes::ENTER_ARG:
|
||||
Writer.write(uint8_t{0});
|
||||
break;
|
||||
case RecordTypes::EXIT:
|
||||
Writer.write(uint8_t{1});
|
||||
break;
|
||||
case RecordTypes::TAIL_EXIT:
|
||||
Writer.write(uint8_t{2});
|
||||
break;
|
||||
}
|
||||
Writer.write(R.FuncId);
|
||||
Writer.write(R.TSC);
|
||||
Writer.write(R.TId);
|
||||
Writer.write(Padding4B);
|
||||
Writer.write(Padding4B);
|
||||
Writer.write(Padding4B);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// A structure that allows building a dictionary of stack ids for the Chrome
|
||||
// trace event format.
|
||||
struct StackIdData {
|
||||
// Each Stack of function calls has a unique ID.
|
||||
unsigned id;
|
||||
|
||||
// Bookkeeping so that IDs can be maintained uniquely across threads.
|
||||
// Traversal keeps sibling pointers to other threads stacks. This is helpful
|
||||
// to determine when a thread encounters a new stack and should assign a new
|
||||
// unique ID.
|
||||
SmallVector<TrieNode<StackIdData> *, 4> siblings;
|
||||
};
|
||||
|
||||
using StackTrieNode = TrieNode<StackIdData>;
|
||||
|
||||
// A helper function to find the sibling nodes for an encountered function in a
|
||||
// thread of execution. Relies on the invariant that each time a new node is
|
||||
// traversed in a thread, sibling bidirectional pointers are maintained.
|
||||
SmallVector<StackTrieNode *, 4>
|
||||
findSiblings(StackTrieNode *parent, int32_t FnId, uint32_t TId,
|
||||
const DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>>
|
||||
&StackRootsByThreadId) {
|
||||
|
||||
SmallVector<StackTrieNode *, 4> Siblings{};
|
||||
|
||||
if (parent == nullptr) {
|
||||
for (auto map_iter : StackRootsByThreadId) {
|
||||
// Only look for siblings in other threads.
|
||||
if (map_iter.first != TId)
|
||||
for (auto node_iter : map_iter.second) {
|
||||
if (node_iter->FuncId == FnId)
|
||||
Siblings.push_back(node_iter);
|
||||
}
|
||||
}
|
||||
return Siblings;
|
||||
}
|
||||
|
||||
for (auto *ParentSibling : parent->ExtraData.siblings)
|
||||
for (auto node_iter : ParentSibling->Callees)
|
||||
if (node_iter->FuncId == FnId)
|
||||
Siblings.push_back(node_iter);
|
||||
|
||||
return Siblings;
|
||||
}
|
||||
|
||||
// Given a function being invoked in a thread with id TId, finds and returns the
|
||||
// StackTrie representing the function call stack. If no node exists, creates
|
||||
// the node. Assigns unique IDs to stacks newly encountered among all threads
|
||||
// and keeps sibling links up to when creating new nodes.
|
||||
StackTrieNode *findOrCreateStackNode(
|
||||
StackTrieNode *Parent, int32_t FuncId, uint32_t TId,
|
||||
DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> &StackRootsByThreadId,
|
||||
DenseMap<unsigned, StackTrieNode *> &StacksByStackId, unsigned *id_counter,
|
||||
std::forward_list<StackTrieNode> &NodeStore) {
|
||||
SmallVector<StackTrieNode *, 4> &ParentCallees =
|
||||
Parent == nullptr ? StackRootsByThreadId[TId] : Parent->Callees;
|
||||
auto match = find_if(ParentCallees, [FuncId](StackTrieNode *ParentCallee) {
|
||||
return FuncId == ParentCallee->FuncId;
|
||||
});
|
||||
if (match != ParentCallees.end())
|
||||
return *match;
|
||||
|
||||
SmallVector<StackTrieNode *, 4> siblings =
|
||||
findSiblings(Parent, FuncId, TId, StackRootsByThreadId);
|
||||
if (siblings.empty()) {
|
||||
NodeStore.push_front({FuncId, Parent, {}, {(*id_counter)++, {}}});
|
||||
StackTrieNode *CurrentStack = &NodeStore.front();
|
||||
StacksByStackId[*id_counter - 1] = CurrentStack;
|
||||
ParentCallees.push_back(CurrentStack);
|
||||
return CurrentStack;
|
||||
}
|
||||
unsigned stack_id = siblings[0]->ExtraData.id;
|
||||
NodeStore.push_front({FuncId, Parent, {}, {stack_id, std::move(siblings)}});
|
||||
StackTrieNode *CurrentStack = &NodeStore.front();
|
||||
for (auto *sibling : CurrentStack->ExtraData.siblings)
|
||||
sibling->ExtraData.siblings.push_back(CurrentStack);
|
||||
ParentCallees.push_back(CurrentStack);
|
||||
return CurrentStack;
|
||||
}
|
||||
|
||||
void writeTraceViewerRecord(raw_ostream &OS, int32_t FuncId, uint32_t TId,
|
||||
bool Symbolize,
|
||||
const FuncIdConversionHelper &FuncIdHelper,
|
||||
double EventTimestampUs,
|
||||
const StackTrieNode &StackCursor,
|
||||
StringRef FunctionPhenotype) {
|
||||
OS << " ";
|
||||
OS << llvm::formatv(
|
||||
R"({ "name" : "{0}", "ph" : "{1}", "tid" : "{2}", "pid" : "1", )"
|
||||
R"("ts" : "{3:f3}", "sf" : "{4}" })",
|
||||
(Symbolize ? FuncIdHelper.SymbolOrNumber(FuncId)
|
||||
: llvm::to_string(FuncId)),
|
||||
FunctionPhenotype, TId, EventTimestampUs, StackCursor.ExtraData.id);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
||||
raw_ostream &OS) {
|
||||
const auto &FH = Records.getFileHeader();
|
||||
auto CycleFreq = FH.CycleFrequency;
|
||||
|
||||
unsigned id_counter = 0;
|
||||
|
||||
OS << "{\n \"traceEvents\": [";
|
||||
DenseMap<uint32_t, StackTrieNode *> StackCursorByThreadId{};
|
||||
DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> StackRootsByThreadId{};
|
||||
DenseMap<unsigned, StackTrieNode *> StacksByStackId{};
|
||||
std::forward_list<StackTrieNode> NodeStore{};
|
||||
int loop_count = 0;
|
||||
for (const auto &R : Records) {
|
||||
if (loop_count++ == 0)
|
||||
OS << "\n";
|
||||
else
|
||||
OS << ",\n";
|
||||
|
||||
// Chrome trace event format always wants data in micros.
|
||||
// CyclesPerMicro = CycleHertz / 10^6
|
||||
// TSC / CyclesPerMicro == TSC * 10^6 / CycleHertz == MicroTimestamp
|
||||
// Could lose some precision here by converting the TSC to a double to
|
||||
// multiply by the period in micros. 52 bit mantissa is a good start though.
|
||||
// TODO: Make feature request to Chrome Trace viewer to accept ticks and a
|
||||
// frequency or do some more involved calculation to avoid dangers of
|
||||
// conversion.
|
||||
double EventTimestampUs = double(1000000) / CycleFreq * double(R.TSC);
|
||||
StackTrieNode *&StackCursor = StackCursorByThreadId[R.TId];
|
||||
switch (R.Type) {
|
||||
case RecordTypes::ENTER:
|
||||
case RecordTypes::ENTER_ARG:
|
||||
StackCursor = findOrCreateStackNode(StackCursor, R.FuncId, R.TId,
|
||||
StackRootsByThreadId, StacksByStackId,
|
||||
&id_counter, NodeStore);
|
||||
// Each record is represented as a json dictionary with function name,
|
||||
// type of B for begin or E for end, thread id, process id (faked),
|
||||
// timestamp in microseconds, and a stack frame id. The ids are logged
|
||||
// in an id dictionary after the events.
|
||||
writeTraceViewerRecord(OS, R.FuncId, R.TId, Symbolize, FuncIdHelper,
|
||||
EventTimestampUs, *StackCursor, "B");
|
||||
break;
|
||||
case RecordTypes::EXIT:
|
||||
case RecordTypes::TAIL_EXIT:
|
||||
// No entries to record end for.
|
||||
if (StackCursor == nullptr)
|
||||
break;
|
||||
// Should we emit an END record anyway or account this condition?
|
||||
// (And/Or in loop termination below)
|
||||
StackTrieNode *PreviousCursor = nullptr;
|
||||
do {
|
||||
writeTraceViewerRecord(OS, StackCursor->FuncId, R.TId, Symbolize,
|
||||
FuncIdHelper, EventTimestampUs, *StackCursor,
|
||||
"E");
|
||||
PreviousCursor = StackCursor;
|
||||
StackCursor = StackCursor->Parent;
|
||||
} while (PreviousCursor->FuncId != R.FuncId && StackCursor != nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
OS << "\n ],\n"; // Close the Trace Events array.
|
||||
OS << " "
|
||||
<< "\"displayTimeUnit\": \"ns\",\n";
|
||||
|
||||
// The stackFrames dictionary substantially reduces size of the output file by
|
||||
// avoiding repeating the entire call stack of function names for each entry.
|
||||
OS << R"( "stackFrames": {)";
|
||||
int stack_frame_count = 0;
|
||||
for (auto map_iter : StacksByStackId) {
|
||||
if (stack_frame_count++ == 0)
|
||||
OS << "\n";
|
||||
else
|
||||
OS << ",\n";
|
||||
OS << " ";
|
||||
OS << llvm::formatv(
|
||||
R"("{0}" : { "name" : "{1}")", map_iter.first,
|
||||
(Symbolize ? FuncIdHelper.SymbolOrNumber(map_iter.second->FuncId)
|
||||
: llvm::to_string(map_iter.second->FuncId)));
|
||||
if (map_iter.second->Parent != nullptr)
|
||||
OS << llvm::formatv(R"(, "parent": "{0}")",
|
||||
map_iter.second->Parent->ExtraData.id);
|
||||
OS << " }";
|
||||
}
|
||||
OS << "\n }\n"; // Close the stack frames map.
|
||||
OS << "}\n"; // Close the JSON entry.
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
static CommandRegistration Unused(&Convert, []() -> Error {
|
||||
// FIXME: Support conversion to BINARY when upgrading XRay trace versions.
|
||||
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 = 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
|
||||
: sys::fs::OpenFlags::F_Text);
|
||||
if (EC)
|
||||
return make_error<StringError>(
|
||||
Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC);
|
||||
|
||||
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;
|
||||
case ConvertFormats::CHROME_TRACE_EVENT:
|
||||
TC.exportAsChromeTraceEventFormat(T, OS);
|
||||
break;
|
||||
}
|
||||
return Error::success();
|
||||
});
|
||||
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
44
external/llvm/tools/llvm-xray/xray-converter.h
vendored
44
external/llvm/tools/llvm-xray/xray-converter.h
vendored
@ -1,44 +0,0 @@
|
||||
//===- xray-converter.h - XRay Trace Conversion ---------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the TraceConverter class for turning binary traces into
|
||||
// human-readable text and vice versa.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_CONVERTER_H
|
||||
#define LLVM_TOOLS_LLVM_XRAY_XRAY_CONVERTER_H
|
||||
|
||||
#include "func-id-helper.h"
|
||||
#include "llvm/XRay/Trace.h"
|
||||
#include "llvm/XRay/XRayRecord.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
class TraceConverter {
|
||||
FuncIdConversionHelper &FuncIdHelper;
|
||||
bool Symbolize;
|
||||
|
||||
public:
|
||||
TraceConverter(FuncIdConversionHelper &FuncIdHelper, bool Symbolize = false)
|
||||
: FuncIdHelper(FuncIdHelper), Symbolize(Symbolize) {}
|
||||
|
||||
void exportAsYAML(const Trace &Records, raw_ostream &OS);
|
||||
void exportAsRAWv1(const Trace &Records, raw_ostream &OS);
|
||||
|
||||
/// For this conversion, the Function records within each thread are expected
|
||||
/// to be in sorted TSC order. The trace event format encodes stack traces, so
|
||||
/// the linear history is essential for correct output.
|
||||
void exportAsChromeTraceEventFormat(const Trace &Records, raw_ostream &OS);
|
||||
};
|
||||
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_CONVERTER_H
|
97
external/llvm/tools/llvm-xray/xray-extract.cc
vendored
97
external/llvm/tools/llvm-xray/xray-extract.cc
vendored
@ -1,97 +0,0 @@
|
||||
//===- xray-extract.cc - 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implementation of the xray-extract.h interface.
|
||||
//
|
||||
// FIXME: Support other XRay-instrumented binary formats other than ELF.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "func-id-helper.h"
|
||||
#include "xray-registry.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/XRay/InstrumentationMap.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::xray;
|
||||
using namespace llvm::yaml;
|
||||
|
||||
// llvm-xray extract
|
||||
// ----------------------------------------------------------------------------
|
||||
static cl::SubCommand Extract("extract", "Extract instrumentation maps");
|
||||
static cl::opt<std::string> ExtractInput(cl::Positional,
|
||||
cl::desc("<input file>"), cl::Required,
|
||||
cl::sub(Extract));
|
||||
static cl::opt<std::string>
|
||||
ExtractOutput("output", cl::value_desc("output file"), cl::init("-"),
|
||||
cl::desc("output file; use '-' for stdout"),
|
||||
cl::sub(Extract));
|
||||
static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput),
|
||||
cl::desc("Alias for -output"),
|
||||
cl::sub(Extract));
|
||||
static cl::opt<bool> ExtractSymbolize("symbolize", cl::value_desc("symbolize"),
|
||||
cl::init(false),
|
||||
cl::desc("symbolize functions"),
|
||||
cl::sub(Extract));
|
||||
static cl::alias ExtractSymbolize2("s", cl::aliasopt(ExtractSymbolize),
|
||||
cl::desc("alias for -symbolize"),
|
||||
cl::sub(Extract));
|
||||
|
||||
namespace {
|
||||
|
||||
void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS,
|
||||
FuncIdConversionHelper &FH) {
|
||||
// First we translate the sleds into the YAMLXRaySledEntry objects in a deque.
|
||||
std::vector<YAMLXRaySledEntry> YAMLSleds;
|
||||
auto Sleds = Map.sleds();
|
||||
YAMLSleds.reserve(std::distance(Sleds.begin(), Sleds.end()));
|
||||
for (const auto &Sled : Sleds) {
|
||||
auto FuncId = Map.getFunctionId(Sled.Function);
|
||||
if (!FuncId)
|
||||
return;
|
||||
YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind,
|
||||
Sled.AlwaysInstrument,
|
||||
ExtractSymbolize ? FH.SymbolOrNumber(*FuncId) : ""});
|
||||
}
|
||||
Output Out(OS, nullptr, 0);
|
||||
Out << YAMLSleds;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static CommandRegistration Unused(&Extract, []() -> Error {
|
||||
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);
|
||||
const auto &FunctionAddresses =
|
||||
InstrumentationMapOrError->getFunctionAddresses();
|
||||
symbolize::LLVMSymbolizer::Options Opts(
|
||||
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
|
||||
symbolize::LLVMSymbolizer Symbolizer(Opts);
|
||||
llvm::xray::FuncIdConversionHelper FuncIdHelper(ExtractInput, Symbolizer,
|
||||
FunctionAddresses);
|
||||
exportAsYAML(*InstrumentationMapOrError, OS, FuncIdHelper);
|
||||
return Error::success();
|
||||
});
|
484
external/llvm/tools/llvm-xray/xray-graph-diff.cc
vendored
484
external/llvm/tools/llvm-xray/xray-graph-diff.cc
vendored
@ -1,484 +0,0 @@
|
||||
//===-- xray-graph-diff.cc - XRay Function Call Graph Renderer ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Generate a DOT file to represent the function call graph encountered in
|
||||
// the trace.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "xray-graph-diff.h"
|
||||
#include "xray-graph.h"
|
||||
#include "xray-registry.h"
|
||||
|
||||
#include "xray-color-helper.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/XRay/Trace.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xray;
|
||||
|
||||
static cl::SubCommand GraphDiff("graph-diff",
|
||||
"Generate diff of function-call graphs");
|
||||
static cl::opt<std::string> GraphDiffInput1(cl::Positional,
|
||||
cl::desc("<xray log file 1>"),
|
||||
cl::Required, cl::sub(GraphDiff));
|
||||
static cl::opt<std::string> GraphDiffInput2(cl::Positional,
|
||||
cl::desc("<xray log file 2>"),
|
||||
cl::Required, cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<bool>
|
||||
GraphDiffKeepGoing("keep-going",
|
||||
cl::desc("Keep going on errors encountered"),
|
||||
cl::sub(GraphDiff), cl::init(false));
|
||||
static cl::alias GraphDiffKeepGoingA("k", cl::aliasopt(GraphDiffKeepGoing),
|
||||
cl::desc("Alias for -keep-going"),
|
||||
cl::sub(GraphDiff));
|
||||
static cl::opt<bool>
|
||||
GraphDiffKeepGoing1("keep-going-1",
|
||||
cl::desc("Keep going on errors encountered in trace 1"),
|
||||
cl::sub(GraphDiff), cl::init(false));
|
||||
static cl::alias GraphDiffKeepGoing1A("k1", cl::aliasopt(GraphDiffKeepGoing1),
|
||||
cl::desc("Alias for -keep-going-1"),
|
||||
cl::sub(GraphDiff));
|
||||
static cl::opt<bool>
|
||||
GraphDiffKeepGoing2("keep-going-2",
|
||||
cl::desc("Keep going on errors encountered in trace 2"),
|
||||
cl::sub(GraphDiff), cl::init(false));
|
||||
static cl::alias GraphDiffKeepGoing2A("k2", cl::aliasopt(GraphDiffKeepGoing2),
|
||||
cl::desc("Alias for -keep-going-2"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<std::string>
|
||||
GraphDiffInstrMap("instr-map",
|
||||
cl::desc("binary with the instrumentation map, or "
|
||||
"a separate instrumentation map for graph"),
|
||||
cl::value_desc("binary with xray_instr_map or yaml"),
|
||||
cl::sub(GraphDiff), cl::init(""));
|
||||
static cl::alias GraphDiffInstrMapA("m", cl::aliasopt(GraphDiffInstrMap),
|
||||
cl::desc("Alias for -instr-map"),
|
||||
cl::sub(GraphDiff));
|
||||
static cl::opt<std::string>
|
||||
GraphDiffInstrMap1("instr-map-1",
|
||||
cl::desc("binary with the instrumentation map, or "
|
||||
"a separate instrumentation map for graph 1"),
|
||||
cl::value_desc("binary with xray_instr_map or yaml"),
|
||||
cl::sub(GraphDiff), cl::init(""));
|
||||
static cl::alias GraphDiffInstrMap1A("m1", cl::aliasopt(GraphDiffInstrMap1),
|
||||
cl::desc("Alias for -instr-map-1"),
|
||||
cl::sub(GraphDiff));
|
||||
static cl::opt<std::string>
|
||||
GraphDiffInstrMap2("instr-map-2",
|
||||
cl::desc("binary with the instrumentation map, or "
|
||||
"a separate instrumentation map for graph 2"),
|
||||
cl::value_desc("binary with xray_instr_map or yaml"),
|
||||
cl::sub(GraphDiff), cl::init(""));
|
||||
static cl::alias GraphDiffInstrMap2A("m2", cl::aliasopt(GraphDiffInstrMap2),
|
||||
cl::desc("Alias for -instr-map-2"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<bool> GraphDiffDeduceSiblingCalls(
|
||||
"deduce-sibling-calls",
|
||||
cl::desc("Deduce sibling calls when unrolling function call stacks"),
|
||||
cl::sub(GraphDiff), cl::init(false));
|
||||
static cl::alias
|
||||
GraphDiffDeduceSiblingCallsA("d", cl::aliasopt(GraphDiffDeduceSiblingCalls),
|
||||
cl::desc("Alias for -deduce-sibling-calls"),
|
||||
cl::sub(GraphDiff));
|
||||
static cl::opt<bool> GraphDiffDeduceSiblingCalls1(
|
||||
"deduce-sibling-calls-1",
|
||||
cl::desc("Deduce sibling calls when unrolling function call stacks"),
|
||||
cl::sub(GraphDiff), cl::init(false));
|
||||
static cl::alias GraphDiffDeduceSiblingCalls1A(
|
||||
"d1", cl::aliasopt(GraphDiffDeduceSiblingCalls1),
|
||||
cl::desc("Alias for -deduce-sibling-calls-1"), cl::sub(GraphDiff));
|
||||
static cl::opt<bool> GraphDiffDeduceSiblingCalls2(
|
||||
"deduce-sibling-calls-2",
|
||||
cl::desc("Deduce sibling calls when unrolling function call stacks"),
|
||||
cl::sub(GraphDiff), cl::init(false));
|
||||
static cl::alias GraphDiffDeduceSiblingCalls2A(
|
||||
"d2", cl::aliasopt(GraphDiffDeduceSiblingCalls2),
|
||||
cl::desc("Alias for -deduce-sibling-calls-2"), cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<GraphRenderer::StatType> GraphDiffEdgeLabel(
|
||||
"edge-label", cl::desc("Output graphs with edges labeled with this field"),
|
||||
cl::value_desc("field"), cl::sub(GraphDiff),
|
||||
cl::init(GraphRenderer::StatType::NONE),
|
||||
cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
|
||||
"Do not label Edges"),
|
||||
clEnumValN(GraphRenderer::StatType::COUNT, "count",
|
||||
"function call counts"),
|
||||
clEnumValN(GraphRenderer::StatType::MIN, "min",
|
||||
"minimum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MED, "med",
|
||||
"median function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT90, "90p",
|
||||
"90th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT99, "99p",
|
||||
"99th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MAX, "max",
|
||||
"maximum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::SUM, "sum",
|
||||
"sum of call durations")));
|
||||
static cl::alias GraphDiffEdgeLabelA("e", cl::aliasopt(GraphDiffEdgeLabel),
|
||||
cl::desc("Alias for -edge-label"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<GraphRenderer::StatType> GraphDiffEdgeColor(
|
||||
"edge-color", cl::desc("Output graphs with edges colored by this field"),
|
||||
cl::value_desc("field"), cl::sub(GraphDiff),
|
||||
cl::init(GraphRenderer::StatType::NONE),
|
||||
cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
|
||||
"Do not color Edges"),
|
||||
clEnumValN(GraphRenderer::StatType::COUNT, "count",
|
||||
"function call counts"),
|
||||
clEnumValN(GraphRenderer::StatType::MIN, "min",
|
||||
"minimum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MED, "med",
|
||||
"median function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT90, "90p",
|
||||
"90th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT99, "99p",
|
||||
"99th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MAX, "max",
|
||||
"maximum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::SUM, "sum",
|
||||
"sum of call durations")));
|
||||
static cl::alias GraphDiffEdgeColorA("c", cl::aliasopt(GraphDiffEdgeColor),
|
||||
cl::desc("Alias for -edge-color"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<GraphRenderer::StatType> GraphDiffVertexLabel(
|
||||
"vertex-label",
|
||||
cl::desc("Output graphs with vertices labeled with this field"),
|
||||
cl::value_desc("field"), cl::sub(GraphDiff),
|
||||
cl::init(GraphRenderer::StatType::NONE),
|
||||
cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
|
||||
"Do not label Vertices"),
|
||||
clEnumValN(GraphRenderer::StatType::COUNT, "count",
|
||||
"function call counts"),
|
||||
clEnumValN(GraphRenderer::StatType::MIN, "min",
|
||||
"minimum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MED, "med",
|
||||
"median function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT90, "90p",
|
||||
"90th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT99, "99p",
|
||||
"99th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MAX, "max",
|
||||
"maximum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::SUM, "sum",
|
||||
"sum of call durations")));
|
||||
static cl::alias GraphDiffVertexLabelA("v", cl::aliasopt(GraphDiffVertexLabel),
|
||||
cl::desc("Alias for -vertex-label"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<GraphRenderer::StatType> GraphDiffVertexColor(
|
||||
"vertex-color",
|
||||
cl::desc("Output graphs with vertices colored by this field"),
|
||||
cl::value_desc("field"), cl::sub(GraphDiff),
|
||||
cl::init(GraphRenderer::StatType::NONE),
|
||||
cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
|
||||
"Do not color Vertices"),
|
||||
clEnumValN(GraphRenderer::StatType::COUNT, "count",
|
||||
"function call counts"),
|
||||
clEnumValN(GraphRenderer::StatType::MIN, "min",
|
||||
"minimum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MED, "med",
|
||||
"median function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT90, "90p",
|
||||
"90th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::PCT99, "99p",
|
||||
"99th percentile durations"),
|
||||
clEnumValN(GraphRenderer::StatType::MAX, "max",
|
||||
"maximum function durations"),
|
||||
clEnumValN(GraphRenderer::StatType::SUM, "sum",
|
||||
"sum of call durations")));
|
||||
static cl::alias GraphDiffVertexColorA("b", cl::aliasopt(GraphDiffVertexColor),
|
||||
cl::desc("Alias for -vertex-color"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<int> GraphDiffVertexLabelTrunc(
|
||||
"vertex-label-trun", cl::desc("What length to truncate vertex labels to "),
|
||||
cl::sub(GraphDiff), cl::init(40));
|
||||
static cl::alias
|
||||
GraphDiffVertexLabelTrunc1("t", cl::aliasopt(GraphDiffVertexLabelTrunc),
|
||||
cl::desc("Alias for -vertex-label-trun"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
static cl::opt<std::string>
|
||||
GraphDiffOutput("output", cl::value_desc("Output file"), cl::init("-"),
|
||||
cl::desc("output file; use '-' for stdout"),
|
||||
cl::sub(GraphDiff));
|
||||
static cl::alias GraphDiffOutputA("o", cl::aliasopt(GraphDiffOutput),
|
||||
cl::desc("Alias for -output"),
|
||||
cl::sub(GraphDiff));
|
||||
|
||||
Expected<GraphDiffRenderer> GraphDiffRenderer::Factory::getGraphDiffRenderer() {
|
||||
GraphDiffRenderer R;
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
const auto &G = this->G[i].get();
|
||||
for (const auto &V : G.vertices()) {
|
||||
const auto &VAttr = V.second;
|
||||
R.G[VAttr.SymbolName].CorrVertexPtr[i] = &V;
|
||||
}
|
||||
for (const auto &E : G.edges()) {
|
||||
auto &EdgeTailID = E.first.first;
|
||||
auto &EdgeHeadID = E.first.second;
|
||||
auto EdgeTailAttrOrErr = G.at(EdgeTailID);
|
||||
auto EdgeHeadAttrOrErr = G.at(EdgeHeadID);
|
||||
if (!EdgeTailAttrOrErr)
|
||||
return EdgeTailAttrOrErr.takeError();
|
||||
if (!EdgeHeadAttrOrErr)
|
||||
return EdgeHeadAttrOrErr.takeError();
|
||||
GraphT::EdgeIdentifier ID{EdgeTailAttrOrErr->SymbolName,
|
||||
EdgeHeadAttrOrErr->SymbolName};
|
||||
R.G[ID].CorrEdgePtr[i] = &E;
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
// Returns the Relative change With respect to LeftStat between LeftStat
|
||||
// and RightStat.
|
||||
static double statRelDiff(const GraphDiffRenderer::TimeStat &LeftStat,
|
||||
const GraphDiffRenderer::TimeStat &RightStat,
|
||||
GraphDiffRenderer::StatType T) {
|
||||
double LeftAttr = LeftStat.getDouble(T);
|
||||
double RightAttr = RightStat.getDouble(T);
|
||||
|
||||
return RightAttr / LeftAttr - 1.0;
|
||||
}
|
||||
|
||||
static std::string getColor(const GraphDiffRenderer::GraphT::EdgeValueType &E,
|
||||
const GraphDiffRenderer::GraphT &G, ColorHelper H,
|
||||
GraphDiffRenderer::StatType T) {
|
||||
auto &EdgeAttr = E.second;
|
||||
if (EdgeAttr.CorrEdgePtr[0] == nullptr)
|
||||
return H.getColorString(2.0); // A number greater than 1.0
|
||||
if (EdgeAttr.CorrEdgePtr[1] == nullptr)
|
||||
return H.getColorString(-2.0); // A number less than -1.0
|
||||
|
||||
if (T == GraphDiffRenderer::StatType::NONE)
|
||||
return H.getDefaultColorString();
|
||||
|
||||
const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
|
||||
const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
|
||||
|
||||
double RelDiff = statRelDiff(LeftStat, RightStat, T);
|
||||
double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
|
||||
|
||||
return H.getColorString(CappedRelDiff);
|
||||
}
|
||||
|
||||
static std::string getColor(const GraphDiffRenderer::GraphT::VertexValueType &V,
|
||||
const GraphDiffRenderer::GraphT &G, ColorHelper H,
|
||||
GraphDiffRenderer::StatType T) {
|
||||
auto &VertexAttr = V.second;
|
||||
if (VertexAttr.CorrVertexPtr[0] == nullptr)
|
||||
return H.getColorString(2.0); // A number greater than 1.0
|
||||
if (VertexAttr.CorrVertexPtr[1] == nullptr)
|
||||
return H.getColorString(-2.0); // A number less than -1.0
|
||||
|
||||
if (T == GraphDiffRenderer::StatType::NONE)
|
||||
return H.getDefaultColorString();
|
||||
|
||||
const auto &LeftStat = VertexAttr.CorrVertexPtr[0]->second.S;
|
||||
const auto &RightStat = VertexAttr.CorrVertexPtr[1]->second.S;
|
||||
|
||||
double RelDiff = statRelDiff(LeftStat, RightStat, T);
|
||||
double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
|
||||
|
||||
return H.getColorString(CappedRelDiff);
|
||||
}
|
||||
|
||||
static Twine truncateString(const StringRef &S, size_t n) {
|
||||
return (S.size() > n) ? Twine(S.substr(0, n)) + "..." : Twine(S);
|
||||
}
|
||||
|
||||
template <typename T> static bool containsNullptr(const T &Collection) {
|
||||
for (const auto &E : Collection)
|
||||
if (E == nullptr)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string getLabel(const GraphDiffRenderer::GraphT::EdgeValueType &E,
|
||||
GraphDiffRenderer::StatType EL) {
|
||||
auto &EdgeAttr = E.second;
|
||||
switch (EL) {
|
||||
case GraphDiffRenderer::StatType::NONE:
|
||||
return "";
|
||||
default:
|
||||
if (containsNullptr(EdgeAttr.CorrEdgePtr))
|
||||
return "";
|
||||
|
||||
const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
|
||||
const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
|
||||
|
||||
double RelDiff = statRelDiff(LeftStat, RightStat, EL);
|
||||
return formatv(R"({0:P})", RelDiff);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getLabel(const GraphDiffRenderer::GraphT::VertexValueType &V,
|
||||
GraphDiffRenderer::StatType VL, int TrunLen) {
|
||||
const auto &VertexId = V.first;
|
||||
const auto &VertexAttr = V.second;
|
||||
switch (VL) {
|
||||
case GraphDiffRenderer::StatType::NONE:
|
||||
return formatv(R"({0})", truncateString(VertexId, TrunLen).str());
|
||||
default:
|
||||
if (containsNullptr(VertexAttr.CorrVertexPtr))
|
||||
return formatv(R"({0})", truncateString(VertexId, TrunLen).str());
|
||||
|
||||
const auto &LeftStat = VertexAttr.CorrVertexPtr[0]->second.S;
|
||||
const auto &RightStat = VertexAttr.CorrVertexPtr[1]->second.S;
|
||||
|
||||
double RelDiff = statRelDiff(LeftStat, RightStat, VL);
|
||||
return formatv(R"({{{0}|{1:P}})", truncateString(VertexId, TrunLen).str(),
|
||||
RelDiff);
|
||||
}
|
||||
}
|
||||
|
||||
static double getLineWidth(const GraphDiffRenderer::GraphT::EdgeValueType &E,
|
||||
GraphDiffRenderer::StatType EL) {
|
||||
auto &EdgeAttr = E.second;
|
||||
switch (EL) {
|
||||
case GraphDiffRenderer::StatType::NONE:
|
||||
return 1.0;
|
||||
default:
|
||||
if (containsNullptr(EdgeAttr.CorrEdgePtr))
|
||||
return 1.0;
|
||||
|
||||
const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
|
||||
const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
|
||||
|
||||
double RelDiff = statRelDiff(LeftStat, RightStat, EL);
|
||||
return (RelDiff > 1.0) ? RelDiff : 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphDiffRenderer::exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel,
|
||||
StatType EdgeColor,
|
||||
StatType VertexLabel,
|
||||
StatType VertexColor, int TruncLen) {
|
||||
// Get numbering of vertices for dot output.
|
||||
StringMap<int32_t> VertexNo;
|
||||
|
||||
int i = 0;
|
||||
for (const auto &V : G.vertices()) {
|
||||
VertexNo[V.first] = i++;
|
||||
}
|
||||
|
||||
ColorHelper H(ColorHelper::DivergingScheme::PiYG);
|
||||
|
||||
OS << "digraph xrayDiff {\n";
|
||||
|
||||
if (VertexLabel != StatType::NONE)
|
||||
OS << "node [shape=record]\n";
|
||||
|
||||
for (const auto &E : G.edges()) {
|
||||
const auto &HeadId = E.first.first;
|
||||
const auto &TailId = E.first.second;
|
||||
OS << formatv(R"(F{0} -> F{1} [tooltip="{2} -> {3}" label="{4}" )"
|
||||
R"(color="{5}" labelfontcolor="{5}" penwidth={6}])"
|
||||
"\n",
|
||||
VertexNo[HeadId], VertexNo[TailId],
|
||||
(HeadId.equals("")) ? static_cast<StringRef>("F0") : HeadId,
|
||||
TailId, getLabel(E, EdgeLabel), getColor(E, G, H, EdgeColor),
|
||||
getLineWidth(E, EdgeColor));
|
||||
}
|
||||
|
||||
for (const auto &V : G.vertices()) {
|
||||
const auto &VertexId = V.first;
|
||||
if (VertexId.equals("")) {
|
||||
OS << formatv(R"(F{0} [label="F0"])"
|
||||
"\n",
|
||||
VertexNo[VertexId]);
|
||||
continue;
|
||||
}
|
||||
OS << formatv(R"(F{0} [label="{1}" color="{2}"])"
|
||||
"\n",
|
||||
VertexNo[VertexId], getLabel(V, VertexLabel, TruncLen),
|
||||
getColor(V, G, H, VertexColor));
|
||||
}
|
||||
|
||||
OS << "}\n";
|
||||
}
|
||||
|
||||
template <typename T> static T &ifSpecified(T &A, cl::alias &AA, T &B) {
|
||||
if (A.getPosition() == 0 && AA.getPosition() == 0)
|
||||
return B;
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
static CommandRegistration Unused(&GraphDiff, []() -> Error {
|
||||
std::array<GraphRenderer::Factory, 2> Factories{
|
||||
{{ifSpecified(GraphDiffKeepGoing1, GraphDiffKeepGoing1A,
|
||||
GraphDiffKeepGoing),
|
||||
ifSpecified(GraphDiffDeduceSiblingCalls1, GraphDiffDeduceSiblingCalls1A,
|
||||
GraphDiffDeduceSiblingCalls),
|
||||
ifSpecified(GraphDiffInstrMap1, GraphDiffInstrMap1A, GraphDiffInstrMap),
|
||||
Trace()},
|
||||
{ifSpecified(GraphDiffKeepGoing2, GraphDiffKeepGoing2A,
|
||||
GraphDiffKeepGoing),
|
||||
ifSpecified(GraphDiffDeduceSiblingCalls2, GraphDiffDeduceSiblingCalls2A,
|
||||
GraphDiffDeduceSiblingCalls),
|
||||
ifSpecified(GraphDiffInstrMap2, GraphDiffInstrMap2A, GraphDiffInstrMap),
|
||||
Trace()}}};
|
||||
|
||||
std::array<std::string, 2> Inputs{{GraphDiffInput1, GraphDiffInput2}};
|
||||
|
||||
std::array<GraphRenderer::GraphT, 2> Graphs;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
auto TraceOrErr = loadTraceFile(Inputs[i], true);
|
||||
if (!TraceOrErr)
|
||||
return make_error<StringError>(
|
||||
Twine("Failed Loading Input File '") + Inputs[i] + "'",
|
||||
make_error_code(llvm::errc::invalid_argument));
|
||||
Factories[i].Trace = std::move(*TraceOrErr);
|
||||
|
||||
auto GraphRendererOrErr = Factories[i].getGraphRenderer();
|
||||
|
||||
if (!GraphRendererOrErr)
|
||||
return GraphRendererOrErr.takeError();
|
||||
|
||||
auto GraphRenderer = *GraphRendererOrErr;
|
||||
|
||||
Graphs[i] = GraphRenderer.getGraph();
|
||||
}
|
||||
|
||||
GraphDiffRenderer::Factory DGF(Graphs[0], Graphs[1]);
|
||||
|
||||
auto GDROrErr = DGF.getGraphDiffRenderer();
|
||||
if (!GDROrErr)
|
||||
return GDROrErr.takeError();
|
||||
|
||||
auto &GDR = *GDROrErr;
|
||||
|
||||
std::error_code EC;
|
||||
raw_fd_ostream OS(GraphDiffOutput, EC, sys::fs::OpenFlags::F_Text);
|
||||
if (EC)
|
||||
return make_error<StringError>(
|
||||
Twine("Cannot open file '") + GraphDiffOutput + "' for writing.", EC);
|
||||
|
||||
GDR.exportGraphAsDOT(OS, GraphDiffEdgeLabel, GraphDiffEdgeColor,
|
||||
GraphDiffVertexLabel, GraphDiffVertexColor,
|
||||
GraphDiffVertexLabelTrunc);
|
||||
|
||||
return Error::success();
|
||||
});
|
74
external/llvm/tools/llvm-xray/xray-graph-diff.h
vendored
74
external/llvm/tools/llvm-xray/xray-graph-diff.h
vendored
@ -1,74 +0,0 @@
|
||||
//===-- xray-graph-diff.h - XRay Graph Diff Renderer ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Generate a DOT file to represent the difference between the function call
|
||||
// graph of two differnent traces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef XRAY_GRAPH_DIFF_H
|
||||
#define XRAY_GRAPH_DIFF_H
|
||||
|
||||
#include "xray-graph.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/XRay/Graph.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
// This class creates a graph representing the difference between two
|
||||
// xray-graphs And allows you to print it to a dot file, with optional color
|
||||
// coding.
|
||||
class GraphDiffRenderer {
|
||||
static const int N = 2;
|
||||
|
||||
public:
|
||||
using StatType = GraphRenderer::StatType;
|
||||
using TimeStat = GraphRenderer::TimeStat;
|
||||
|
||||
using GREdgeValueType = GraphRenderer::GraphT::EdgeValueType;
|
||||
using GRVertexValueType = GraphRenderer::GraphT::VertexValueType;
|
||||
|
||||
struct EdgeAttribute {
|
||||
std::array<const GREdgeValueType *, N> CorrEdgePtr = {};
|
||||
};
|
||||
|
||||
struct VertexAttribute {
|
||||
std::array<const GRVertexValueType *, N> CorrVertexPtr = {};
|
||||
};
|
||||
|
||||
using GraphT = Graph<VertexAttribute, EdgeAttribute, StringRef>;
|
||||
|
||||
class Factory {
|
||||
std::array<std::reference_wrapper<const GraphRenderer::GraphT>, N> G;
|
||||
|
||||
public:
|
||||
template <typename... Ts> Factory(Ts &... Args) : G{{Args...}} {}
|
||||
|
||||
Expected<GraphDiffRenderer> getGraphDiffRenderer();
|
||||
};
|
||||
|
||||
private:
|
||||
GraphT G;
|
||||
|
||||
GraphDiffRenderer() = default;
|
||||
|
||||
public:
|
||||
void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
|
||||
StatType EdgeColor = StatType::NONE,
|
||||
StatType VertexLabel = StatType::NONE,
|
||||
StatType VertexColor = StatType::NONE,
|
||||
int TruncLen = 40);
|
||||
|
||||
const GraphT &getGraph() { return G; }
|
||||
};
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
516
external/llvm/tools/llvm-xray/xray-graph.cc
vendored
516
external/llvm/tools/llvm-xray/xray-graph.cc
vendored
File diff suppressed because it is too large
Load Diff
233
external/llvm/tools/llvm-xray/xray-graph.h
vendored
233
external/llvm/tools/llvm-xray/xray-graph.h
vendored
@ -1,233 +0,0 @@
|
||||
//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Generate a DOT file to represent the function call graph encountered in
|
||||
// the trace.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef XRAY_GRAPH_H
|
||||
#define XRAY_GRAPH_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "func-id-helper.h"
|
||||
#include "xray-color-helper.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/XRay/Graph.h"
|
||||
#include "llvm/XRay/Trace.h"
|
||||
#include "llvm/XRay/XRayRecord.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
/// A class encapsulating the logic related to analyzing XRay traces, producting
|
||||
/// Graphs from them and then exporting those graphs for review.
|
||||
class GraphRenderer {
|
||||
public:
|
||||
/// An enum for enumerating the various statistics gathered on latencies
|
||||
enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM };
|
||||
|
||||
/// An inner struct for common timing statistics information
|
||||
struct TimeStat {
|
||||
int64_t Count;
|
||||
double Min;
|
||||
double Median;
|
||||
double Pct90;
|
||||
double Pct99;
|
||||
double Max;
|
||||
double Sum;
|
||||
|
||||
std::string getString(StatType T) const;
|
||||
double getDouble(StatType T) const;
|
||||
};
|
||||
using TimestampT = uint64_t;
|
||||
|
||||
/// An inner struct for storing edge attributes for our graph. Here the
|
||||
/// attributes are mainly function call statistics.
|
||||
///
|
||||
/// FIXME: expand to contain more information eg call latencies.
|
||||
struct CallStats {
|
||||
TimeStat S;
|
||||
std::vector<TimestampT> Timings;
|
||||
};
|
||||
|
||||
/// An Inner Struct for storing vertex attributes, at the moment just
|
||||
/// SymbolNames, however in future we could store bulk function statistics.
|
||||
///
|
||||
/// FIXME: Store more attributes based on instrumentation map.
|
||||
struct FunctionStats {
|
||||
std::string SymbolName;
|
||||
TimeStat S = {};
|
||||
};
|
||||
|
||||
struct FunctionAttr {
|
||||
int32_t FuncId;
|
||||
uint64_t TSC;
|
||||
};
|
||||
|
||||
using FunctionStack = SmallVector<FunctionAttr, 4>;
|
||||
|
||||
using PerThreadFunctionStackMap =
|
||||
DenseMap<llvm::sys::ProcessInfo::ProcessId, FunctionStack>;
|
||||
|
||||
class GraphT : public Graph<FunctionStats, CallStats, int32_t> {
|
||||
public:
|
||||
TimeStat GraphEdgeMax = {};
|
||||
TimeStat GraphVertexMax = {};
|
||||
};
|
||||
|
||||
GraphT G;
|
||||
using VertexIdentifier = typename decltype(G)::VertexIdentifier;
|
||||
using EdgeIdentifier = decltype(G)::EdgeIdentifier;
|
||||
|
||||
/// Use a Map to store the Function stack for each thread whilst building the
|
||||
/// graph.
|
||||
///
|
||||
/// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa?
|
||||
PerThreadFunctionStackMap PerThreadFunctionStack;
|
||||
|
||||
/// Usefull object for getting human readable Symbol Names.
|
||||
FuncIdConversionHelper FuncIdHelper;
|
||||
bool DeduceSiblingCalls = false;
|
||||
TimestampT CurrentMaxTSC = 0;
|
||||
|
||||
/// A private function to help implement the statistic generation functions;
|
||||
template <typename U>
|
||||
void getStats(U begin, U end, GraphRenderer::TimeStat &S);
|
||||
void updateMaxStats(const TimeStat &S, TimeStat &M);
|
||||
|
||||
/// Calculates latency statistics for each edge and stores the data in the
|
||||
/// Graph
|
||||
void calculateEdgeStatistics();
|
||||
|
||||
/// Calculates latency statistics for each vertex and stores the data in the
|
||||
/// Graph
|
||||
void calculateVertexStatistics();
|
||||
|
||||
/// Normalises latency statistics for each edge and vertex by CycleFrequency;
|
||||
void normalizeStatistics(double CycleFrequency);
|
||||
|
||||
/// An object to color gradients
|
||||
ColorHelper CHelper;
|
||||
|
||||
public:
|
||||
/// Takes in a reference to a FuncIdHelper in order to have ready access to
|
||||
/// Symbol names.
|
||||
explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC)
|
||||
: FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC),
|
||||
CHelper(ColorHelper::SequentialScheme::OrRd) {
|
||||
G[0] = {};
|
||||
}
|
||||
|
||||
/// Process an Xray record and expand the graph.
|
||||
///
|
||||
/// This Function will return true on success, or false if records are not
|
||||
/// presented in per-thread call-tree DFS order. (That is for each thread the
|
||||
/// Records should be in order runtime on an ideal system.)
|
||||
///
|
||||
/// FIXME: Make this more robust against small irregularities.
|
||||
Error accountRecord(const XRayRecord &Record);
|
||||
|
||||
const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
|
||||
return PerThreadFunctionStack;
|
||||
}
|
||||
|
||||
class Factory {
|
||||
public:
|
||||
bool KeepGoing;
|
||||
bool DeduceSiblingCalls;
|
||||
std::string InstrMap;
|
||||
::llvm::xray::Trace Trace;
|
||||
Expected<GraphRenderer> getGraphRenderer();
|
||||
};
|
||||
|
||||
/// Output the Embedded graph in DOT format on \p OS, labeling the edges by
|
||||
/// \p T
|
||||
void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
|
||||
StatType EdgeColor = StatType::NONE,
|
||||
StatType VertexLabel = StatType::NONE,
|
||||
StatType VertexColor = StatType::NONE);
|
||||
|
||||
/// Get a reference to the internal graph.
|
||||
const GraphT &getGraph() { return G; }
|
||||
};
|
||||
|
||||
/// Vector Sum of TimeStats
|
||||
inline GraphRenderer::TimeStat operator+(const GraphRenderer::TimeStat &A,
|
||||
const GraphRenderer::TimeStat &B) {
|
||||
return {A.Count + B.Count, A.Min + B.Min, A.Median + B.Median,
|
||||
A.Pct90 + B.Pct90, A.Pct99 + B.Pct99, A.Max + B.Max,
|
||||
A.Sum + B.Sum};
|
||||
}
|
||||
|
||||
/// Vector Difference of Timestats
|
||||
inline GraphRenderer::TimeStat operator-(const GraphRenderer::TimeStat &A,
|
||||
const GraphRenderer::TimeStat &B) {
|
||||
|
||||
return {A.Count - B.Count, A.Min - B.Min, A.Median - B.Median,
|
||||
A.Pct90 - B.Pct90, A.Pct99 - B.Pct99, A.Max - B.Max,
|
||||
A.Sum - B.Sum};
|
||||
}
|
||||
|
||||
/// Scalar Diference of TimeStat and double
|
||||
inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
|
||||
double B) {
|
||||
|
||||
return {static_cast<int64_t>(A.Count / B),
|
||||
A.Min / B,
|
||||
A.Median / B,
|
||||
A.Pct90 / B,
|
||||
A.Pct99 / B,
|
||||
A.Max / B,
|
||||
A.Sum / B};
|
||||
}
|
||||
|
||||
/// Scalar product of TimeStat and Double
|
||||
inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
|
||||
double B) {
|
||||
return {static_cast<int64_t>(A.Count * B),
|
||||
A.Min * B,
|
||||
A.Median * B,
|
||||
A.Pct90 * B,
|
||||
A.Pct99 * B,
|
||||
A.Max * B,
|
||||
A.Sum * B};
|
||||
}
|
||||
|
||||
/// Scalar product of double TimeStat
|
||||
inline GraphRenderer::TimeStat operator*(double A,
|
||||
const GraphRenderer::TimeStat &B) {
|
||||
return B * A;
|
||||
}
|
||||
|
||||
/// Hadamard Product of TimeStats
|
||||
inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
|
||||
const GraphRenderer::TimeStat &B) {
|
||||
return {A.Count * B.Count, A.Min * B.Min, A.Median * B.Median,
|
||||
A.Pct90 * B.Pct90, A.Pct99 * B.Pct99, A.Max * B.Max,
|
||||
A.Sum * B.Sum};
|
||||
}
|
||||
|
||||
/// Hadamard Division of TimeStats
|
||||
inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
|
||||
const GraphRenderer::TimeStat &B) {
|
||||
return {A.Count / B.Count, A.Min / B.Min, A.Median / B.Median,
|
||||
A.Pct90 / B.Pct90, A.Pct99 / B.Pct99, A.Max / B.Max,
|
||||
A.Sum / B.Sum};
|
||||
}
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
||||
|
||||
#endif // XRAY_GRAPH_H
|
41
external/llvm/tools/llvm-xray/xray-registry.cc
vendored
41
external/llvm/tools/llvm-xray/xray-registry.cc
vendored
@ -1,41 +0,0 @@
|
||||
//===- xray-registry.cc - Implement a command registry. -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implement a simple subcommand registry.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "xray-registry.h"
|
||||
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
using HandlerType = std::function<Error()>;
|
||||
|
||||
ManagedStatic<std::unordered_map<cl::SubCommand *, HandlerType>> Commands;
|
||||
|
||||
CommandRegistration::CommandRegistration(cl::SubCommand *SC,
|
||||
HandlerType Command) {
|
||||
assert(Commands->count(SC) == 0 &&
|
||||
"Attempting to overwrite a command handler");
|
||||
assert(Command && "Attempting to register an empty std::function<Error()>");
|
||||
(*Commands)[SC] = Command;
|
||||
}
|
||||
|
||||
HandlerType dispatch(cl::SubCommand *SC) {
|
||||
auto It = Commands->find(SC);
|
||||
assert(It != Commands->end() &&
|
||||
"Attempting to dispatch on un-registered SubCommand.");
|
||||
return It->second;
|
||||
}
|
||||
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
41
external/llvm/tools/llvm-xray/xray-registry.h
vendored
41
external/llvm/tools/llvm-xray/xray-registry.h
vendored
@ -1,41 +0,0 @@
|
||||
//===- xray-registry.h - Define registry mechanism for commands. ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implement a simple subcommand registry.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef TOOLS_LLVM_XRAY_XRAY_REGISTRY_H
|
||||
#define TOOLS_LLVM_XRAY_XRAY_REGISTRY_H
|
||||
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace xray {
|
||||
|
||||
// Use |CommandRegistration| as a global initialiser that registers a function
|
||||
// and associates it with |SC|. This requires that a command has not been
|
||||
// registered to a given |SC|.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // At namespace scope.
|
||||
// static CommandRegistration Unused(&MySubCommand, [] { ... });
|
||||
//
|
||||
struct CommandRegistration {
|
||||
CommandRegistration(cl::SubCommand *SC, std::function<Error()> Command);
|
||||
};
|
||||
|
||||
// Requires that |SC| is not null and has an associated function to it.
|
||||
std::function<Error()> dispatch(cl::SubCommand *SC);
|
||||
|
||||
} // namespace xray
|
||||
} // namespace llvm
|
||||
|
||||
#endif // TOOLS_LLVM_XRAY_XRAY_REGISTRY_H
|
797
external/llvm/tools/llvm-xray/xray-stacks.cc
vendored
797
external/llvm/tools/llvm-xray/xray-stacks.cc
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user