Skip to content

Commit ee27d2e

Browse files
committedDec 14, 2017
[clangd] Implemented tracing using Context
Reviewers: sammccall, ioeric, hokein Reviewed By: sammccall Subscribers: klimek, luckygeck, cfe-commits Differential Revision: https://reviews.llvm.org/D40488 llvm-svn: 320706
1 parent f1208e7 commit ee27d2e

File tree

6 files changed

+90
-58
lines changed

6 files changed

+90
-58
lines changed
 

‎clang-tools-extra/clangd/ClangdUnit.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ CppFile::deferRebuild(StringRef NewContents,
770770
// (if there are no other references to it).
771771
OldPreamble.reset();
772772

773-
trace::Span Tracer("Preamble");
773+
trace::Span Tracer(Ctx, "Preamble");
774774
SPAN_ATTACH(Tracer, "File", That->FileName);
775775
std::vector<DiagWithFixIts> PreambleDiags;
776776
StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
@@ -816,7 +816,7 @@ CppFile::deferRebuild(StringRef NewContents,
816816
// Compute updated AST.
817817
llvm::Optional<ParsedAST> NewAST;
818818
{
819-
trace::Span Tracer("Build");
819+
trace::Span Tracer(Ctx, "Build");
820820
SPAN_ATTACH(Tracer, "File", That->FileName);
821821
NewAST = ParsedAST::Build(Ctx, std::move(CI), std::move(NewPreamble),
822822
std::move(ContentsBuffer), PCHs, VFS);

‎clang-tools-extra/clangd/JSONRPCDispatcher.cpp

+10-7
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void JSONOutput::writeMessage(const json::Expr &Message) {
4545
}
4646

4747
void JSONOutput::log(const Context &Ctx, const Twine &Message) {
48-
trace::log(Message);
48+
trace::log(Ctx, Message);
4949
std::lock_guard<std::mutex> Guard(StreamMutex);
5050
Logs << Message << '\n';
5151
Logs.flush();
@@ -137,16 +137,19 @@ bool JSONRPCDispatcher::call(const json::Expr &Message, JSONOutput &Out) const {
137137
auto I = Handlers.find(*Method);
138138
auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
139139

140-
auto Tracer = llvm::make_unique<trace::Span>(*Method);
140+
// Create a Context that contains request information.
141+
auto Ctx = Context::empty().derive(RequestOut, &Out);
142+
if (ID)
143+
Ctx = std::move(Ctx).derive(RequestID, *ID);
144+
145+
// Create a tracing Span covering the whole request lifetime.
146+
auto Tracer = llvm::make_unique<trace::Span>(Ctx, *Method);
141147
if (ID)
142148
SPAN_ATTACH(*Tracer, "ID", *ID);
143149
SPAN_ATTACH(*Tracer, "Params", Params);
144150

145-
auto Ctx = Context::empty()
146-
.derive(RequestOut, &Out)
147-
.derive(RequestSpan, std::move(Tracer));
148-
if (ID)
149-
Ctx = std::move(Ctx).derive(RequestID, *ID);
151+
// Update Ctx to include Tracer.
152+
Ctx = std::move(Ctx).derive(RequestSpan, std::move(Tracer));
150153

151154
Handler(std::move(Ctx), std::move(Params));
152155
return true;

‎clang-tools-extra/clangd/Trace.cpp

+27-20
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ using namespace llvm;
2424
namespace {
2525
// The current implementation is naive: each thread writes to Out guarded by Mu.
2626
// Perhaps we should replace this by something that disturbs performance less.
27-
class Tracer {
27+
class JSONTracer : public EventTracer {
2828
public:
29-
Tracer(raw_ostream &Out, bool Pretty)
29+
JSONTracer(raw_ostream &Out, bool Pretty)
3030
: Out(Out), Sep(""), Start(std::chrono::system_clock::now()),
3131
JSONFormat(Pretty ? "{0:2}" : "{0}") {
3232
// The displayTimeUnit must be ns to avoid low-precision overlap
@@ -39,14 +39,15 @@ class Tracer {
3939
});
4040
}
4141

42-
~Tracer() {
42+
~JSONTracer() {
4343
Out << "\n]}";
4444
Out.flush();
4545
}
4646

4747
// Record an event on the current thread. ph, pid, tid, ts are set.
4848
// Contents must be a list of the other JSON key/values.
49-
void event(StringRef Phase, json::obj &&Contents) {
49+
void event(const Context &Ctx, StringRef Phase,
50+
json::obj &&Contents) override {
5051
uint64_t TID = get_threadid();
5152
std::lock_guard<std::mutex> Lock(Mu);
5253
// If we haven't already, emit metadata describing this thread.
@@ -90,33 +91,38 @@ class Tracer {
9091
const char *JSONFormat;
9192
};
9293

93-
static Tracer *T = nullptr;
94+
EventTracer *T = nullptr;
9495
} // namespace
9596

96-
std::unique_ptr<Session> Session::create(raw_ostream &OS, bool Pretty) {
97-
assert(!T && "A session is already active");
98-
T = new Tracer(OS, Pretty);
99-
return std::unique_ptr<Session>(new Session());
97+
Session::Session(EventTracer &Tracer) {
98+
assert(!T && "Resetting global tracer is not allowed.");
99+
T = &Tracer;
100100
}
101101

102-
Session::~Session() {
103-
delete T;
104-
T = nullptr;
102+
Session::~Session() { T = nullptr; }
103+
104+
std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
105+
bool Pretty) {
106+
return llvm::make_unique<JSONTracer>(OS, Pretty);
105107
}
106108

107-
void log(const Twine &Message) {
109+
void log(const Context &Ctx, const Twine &Message) {
108110
if (!T)
109111
return;
110-
T->event("i", json::obj{
111-
{"name", "Log"},
112-
{"args", json::obj{{"Message", Message.str()}}},
113-
});
112+
T->event(Ctx, "i",
113+
json::obj{
114+
{"name", "Log"},
115+
{"args", json::obj{{"Message", Message.str()}}},
116+
});
114117
}
115118

116-
Span::Span(std::string Name) {
119+
Span::Span(const Context &Ctx, std::string Name) {
117120
if (!T)
118121
return;
119-
T->event("B", json::obj{{"name", std::move(Name)}});
122+
// 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)}});
120126
Args = llvm::make_unique<json::obj>();
121127
}
122128

@@ -125,7 +131,8 @@ Span::~Span() {
125131
return;
126132
if (!Args)
127133
Args = llvm::make_unique<json::obj>();
128-
T->event("E", Args ? json::obj{{"args", std::move(*Args)}} : json::obj{});
134+
T->event(*Ctx, "E",
135+
Args ? json::obj{{"args", std::move(*Args)}} : json::obj{});
129136
}
130137

131138
} // namespace trace

‎clang-tools-extra/clangd/Trace.h

+38-24
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@
88
//===----------------------------------------------------------------------===//
99
//
1010
// Supports writing performance traces describing clangd's behavior.
11-
// Traces are written in the Trace Event format supported by chrome's trace
12-
// viewer (chrome://tracing).
11+
// Traces are consumed by implementations of the EventTracer interface.
1312
//
14-
// The format is documented here:
15-
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
1613
//
1714
// All APIs are no-ops unless a Session is active (created by ClangdMain).
1815
//
@@ -21,6 +18,7 @@
2118
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_
2219
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_
2320

21+
#include "Context.h"
2422
#include "JSONExpr.h"
2523
#include "llvm/ADT/Twine.h"
2624
#include "llvm/Support/raw_ostream.h"
@@ -29,39 +27,55 @@ namespace clang {
2927
namespace clangd {
3028
namespace trace {
3129

32-
// A session directs the output of trace events. Only one Session can exist.
33-
// It should be created before clangd threads are spawned, and destroyed after
34-
// they exit.
35-
// TODO: we may want to add pluggable support for other tracing backends.
30+
/// A consumer of trace events. The events are produced by Spans and trace::log.
31+
class EventTracer {
32+
public:
33+
virtual ~EventTracer() = default;
34+
/// Consume a trace event.
35+
virtual void event(const Context &Ctx, llvm::StringRef Phase,
36+
json::obj &&Contents) = 0;
37+
};
38+
39+
/// Sets up a global EventTracer that consumes events produced by Span and
40+
/// trace::log. Only one TracingSession can be active at a time and it should be
41+
/// set up before calling any clangd-specific functions.
3642
class Session {
3743
public:
38-
// Starts a sessions capturing trace events and writing Trace Event JSON.
39-
static std::unique_ptr<Session> create(llvm::raw_ostream &OS,
40-
bool Pretty = false);
44+
Session(EventTracer &Tracer);
4145
~Session();
42-
43-
private:
44-
Session() = default;
4546
};
4647

47-
// Records a single instant event, associated with the current thread.
48-
void log(const llvm::Twine &Name);
48+
/// Create an instance of EventTracer that produces an output in the Trace Event
49+
/// format supported by Chrome's trace viewer (chrome://tracing).
50+
///
51+
/// The format is documented here:
52+
/// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
53+
///
54+
/// The implementation supports concurrent calls and can be used as a global
55+
/// tracer (i.e., can be put into a global Context).
56+
std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
57+
bool Pretty = false);
4958

50-
// Records an event whose duration is the lifetime of the Span object.
51-
//
52-
// Arbitrary JSON metadata can be attached while this span is active:
53-
// SPAN_ATTACH(MySpan, "Payload", SomeJSONExpr);
54-
// SomeJSONExpr is evaluated and copied only if actually needed.
59+
/// Records a single instant event, associated with the current thread.
60+
void log(const Context &Ctx, const llvm::Twine &Name);
61+
62+
/// Records an event whose duration is the lifetime of the Span object.
63+
/// This is the main public interface for producing tracing events.
64+
///
65+
/// Arbitrary JSON metadata can be attached while this span is active:
66+
/// SPAN_ATTACH(MySpan, "Payload", SomeJSONExpr);
67+
/// SomeJSONExpr is evaluated and copied only if actually needed.
5568
class Span {
5669
public:
57-
Span(std::string Name);
70+
Span(const Context &Ctx, std::string Name);
5871
~Span();
5972

60-
// Returns mutable span metadata if this span is interested.
61-
// Prefer to use SPAN_ATTACH rather than accessing this directly.
73+
/// Returns mutable span metadata if this span is interested.
74+
/// Prefer to use SPAN_ATTACH rather than accessing this directly.
6275
json::obj *args() { return Args.get(); }
6376

6477
private:
78+
llvm::Optional<Context> Ctx;
6579
std::unique_ptr<json::obj> Args;
6680
};
6781

‎clang-tools-extra/clangd/tool/ClangdMain.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,25 @@ int main(int argc, char *argv[]) {
115115
<< EC.message();
116116
}
117117
}
118+
119+
// Setup tracing facilities.
118120
llvm::Optional<llvm::raw_fd_ostream> TraceStream;
119-
std::unique_ptr<trace::Session> TraceSession;
121+
std::unique_ptr<trace::EventTracer> Tracer;
120122
if (!TraceFile.empty()) {
121123
std::error_code EC;
122124
TraceStream.emplace(TraceFile, /*ref*/ EC, llvm::sys::fs::F_RW);
123125
if (EC) {
124126
TraceFile.reset();
125127
llvm::errs() << "Error while opening trace file: " << EC.message();
126128
} else {
127-
TraceSession = trace::Session::create(*TraceStream, PrettyPrint);
129+
Tracer = trace::createJSONTracer(*TraceStream, PrettyPrint);
128130
}
129131
}
130132

133+
llvm::Optional<trace::Session> TracingSession;
134+
if (Tracer)
135+
TracingSession.emplace(*Tracer);
136+
131137
llvm::raw_ostream &Outs = llvm::outs();
132138
llvm::raw_ostream &Logs = llvm::errs();
133139
JSONOutput Out(Outs, Logs,

‎clang-tools-extra/unittests/clangd/TraceTests.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//
88
//===----------------------------------------------------------------------===//
99

10+
#include "Context.h"
1011
#include "Trace.h"
1112

1213
#include "llvm/ADT/DenseMap.h"
@@ -74,10 +75,11 @@ TEST(TraceTest, SmokeTest) {
7475
std::string JSON;
7576
{
7677
raw_string_ostream OS(JSON);
77-
auto Session = trace::Session::create(OS);
78+
auto JSONTracer = trace::createJSONTracer(OS);
79+
trace::Session Session(*JSONTracer);
7880
{
79-
trace::Span S("A");
80-
trace::log("B");
81+
trace::Span S(Context::empty(), "A");
82+
trace::log(Context::empty(), "B");
8183
}
8284
}
8385

0 commit comments

Comments
 (0)
Please sign in to comment.