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/FileSystem.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
@ -234,31 +235,6 @@ StackTrieNode *findOrCreateStackNode(
|
|||
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
|
||||
|
||||
void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
||||
|
@ -269,18 +245,14 @@ void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
|||
|
||||
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";
|
||||
|
||||
// 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.
|
||||
// CyclesPerMicro = CycleHertz / 10^6
|
||||
// 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,
|
||||
// timestamp in microseconds, and a stack frame id. The ids are logged
|
||||
// in an id dictionary after the events.
|
||||
writeTraceViewerRecord(Version, OS, R.FuncId, R.TId, R.PId, Symbolize,
|
||||
FuncIdHelper, EventTimestampUs, *StackCursor, "B");
|
||||
TraceEvents.push_back(json::Object({
|
||||
{"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;
|
||||
case RecordTypes::EXIT:
|
||||
case RecordTypes::TAIL_EXIT:
|
||||
|
@ -313,43 +292,51 @@ void TraceConverter::exportAsChromeTraceEventFormat(const Trace &Records,
|
|||
// (And/Or in loop termination below)
|
||||
StackTrieNode *PreviousCursor = nullptr;
|
||||
do {
|
||||
if (PreviousCursor != nullptr) {
|
||||
OS << ",\n";
|
||||
}
|
||||
writeTraceViewerRecord(Version, OS, StackCursor->FuncId, R.TId, R.PId,
|
||||
Symbolize, FuncIdHelper, EventTimestampUs,
|
||||
*StackCursor, "E");
|
||||
TraceEvents.push_back(json::Object({
|
||||
{"name", Symbolize
|
||||
? FuncIdHelper.SymbolOrNumber(StackCursor->FuncId)
|
||||
: llvm::to_string(StackCursor->FuncId)},
|
||||
{"ph", "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;
|
||||
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 << " }";
|
||||
json::Object StackFrames;
|
||||
for (const auto &Stack : StacksByStackId) {
|
||||
const auto &StackId = Stack.first;
|
||||
const auto &StackFunctionNode = Stack.second;
|
||||
json::Object::iterator It;
|
||||
std::tie(It, std::ignore) = StackFrames.insert({
|
||||
llvm::to_string(StackId),
|
||||
json::Object{
|
||||
{"name",
|
||||
Symbolize ? FuncIdHelper.SymbolOrNumber(StackFunctionNode->FuncId)
|
||||
: llvm::to_string(StackFunctionNode->FuncId)}},
|
||||
});
|
||||
|
||||
if (StackFunctionNode->Parent != nullptr)
|
||||
It->second.getAsObject()->insert(
|
||||
{"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 {
|
||||
|
|
Loading…
Reference in New Issue