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