forked from OSchip/llvm-project
[XRay][tools] Use Support/JSON.h in llvm-xray convert
Summary: This change removes the ad-hoc implementation used by llvm-xray's `convert` subcommand to generate JSON encoded catapult (AKA Chrome Trace Viewer) trace output, to instead use the JSON encoder now in the Support library. Reviewers: kpw, zturner, eizan Reviewed By: kpw Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D50129 llvm-svn: 338834
This commit is contained in:
parent
4014fb1049
commit
2c4dcf0576
llvm/tools/llvm-xray
|
@ -18,6 +18,7 @@
|
||||||
#include "llvm/Support/EndianStream.h"
|
#include "llvm/Support/EndianStream.h"
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
#include "llvm/Support/FormatVariadic.h"
|
#include "llvm/Support/FormatVariadic.h"
|
||||||
|
#include "llvm/Support/JSON.h"
|
||||||
#include "llvm/Support/ScopedPrinter.h"
|
#include "llvm/Support/ScopedPrinter.h"
|
||||||
#include "llvm/Support/YAMLTraits.h"
|
#include "llvm/Support/YAMLTraits.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
@ -234,31 +235,6 @@ StackTrieNode *findOrCreateStackNode(
|
||||||
return CurrentStack;
|
return CurrentStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeTraceViewerRecord(uint16_t Version, raw_ostream &OS, int32_t FuncId,
|
|
||||||
uint32_t TId, uint32_t PId, bool Symbolize,
|
|
||||||
const FuncIdConversionHelper &FuncIdHelper,
|
|
||||||
double EventTimestampUs,
|
|
||||||
const StackTrieNode &StackCursor,
|
|
||||||
StringRef FunctionPhenotype) {
|
|
||||||
OS << " ";
|
|
||||||
if (Version >= 3) {
|
|
||||||
OS << llvm::formatv(
|
|
||||||
R"({ "name" : "{0}", "ph" : "{1}", "tid" : "{2}", "pid" : "{3}", )"
|
|
||||||
R"("ts" : "{4:f4}", "sf" : "{5}" })",
|
|
||||||
(Symbolize ? FuncIdHelper.SymbolOrNumber(FuncId)
|
|
||||||
: llvm::to_string(FuncId)),
|
|
||||||
FunctionPhenotype, TId, PId, EventTimestampUs,
|
|
||||||
StackCursor.ExtraData.id);
|
|
||||||
} else {
|
|
||||||
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
|
} // namespace
|
||||||
|
|
||||||
void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
||||||
|
@ -269,18 +245,14 @@ void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
||||||
|
|
||||||
unsigned id_counter = 0;
|
unsigned id_counter = 0;
|
||||||
|
|
||||||
OS << "{\n \"traceEvents\": [";
|
|
||||||
DenseMap<uint32_t, StackTrieNode *> StackCursorByThreadId{};
|
DenseMap<uint32_t, StackTrieNode *> StackCursorByThreadId{};
|
||||||
DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> StackRootsByThreadId{};
|
DenseMap<uint32_t, SmallVector<StackTrieNode *, 4>> StackRootsByThreadId{};
|
||||||
DenseMap<unsigned, StackTrieNode *> StacksByStackId{};
|
DenseMap<unsigned, StackTrieNode *> StacksByStackId{};
|
||||||
std::forward_list<StackTrieNode> NodeStore{};
|
std::forward_list<StackTrieNode> NodeStore{};
|
||||||
int loop_count = 0;
|
|
||||||
for (const auto &R : Records) {
|
|
||||||
if (loop_count++ == 0)
|
|
||||||
OS << "\n";
|
|
||||||
else
|
|
||||||
OS << ",\n";
|
|
||||||
|
|
||||||
|
// Create a JSON Array which will hold all trace events.
|
||||||
|
json::Array TraceEvents;
|
||||||
|
for (const auto &R : Records) {
|
||||||
// Chrome trace event format always wants data in micros.
|
// Chrome trace event format always wants data in micros.
|
||||||
// CyclesPerMicro = CycleHertz / 10^6
|
// CyclesPerMicro = CycleHertz / 10^6
|
||||||
// TSC / CyclesPerMicro == TSC * 10^6 / CycleHertz == MicroTimestamp
|
// TSC / CyclesPerMicro == TSC * 10^6 / CycleHertz == MicroTimestamp
|
||||||
|
@ -301,8 +273,15 @@ void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
||||||
// type of B for begin or E for end, thread id, process id,
|
// type of B for begin or E for end, thread id, process id,
|
||||||
// timestamp in microseconds, and a stack frame id. The ids are logged
|
// timestamp in microseconds, and a stack frame id. The ids are logged
|
||||||
// in an id dictionary after the events.
|
// in an id dictionary after the events.
|
||||||
writeTraceViewerRecord(Version, OS, R.FuncId, R.TId, R.PId, Symbolize,
|
TraceEvents.push_back(json::Object({
|
||||||
FuncIdHelper, EventTimestampUs, *StackCursor, "B");
|
{"name", Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId)
|
||||||
|
: llvm::to_string(R.FuncId)},
|
||||||
|
{"ph", "B"},
|
||||||
|
{"tid", llvm::to_string(R.TId)},
|
||||||
|
{"pid", llvm::to_string(Version >= 3 ? R.PId : 1)},
|
||||||
|
{"ts", llvm::formatv("{0:f4}", EventTimestampUs)},
|
||||||
|
{"sf", llvm::to_string(StackCursor->ExtraData.id)},
|
||||||
|
}));
|
||||||
break;
|
break;
|
||||||
case RecordTypes::EXIT:
|
case RecordTypes::EXIT:
|
||||||
case RecordTypes::TAIL_EXIT:
|
case RecordTypes::TAIL_EXIT:
|
||||||
|
@ -313,43 +292,51 @@ void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
||||||
// (And/Or in loop termination below)
|
// (And/Or in loop termination below)
|
||||||
StackTrieNode *PreviousCursor = nullptr;
|
StackTrieNode *PreviousCursor = nullptr;
|
||||||
do {
|
do {
|
||||||
if (PreviousCursor != nullptr) {
|
TraceEvents.push_back(json::Object({
|
||||||
OS << ",\n";
|
{"name", Symbolize
|
||||||
}
|
? FuncIdHelper.SymbolOrNumber(StackCursor->FuncId)
|
||||||
writeTraceViewerRecord(Version, OS, StackCursor->FuncId, R.TId, R.PId,
|
: llvm::to_string(StackCursor->FuncId)},
|
||||||
Symbolize, FuncIdHelper, EventTimestampUs,
|
{"ph", "E"},
|
||||||
*StackCursor, "E");
|
{"tid", llvm::to_string(R.TId)},
|
||||||
|
{"pid", llvm::to_string(Version >= 3 ? R.PId : 1)},
|
||||||
|
{"ts", llvm::formatv("{0:f4}", EventTimestampUs)},
|
||||||
|
{"sf", llvm::to_string(StackCursor->ExtraData.id)},
|
||||||
|
}));
|
||||||
PreviousCursor = StackCursor;
|
PreviousCursor = StackCursor;
|
||||||
StackCursor = StackCursor->Parent;
|
StackCursor = StackCursor->Parent;
|
||||||
} while (PreviousCursor->FuncId != R.FuncId && StackCursor != nullptr);
|
} while (PreviousCursor->FuncId != R.FuncId && StackCursor != nullptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OS << "\n ],\n"; // Close the Trace Events array.
|
|
||||||
OS << " "
|
|
||||||
<< "\"displayTimeUnit\": \"ns\",\n";
|
|
||||||
|
|
||||||
// The stackFrames dictionary substantially reduces size of the output file by
|
// The stackFrames dictionary substantially reduces size of the output file by
|
||||||
// avoiding repeating the entire call stack of function names for each entry.
|
// avoiding repeating the entire call stack of function names for each entry.
|
||||||
OS << R"( "stackFrames": {)";
|
json::Object StackFrames;
|
||||||
int stack_frame_count = 0;
|
for (const auto &Stack : StacksByStackId) {
|
||||||
for (auto map_iter : StacksByStackId) {
|
const auto &StackId = Stack.first;
|
||||||
if (stack_frame_count++ == 0)
|
const auto &StackFunctionNode = Stack.second;
|
||||||
OS << "\n";
|
json::Object::iterator It;
|
||||||
else
|
std::tie(It, std::ignore) = StackFrames.insert({
|
||||||
OS << ",\n";
|
llvm::to_string(StackId),
|
||||||
OS << " ";
|
json::Object{
|
||||||
OS << llvm::formatv(
|
{"name",
|
||||||
R"("{0}" : { "name" : "{1}")", map_iter.first,
|
Symbolize ? FuncIdHelper.SymbolOrNumber(StackFunctionNode->FuncId)
|
||||||
(Symbolize ? FuncIdHelper.SymbolOrNumber(map_iter.second->FuncId)
|
: llvm::to_string(StackFunctionNode->FuncId)}},
|
||||||
: llvm::to_string(map_iter.second->FuncId)));
|
});
|
||||||
if (map_iter.second->Parent != nullptr)
|
|
||||||
OS << llvm::formatv(R"(, "parent": "{0}")",
|
if (StackFunctionNode->Parent != nullptr)
|
||||||
map_iter.second->Parent->ExtraData.id);
|
It->second.getAsObject()->insert(
|
||||||
OS << " }";
|
{"parent", llvm::to_string(StackFunctionNode->Parent->ExtraData.id)});
|
||||||
}
|
}
|
||||||
OS << "\n }\n"; // Close the stack frames map.
|
|
||||||
OS << "}\n"; // Close the JSON entry.
|
json::Object TraceJSON{
|
||||||
|
{"displayTimeUnit", "ns"},
|
||||||
|
{"traceEvents", std::move(TraceEvents)},
|
||||||
|
{"stackFrames", std::move(StackFrames)},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pretty-print the JSON using two spaces for indentations.
|
||||||
|
OS << formatv("{0:2}", json::Value(std::move(TraceJSON)));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
Loading…
Reference in New Issue