blob: e0f092182cec5ef19b5efc8beb3a006982e9e9cf [file] [log] [blame]
Sam McCall8567cb32017-11-02 09:21:51 +00001//===--- Trace.cpp - Performance tracing facilities -----------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Trace.h"
11
12#include "llvm/ADT/DenseSet.h"
13#include "llvm/Support/Chrono.h"
14#include "llvm/Support/FormatProviders.h"
15#include "llvm/Support/FormatVariadic.h"
16#include "llvm/Support/Threading.h"
Sam McCall8567cb32017-11-02 09:21:51 +000017#include <mutex>
18
19namespace clang {
20namespace clangd {
21namespace trace {
22using namespace llvm;
23
24namespace {
25// The current implementation is naive: each thread writes to Out guarded by Mu.
26// Perhaps we should replace this by something that disturbs performance less.
Ilya Biryukovee27d2e2017-12-14 15:04:59 +000027class JSONTracer : public EventTracer {
Sam McCall8567cb32017-11-02 09:21:51 +000028public:
Ilya Biryukovee27d2e2017-12-14 15:04:59 +000029 JSONTracer(raw_ostream &Out, bool Pretty)
Sam McCall9cfd9c92017-11-23 17:12:04 +000030 : Out(Out), Sep(""), Start(std::chrono::system_clock::now()),
31 JSONFormat(Pretty ? "{0:2}" : "{0}") {
Sam McCall8567cb32017-11-02 09:21:51 +000032 // The displayTimeUnit must be ns to avoid low-precision overlap
33 // calculations!
34 Out << R"({"displayTimeUnit":"ns","traceEvents":[)"
35 << "\n";
Sam McCall9cfd9c92017-11-23 17:12:04 +000036 rawEvent("M", json::obj{
37 {"name", "process_name"},
38 {"args", json::obj{{"name", "clangd"}}},
39 });
Sam McCall8567cb32017-11-02 09:21:51 +000040 }
41
Ilya Biryukovee27d2e2017-12-14 15:04:59 +000042 ~JSONTracer() {
Sam McCall8567cb32017-11-02 09:21:51 +000043 Out << "\n]}";
44 Out.flush();
45 }
46
47 // Record an event on the current thread. ph, pid, tid, ts are set.
48 // Contents must be a list of the other JSON key/values.
Ilya Biryukovee27d2e2017-12-14 15:04:59 +000049 void event(const Context &Ctx, StringRef Phase,
50 json::obj &&Contents) override {
Sam McCall8567cb32017-11-02 09:21:51 +000051 uint64_t TID = get_threadid();
52 std::lock_guard<std::mutex> Lock(Mu);
53 // If we haven't already, emit metadata describing this thread.
54 if (ThreadsWithMD.insert(TID).second) {
55 SmallString<32> Name;
56 get_thread_name(Name);
57 if (!Name.empty()) {
Sam McCall9cfd9c92017-11-23 17:12:04 +000058 rawEvent("M", json::obj{
59 {"tid", TID},
60 {"name", "thread_name"},
61 {"args", json::obj{{"name", Name}}},
62 });
Sam McCall8567cb32017-11-02 09:21:51 +000063 }
64 }
Sam McCall9cfd9c92017-11-23 17:12:04 +000065 Contents["ts"] = timestamp();
66 Contents["tid"] = TID;
67 rawEvent(Phase, std::move(Contents));
Sam McCall8567cb32017-11-02 09:21:51 +000068 }
69
70private:
71 // Record an event. ph and pid are set.
72 // Contents must be a list of the other JSON key/values.
Sam McCall9cfd9c92017-11-23 17:12:04 +000073 void rawEvent(StringRef Phase, json::obj &&Event) /*REQUIRES(Mu)*/ {
Sam McCall8567cb32017-11-02 09:21:51 +000074 // PID 0 represents the clangd process.
Sam McCall9cfd9c92017-11-23 17:12:04 +000075 Event["pid"] = 0;
76 Event["ph"] = Phase;
77 Out << Sep << formatv(JSONFormat, json::Expr(std::move(Event)));
Sam McCall8567cb32017-11-02 09:21:51 +000078 Sep = ",\n";
79 }
80
81 double timestamp() {
82 using namespace std::chrono;
Sam McCall3d9e0242017-11-15 17:53:46 +000083 return duration<double, std::micro>(system_clock::now() - Start).count();
Sam McCall8567cb32017-11-02 09:21:51 +000084 }
85
86 std::mutex Mu;
87 raw_ostream &Out /*GUARDED_BY(Mu)*/;
88 const char *Sep /*GUARDED_BY(Mu)*/;
89 DenseSet<uint64_t> ThreadsWithMD /*GUARDED_BY(Mu)*/;
90 const sys::TimePoint<> Start;
Sam McCall9cfd9c92017-11-23 17:12:04 +000091 const char *JSONFormat;
Sam McCall8567cb32017-11-02 09:21:51 +000092};
93
Ilya Biryukovee27d2e2017-12-14 15:04:59 +000094EventTracer *T = nullptr;
Sam McCall8567cb32017-11-02 09:21:51 +000095} // namespace
96
Ilya Biryukovee27d2e2017-12-14 15:04:59 +000097Session::Session(EventTracer &Tracer) {
98 assert(!T && "Resetting global tracer is not allowed.");
99 T = &Tracer;
Sam McCall8567cb32017-11-02 09:21:51 +0000100}
101
Ilya Biryukovee27d2e2017-12-14 15:04:59 +0000102Session::~Session() { T = nullptr; }
103
104std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
105 bool Pretty) {
106 return llvm::make_unique<JSONTracer>(OS, Pretty);
Sam McCall8567cb32017-11-02 09:21:51 +0000107}
108
Ilya Biryukovee27d2e2017-12-14 15:04:59 +0000109void log(const Context &Ctx, const Twine &Message) {
Sam McCall8567cb32017-11-02 09:21:51 +0000110 if (!T)
111 return;
Ilya Biryukovee27d2e2017-12-14 15:04:59 +0000112 T->event(Ctx, "i",
113 json::obj{
114 {"name", "Log"},
115 {"args", json::obj{{"Message", Message.str()}}},
116 });
Sam McCall8567cb32017-11-02 09:21:51 +0000117}
118
Ilya Biryukovee27d2e2017-12-14 15:04:59 +0000119Span::Span(const Context &Ctx, std::string Name) {
Sam McCall8567cb32017-11-02 09:21:51 +0000120 if (!T)
121 return;
Ilya Biryukovee27d2e2017-12-14 15:04:59 +0000122 // Clone the context, so that the original Context can be moved.
123 this->Ctx.emplace(Ctx.clone());
124
125 T->event(*this->Ctx, "B", json::obj{{"name", std::move(Name)}});
Sam McCall9cfd9c92017-11-23 17:12:04 +0000126 Args = llvm::make_unique<json::obj>();
Sam McCall8567cb32017-11-02 09:21:51 +0000127}
128
129Span::~Span() {
130 if (!T)
131 return;
Sam McCall9cfd9c92017-11-23 17:12:04 +0000132 if (!Args)
133 Args = llvm::make_unique<json::obj>();
Ilya Biryukovee27d2e2017-12-14 15:04:59 +0000134 T->event(*Ctx, "E",
135 Args ? json::obj{{"args", std::move(*Args)}} : json::obj{});
Sam McCall8567cb32017-11-02 09:21:51 +0000136}
137
138} // namespace trace
139} // namespace clangd
140} // namespace clang