11#include "llvm/ADT/DenseSet.h"
12#include "llvm/ADT/ScopeExit.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/Chrono.h"
15#include "llvm/Support/FormatVariadic.h"
16#include "llvm/Support/Threading.h"
32 JSONTracer(llvm::raw_ostream &
OS,
bool Pretty)
33 :
Out(
OS, Pretty ? 2 : 0), Start(std::chrono::system_clock::now()) {
37 Out.attribute(
"displayTimeUnit",
"ns");
38 Out.attributeBegin(
"traceEvents");
40 rawEvent(
"M", llvm::json::Object{
41 {
"name",
"process_name"},
42 {
"args", llvm::json::Object{{
"name",
"clangd"}}},
57 llvm::function_ref<
void(llvm::json::Object *)> AttachDetails)
override {
58 auto JS = std::make_unique<JSONSpan>(
this,
Name);
59 AttachDetails(&JS->Args);
67 void endSpan()
override {
71 void instant(llvm::StringRef
Name, llvm::json::Object &&
Args)
override {
72 captureThreadMetadata();
74 llvm::json::Object{{
"name",
Name}, {
"args", std::move(
Args)}});
79 void jsonEvent(llvm::StringRef Phase, llvm::json::Object &&Contents,
80 uint64_t TID = llvm::get_threadid(),
double Timestamp = 0) {
81 Contents[
"ts"] = Timestamp ? Timestamp : timestamp();
82 Contents[
"tid"] = int64_t(TID);
83 std::lock_guard<std::mutex> Lock(Mu);
84 rawEvent(Phase, Contents);
90 JSONSpan(JSONTracer *Tracer, llvm::StringRef
Name)
91 : StartTime(Tracer->timestamp()), EndTime(0),
Name(
Name),
92 TID(llvm::get_threadid()), Tracer(Tracer) {
94 Tracer->captureThreadMetadata();
105 double OriginTime = (*Parent)->EndTime;
107 OriginTime = (*Parent)->StartTime;
109 auto FlowID = nextID();
112 llvm::json::Object{{
"id", FlowID},
113 {
"name",
"Context crosses threads"},
114 {
"cat",
"mock_cat"}},
115 (*Parent)->TID, (*Parent)->StartTime);
118 llvm::json::Object{{
"id", FlowID},
120 {
"name",
"Context crosses threads"},
121 {
"cat",
"mock_cat"}},
128 Tracer->jsonEvent(
"X",
129 llvm::json::Object{{
"name", std::move(
Name)},
130 {
"args", std::move(
Args)},
131 {
"dur", EndTime - StartTime}},
136 void markEnded() { EndTime = Tracer->timestamp(); }
141 static int64_t nextID() {
142 static std::atomic<int64_t> Next = {0};
147 std::atomic<double> EndTime;
152 static Key<std::unique_ptr<JSONSpan>> SpanKey;
156 void rawEvent(llvm::StringRef Phase,
157 const llvm::json::Object &Event) {
160 Out.attribute(
"pid", 0);
161 Out.attribute(
"ph", Phase);
162 for (
const auto *KV : llvm::json::sortedElements(Event))
163 Out.attribute(KV->first, KV->second);
168 void captureThreadMetadata() {
169 uint64_t TID = llvm::get_threadid();
170 std::lock_guard<std::mutex> Lock(Mu);
171 if (ThreadsWithMD.insert(TID).second) {
172 llvm::SmallString<32>
Name;
173 llvm::get_thread_name(
Name);
175 rawEvent(
"M", llvm::json::Object{
176 {
"tid", int64_t(TID)},
177 {
"name",
"thread_name"},
178 {
"args", llvm::json::Object{{
"name",
Name}}},
185 using namespace std::chrono;
186 return duration<double, std::micro>(system_clock::now() - Start).count();
190 llvm::json::OStream
Out ;
191 llvm::DenseSet<uint64_t> ThreadsWithMD ;
192 const llvm::sys::TimePoint<> Start;
197class CSVMetricTracer :
public EventTracer {
199 CSVMetricTracer(llvm::raw_ostream &Out) :
Out(
Out) {
200 Start = std::chrono::steady_clock::now();
203 Out <<
"Kind,Metric,Label,Value,Timestamp\r\n";
207 llvm::StringRef
Label)
override {
208 assert(!needsQuote(Metric.Name));
209 std::string QuotedLabel;
210 if (needsQuote(
Label))
212 uint64_t Micros = std::chrono::duration_cast<std::chrono::microseconds>(
213 std::chrono::steady_clock::now() - Start)
215 std::lock_guard<std::mutex> Lock(Mu);
216 Out << llvm::formatv(
"{0},{1},{2},{3:e},{4}.{5:6}\r\n",
217 typeName(Metric.Type), Metric.Name,
Label,
Value,
218 Micros / 1000000, Micros % 1000000);
231 llvm_unreachable(
"Unknown Metric::MetricType enum");
234 static bool needsQuote(llvm::StringRef
Text) {
236 return Text.find_first_of(
",\"\r\n") != llvm::StringRef::npos;
239 std::string quote(llvm::StringRef
Text) {
240 std::string Result =
"\"";
241 for (
char C :
Text) {
244 Result.push_back(
'"');
246 Result.push_back(
'"');
252 llvm::raw_ostream &
Out ;
253 std::chrono::steady_clock::time_point Start;
256Key<std::unique_ptr<JSONTracer::JSONSpan>> JSONTracer::SpanKey;
258EventTracer *
T =
nullptr;
262 assert(!T &&
"Resetting global tracer is not allowed.");
270 return std::make_unique<JSONTracer>(
OS, Pretty);
274 return std::make_unique<CSVMetricTracer>(
OS);
277void log(
const llvm::Twine &Message) {
280 T->instant(
"Log", llvm::json::Object{{
"Message", Message.str()}});
286static std::pair<Context, llvm::json::Object *>
290 std::optional<WithContextValue> WithLatency;
291 using Clock = std::chrono::high_resolution_clock;
292 WithLatency.emplace(llvm::make_scope_exit(
293 [StartTime = Clock::now(),
Name =
Name.str(), &LatencyMetric] {
294 LatencyMetric.record(
295 std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() -
300 llvm::json::Object *
Args =
nullptr;
302 Name.isSingleStringRef() ?
Name.getSingleStringRef()
303 : llvm::StringRef(
Name.str()),
304 [&](llvm::json::Object *A) {
305 assert(A && A->empty() &&
"Invalid AttachDetails() placeholder!");
308 return std::make_pair(std::move(Ctx),
Args);
321Span::Span(std::pair<Context, llvm::json::Object *> Pair)
322 :
Args(
Pair.second), RestoreCtx(std::move(
Pair.first)) {}
333 "recording a measurement with inconsistent labeling");
338 llvm::StringRef
Name,
339 llvm::function_ref<
void(llvm::json::Object *)> AttachDetails) {
llvm::SmallString< 256U > Name
CompiledFragmentImpl & Out
A context is an immutable container for per-request data that must be propagated through layers that ...
Context derive(const Key< Type > &Key, std::decay_t< Type > Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive().
Context clone() const
Clone this context object.
static const Context & current()
Returns the context for the current thread, creating it if needed.
const Type * get(const Key< Type > &Key) const
Get data stored for a typed Key.
const Type & getExisting(const Key< Type > &Key) const
A helper to get a reference to a Key that must exist in the map.
A consumer of trace events and measurements.
virtual Context beginSpan(llvm::StringRef Name, llvm::function_ref< void(llvm::json::Object *)> AttachDetails)
Called when event that has a duration starts.
Session(EventTracer &Tracer)
Records an event whose duration is the lifetime of the Span object.
std::unique_ptr< EventTracer > createJSONTracer(llvm::raw_ostream &OS, bool Pretty)
Create an instance of EventTracer that produces an output in the Trace Event format supported by Chro...
static std::pair< Context, llvm::json::Object * > makeSpanContext(llvm::Twine Name, const Metric &LatencyMetric)
std::unique_ptr< EventTracer > createCSVMetricTracer(llvm::raw_ostream &OS)
Create an instance of EventTracer that outputs metric measurements as CSV.
void log(const llvm::Twine &Message)
Records a single instant event, associated with the current thread.
constexpr Metric SpanLatency("span_latency", Metric::Distribution, "span_name")
bool enabled()
Returns true if there is an active tracer.
void record(const MemoryTree &MT, std::string RootName, const trace::Metric &Out)
Records total memory usage of each node under Out.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents measurements of clangd events, e.g.
const llvm::StringLiteral LabelName
Indicates what measurement labels represent, e.g.
@ Value
A number whose value is meaningful, and may vary over time.
@ Counter
An aggregate number whose rate of change over time is meaningful.
@ Distribution
A distribution of values with a meaningful mean and count.
void record(double Value, llvm::StringRef Label="") const
Records a measurement for this metric to active tracer.