ilya-biryukov created this revision.

https://reviews.llvm.org/D40488

Files:
  clangd/ClangdUnit.cpp
  clangd/JSONRPCDispatcher.cpp
  clangd/JSONRPCDispatcher.h
  clangd/ProtocolHandlers.cpp
  clangd/Trace.cpp
  clangd/Trace.h
  clangd/tool/ClangdMain.cpp
  unittests/clangd/TraceTests.cpp

Index: unittests/clangd/TraceTests.cpp
===================================================================
--- unittests/clangd/TraceTests.cpp
+++ unittests/clangd/TraceTests.cpp
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Context.h"
 #include "Trace.h"
 
 #include "llvm/ADT/DenseMap.h"
@@ -74,10 +75,12 @@
   std::string JSON;
   {
     raw_string_ostream OS(JSON);
-    auto Session = trace::Session::create(OS);
+    auto JSONTracer = trace::createJSONTracer(OS);
+    Context TraceCtx =
+        buildCtx().add(trace::EventTracer::CtxKey, JSONTracer.get());
     {
-      trace::Span S("A");
-      trace::log("B");
+      trace::Span S(TraceCtx, "A");
+      trace::log(TraceCtx, "B");
     }
   }
 
Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -116,15 +116,15 @@
     }
   }
   llvm::Optional<llvm::raw_fd_ostream> TraceStream;
-  std::unique_ptr<trace::Session> TraceSession;
+  std::unique_ptr<trace::EventTracer> TraceSession;
   if (!TraceFile.empty()) {
     std::error_code EC;
     TraceStream.emplace(TraceFile, /*ref*/ EC, llvm::sys::fs::F_RW);
     if (EC) {
       TraceFile.reset();
       llvm::errs() << "Error while opening trace file: " << EC.message();
     } else {
-      TraceSession = trace::Session::create(*TraceStream, PrettyPrint);
+      TraceSession = trace::createJSONTracer(*TraceStream, PrettyPrint);
     }
   }
 
@@ -134,7 +134,11 @@
                  InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,
                  PrettyPrint);
 
-  GlobalSession Session(buildCtx().add(Logger::CtxKey, &Out));
+  TypedValueMap ContextMap;
+  ContextMap.emplace(Logger::CtxKey, &Out);
+  if (TraceSession)
+    ContextMap.emplace(trace::EventTracer::CtxKey, TraceSession.get());
+  GlobalSession Session(Context(/*Parent=*/nullptr, std::move(ContextMap)));
 
   // If --compile-commands-dir arg was invoked, check value and override default
   // path.
Index: clangd/Trace.h
===================================================================
--- clangd/Trace.h
+++ clangd/Trace.h
@@ -8,60 +8,64 @@
 //===----------------------------------------------------------------------===//
 //
 // Supports writing performance traces describing clangd's behavior.
-// Traces are written in the Trace Event format supported by chrome's trace
-// viewer (chrome://tracing).
+// Traces are consumed by implementations of the EventTracer interface.
 //
-// The format is documented here:
-// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
 //
 // All APIs are no-ops unless a Session is active (created by ClangdMain).
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_
 
