Index: clangd/Trace.h =================================================================== --- clangd/Trace.h +++ clangd/Trace.h @@ -27,12 +27,29 @@ namespace clangd { namespace trace { +/// A sink for consuming tracing events. Calls to begin_event and end_event with +/// the same name are always properly nested by using a RAII object (Span). +/// However, global tracers (i.e., returned from the global Context object) may +/// be called concurrently and have to be properly synchronized. For per-request +/// EventTracers (i.e., returned from the request-specific Context objects) the +/// calls to begin_event and end_event must be properly synchronized and must +/// never be called concurrently. class EventTracer { public: + /// A key used by trace::Span and trace::log to find EventTracer in a \p + /// Context. static PtrKey CtxKey; virtual ~EventTracer() = default; - virtual void event(llvm::StringRef Phase, json::obj &&Contents) = 0; + + /// Called when event with \p Name starts. + virtual void begin_event(Context &Ctx, llvm::StringRef Name) = 0; + /// Called when event with \p Name ends. + virtual void end_event(Context &Ctx, llvm::StringRef Name, + json::obj &&Args) = 0; + /// Called for instant events. + virtual void instant_event(Context &Ctx, llvm::StringRef Name, + json::obj &&Args) = 0; }; /// Create an instance of EventTracer that produces an output in the Trace Event @@ -66,6 +83,7 @@ private: Context &Ctx; + std::string Name; std::unique_ptr Args; }; Index: clangd/Trace.cpp =================================================================== --- clangd/Trace.cpp +++ clangd/Trace.cpp @@ -45,9 +45,23 @@ Out.flush(); } + void begin_event(Context &Ctx, llvm::StringRef Name) override { + jsonEvent("B", json::obj{{"name", Name}}); + } + + void end_event(Context &Ctx, llvm::StringRef Name, + json::obj &&Args) override { + jsonEvent("E", json::obj{{"name", Name}, {"args", std::move(Args)}}); + } + + void instant_event(Context &Ctx, llvm::StringRef Name, + json::obj &&Args) override { + jsonEvent("i", json::obj{{"name", Name}, {"args", std::move(Args)}}); + } + // 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) override { + void jsonEvent(StringRef Phase, json::obj &&Contents) { uint64_t TID = get_threadid(); std::lock_guard Lock(Mu); // If we haven't already, emit metadata describing this thread. @@ -103,17 +117,14 @@ EventTracer *T = Ctx.get(EventTracer::CtxKey); if (!T) return; - T->event("i", json::obj{ - {"name", "Log"}, - {"args", json::obj{{"Message", Message.str()}}}, - }); + T->instant_event("Log", json::obj{{"Message", Message.str()}}); } -Span::Span(Context &Ctx, std::string Name) : Ctx(Ctx) { - EventTracer* T = Ctx.get(EventTracer::CtxKey); +Span::Span(Context &Ctx, std::string Name) : Ctx(Ctx), Name(std::move(Name)) { + EventTracer *T = Ctx.get(EventTracer::CtxKey); if (!T) return; - T->event("B", json::obj{{"name", std::move(Name)}}); + T->begin_event(this->Name); Args = llvm::make_unique(); } @@ -121,9 +132,8 @@ auto T = Ctx.get(EventTracer::CtxKey); if (!T) return; - if (!Args) - Args = llvm::make_unique(); - T->event("E", Args ? json::obj{{"args", std::move(*Args)}} : json::obj{}); + assert(Args && "Args can't be null at this point"); + T->end_event(Name, std::move(*Args)); } } // namespace trace