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
29namespace clang {
30namespace clangd {
31namespace 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.
38struct 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(""))
56 : 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.
74class EventTracer {
75public:
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.
94 virtual void endSpan() {}
95
96 /// Called for instant events.
97 virtual void instant(llvm::StringRef Name, llvm::json::Object &&Args) {}
98
99 /// Called whenever a metrics records a measurement.
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.
107class Session {
108public:
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
120std::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.
126std::unique_ptr<EventTracer> createCSVMetricTracer(llvm::raw_ostream &OS);
127
128/// Records a single instant event, associated with the current thread.
129void log(const llvm::Twine &Name);
130
131/// Returns true if there is an active tracer.
132bool 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.
143class Span {
144public:
145 Span(llvm::Twine Name);
146 /// Records span's duration in milliseconds to \p LatencyMetric with \p Name
147 /// as the 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
156private:
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

source code of clang-tools-extra/clangd/support/Trace.h