xref: /llvm-project/clang-tools-extra/clangd/support/Trace.cpp (revision b15fcdaf79e9b5931e8a7f9e09f8e3842d262dd7)
1ad97ccf6SSam McCall //===--- Trace.cpp - Performance tracing facilities -----------------------===//
2ad97ccf6SSam McCall //
3ad97ccf6SSam McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ad97ccf6SSam McCall // See https://llvm.org/LICENSE.txt for license information.
5ad97ccf6SSam McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ad97ccf6SSam McCall //
7ad97ccf6SSam McCall //===----------------------------------------------------------------------===//
8ad97ccf6SSam McCall 
9ad97ccf6SSam McCall #include "support/Trace.h"
10ad97ccf6SSam McCall #include "support/Context.h"
11ad97ccf6SSam McCall #include "llvm/ADT/DenseSet.h"
12ad97ccf6SSam McCall #include "llvm/ADT/ScopeExit.h"
13e64f99c5SKadir Cetinkaya #include "llvm/ADT/StringRef.h"
14ad97ccf6SSam McCall #include "llvm/Support/Chrono.h"
15ad97ccf6SSam McCall #include "llvm/Support/FormatVariadic.h"
16ad97ccf6SSam McCall #include "llvm/Support/Threading.h"
17ad97ccf6SSam McCall #include <atomic>
18e64f99c5SKadir Cetinkaya #include <chrono>
19e64f99c5SKadir Cetinkaya #include <memory>
20ad97ccf6SSam McCall #include <mutex>
212c675be9SKazu Hirata #include <optional>
22ad97ccf6SSam McCall 
23ad97ccf6SSam McCall namespace clang {
24ad97ccf6SSam McCall namespace clangd {
25ad97ccf6SSam McCall namespace trace {
26ad97ccf6SSam McCall 
27ad97ccf6SSam McCall namespace {
28ad97ccf6SSam McCall // The current implementation is naive: each thread writes to Out guarded by Mu.
29ad97ccf6SSam McCall // Perhaps we should replace this by something that disturbs performance less.
30ad97ccf6SSam McCall class JSONTracer : public EventTracer {
31ad97ccf6SSam McCall public:
JSONTracer(llvm::raw_ostream & OS,bool Pretty)32ad97ccf6SSam McCall   JSONTracer(llvm::raw_ostream &OS, bool Pretty)
33ad97ccf6SSam McCall       : Out(OS, Pretty ? 2 : 0), Start(std::chrono::system_clock::now()) {
34ad97ccf6SSam McCall     // The displayTimeUnit must be ns to avoid low-precision overlap
35ad97ccf6SSam McCall     // calculations!
36ad97ccf6SSam McCall     Out.objectBegin();
37ad97ccf6SSam McCall     Out.attribute("displayTimeUnit", "ns");
38ad97ccf6SSam McCall     Out.attributeBegin("traceEvents");
39ad97ccf6SSam McCall     Out.arrayBegin();
40ad97ccf6SSam McCall     rawEvent("M", llvm::json::Object{
41ad97ccf6SSam McCall                       {"name", "process_name"},
42ad97ccf6SSam McCall                       {"args", llvm::json::Object{{"name", "clangd"}}},
43ad97ccf6SSam McCall                   });
44ad97ccf6SSam McCall   }
45ad97ccf6SSam McCall 
~JSONTracer()46ad97ccf6SSam McCall   ~JSONTracer() {
47ad97ccf6SSam McCall     Out.arrayEnd();
48ad97ccf6SSam McCall     Out.attributeEnd();
49ad97ccf6SSam McCall     Out.objectEnd();
50ad97ccf6SSam McCall     Out.flush();
51ad97ccf6SSam McCall   }
52ad97ccf6SSam McCall 
53ad97ccf6SSam McCall   // We stash a Span object in the context. It will record the start/end,
54ad97ccf6SSam McCall   // and this also allows us to look up the parent Span's information.
beginSpan(llvm::StringRef Name,llvm::function_ref<void (llvm::json::Object *)> AttachDetails)558f1de22cSSam McCall   Context beginSpan(
568f1de22cSSam McCall       llvm::StringRef Name,
578f1de22cSSam McCall       llvm::function_ref<void(llvm::json::Object *)> AttachDetails) override {
588f1de22cSSam McCall     auto JS = std::make_unique<JSONSpan>(this, Name);
598f1de22cSSam McCall     AttachDetails(&JS->Args);
608f1de22cSSam McCall     return Context::current().derive(SpanKey, std::move(JS));
61ad97ccf6SSam McCall   }
62ad97ccf6SSam McCall 
63ad97ccf6SSam McCall   // Trace viewer requires each thread to properly stack events.
64ad97ccf6SSam McCall   // So we need to mark only duration that the span was active on the thread.
65ad97ccf6SSam McCall   // (Hopefully any off-thread activity will be connected by a flow event).
66ad97ccf6SSam McCall   // Record the end time here, but don't write the event: Args aren't ready yet.
endSpan()67ad97ccf6SSam McCall   void endSpan() override {
68ad97ccf6SSam McCall     Context::current().getExisting(SpanKey)->markEnded();
69ad97ccf6SSam McCall   }
70ad97ccf6SSam McCall 
instant(llvm::StringRef Name,llvm::json::Object && Args)71ad97ccf6SSam McCall   void instant(llvm::StringRef Name, llvm::json::Object &&Args) override {
72ad97ccf6SSam McCall     captureThreadMetadata();
73ad97ccf6SSam McCall     jsonEvent("i",
74ad97ccf6SSam McCall               llvm::json::Object{{"name", Name}, {"args", std::move(Args)}});
75ad97ccf6SSam McCall   }
76ad97ccf6SSam McCall 
77ad97ccf6SSam McCall   // Record an event on the current thread. ph, pid, tid, ts are set.
78ad97ccf6SSam McCall   // Contents must be a list of the other JSON key/values.
jsonEvent(llvm::StringRef Phase,llvm::json::Object && Contents,uint64_t TID=llvm::get_threadid (),double Timestamp=0)79ad97ccf6SSam McCall   void jsonEvent(llvm::StringRef Phase, llvm::json::Object &&Contents,
80ad97ccf6SSam McCall                  uint64_t TID = llvm::get_threadid(), double Timestamp = 0) {
81ad97ccf6SSam McCall     Contents["ts"] = Timestamp ? Timestamp : timestamp();
82ad97ccf6SSam McCall     Contents["tid"] = int64_t(TID);
83ad97ccf6SSam McCall     std::lock_guard<std::mutex> Lock(Mu);
84ad97ccf6SSam McCall     rawEvent(Phase, Contents);
85ad97ccf6SSam McCall   }
86ad97ccf6SSam McCall 
87ad97ccf6SSam McCall private:
88ad97ccf6SSam McCall   class JSONSpan {
89ad97ccf6SSam McCall   public:
JSONSpan(JSONTracer * Tracer,llvm::StringRef Name)908f1de22cSSam McCall     JSONSpan(JSONTracer *Tracer, llvm::StringRef Name)
91ad97ccf6SSam McCall         : StartTime(Tracer->timestamp()), EndTime(0), Name(Name),
928f1de22cSSam McCall           TID(llvm::get_threadid()), Tracer(Tracer) {
93ad97ccf6SSam McCall       // ~JSONSpan() may run in a different thread, so we need to capture now.
94ad97ccf6SSam McCall       Tracer->captureThreadMetadata();
95ad97ccf6SSam McCall 
96ad97ccf6SSam McCall       // We don't record begin events here (and end events in the destructor)
97ad97ccf6SSam McCall       // because B/E pairs have to appear in the right order, which is awkward.
98ad97ccf6SSam McCall       // Instead we send the complete (X) event in the destructor.
99ad97ccf6SSam McCall 
100ad97ccf6SSam McCall       // If our parent was on a different thread, add an arrow to this span.
101ad97ccf6SSam McCall       auto *Parent = Context::current().get(SpanKey);
102ad97ccf6SSam McCall       if (Parent && *Parent && (*Parent)->TID != TID) {
103ad97ccf6SSam McCall         // If the parent span ended already, then show this as "following" it.
104ad97ccf6SSam McCall         // Otherwise show us as "parallel".
105ad97ccf6SSam McCall         double OriginTime = (*Parent)->EndTime;
106ad97ccf6SSam McCall         if (!OriginTime)
107ad97ccf6SSam McCall           OriginTime = (*Parent)->StartTime;
108ad97ccf6SSam McCall 
109ad97ccf6SSam McCall         auto FlowID = nextID();
110ad97ccf6SSam McCall         Tracer->jsonEvent(
111ad97ccf6SSam McCall             "s",
112ad97ccf6SSam McCall             llvm::json::Object{{"id", FlowID},
113ad97ccf6SSam McCall                                {"name", "Context crosses threads"},
114f71404c3SKadir Cetinkaya                                {"cat", "mock_cat"}},
115ad97ccf6SSam McCall             (*Parent)->TID, (*Parent)->StartTime);
116ad97ccf6SSam McCall         Tracer->jsonEvent(
117ad97ccf6SSam McCall             "f",
118ad97ccf6SSam McCall             llvm::json::Object{{"id", FlowID},
119ad97ccf6SSam McCall                                {"bp", "e"},
120ad97ccf6SSam McCall                                {"name", "Context crosses threads"},
121f71404c3SKadir Cetinkaya                                {"cat", "mock_cat"}},
122ad97ccf6SSam McCall             TID);
123ad97ccf6SSam McCall       }
124ad97ccf6SSam McCall     }
125ad97ccf6SSam McCall 
~JSONSpan()126ad97ccf6SSam McCall     ~JSONSpan() {
127ad97ccf6SSam McCall       // Finally, record the event (ending at EndTime, not timestamp())!
128ad97ccf6SSam McCall       Tracer->jsonEvent("X",
129ad97ccf6SSam McCall                         llvm::json::Object{{"name", std::move(Name)},
1308f1de22cSSam McCall                                            {"args", std::move(Args)},
131ad97ccf6SSam McCall                                            {"dur", EndTime - StartTime}},
132ad97ccf6SSam McCall                         TID, StartTime);
133ad97ccf6SSam McCall     }
134ad97ccf6SSam McCall 
135ad97ccf6SSam McCall     // May be called by any thread.
markEnded()136ad97ccf6SSam McCall     void markEnded() { EndTime = Tracer->timestamp(); }
137ad97ccf6SSam McCall 
1388f1de22cSSam McCall     llvm::json::Object Args;
1398f1de22cSSam McCall 
140ad97ccf6SSam McCall   private:
nextID()141ad97ccf6SSam McCall     static int64_t nextID() {
142ad97ccf6SSam McCall       static std::atomic<int64_t> Next = {0};
143ad97ccf6SSam McCall       return Next++;
144ad97ccf6SSam McCall     }
145ad97ccf6SSam McCall 
146ad97ccf6SSam McCall     double StartTime;
147ad97ccf6SSam McCall     std::atomic<double> EndTime; // Filled in by markEnded().
148ad97ccf6SSam McCall     std::string Name;
149ad97ccf6SSam McCall     uint64_t TID;
150ad97ccf6SSam McCall     JSONTracer *Tracer;
151ad97ccf6SSam McCall   };
152ad97ccf6SSam McCall   static Key<std::unique_ptr<JSONSpan>> SpanKey;
153ad97ccf6SSam McCall 
154ad97ccf6SSam McCall   // Record an event. ph and pid are set.
155ad97ccf6SSam McCall   // Contents must be a list of the other JSON key/values.
rawEvent(llvm::StringRef Phase,const llvm::json::Object & Event)156ad97ccf6SSam McCall   void rawEvent(llvm::StringRef Phase,
157ad97ccf6SSam McCall                 const llvm::json::Object &Event) /*REQUIRES(Mu)*/ {
158ad97ccf6SSam McCall     // PID 0 represents the clangd process.
159ad97ccf6SSam McCall     Out.object([&] {
160ad97ccf6SSam McCall       Out.attribute("pid", 0);
161ad97ccf6SSam McCall       Out.attribute("ph", Phase);
162*b15fcdafSFangrui Song       for (const auto *KV : llvm::json::sortedElements(Event))
163*b15fcdafSFangrui Song         Out.attribute(KV->first, KV->second);
164ad97ccf6SSam McCall     });
165ad97ccf6SSam McCall   }
166ad97ccf6SSam McCall 
167ad97ccf6SSam McCall   // If we haven't already, emit metadata describing this thread.
captureThreadMetadata()168ad97ccf6SSam McCall   void captureThreadMetadata() {
169ad97ccf6SSam McCall     uint64_t TID = llvm::get_threadid();
170ad97ccf6SSam McCall     std::lock_guard<std::mutex> Lock(Mu);
171ad97ccf6SSam McCall     if (ThreadsWithMD.insert(TID).second) {
172ad97ccf6SSam McCall       llvm::SmallString<32> Name;
173ad97ccf6SSam McCall       llvm::get_thread_name(Name);
174ad97ccf6SSam McCall       if (!Name.empty()) {
175ad97ccf6SSam McCall         rawEvent("M", llvm::json::Object{
176ad97ccf6SSam McCall                           {"tid", int64_t(TID)},
177ad97ccf6SSam McCall                           {"name", "thread_name"},
178ad97ccf6SSam McCall                           {"args", llvm::json::Object{{"name", Name}}},
179ad97ccf6SSam McCall                       });
180ad97ccf6SSam McCall       }
181ad97ccf6SSam McCall     }
182ad97ccf6SSam McCall   }
183ad97ccf6SSam McCall 
timestamp()184ad97ccf6SSam McCall   double timestamp() {
185ad97ccf6SSam McCall     using namespace std::chrono;
186ad97ccf6SSam McCall     return duration<double, std::micro>(system_clock::now() - Start).count();
187ad97ccf6SSam McCall   }
188ad97ccf6SSam McCall 
189ad97ccf6SSam McCall   std::mutex Mu;
190ad97ccf6SSam McCall   llvm::json::OStream Out /*GUARDED_BY(Mu)*/;
191ad97ccf6SSam McCall   llvm::DenseSet<uint64_t> ThreadsWithMD /*GUARDED_BY(Mu)*/;
192ad97ccf6SSam McCall   const llvm::sys::TimePoint<> Start;
193ad97ccf6SSam McCall };
194ad97ccf6SSam McCall 
1959b88a190SSam McCall // We emit CSV as specified in RFC 4180: https://www.ietf.org/rfc/rfc4180.txt.
1969b88a190SSam McCall // \r\n line endings are used, cells with \r\n," are quoted, quotes are doubled.
1979b88a190SSam McCall class CSVMetricTracer : public EventTracer {
1989b88a190SSam McCall public:
CSVMetricTracer(llvm::raw_ostream & Out)1999b88a190SSam McCall   CSVMetricTracer(llvm::raw_ostream &Out) : Out(Out) {
2009b88a190SSam McCall     Start = std::chrono::steady_clock::now();
2019b88a190SSam McCall 
2029b88a190SSam McCall     Out.SetUnbuffered(); // We write each line atomically.
2039b88a190SSam McCall     Out << "Kind,Metric,Label,Value,Timestamp\r\n";
2049b88a190SSam McCall   }
2059b88a190SSam McCall 
record(const Metric & Metric,double Value,llvm::StringRef Label)2069b88a190SSam McCall   void record(const Metric &Metric, double Value,
2079b88a190SSam McCall               llvm::StringRef Label) override {
2089b88a190SSam McCall     assert(!needsQuote(Metric.Name));
2099b88a190SSam McCall     std::string QuotedLabel;
2109b88a190SSam McCall     if (needsQuote(Label))
2119b88a190SSam McCall       Label = QuotedLabel = quote(Label);
2129b88a190SSam McCall     uint64_t Micros = std::chrono::duration_cast<std::chrono::microseconds>(
2139b88a190SSam McCall                           std::chrono::steady_clock::now() - Start)
2149b88a190SSam McCall                           .count();
2159b88a190SSam McCall     std::lock_guard<std::mutex> Lock(Mu);
2169b88a190SSam McCall     Out << llvm::formatv("{0},{1},{2},{3:e},{4}.{5:6}\r\n",
2179b88a190SSam McCall                          typeName(Metric.Type), Metric.Name, Label, Value,
2189b88a190SSam McCall                          Micros / 1000000, Micros % 1000000);
2199b88a190SSam McCall   }
2209b88a190SSam McCall 
2219b88a190SSam McCall private:
typeName(Metric::MetricType T)2229b88a190SSam McCall   llvm::StringRef typeName(Metric::MetricType T) {
2239b88a190SSam McCall     switch (T) {
2249b88a190SSam McCall     case Metric::Value:
2259b88a190SSam McCall       return "v";
2269b88a190SSam McCall     case Metric::Counter:
2279b88a190SSam McCall       return "c";
2289b88a190SSam McCall     case Metric::Distribution:
2299b88a190SSam McCall       return "d";
2309b88a190SSam McCall     }
2316e991994SSimon Pilgrim     llvm_unreachable("Unknown Metric::MetricType enum");
2329b88a190SSam McCall   }
2339b88a190SSam McCall 
needsQuote(llvm::StringRef Text)2349b88a190SSam McCall   static bool needsQuote(llvm::StringRef Text) {
2359b88a190SSam McCall     // https://www.ietf.org/rfc/rfc4180.txt section 2.6
2369b88a190SSam McCall     return Text.find_first_of(",\"\r\n") != llvm::StringRef::npos;
2379b88a190SSam McCall   }
2389b88a190SSam McCall 
quote(llvm::StringRef Text)2399b88a190SSam McCall   std::string quote(llvm::StringRef Text) {
2409b88a190SSam McCall     std::string Result = "\"";
2419b88a190SSam McCall     for (char C : Text) {
2429b88a190SSam McCall       Result.push_back(C);
2439b88a190SSam McCall       if (C == '"')
2449b88a190SSam McCall         Result.push_back('"');
2459b88a190SSam McCall     }
2469b88a190SSam McCall     Result.push_back('"');
2479b88a190SSam McCall     return Result;
2489b88a190SSam McCall   }
2499b88a190SSam McCall 
2509b88a190SSam McCall private:
2519b88a190SSam McCall   std::mutex Mu;
2529b88a190SSam McCall   llvm::raw_ostream &Out /*GUARDED_BY(Mu)*/;
2539b88a190SSam McCall   std::chrono::steady_clock::time_point Start;
2549b88a190SSam McCall };
2559b88a190SSam McCall 
256ad97ccf6SSam McCall Key<std::unique_ptr<JSONTracer::JSONSpan>> JSONTracer::SpanKey;
257ad97ccf6SSam McCall 
258ad97ccf6SSam McCall EventTracer *T = nullptr;
259ad97ccf6SSam McCall } // namespace
260ad97ccf6SSam McCall 
Session(EventTracer & Tracer)261ad97ccf6SSam McCall Session::Session(EventTracer &Tracer) {
262ad97ccf6SSam McCall   assert(!T && "Resetting global tracer is not allowed.");
263ad97ccf6SSam McCall   T = &Tracer;
264ad97ccf6SSam McCall }
265ad97ccf6SSam McCall 
~Session()266ad97ccf6SSam McCall Session::~Session() { T = nullptr; }
267ad97ccf6SSam McCall 
createJSONTracer(llvm::raw_ostream & OS,bool Pretty)268ad97ccf6SSam McCall std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
269ad97ccf6SSam McCall                                               bool Pretty) {
270ad97ccf6SSam McCall   return std::make_unique<JSONTracer>(OS, Pretty);
271ad97ccf6SSam McCall }
272ad97ccf6SSam McCall 
createCSVMetricTracer(llvm::raw_ostream & OS)2739b88a190SSam McCall std::unique_ptr<EventTracer> createCSVMetricTracer(llvm::raw_ostream &OS) {
2749b88a190SSam McCall   return std::make_unique<CSVMetricTracer>(OS);
2759b88a190SSam McCall }
2769b88a190SSam McCall 
log(const llvm::Twine & Message)277ad97ccf6SSam McCall void log(const llvm::Twine &Message) {
278ad97ccf6SSam McCall   if (!T)
279ad97ccf6SSam McCall     return;
280ad97ccf6SSam McCall   T->instant("Log", llvm::json::Object{{"Message", Message.str()}});
281ad97ccf6SSam McCall }
282ad97ccf6SSam McCall 
enabled()28320f69ccfSKadir Cetinkaya bool enabled() { return T != nullptr; }
28420f69ccfSKadir Cetinkaya 
2858f1de22cSSam McCall // The JSON object is event args (owned by context), if the tracer wants them.
2868f1de22cSSam McCall static std::pair<Context, llvm::json::Object *>
makeSpanContext(llvm::Twine Name,const Metric & LatencyMetric)2878f1de22cSSam McCall makeSpanContext(llvm::Twine Name, const Metric &LatencyMetric) {
288ad97ccf6SSam McCall   if (!T)
2898f1de22cSSam McCall     return std::make_pair(Context::current().clone(), nullptr);
2902c675be9SKazu Hirata   std::optional<WithContextValue> WithLatency;
291e64f99c5SKadir Cetinkaya   using Clock = std::chrono::high_resolution_clock;
292e64f99c5SKadir Cetinkaya   WithLatency.emplace(llvm::make_scope_exit(
293e64f99c5SKadir Cetinkaya       [StartTime = Clock::now(), Name = Name.str(), &LatencyMetric] {
294e64f99c5SKadir Cetinkaya         LatencyMetric.record(
295e64f99c5SKadir Cetinkaya             std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() -
296e64f99c5SKadir Cetinkaya                                                                   StartTime)
297e64f99c5SKadir Cetinkaya                 .count(),
298e64f99c5SKadir Cetinkaya             Name);
299e64f99c5SKadir Cetinkaya       }));
3008f1de22cSSam McCall   llvm::json::Object *Args = nullptr;
3018f1de22cSSam McCall   Context Ctx = T->beginSpan(
3028f1de22cSSam McCall       Name.isSingleStringRef() ? Name.getSingleStringRef()
303ad97ccf6SSam McCall                                : llvm::StringRef(Name.str()),
3048f1de22cSSam McCall       [&](llvm::json::Object *A) {
3058f1de22cSSam McCall         assert(A && A->empty() && "Invalid AttachDetails() placeholder!");
3068f1de22cSSam McCall         Args = A;
3078f1de22cSSam McCall       });
3088f1de22cSSam McCall   return std::make_pair(std::move(Ctx), Args);
309ad97ccf6SSam McCall }
310ad97ccf6SSam McCall 
311e64f99c5SKadir Cetinkaya // Fallback metric that measures latencies for spans without an explicit latency
312e64f99c5SKadir Cetinkaya // metric. Labels are span names.
313e64f99c5SKadir Cetinkaya constexpr Metric SpanLatency("span_latency", Metric::Distribution, "span_name");
314e64f99c5SKadir Cetinkaya 
315ad97ccf6SSam McCall // Span keeps a non-owning pointer to the args, which is how users access them.
316ad97ccf6SSam McCall // The args are owned by the context though. They stick around until the
317ad97ccf6SSam McCall // beginSpan() context is destroyed, when the tracing engine will consume them.
Span(llvm::Twine Name)318e64f99c5SKadir Cetinkaya Span::Span(llvm::Twine Name) : Span(Name, SpanLatency) {}
Span(llvm::Twine Name,const Metric & LatencyMetric)319e64f99c5SKadir Cetinkaya Span::Span(llvm::Twine Name, const Metric &LatencyMetric)
3208f1de22cSSam McCall     : Span(makeSpanContext(Name, LatencyMetric)) {}
Span(std::pair<Context,llvm::json::Object * > Pair)3218f1de22cSSam McCall Span::Span(std::pair<Context, llvm::json::Object *> Pair)
3228f1de22cSSam McCall     : Args(Pair.second), RestoreCtx(std::move(Pair.first)) {}
323ad97ccf6SSam McCall 
~Span()324ad97ccf6SSam McCall Span::~Span() {
325ad97ccf6SSam McCall   if (T)
326ad97ccf6SSam McCall     T->endSpan();
327ad97ccf6SSam McCall }
328ad97ccf6SSam McCall 
record(double Value,llvm::StringRef Label) const329e64f99c5SKadir Cetinkaya void Metric::record(double Value, llvm::StringRef Label) const {
330e64f99c5SKadir Cetinkaya   if (!T)
331e64f99c5SKadir Cetinkaya     return;
332e64f99c5SKadir Cetinkaya   assert((LabelName.empty() == Label.empty()) &&
333e64f99c5SKadir Cetinkaya          "recording a measurement with inconsistent labeling");
334e64f99c5SKadir Cetinkaya   T->record(*this, Value, Label);
335e64f99c5SKadir Cetinkaya }
336e64f99c5SKadir Cetinkaya 
beginSpan(llvm::StringRef Name,llvm::function_ref<void (llvm::json::Object *)> AttachDetails)3378f1de22cSSam McCall Context EventTracer::beginSpan(
3388f1de22cSSam McCall     llvm::StringRef Name,
3398f1de22cSSam McCall     llvm::function_ref<void(llvm::json::Object *)> AttachDetails) {
340e64f99c5SKadir Cetinkaya   return Context::current().clone();
341e64f99c5SKadir Cetinkaya }
342ad97ccf6SSam McCall } // namespace trace
343ad97ccf6SSam McCall } // namespace clangd
344ad97ccf6SSam McCall } // namespace clang
345