175 lines · c
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-exception6//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_H18#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_TRACE_H19 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. Those34/// measurements are recorded per-label, defaulting to an empty one for metrics35/// that don't care about it. This enables aggregation of measurements across36/// labels. For example a metric tracking accesses to a cache can have labels37/// 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 over51 /// 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 use62 /// 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 a66 /// metric tracking latencies. If non empty all measurements must also have a67 /// non-empty label.68 const llvm::StringLiteral LabelName;69};70 71/// A consumer of trace events and measurements. The events are produced by72/// 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 context81 /// 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 Object84 /// to hold them. This Object should be owned by the context, and the data85 /// will be complete by the time the context is destroyed.86 virtual Context87 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 strict93 // 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 and105/// trace::log. Only one TracingSession can be active at a time and it should be106/// 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 Event114/// 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/preview120std::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 Name147 /// 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 trace171} // namespace clangd172} // namespace clang173 174#endif175