+#include "Context.h"
 #include "JSONExpr.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace clang {
 namespace clangd {
 namespace trace {
 
-// A session directs the output of trace events. Only one Session can exist.
-// It should be created before clangd threads are spawned, and destroyed after
-// they exit.
-// TODO: we may want to add pluggable support for other tracing backends.
-class Session {
+class EventTracer {
 public:
-  // Starts a sessions capturing trace events and writing Trace Event JSON.
-  static std::unique_ptr<Session> create(llvm::raw_ostream &OS,
-                                         bool Pretty = false);
-  ~Session();
+  static PtrKey<EventTracer> CtxKey;
 
-private:
-  Session() = default;
+  virtual ~EventTracer() = default;
+  virtual void event(llvm::StringRef Phase, json::obj &&Contents) = 0;
 };
 
-// Records a single instant event, associated with the current thread.
-void log(const llvm::Twine &Name);
+/// Create an instance of EventTracer that produces an output in the Trace Event
+/// format supported by Chrome's trace viewer (chrome://tracing).
+///
+/// The format is documented here:
+/// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+///
+/// The implementation supports concurrent calls and can be used as a global
+/// tracer (i.e., can be put into a global Context).
+std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
+                                              bool Pretty = false);
 
-// Records an event whose duration is the lifetime of the Span object.
-//
-// Arbitrary JSON metadata can be attached while this span is active:
-//   SPAN_ATTACH(MySpan, "Payload", SomeJSONExpr);
-// SomeJSONExpr is evaluated and copied only if actually needed.
+/// Records a single instant event, associated with the current thread.
+void log(Context &Ctx, const llvm::Twine &Name);
+
+/// Records an event whose duration is the lifetime of the Span object.
+/// This is the main public interface for producing tracing events.
+///
+/// Arbitrary JSON metadata can be attached while this span is active:
+///   SPAN_ATTACH(MySpan, "Payload", SomeJSONExpr);
+/// SomeJSONExpr is evaluated and copied only if actually needed.
 class Span {
 public:
-  Span(std::string Name);
+  Span(Context &Ctx, std::string Name);
   ~Span();
 
-  // Returns mutable span metadata if this span is interested.
-  // Prefer to use SPAN_ATTACH rather than accessing this directly.
+  /// Returns mutable span metadata if this span is interested.
+  /// Prefer to use SPAN_ATTACH rather than accessing this directly.
   json::obj *args() { return Args.get(); }
 
 private:
+  Context &Ctx;
   std::unique_ptr<json::obj> Args;
 };
 
Index: clangd/Trace.cpp
===================================================================
--- clangd/Trace.cpp
+++ clangd/Trace.cpp
@@ -25,9 +25,9 @@
 namespace {
 // The current implementation is naive: each thread writes to Out guarded by Mu.
 // Perhaps we should replace this by something that disturbs performance less.
-class Tracer {
+class JSONTracer : public EventTracer {
 public:
-  Tracer(raw_ostream &Out, bool Pretty)
+  JSONTracer(raw_ostream &Out, bool Pretty)
       : Out(Out), Sep(""), Start(std::chrono::system_clock::now()),
         JSONFormat(Pretty ? "{0:2}" : "{0}") {
     // The displayTimeUnit must be ns to avoid low-precision overlap
@@ -40,14 +40,14 @@
                   });
   }
 
-  ~Tracer() {
+  ~JSONTracer() {
     Out << "\n]}";
     Out.flush();
   }
 
   // Record an event on the current thread. ph, pid, tid, ts are set.
   // Contents must be a list of the other JSON key/values.
-  void event(StringRef Phase, json::obj &&Contents) {
+  void event(StringRef Phase, json::obj &&Contents) override {
     uint64_t TID = get_threadid();
     std::lock_guard<std::mutex> Lock(Mu);
     // If we haven't already, emit metadata describing this thread.
@@ -90,38 +90,35 @@
   const sys::TimePoint<> Start;
   const char *JSONFormat;
 };
-
-static Tracer *T = nullptr;
 } // namespace
 
-std::unique_ptr<Session> Session::create(raw_ostream &OS, bool Pretty) {
-  assert(!T && "A session is already active");
-  T = new Tracer(OS, Pretty);
-  return std::unique_ptr<Session>(new Session());
-}
+PtrKey<EventTracer> EventTracer::CtxKey;
 
-Session::~Session() {
-  delete T;
-  T = nullptr;
+std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
+                                              bool Pretty) {
+  return llvm::make_unique<JSONTracer>(OS, Pretty);
 }
 
-void log(const Twine &Message) {
+void log(Context &Ctx, const Twine &Message) {
+  EventTracer *T = Ctx.get(EventTracer::CtxKey);
   if (!T)
     return;
   T->event("i", json::obj{
                     {"name", "Log"},
                     {"args", json::obj{{"Message", Message.str()}}},
                 });
 }
 
-Span::Span(std::string Name) {
+Span::Span(Context &Ctx, std::string Name) : Ctx(Ctx) {
+  EventTracer* T = Ctx.get(EventTracer::CtxKey);
   if (!T)
     return;
   T->event("B", json::obj{{"name", std::move(Name)}});
   Args = llvm::make_unique<json::obj>();
 }
 
 Span::~Span() {
+  auto T = Ctx.get(EventTracer::CtxKey);
   if (!T)
     return;
   if (!Args)
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -31,7 +31,7 @@
     Dispatcher.registerHandler(
         Method, [=](RequestContext C, llvm::yaml::MappingNode *RawParams) {
           if (auto P = [&] {
-                trace::Span Tracer("Parse");
+                trace::Span Tracer(C.ctx(), "Parse");
                 return std::decay<Param>::type::parse(RawParams, C.ctx());
               }()) {
             (Callbacks->*Handler)(std::move(C), *P);
Index: clangd/JSONRPCDispatcher.h
===================================================================
--- clangd/JSONRPCDispatcher.h
+++ clangd/JSONRPCDispatcher.h
@@ -60,7 +60,7 @@
   RequestContext(Context Ctx, JSONOutput &Out, StringRef Method,
                  llvm::Optional<json::Expr> ID)
       : Ctx(std::move(Ctx)), Out(Out), ID(std::move(ID)),
-        Tracer(llvm::make_unique<trace::Span>(Method)) {
+        Tracer(llvm::make_unique<trace::Span>(this->Ctx, Method)) {
     if (this->ID)
       SPAN_ATTACH(tracer(), "ID", *this->ID);
   }
@@ -76,6 +76,7 @@
   Context &ctx() { return Ctx; }
 
 private:
+  // Ctx must be before Tracer!
   Context Ctx;
   JSONOutput &Out;
   llvm::Optional<json::Expr> ID;
Index: clangd/JSONRPCDispatcher.cpp
===================================================================
--- clangd/JSONRPCDispatcher.cpp
+++ clangd/JSONRPCDispatcher.cpp
@@ -40,8 +40,7 @@
 }
 
 void JSONOutput::logImpl(Context &Ctx, const Twine &Message) {
-  // FIXME(ibiryukov): get rid of trace::log here.
-  trace::log(Message);
+  trace::log(Ctx, Message);
   std::lock_guard<std::mutex> Guard(StreamMutex);
   Logs << Message;
   Logs.flush();
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -1286,7 +1286,7 @@
       // (if there are no other references to it).
       OldPreamble.reset();
 
-      trace::Span Tracer("Preamble");
+      trace::Span Tracer(Ctx, "Preamble");
       SPAN_ATTACH(Tracer, "File", That->FileName);
       std::vector<DiagWithFixIts> PreambleDiags;
       StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
@@ -1332,7 +1332,7 @@
     // Compute updated AST.
     llvm::Optional<ParsedAST> NewAST;
     {
-      trace::Span Tracer("Build");
+      trace::Span Tracer(Ctx, "Build");
       SPAN_ATTACH(Tracer, "File", That->FileName);
       NewAST = ParsedAST::Build(std::move(CI), std::move(NewPreamble),
                                 std::move(ContentsBuffer), PCHs, VFS, Ctx);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to