1 //===--- Trace.h - Performance tracing facilities ---------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Supports writing performance traces describing clangd's behavior.
10 // Traces are consumed by implementations of the EventTracer interface.
13 // All APIs are no-ops unless a Session is active (created by ClangdMain).
15 //===----------------------------------------------------------------------===//
17 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_TRACE_H_
18 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_TRACE_H_
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"
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.
40 /// A number whose value is meaningful, and may vary over time.
41 /// Each measurement replaces the current value.
44 /// An aggregate number whose rate of change over time is meaningful.
45 /// Each measurement is an increment for the counter.
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
54 constexpr Metric(llvm::StringLiteral Name
, MetricType Type
,
55 llvm::StringLiteral LabelName
= llvm::StringLiteral(""))
56 : Name(Name
), Type(Type
), LabelName(LabelName
) {}
58 /// Records a measurement for this metric to active tracer.
59 void record(double Value
, llvm::StringRef Label
= "") const;
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
68 const llvm::StringLiteral LabelName
;
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.
76 virtual ~EventTracer() = default;
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.
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.
94 virtual void endSpan() {}
96 /// Called for instant events.
97 virtual void instant(llvm::StringRef Name
, llvm::json::Object
&&Args
) {}
99 /// Called whenever a metrics records a measurement.
100 virtual void record(const Metric
&Metric
, double Value
,
101 llvm::StringRef Label
) {}
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.
109 Session(EventTracer
&Tracer
);
113 /// Create an instance of EventTracer that produces an output in the Trace Event
114 /// format supported by Chrome's trace viewer (chrome://tracing).
116 /// FIXME: Metrics are not recorded, some could become counter events.
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);
123 /// Create an instance of EventTracer that outputs metric measurements as CSV.
125 /// Trace spans and instant events are ignored.
126 std::unique_ptr
<EventTracer
> createCSVMetricTracer(llvm::raw_ostream
&OS
);
128 /// Records a single instant event, associated with the current thread.
129 void log(const llvm::Twine
&Name
);
131 /// Returns true if there is an active tracer.
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.
137 /// This is the main public interface for producing tracing events.
139 /// Arbitrary JSON metadata can be attached while this span is active:
140 /// SPAN_ATTACH(MySpan, "Payload", SomeJSONExpr);
142 /// SomeJSONExpr is evaluated and copied only if actually needed.
145 Span(llvm::Twine Name
);
146 /// Records span's duration in seconds to \p LatencyMetric with \p Name as the
148 Span(llvm::Twine Name
, const Metric
&LatencyMetric
);
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
;
157 // Awkward constructor works around constant initialization.
158 Span(std::pair
<Context
, llvm::json::Object
*>);
159 WithContext RestoreCtx
;
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) \
166 if (auto *Args = (S).Args) \
167 (*Args)[Name] = Expr; \
171 } // namespace clangd