19#ifdef AEGIR_ENABLE_TRACE
21#include <sys/syscall.h>
31namespace aegir::trace {
33inline std::FILE* file_handle() {
34 static std::FILE* f = []() -> std::FILE* {
35 char const* path = std::getenv(
"AEGIR_TRACE_FILE");
36 if (!path || !*path)
return nullptr;
37 std::FILE* fp = std::fopen(path,
"w");
38 if (!fp)
return nullptr;
39 std::fprintf(fp,
"[\n");
42 static std::FILE* cached = file_handle();
44 std::fprintf(cached,
"\n]\n");
54inline std::mutex& write_mutex() {
59inline std::atomic<bool>& first_event() {
60 static std::atomic<bool> v{
true};
64inline long long now_us() {
65 using namespace std::chrono;
66 return duration_cast<microseconds>(steady_clock::now().time_since_epoch())
74inline long long thread_id() {
75 static thread_local long long id =
76 static_cast<long long>(syscall(SYS_gettid));
80inline void write_complete(
char const* cat,
char const* name,
long long ts,
82 auto* f = file_handle();
84 std::lock_guard lock(write_mutex());
86 "%s{\"name\":\"%s\",\"cat\":\"%s\",\"ph\":\"X\","
87 "\"ts\":%lld,\"dur\":%lld,\"pid\":1,\"tid\":%lld}",
88 first_event().exchange(
false) ?
"" :
",\n", name, cat, ts, dur,
92inline void write_counter(
char const* cat,
char const* name,
long long value) {
93 auto* f = file_handle();
95 std::lock_guard lock(write_mutex());
97 "%s{\"name\":\"%s\",\"cat\":\"%s\",\"ph\":\"C\","
98 "\"ts\":%lld,\"pid\":1,\"tid\":%lld,\"args\":{\"value\":%lld}}",
99 first_event().exchange(
false) ?
"" :
",\n", name, cat, now_us(),
103inline void set_thread_name(std::string
const& name) {
104 auto* f = file_handle();
106 std::lock_guard lock(write_mutex());
108 "%s{\"name\":\"thread_name\",\"ph\":\"M\","
109 "\"pid\":1,\"tid\":%lld,\"args\":{\"name\":\"%s\"}}",
110 first_event().exchange(
false) ?
"" :
",\n", thread_id(),
116 ScopedEvent(
char const* cat,
char const* name)
117 : cat_{cat}, name_{name}, start_{now_us()} {}
120 write_complete(cat_, name_, start_, end - start_);
131#define AEGIR_TRACE_CONCAT_(a, b) a##b
132#define AEGIR_TRACE_CONCAT(a, b) AEGIR_TRACE_CONCAT_(a, b)
133#define AEGIR_TRACE_EVENT(cat, name) \
134 ::aegir::trace::ScopedEvent AEGIR_TRACE_CONCAT(_aegir_trace_, __LINE__) { \
137#define AEGIR_TRACE_COUNTER(cat, name, value) \
138 ::aegir::trace::write_counter(cat, name, static_cast<long long>(value))
139#define AEGIR_TRACE_THREAD_NAME(name) ::aegir::trace::set_thread_name(name)
143#define AEGIR_TRACE_EVENT(cat, name) ((void)0)
144#define AEGIR_TRACE_COUNTER(cat, name, value) ((void)0)
145#define AEGIR_TRACE_THREAD_NAME(name) ((void)0)