11 #include "llvm/ADT/DenseSet.h"
12 #include "llvm/ADT/Optional.h"
13 #include "llvm/ADT/ScopeExit.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/Chrono.h"
16 #include "llvm/Support/FormatProviders.h"
17 #include "llvm/Support/FormatVariadic.h"
18 #include "llvm/Support/Threading.h"
33 JSONTracer(llvm::raw_ostream &
OS,
bool Pretty)
34 :
Out(
OS, Pretty ? 2 : 0), Start(std::chrono::system_clock::now()) {
38 Out.attribute(
"displayTimeUnit",
"ns");
39 Out.attributeBegin(
"traceEvents");
41 rawEvent(
"M", llvm::json::Object{
42 {
"name",
"process_name"},
43 {
"args", llvm::json::Object{{
"name",
"clangd"}}},
56 Context beginSpan(llvm::StringRef
Name, llvm::json::Object *Args)
override {
58 SpanKey, std::make_unique<JSONSpan>(
this,
Name, Args));
65 void endSpan()
override {
69 void instant(llvm::StringRef
Name, llvm::json::Object &&Args)
override {
70 captureThreadMetadata();
72 llvm::json::Object{{
"name",
Name}, {
"args", std::move(Args)}});
77 void jsonEvent(llvm::StringRef Phase, llvm::json::Object &&
Contents,
78 uint64_t TID = llvm::get_threadid(),
double Timestamp = 0) {
79 Contents[
"ts"] = Timestamp ? Timestamp : timestamp();
81 std::lock_guard<std::mutex> Lock(Mu);
88 JSONSpan(JSONTracer *
Tracer, llvm::StringRef
Name, llvm::json::Object *Args)
92 Tracer->captureThreadMetadata();
103 double OriginTime = (*Parent)->EndTime;
105 OriginTime = (*Parent)->StartTime;
107 auto FlowID = nextID();
110 llvm::json::Object{{
"id", FlowID},
111 {
"name",
"Context crosses threads"},
113 (*Parent)->TID, (*Parent)->StartTime);
116 llvm::json::Object{{
"id", FlowID},
118 {
"name",
"Context crosses threads"},
127 llvm::json::Object{{
"name", std::move(
Name)},
128 {
"args", std::move(*Args)},
129 {
"dur", EndTime - StartTime}},
134 void markEnded() { EndTime =
Tracer->timestamp(); }
137 static int64_t nextID() {
138 static std::atomic<int64_t> Next = {0};
143 std::atomic<double> EndTime;
147 llvm::json::Object *Args;
153 void rawEvent(llvm::StringRef Phase,
154 const llvm::json::Object &
Event) {
157 Out.attribute(
"pid", 0);
158 Out.attribute(
"ph", Phase);
159 for (
const auto &KV :
Event)
160 Out.attribute(KV.first, KV.second);
165 void captureThreadMetadata() {
166 uint64_t TID = llvm::get_threadid();
167 std::lock_guard<std::mutex> Lock(Mu);
168 if (ThreadsWithMD.insert(TID).second) {
169 llvm::SmallString<32>
Name;
170 llvm::get_thread_name(
Name);
172 rawEvent(
"M", llvm::json::Object{
173 {
"tid", int64_t(TID)},
174 {
"name",
"thread_name"},
175 {
"args", llvm::json::Object{{
"name",
Name}}},
182 using namespace std::chrono;
183 return duration<double, std::micro>(system_clock::now() - Start).count();
187 llvm::json::OStream
Out ;
188 llvm::DenseSet<uint64_t> ThreadsWithMD ;
189 const llvm::sys::TimePoint<> Start;
196 CSVMetricTracer(llvm::raw_ostream &
Out) :
Out(
Out) {
197 Start = std::chrono::steady_clock::now();
200 Out <<
"Kind,Metric,Label,Value,Timestamp\r\n";
204 llvm::StringRef Label)
override {
206 std::string QuotedLabel;
207 if (needsQuote(Label))
208 Label = QuotedLabel = quote(Label);
209 uint64_t Micros = std::chrono::duration_cast<std::chrono::microseconds>(
210 std::chrono::steady_clock::now() - Start)
212 std::lock_guard<std::mutex> Lock(Mu);
213 Out << llvm::formatv(
"{0},{1},{2},{3:e},{4}.{5:6}\r\n",
215 Micros / 1000000, Micros % 1000000);
228 llvm_unreachable(
"Unknown Metric::MetricType enum");
231 static bool needsQuote(llvm::StringRef
Text) {
233 return Text.find_first_of(
",\"\r\n") != llvm::StringRef::npos;
236 std::string quote(llvm::StringRef
Text) {
237 std::string Result =
"\"";
238 for (
char C :
Text) {
241 Result.push_back(
'"');
243 Result.push_back(
'"');
249 llvm::raw_ostream &
Out ;
250 std::chrono::steady_clock::time_point Start;
259 assert(!T &&
"Resetting global tracer is not allowed.");
267 return std::make_unique<JSONTracer>(
OS, Pretty);
271 return std::make_unique<CSVMetricTracer>(
OS);
277 T->instant(
"Log", llvm::json::Object{{
"Message",
Message.str()}});
282 const Metric &LatencyMetric) {
286 llvm::Optional<WithContextValue> WithLatency;
287 using Clock = std::chrono::high_resolution_clock;
288 WithLatency.emplace(llvm::make_scope_exit(
289 [StartTime = Clock::now(),
Name =
Name.str(), &LatencyMetric] {
291 std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() -
296 return T->beginSpan(
Name.isSingleStringRef() ?
Name.getSingleStringRef()
297 : llvm::StringRef(
Name.str()),
310 : Args(T ? new
llvm::json::
Object() : nullptr),
321 assert((
LabelName.empty() == Label.empty()) &&
322 "recording a measurement with inconsistent labeling");
323 T->record(*
this,
Value, Label);