ilya-biryukov updated this revision to Diff 126328.
ilya-biryukov added a comment.

Updated the patch after changes to Context


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D40488

Files:
  clangd/ClangdUnit.cpp
  clangd/JSONRPCDispatcher.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,11 @@
   std::string JSON;
   {
     raw_string_ostream OS(JSON);
-    auto Session = trace::Session::create(OS);
+    auto JSONTracer = trace::createJSONTracer(OS);
+    trace::TracingSession Session(*JSONTracer);
     {
-      trace::Span S("A");
-      trace::log("B");
+      trace::Span S(Context::empty(), "A");
+      trace::log(Context::empty(), "B");
     }
   }
 
Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -115,19 +115,25 @@
                    << EC.message();
     }
   }
+
+  // Setup tracing facilities.
   llvm::Optional<llvm::raw_fd_ostream> TraceStream;
-  std::unique_ptr<trace::Session> TraceSession;
+  std::unique_ptr<trace::EventTracer> Tracer;
   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);
+      Tracer = trace::createJSONTracer(*TraceStream, PrettyPrint);
     }
   }
 
+  llvm::Optional<trace::TracingSession> TracingSession;
+  if (Tracer)
+    TracingSession.emplace(*Tracer);
+
   llvm::raw_ostream &Outs = llvm::outs();
   llvm::raw_ostream &Logs = llvm::errs();
   JSONOutput Out(Outs, Logs,
Index: clangd/Trace.h
===================================================================
--- clangd/Trace.h
+++ clangd/Trace.h
@@ -8,60 +8,74 @@
 //===----------------------------------------------------------------------===//
 //
 // 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 {
+/// A consumer of trace events. The events are produced by Spans and trace::log.
+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();
+  virtual ~EventTracer() = default;
+  /// Consume a trace event.
+  virtual void event(const Context &Ctx, llvm::StringRef Phase,
+                     json::obj &&Contents) = 0;
+};
 
-private:
-  Session() = default;
+/// Sets up a global EventTracer that consumes events produced by Span and
+/// trace::log. Only one TracingSession can be active at a time and it should be
+/// set up before calling any clangd-specific functions.
+class TracingSession {
+public:
+  TracingSession(EventTracer &Tracer);
+  ~TracingSession();
 };
 
-// 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(const 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(const 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:
+  llvm::Optional<Context> Ctx;
   std::unique_ptr<json::obj> Args;
 };
 
Index: clangd/Trace.cpp
===================================================================
--- clangd/Trace.cpp
+++ clangd/Trace.cpp
@@ -24,9 +24,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
@@ -39,14 +39,15 @@
                   });
   }
 
-  ~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(const Context &Ctx, 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,42 +91,48 @@
   const char *JSONFormat;
 };
 
-static Tracer *T = nullptr;
+EventTracer *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());
+TracingSession::TracingSession(EventTracer &Tracer) {
+  assert(!T && "Resetting global tracer is not allowed.");
+  T = &Tracer;
 }
 
-Session::~Session() {
-  delete T;
-  T = nullptr;
+TracingSession::~TracingSession() { 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(const Context &Ctx, const Twine &Message) {
   if (!T)
     return;
-  T->event("i", json::obj{
-                    {"name", "Log"},
-                    {"args", json::obj{{"Message", Message.str()}}},
-                });
+  T->event(Ctx, "i",
+           json::obj{
+               {"name", "Log"},
+               {"args", json::obj{{"Message", Message.str()}}},
+           });
 }
 
-Span::Span(std::string Name) {
+Span::Span(const Context &Ctx, std::string Name) {
   if (!T)
     return;
-  T->event("B", json::obj{{"name", std::move(Name)}});
+  // Clone the context, so that the original Context can be moved.
+  this->Ctx.emplace(Ctx.clone());
+
+  T->event(*this->Ctx, "B", json::obj{{"name", std::move(Name)}});
   Args = llvm::make_unique<json::obj>();
 }
 
 Span::~Span() {
   if (!T)
     return;
   if (!Args)
     Args = llvm::make_unique<json::obj>();
-  T->event("E", Args ? json::obj{{"args", std::move(*Args)}} : json::obj{});
+  T->event(*Ctx, "E",
+           Args ? json::obj{{"args", std::move(*Args)}} : json::obj{});
 }
 
 } // namespace trace
Index: clangd/JSONRPCDispatcher.cpp
===================================================================
--- clangd/JSONRPCDispatcher.cpp
+++ clangd/JSONRPCDispatcher.cpp
@@ -45,8 +45,7 @@
 }
 
 void JSONOutput::log(const 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 << '\n';
   Logs.flush();
@@ -131,15 +130,17 @@
   auto I = Handlers.find(*Method);
   auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
 
-  auto Tracer = llvm::make_unique<trace::Span>(*Method);
+  // Create a Context that contains request information.
+  Context Ctx = buildCtx().addOpt(IDKey, ID).add(OutKey, &Out);
+
+  // Create a tracing Span covering the whole request lifetime.
+  auto Tracer = llvm::make_unique<trace::Span>(Ctx, *Method);
   if (ID)
     SPAN_ATTACH(*Tracer, "ID", *ID);
   SPAN_ATTACH(*Tracer, "Params", Params);
 
-  auto Ctx = buildCtx()
-                 .addOpt(IDKey, ID)
-                 .add(OutKey, &Out)
-                 .add(TracerKey, std::move(Tracer));
+  // Update Ctx to include Tracer.
+  Ctx = Ctx.derive().add(TracerKey, std::move(Tracer));
 
   Handler(std::move(Ctx), std::move(Params));
   return true;
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -580,7 +580,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);
@@ -626,7 +626,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