[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:
Dean Michael Berris 2018-08-03 09:21:31 +00:00
parent 4014fb1049
commit 2c4dcf0576
1 changed files with 48 additions and 61 deletions
llvm/tools/llvm-xray

View File

@ -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 {