blob: 6034014929acc927e247493aa36f9bbdce7714e9 [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.
27class Tracer {
28public:
Sam McCall9cfd9c92017-11-23 17:12:04 +000029 Tracer(raw_ostream &Out, bool Pretty)
30 : 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
42 ~Tracer() {
43 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.
Sam McCall9cfd9c92017-11-23 17:12:04 +000049 void event(StringRef Phase, json::obj &&Contents) {
Sam McCall8567cb32017-11-02 09:21:51 +000050 uint64_t TID = get_threadid();
51 std::lock_guard<std::mutex> Lock(Mu);
52 // If we haven't already, emit metadata describing this thread.
53 if (ThreadsWithMD.insert(TID).second) {
54 SmallString<32> Name;
55 get_thread_name(Name);
56 if (!Name.empty()) {
Sam McCall9cfd9c92017-11-23 17:12:04 +000057 rawEvent("M", json::obj{
58 {"tid", TID},
59 {"name", "thread_name"},
60 {"args", json::obj{{"name", Name}}},
61 });
Sam McCall8567cb32017-11-02 09:21:51 +000062 }
63 }
Sam McCall9cfd9c92017-11-23 17:12:04 +000064 Contents["ts"] = timestamp();
65 Contents["tid"] = TID;
66 rawEvent(Phase, std::move(Contents));
Sam McCall8567cb32017-11-02 09:21:51 +000067 }
68
69private:
70 // Record an event. ph and pid are set.
71 // Contents must be a list of the other JSON key/values.
Sam McCall9cfd9c92017-11-23 17:12:04 +000072 void rawEvent(StringRef Phase, json::obj &&Event) /*REQUIRES(Mu)*/ {
Sam McCall8567cb32017-11-02 09:21:51 +000073 // PID 0 represents the clangd process.
Sam McCall9cfd9c92017-11-23 17:12:04 +000074 Event["pid"] = 0;
75 Event["ph"] = Phase;
76 Out << Sep << formatv(JSONFormat, json::Expr(std::move(Event)));
Sam McCall8567cb32017-11-02 09:21:51 +000077 Sep = ",\n";
78 }
79
80 double timestamp() {
81 using namespace std::chrono;
Sam McCall3d9e0242017-11-15 17:53:46 +000082 return duration<double, std::micro>(system_clock::now() - Start).count();
Sam McCall8567cb32017-11-02 09:21:51 +000083 }
84
85 std::mutex Mu;
86 raw_ostream &Out /*GUARDED_BY(Mu)*/;
87 const char *Sep /*GUARDED_BY(Mu)*/;
88 DenseSet<uint64_t> ThreadsWithMD /*GUARDED_BY(Mu)*/;
89 const sys::TimePoint<> Start;
Sam McCall9cfd9c92017-11-23 17:12:04 +000090 const char *JSONFormat;
Sam McCall8567cb32017-11-02 09:21:51 +000091};
92
93static Tracer *T = nullptr;
94} // namespace
95
Sam McCall9cfd9c92017-11-23 17:12:04 +000096std::unique_ptr<Session> Session::create(raw_ostream &OS, bool Pretty) {
Sam McCall8567cb32017-11-02 09:21:51 +000097 assert(!T && "A session is already active");
Sam McCall9cfd9c92017-11-23 17:12:04 +000098 T = new Tracer(OS, Pretty);
Sam McCall8567cb32017-11-02 09:21:51 +000099 return std::unique_ptr<Session>(new Session());
100}
101
102Session::~Session() {
103 delete T;
104 T = nullptr;
105}
106
107void log(const Twine &Message) {
108 if (!T)
109 return;
Sam McCall9cfd9c92017-11-23 17:12:04 +0000110 T->event("i", json::obj{
111 {"name", "Log"},
112 {"args", json::obj{{"Message", Message.str()}}},
113 });
Sam McCall8567cb32017-11-02 09:21:51 +0000114}
115
Sam McCall9cfd9c92017-11-23 17:12:04 +0000116Span::Span(std::string Name) {
Sam McCall8567cb32017-11-02 09:21:51 +0000117 if (!T)
118 return;
Sam McCall9cfd9c92017-11-23 17:12:04 +0000119 T->event("B", json::obj{{"name", std::move(Name)}});
120 Args = llvm::make_unique<json::obj>();
Sam McCall8567cb32017-11-02 09:21:51 +0000121}
122
123Span::~Span() {
124 if (!T)
125 return;
Sam McCall9cfd9c92017-11-23 17:12:04 +0000126 if (!Args)
127 Args = llvm::make_unique<json::obj>();
128 T->event("E", Args ? json::obj{{"args", std::move(*Args)}} : json::obj{});
Sam McCall8567cb32017-11-02 09:21:51 +0000129}
130
131} // namespace trace
132} // namespace clangd
133} // namespace clang