2017-11-02 17:21:51 +08:00
|
|
|
//===--- Trace.cpp - Performance tracing facilities -----------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Trace.h"
|
|
|
|
|
|
|
|
#include "llvm/ADT/DenseSet.h"
|
|
|
|
#include "llvm/Support/Chrono.h"
|
|
|
|
#include "llvm/Support/FormatProviders.h"
|
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/Support/Threading.h"
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace trace {
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// The current implementation is naive: each thread writes to Out guarded by Mu.
|
|
|
|
// Perhaps we should replace this by something that disturbs performance less.
|
2017-12-14 23:04:59 +08:00
|
|
|
class JSONTracer : public EventTracer {
|
2017-11-02 17:21:51 +08:00
|
|
|
public:
|
2017-12-14 23:04:59 +08:00
|
|
|
JSONTracer(raw_ostream &Out, bool Pretty)
|
2017-11-24 01:12:04 +08:00
|
|
|
: Out(Out), Sep(""), Start(std::chrono::system_clock::now()),
|
|
|
|
JSONFormat(Pretty ? "{0:2}" : "{0}") {
|
2017-11-02 17:21:51 +08:00
|
|
|
// The displayTimeUnit must be ns to avoid low-precision overlap
|
|
|
|
// calculations!
|
|
|
|
Out << R"({"displayTimeUnit":"ns","traceEvents":[)"
|
|
|
|
<< "\n";
|
2017-11-24 01:12:04 +08:00
|
|
|
rawEvent("M", json::obj{
|
|
|
|
{"name", "process_name"},
|
|
|
|
{"args", json::obj{{"name", "clangd"}}},
|
|
|
|
});
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
~JSONTracer() {
|
2017-11-02 17:21:51 +08:00
|
|
|
Out << "\n]}";
|
|
|
|
Out.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Record an event on the current thread. ph, pid, tid, ts are set.
|
|
|
|
// Contents must be a list of the other JSON key/values.
|
2017-12-14 23:04:59 +08:00
|
|
|
void event(const Context &Ctx, StringRef Phase,
|
|
|
|
json::obj &&Contents) override {
|
2017-11-02 17:21:51 +08:00
|
|
|
uint64_t TID = get_threadid();
|
|
|
|
std::lock_guard<std::mutex> Lock(Mu);
|
|
|
|
// If we haven't already, emit metadata describing this thread.
|
|
|
|
if (ThreadsWithMD.insert(TID).second) {
|
|
|
|
SmallString<32> Name;
|
|
|
|
get_thread_name(Name);
|
|
|
|
if (!Name.empty()) {
|
2017-11-24 01:12:04 +08:00
|
|
|
rawEvent("M", json::obj{
|
|
|
|
{"tid", TID},
|
|
|
|
{"name", "thread_name"},
|
|
|
|
{"args", json::obj{{"name", Name}}},
|
|
|
|
});
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
}
|
2017-11-24 01:12:04 +08:00
|
|
|
Contents["ts"] = timestamp();
|
|
|
|
Contents["tid"] = TID;
|
|
|
|
rawEvent(Phase, std::move(Contents));
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Record an event. ph and pid are set.
|
|
|
|
// Contents must be a list of the other JSON key/values.
|
2017-11-24 01:12:04 +08:00
|
|
|
void rawEvent(StringRef Phase, json::obj &&Event) /*REQUIRES(Mu)*/ {
|
2017-11-02 17:21:51 +08:00
|
|
|
// PID 0 represents the clangd process.
|
2017-11-24 01:12:04 +08:00
|
|
|
Event["pid"] = 0;
|
|
|
|
Event["ph"] = Phase;
|
|
|
|
Out << Sep << formatv(JSONFormat, json::Expr(std::move(Event)));
|
2017-11-02 17:21:51 +08:00
|
|
|
Sep = ",\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
double timestamp() {
|
|
|
|
using namespace std::chrono;
|
2017-11-16 01:53:46 +08:00
|
|
|
return duration<double, std::micro>(system_clock::now() - Start).count();
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::mutex Mu;
|
|
|
|
raw_ostream &Out /*GUARDED_BY(Mu)*/;
|
|
|
|
const char *Sep /*GUARDED_BY(Mu)*/;
|
|
|
|
DenseSet<uint64_t> ThreadsWithMD /*GUARDED_BY(Mu)*/;
|
|
|
|
const sys::TimePoint<> Start;
|
2017-11-24 01:12:04 +08:00
|
|
|
const char *JSONFormat;
|
2017-11-02 17:21:51 +08:00
|
|
|
};
|
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
EventTracer *T = nullptr;
|
2017-11-02 17:21:51 +08:00
|
|
|
} // namespace
|
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
Session::Session(EventTracer &Tracer) {
|
|
|
|
assert(!T && "Resetting global tracer is not allowed.");
|
|
|
|
T = &Tracer;
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
Session::~Session() { T = nullptr; }
|
|
|
|
|
|
|
|
std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
|
|
|
|
bool Pretty) {
|
|
|
|
return llvm::make_unique<JSONTracer>(OS, Pretty);
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
void log(const Context &Ctx, const Twine &Message) {
|
2017-11-02 17:21:51 +08:00
|
|
|
if (!T)
|
|
|
|
return;
|
2017-12-14 23:04:59 +08:00
|
|
|
T->event(Ctx, "i",
|
|
|
|
json::obj{
|
|
|
|
{"name", "Log"},
|
|
|
|
{"args", json::obj{{"Message", Message.str()}}},
|
|
|
|
});
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
2017-12-14 23:04:59 +08:00
|
|
|
Span::Span(const Context &Ctx, std::string Name) {
|
2017-11-02 17:21:51 +08:00
|
|
|
if (!T)
|
|
|
|
return;
|
2017-12-14 23:04:59 +08:00
|
|
|
// Clone the context, so that the original Context can be moved.
|
|
|
|
this->Ctx.emplace(Ctx.clone());
|
|
|
|
|
|
|
|
T->event(*this->Ctx, "B", json::obj{{"name", std::move(Name)}});
|
2017-11-24 01:12:04 +08:00
|
|
|
Args = llvm::make_unique<json::obj>();
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Span::~Span() {
|
|
|
|
if (!T)
|
|
|
|
return;
|
2017-11-24 01:12:04 +08:00
|
|
|
if (!Args)
|
|
|
|
Args = llvm::make_unique<json::obj>();
|
2017-12-14 23:04:59 +08:00
|
|
|
T->event(*Ctx, "E",
|
|
|
|
Args ? json::obj{{"args", std::move(*Args)}} : json::obj{});
|
2017-11-02 17:21:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace trace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|