clang-tools 8.0.0

Trace.cpp
Go to the documentation of this file.
1 //===--- 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 #include "Context.h"
12 #include "Function.h"
13 #include "llvm/ADT/DenseSet.h"
14 #include "llvm/ADT/ScopeExit.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"
19 #include <atomic>
20 #include <mutex>
21
22 namespace clang {
23 namespace clangd {
24 namespace trace {
25
26 namespace {
27 // The current implementation is naive: each thread writes to Out guarded by Mu.
28 // Perhaps we should replace this by something that disturbs performance less.
29 class JSONTracer : public EventTracer {
30 public:
31 JSONTracer(llvm::raw_ostream &Out, bool Pretty)
32 : Out(Out), Sep(""), Start(std::chrono::system_clock::now()),
33 JSONFormat(Pretty ? "{0:2}" : "{0}") {
34 // The displayTimeUnit must be ns to avoid low-precision overlap
35 // calculations!
36 Out << R"({"displayTimeUnit":"ns","traceEvents":[)"
37 << "\n";
38 rawEvent("M", llvm::json::Object{
39 {"name", "process_name"},
40 {"args", llvm::json::Object{{"name", "clangd"}}},
41 });
42 }
43
44 ~JSONTracer() {
45 Out << "\n]}";
46 Out.flush();
47 }
48
49 // We stash a Span object in the context. It will record the start/end,
50 // and this also allows us to look up the parent Span's information.
51 Context beginSpan(llvm::StringRef Name, llvm::json::Object *Args) override {
52 return Context::current().derive(
53 SpanKey, llvm::make_unique<JSONSpan>(this, Name, Args));
54 }
55
56 // Trace viewer requires each thread to properly stack events.
57 // So we need to mark only duration that the span was active on the thread.
58 // (Hopefully any off-thread activity will be connected by a flow event).
59 // Record the end time here, but don't write the event: Args aren't ready yet.
60 void endSpan() override {
61 Context::current().getExisting(SpanKey)->markEnded();
62 }
63
64 void instant(llvm::StringRef Name, llvm::json::Object &&Args) override {
65 captureThreadMetadata();
66 jsonEvent("i",
67 llvm::json::Object{{"name", Name}, {"args", std::move(Args)}});
68 }
69
70 // Record an event on the current thread. ph, pid, tid, ts are set.
71 // Contents must be a list of the other JSON key/values.
72 void jsonEvent(llvm::StringRef Phase, llvm::json::Object &&Contents,
73 uint64_t TID = llvm::get_threadid(), double Timestamp = 0) {
74 Contents["ts"] = Timestamp ? Timestamp : timestamp();
75 Contents["tid"] = int64_t(TID);
76 std::lock_guard<std::mutex> Lock(Mu);
77 rawEvent(Phase, std::move(Contents));
78 }
79
80 private:
81 class JSONSpan {
82 public:
83 JSONSpan(JSONTracer *Tracer, llvm::StringRef Name, llvm::json::Object *Args)
84 : StartTime(Tracer->timestamp()), EndTime(0), Name(Name),
85 TID(llvm::get_threadid()), Tracer(Tracer), Args(Args) {
86 // ~JSONSpan() may run in a different thread, so we need to capture now.
87 Tracer->captureThreadMetadata();
88
89 // We don't record begin events here (and end events in the destructor)
90 // because B/E pairs have to appear in the right order, which is awkward.
91 // Instead we send the complete (X) event in the destructor.
92
93 // If our parent was on a different thread, add an arrow to this span.
94 auto *Parent = Context::current().get(SpanKey);
95 if (Parent && *Parent && (*Parent)->TID != TID) {
96 // If the parent span ended already, then show this as "following" it.
97 // Otherwise show us as "parallel".
98 double OriginTime = (*Parent)->EndTime;
99 if (!OriginTime)
100 OriginTime = (*Parent)->StartTime;
101
102 auto FlowID = nextID();
103 Tracer->jsonEvent(
104 "s",
105 llvm::json::Object{{"id", FlowID},
106 {"name", "Context crosses threads"},
107 {"cat", "dummy"}},
108 (*Parent)->TID, (*Parent)->StartTime);
109 Tracer->jsonEvent(
110 "f",
111 llvm::json::Object{{"id", FlowID},
112 {"bp", "e"},
113 {"name", "Context crosses threads"},
114 {"cat", "dummy"}},
115 TID);
116 }
117 }
118
119 ~JSONSpan() {
120 // Finally, record the event (ending at EndTime, not timestamp())!
121 Tracer->jsonEvent("X",
122 llvm::json::Object{{"name", std::move(Name)},
123 {"args", std::move(*Args)},
124 {"dur", EndTime - StartTime}},
125 TID, StartTime);
126 }
127
128 // May be called by any thread.
129 void markEnded() { EndTime = Tracer->timestamp(); }
130
131 private:
132 static int64_t nextID() {
133 static std::atomic<int64_t> Next = {0};
134 return Next++;
135 }
136
137 double StartTime;
138 std::atomic<double> EndTime; // Filled in by markEnded().
139 std::string Name;
140 uint64_t TID;
141 JSONTracer *Tracer;
142 llvm::json::Object *Args;
143 };
144 static Key<std::unique_ptr<JSONSpan>> SpanKey;
145
146 // Record an event. ph and pid are set.
147 // Contents must be a list of the other JSON key/values.
148 void rawEvent(llvm::StringRef Phase,
149 llvm::json::Object &&Event) /*REQUIRES(Mu)*/ {
150 // PID 0 represents the clangd process.
151 Event["pid"] = 0;
152 Event["ph"] = Phase;
153 Out << Sep
154 << llvm::formatv(JSONFormat, llvm::json::Value(std::move(Event)));
155 Sep = ",\n";
156 }
157
158 // If we haven't already, emit metadata describing this thread.
159 void captureThreadMetadata() {
160 uint64_t TID = llvm::get_threadid();
161 std::lock_guard<std::mutex> Lock(Mu);
162 if (ThreadsWithMD.insert(TID).second) {
163 llvm::SmallString<32> Name;
164 llvm::get_thread_name(Name);
165 if (!Name.empty()) {
166 rawEvent("M", llvm::json::Object{
167 {"tid", int64_t(TID)},
168 {"name", "thread_name"},
169 {"args", llvm::json::Object{{"name", Name}}},
170 });
171 }
172 }
173 }
174
175 double timestamp() {
176 using namespace std::chrono;
177 return duration<double, std::micro>(system_clock::now() - Start).count();
178 }
179
180 std::mutex Mu;
181 llvm::raw_ostream &Out /*GUARDED_BY(Mu)*/;
182 const char *Sep /*GUARDED_BY(Mu)*/;
183 llvm::DenseSet<uint64_t> ThreadsWithMD /*GUARDED_BY(Mu)*/;
184 const llvm::sys::TimePoint<> Start;
185 const char *JSONFormat;
186 };
187
188 Key<std::unique_ptr<JSONTracer::JSONSpan>> JSONTracer::SpanKey;
189
190 EventTracer *T = nullptr;
191 } // namespace
192
193 Session::Session(EventTracer &Tracer) {
194 assert(!T && "Resetting global tracer is not allowed.");
195 T = &Tracer;
196 }
197
198 Session::~Session() { T = nullptr; }
199
200 std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
201 bool Pretty) {
202 return llvm::make_unique<JSONTracer>(OS, Pretty);
203 }
204
205 void log(const llvm::Twine &Message) {
206 if (!T)
207 return;
208 T->instant("Log", llvm::json::Object{{"Message", Message.str()}});
209 }
210
211 // Returned context owns Args.
212 static Context makeSpanContext(llvm::Twine Name, llvm::json::Object *Args) {
213 if (!T)
214 return Context::current().clone();
215 WithContextValue WithArgs{std::unique_ptr<llvm::json::Object>(Args)};
216 return T->beginSpan(Name.isSingleStringRef() ? Name.getSingleStringRef()
217 : llvm::StringRef(Name.str()),
218 Args);
219 }
220
221 // Span keeps a non-owning pointer to the args, which is how users access them.
222 // The args are owned by the context though. They stick around until the
223 // beginSpan() context is destroyed, when the tracing engine will consume them.
224 Span::Span(llvm::Twine Name)
225 : Args(T ? new llvm::json::Object() : nullptr),
226 RestoreCtx(makeSpanContext(Name, Args)) {}
227
228 Span::~Span() {
229 if (T)
230 T->endSpan();
231 }
232
233 } // namespace trace
234 } // namespace clangd
235 } // namespace clang
Name
llvm::StringRef Name
Definition: CodeComplete.cpp:206
clang::clangd::trace::Session::Session
Session(EventTracer &Tracer)
Definition: Trace.cpp:193
Trace.h
Contents
llvm::StringRef Contents
Definition: CodeComplete.cpp:1007
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:28
clang::clangd::Event
An Event<T> allows events of type T to be broadcast to listeners.
Definition: Function.h:88
clang::clangd::Key
Values in a Context are indexed by typed keys.
Definition: Context.h:41
clang::tidy::modernize::Message
static const StringRef Message
Definition: UseTransparentFunctorsCheck.cpp:71
Context.h
clang::clangd::SymbolKind::Object
clang::clangd::Context::get
const Type * get(const Key< Type > &Key) const
Get data stored for a typed Key.
Definition: Context.h:101
clang::clangd::Context::clone
Context clone() const
Clone this context object.
Definition: Context.cpp:21
clang::clangd::Context::current
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:28
clang::clangd::trace::Span::~Span
~Span()
Definition: Trace.cpp:228
clang::clangd::Context
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:70
clang::clangd::Context::getExisting
const Type & getExisting(const Key< Type > &Key) const
A helper to get a reference to a Key that must exist in the map.
Definition: Context.h:112
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::clangd::trace::log
void log(const llvm::Twine &Message)
Records a single instant event, associated with the current thread.
Definition: Trace.cpp:205
clang::clangd::Context::derive
Context derive(const Key< Type > &Key, typename std::decay< Type >::type Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive()...
Definition: Context.h:122
Function.h
clang::clangd::trace::Span::Span
Span(llvm::Twine Name)
Definition: Trace.cpp:224
clang::clangd::trace::createJSONTracer
std::unique_ptr< EventTracer > createJSONTracer(llvm::raw_ostream &OS, bool Pretty)
Create an instance of EventTracer that produces an output in the Trace Event format supported by Chro...
Definition: Trace.cpp:200
clang::clangd::WithContextValue
WithContextValue extends Context::current() with a single value.
Definition: Context.h:205
clang::clangd::trace::makeSpanContext
static Context makeSpanContext(llvm::Twine Name, llvm::json::Object *Args)
Definition: Trace.cpp:212
clang::clangd::trace::EventTracer
A consumer of trace events.
Definition: Trace.h:33
clang::clangd::trace::Session::~Session
~Session()
Definition: Trace.cpp:198