Index: clangd/Trace.h =================================================================== --- clangd/Trace.h +++ clangd/Trace.h @@ -19,6 +19,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_ #include "Context.h" +#include "Function.h" #include "JSONExpr.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" @@ -28,12 +29,24 @@ namespace trace { /// A consumer of trace events. The events are produced by Spans and trace::log. +/// Implmentations of this interface must be thread-safe. class EventTracer { public: + /// A callback executed when an event with duration ends. Args represent data + /// that was attached to the event via SPAN_ATTACH. + using EndEventCallback = UniqueFunction; + virtual ~EventTracer() = default; - /// Consume a trace event. - virtual void event(const Context &Ctx, llvm::StringRef Phase, - json::obj &&Contents) = 0; + + /// Called when event that has a duration starts. The returned callback will + /// be executed when the event ends. \p Name is a descriptive name + /// of the event that was passed to Span constructor. + virtual EndEventCallback beginSpan(const Context &Ctx, + llvm::StringRef Name) = 0; + + /// Called for instant events. + virtual void instant(const Context &Ctx, llvm::StringRef Name, + json::obj &&Args) = 0; }; /// Sets up a global EventTracer that consumes events produced by Span and @@ -50,9 +63,6 @@ /// /// 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 createJSONTracer(llvm::raw_ostream &OS, bool Pretty = false); @@ -67,7 +77,7 @@ /// SomeJSONExpr is evaluated and copied only if actually needed. class Span { public: - Span(const Context &Ctx, std::string Name); + Span(const Context &Ctx, llvm::StringRef Name); ~Span(); /// Returns mutable span metadata if this span is interested. @@ -75,8 +85,8 @@ json::obj *args() { return Args.get(); } private: - llvm::Optional Ctx; std::unique_ptr Args; + EventTracer::EndEventCallback Callback; }; #define SPAN_ATTACH(S, Name, Expr) \ Index: clangd/Trace.cpp =================================================================== --- clangd/Trace.cpp +++ clangd/Trace.cpp @@ -44,10 +44,24 @@ Out.flush(); } + EndEventCallback beginSpan(const Context &Ctx, + llvm::StringRef Name) override { + jsonEvent("B", json::obj{{"name", Name}}); + + // The callback that will run when event ends. + return [this](json::Expr &&Args) { + jsonEvent("E", json::obj{{"args", std::move(Args)}}); + }; + } + + void instant(const 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(const Context &Ctx, 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. @@ -109,30 +123,26 @@ void log(const Context &Ctx, const Twine &Message) { if (!T) return; - T->event(Ctx, "i", - json::obj{ - {"name", "Log"}, - {"args", json::obj{{"Message", Message.str()}}}, - }); + T->instant(Ctx, "Log", json::obj{{"Message", Message.str()}}); } -Span::Span(const Context &Ctx, std::string Name) { +Span::Span(const Context &Ctx, llvm::StringRef Name) { if (!T) return; - // 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)}}); + Callback = T->beginSpan(Ctx, Name); + if (!Callback) + return; + Args = llvm::make_unique(); } Span::~Span() { - if (!T) + if (!Callback) return; - if (!Args) - Args = llvm::make_unique(); - T->event(*Ctx, "E", - Args ? json::obj{{"args", std::move(*Args)}} : json::obj{}); + + assert(Args && "Args must be non-null if Callback is defined"); + Callback(std::move(*Args)); } } // namespace trace