1 //===--- Trace.h - Performance tracing facilities ---------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Supports writing performance traces describing clangd's behavior.
10 // Traces are consumed by implementations of the EventTracer interface.
11 //
12 //
13 // All APIs are no-ops unless a Session is active (created by ClangdMain).
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_TRACE_H_
18 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_TRACE_H_
19 
20 #include "support/Context.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/ADT/Twine.h"
23 #include "llvm/Support/JSON.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <chrono>
26 #include <string>
27 #include <vector>
28 
29 namespace clang {
30 namespace clangd {
31 namespace trace {
32 
33 /// Represents measurements of clangd events, e.g. operation latency. Those
34 /// measurements are recorded per-label, defaulting to an empty one for metrics
35 /// that don't care about it. This enables aggregation of measurements across
36 /// labels. For example a metric tracking accesses to a cache can have labels
37 /// named hit and miss.
38 struct Metric {
39   enum MetricType {
40     /// A number whose value is meaningful, and may vary over time.
41     /// Each measurement replaces the current value.
42     Value,
43 
44     /// An aggregate number whose rate of change over time is meaningful.
45     /// Each measurement is an increment for the counter.
46     Counter,
47 
48     /// A distribution of values with a meaningful mean and count.
49     /// Each measured value is a sample for the distribution.
50     /// The distribution is assumed not to vary, samples are aggregated over
51     /// time.
52     Distribution,
53   };
54   constexpr Metric(llvm::StringLiteral Name, MetricType Type,
55                    llvm::StringLiteral LabelName = llvm::StringLiteral(""))
NameMetric56       : Name(Name), Type(Type), LabelName(LabelName) {}
57 
58   /// Records a measurement for this metric to active tracer.
59   void record(double Value, llvm::StringRef Label = "") const;
60 
61   /// Uniquely identifies the metric. Should use snake_case identifiers, can use
62   /// dots for hierarchy if needed. e.g. method_latency, foo.bar.
63   const llvm::StringLiteral Name;
64   const MetricType Type;
65   /// Indicates what measurement labels represent, e.g. "operation_name" for a
66   /// metric tracking latencies. If non empty all measurements must also have a
67   /// non-empty label.
68   const llvm::StringLiteral LabelName;
69 };
70 
71 /// A consumer of trace events and measurements. The events are produced by
72 /// Spans and trace::log, the measurements are produced by Metrics::record.
73 /// Implementations of this interface must be thread-safe.
74 class EventTracer {
75 public:
76   virtual ~EventTracer() = default;
77 
78   /// Called when event that has a duration starts. \p Name describes the event.
79   /// Returns a derived context that will be destroyed when the event ends.
80   /// Usually implementations will store an object in the returned context
81   /// whose destructor records the end of the event.
82   /// The tracer may capture event details provided in SPAN_ATTACH() calls.
83   /// In this case it should call AttachDetails(), and pass in an empty Object
84   /// to hold them. This Object should be owned by the context, and the data
85   /// will be complete by the time the context is destroyed.
86   virtual Context
87   beginSpan(llvm::StringRef Name,
88             llvm::function_ref<void(llvm::json::Object *)> AttachDetails);
89   // Called when a Span is destroyed (it may still be active on other threads).
90   // beginSpan() and endSpan() will always form a proper stack on each thread.
91   // The Context returned by beginSpan is active, but Args is not ready.
92   // Tracers should not override this unless they need to observe strict
93   // per-thread nesting. Instead they should observe context destruction.
endSpan()94   virtual void endSpan() {}
95 
96   /// Called for instant events.
instant(llvm::StringRef Name,llvm::json::Object && Args)97   virtual void instant(llvm::StringRef Name, llvm::json::Object &&Args) {}
98 
99   /// Called whenever a metrics records a measurement.
record(const Metric & Metric,double Value,llvm::StringRef Label)100   virtual void record(const Metric &Metric, double Value,
101                       llvm::StringRef Label) {}
102 };
103 
104 /// Sets up a global EventTracer that consumes events produced by Span and
105 /// trace::log. Only one TracingSession can be active at a time and it should be
106 /// set up before calling any clangd-specific functions.
107 class Session {
108 public:
109   Session(EventTracer &Tracer);
110   ~Session();
111 };
112 
113 /// Create an instance of EventTracer that produces an output in the Trace Event
114 /// format supported by Chrome's trace viewer (chrome://tracing).
115 ///
116 /// FIXME: Metrics are not recorded, some could become counter events.
117 ///
118 /// The format is documented here:
119 /// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
120 std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
121                                               bool Pretty = false);
122 
123 /// Create an instance of EventTracer that outputs metric measurements as CSV.
124 ///
125 /// Trace spans and instant events are ignored.
126 std::unique_ptr<EventTracer> createCSVMetricTracer(llvm::raw_ostream &OS);
127 
128 /// Records a single instant event, associated with the current thread.
129 void log(const llvm::Twine &Name);
130 
131 /// Returns true if there is an active tracer.
132 bool enabled();
133 
134 /// Records an event whose duration is the lifetime of the Span object.
135 /// This lifetime is extended when the span's context is reused.
136 ///
137 /// This is the main public interface for producing tracing events.
138 ///
139 /// Arbitrary JSON metadata can be attached while this span is active:
140 ///   SPAN_ATTACH(MySpan, "Payload", SomeJSONExpr);
141 ///
142 /// SomeJSONExpr is evaluated and copied only if actually needed.
143 class Span {
144 public:
145   Span(llvm::Twine Name);
146   /// Records span's duration in seconds to \p LatencyMetric with \p Name as the
147   /// label.
148   Span(llvm::Twine Name, const Metric &LatencyMetric);
149   ~Span();
150 
151   /// Mutable metadata, if this span is interested.
152   /// Prefer to use SPAN_ATTACH rather than accessing this directly.
153   /// The lifetime of Args is the whole event, even if the Span dies.
154   llvm::json::Object *const Args;
155 
156 private:
157   // Awkward constructor works around constant initialization.
158   Span(std::pair<Context, llvm::json::Object *>);
159   WithContext RestoreCtx;
160 };
161 
162 /// Attach a key-value pair to a Span event.
163 /// This is not threadsafe when used with the same Span.
164 #define SPAN_ATTACH(S, Name, Expr)                                             \
165   do {                                                                         \
166     if (auto *Args = (S).Args)                                                 \
167       (*Args)[Name] = Expr;                                                    \
168   } while (0)
169 
170 } // namespace trace
171 } // namespace clangd
172 } // namespace clang
173 
174 #endif
175