brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.9 KiB · 36c3745 Raw
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