Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
trace_session.hpp
Go to the documentation of this file.
1// trace_session.hpp — process-global tracing session control (DEV ONLY).
2//
3// The lifecycle facade behind <pulp/runtime/trace.hpp>'s span macros. Perfetto's
4// Tracing::Initialize() + TrackEvent::Register() are PROCESS singletons and a
5// DAW loads N plugin instances into one process, so this is a single process
6// wide controller with reference-counted attachment (plan §0b item 5), not a
7// per-instance object. One active in-process session at a time.
8//
9// The API is identical in both build configs: with PULP_TRACING=OFF every call
10// is a no-op returning "inactive", so callers need no #ifdef. No Perfetto type
11// appears in this header, so OFF consumers pull in zero Perfetto headers.
12//
13// RT-safety (D1): tracing here rides UI/render/process + OFFLINE-audio threads
14// only. Never call start()/the span macros from a live audio callback.
15#pragma once
16
17#include <atomic>
18#include <cstdint>
19#include <optional>
20#include <string>
21#include <string_view>
22#include <utility>
23#include <vector>
24
25namespace pulp::runtime {
26
32bool tracing_reminder_first_time(std::atomic<bool>& already_emitted);
33
40
41namespace detail {
42
45inline constexpr std::uint32_t default_autostart_ring_kb = 80u * 1024u;
47inline constexpr std::uint32_t min_autostart_ring_kb = 1024u;
48inline constexpr std::uint32_t max_autostart_ring_kb = 4u * 1024u * 1024u;
49
63inline std::optional<std::uint32_t> parse_autostart_ring_kb(const char* raw) {
64 if (raw == nullptr || *raw == '\0') return std::nullopt;
65 std::uint64_t value = 0;
66 for (const char* c = raw; *c != '\0'; ++c) {
67 if (*c < '0' || *c > '9') return std::nullopt;
68 value = value * 10u + static_cast<std::uint64_t>(*c - '0');
69 if (value > max_autostart_ring_kb) return std::nullopt;
70 }
71 if (value < min_autostart_ring_kb) return std::nullopt;
72 return static_cast<std::uint32_t>(value);
73}
74
89 std::string path;
90 std::string seconds;
91 std::string ring_kb;
92};
93
96inline TraceAutostartConfig parse_trace_autostart(std::string_view text) {
98 while (!text.empty()) {
99 const auto end = text.find('\n');
100 auto line = text.substr(0, end);
101 text = end == std::string_view::npos ? std::string_view{} : text.substr(end + 1);
102 while (!line.empty() && (line.back() == '\r' || line.back() == ' ' || line.back() == '\t'))
103 line.remove_suffix(1);
104 while (!line.empty() && (line.front() == ' ' || line.front() == '\t')) line.remove_prefix(1);
105 if (line.empty() || line.front() == '#') continue;
106 const auto eq = line.find('=');
107 if (eq == std::string_view::npos) continue;
108 const auto key = line.substr(0, eq);
109 const auto value = std::string(line.substr(eq + 1));
110 if (key == "PULP_TRACE_PATH") config.path = value;
111 else if (key == "PULP_TRACE_SECONDS") config.seconds = value;
112 else if (key == "PULP_TRACE_RING_KB") config.ring_kb = value;
113 }
114 return config;
115}
116
120inline std::string trace_autostart_expand(const std::string& path, const std::string& temp_dir) {
121 constexpr std::string_view token = "$TMPDIR";
122 if (path.compare(0, token.size(), token) != 0) return path;
123 std::string base = temp_dir;
124 if (!base.empty() && base.back() == '/') base.pop_back();
125 return base + path.substr(token.size());
126}
127
130inline std::string trace_autostart_output_path(const std::string& path,
131 std::string_view process_name, long pid) {
132 if (path.empty() || path.back() != '/') return path;
133 std::string name(process_name.empty() ? std::string_view{"pulp"} : process_name);
134 for (auto& c : name)
135 if (c == '/' || c == ' ') c = '_';
136 return path + name + "-" + std::to_string(pid) + ".pftrace";
137}
138
139} // namespace detail
140
144 bool ok = false;
145 std::string path;
146 std::uint64_t trace_bytes = 0;
147};
148
157
160public:
162 : generation_(std::exchange(other.generation_, 0)),
163 token_(std::exchange(other.token_, 0)) {}
165 if (this != &other) {
166 generation_ = std::exchange(other.generation_, 0);
167 token_ = std::exchange(other.token_, 0);
168 }
169 return *this;
170 }
173
174private:
175 friend class Tracing;
176 TraceOwnership(std::uint64_t generation,
177 std::uint64_t token) noexcept
178 : generation_(generation), token_(token) {}
179
180 std::uint64_t generation_ = 0;
181 std::uint64_t token_ = 0;
182};
183
189
192 bool active = false;
193 bool owned = false;
194};
195
219class Tracing {
220public:
226 static bool start(const std::vector<std::string>& categories = {},
227 const std::string& out_path = {},
228 std::uint32_t ring_kb = 80u * 1024u);
229
233 const std::vector<std::string>& categories = {},
234 const std::string& out_path = {},
235 std::uint32_t ring_kb = 80u * 1024u);
236
239
241 static TraceStopResult stop_owned(const TraceOwnership& ownership);
242
245 const TraceOwnership* ownership);
246
248 static bool active();
249
254 static void attach();
255 static void detach();
256
261 static std::uint64_t session_generation();
262
265 static int attachment_count();
266};
267
277public:
278 ScopedTracingAttachment() : attached_(true) { Tracing::attach(); }
282 : attached_(other.attached_) {
283 other.attached_ = false;
284 }
286 if (this != &other) {
287 reset();
288 attached_ = other.attached_;
289 other.attached_ = false;
290 }
291 return *this;
292 }
294
296 void reset() noexcept {
297 if (!attached_) return;
298 attached_ = false;
300 }
301
302 bool attached() const noexcept { return attached_; }
303
304private:
305 bool attached_ = false;
306};
307
308} // namespace pulp::runtime
ScopedTracingAttachment & operator=(ScopedTracingAttachment &&other) noexcept
Definition trace_session.hpp:285
~ScopedTracingAttachment()
Definition trace_session.hpp:293
ScopedTracingAttachment & operator=(const ScopedTracingAttachment &)=delete
void reset() noexcept
Detach early. Idempotent.
Definition trace_session.hpp:296
ScopedTracingAttachment(const ScopedTracingAttachment &)=delete
bool attached() const noexcept
Definition trace_session.hpp:302
ScopedTracingAttachment()
Definition trace_session.hpp:278
ScopedTracingAttachment(ScopedTracingAttachment &&other) noexcept
Definition trace_session.hpp:281
Opaque authority over one exact process-global trace generation.
Definition trace_session.hpp:159
TraceOwnership(TraceOwnership &&other) noexcept
Definition trace_session.hpp:161
TraceOwnership & operator=(const TraceOwnership &)=delete
TraceOwnership & operator=(TraceOwnership &&other) noexcept
Definition trace_session.hpp:164
friend class Tracing
Definition trace_session.hpp:175
TraceOwnership(const TraceOwnership &)=delete
Process-global tracing controller.
Definition trace_session.hpp:219
static TraceStartResult start_exclusive(const std::vector< std::string > &categories={}, const std::string &out_path={}, std::uint32_t ring_kb=80u *1024u)
Start only when no process session exists, reporting whether this call actually applied the requested...
static TraceStopResult stop()
Stop the active session, flush, and write the .pftrace. No-op → ok=false.
static bool active()
Whether a process session is currently active.
static int attachment_count()
Current attachment count.
static std::uint64_t session_generation()
Generation of the session currently active, or 0 when none is.
static TraceStopResult stop_owned(const TraceOwnership &ownership)
Stop only when both opaque ownership fields match the active session.
static bool start(const std::vector< std::string > &categories={}, const std::string &out_path={}, std::uint32_t ring_kb=80u *1024u)
Start the single process session if none is active.
static void attach()
Reference-counted attachment for multi-instance hosts.
static void detach()
static TraceOwnershipStatus ownership_status(const TraceOwnership *ownership)
Read active and ownership state under one runtime lock.
Definition assert.hpp:29
constexpr std::uint32_t max_autostart_ring_kb
Definition trace_session.hpp:48
std::optional< std::uint32_t > parse_autostart_ring_kb(const char *raw)
Parse a $PULP_TRACE_RING_KB value.
Definition trace_session.hpp:63
std::string trace_autostart_expand(const std::string &path, const std::string &temp_dir)
Expand a leading $TMPDIR in an autostart path to temp_dir (the process's own temporary directory: a s...
Definition trace_session.hpp:120
constexpr std::uint32_t default_autostart_ring_kb
Ring size the env-driven autostart uses when $PULP_TRACE_RING_KB is unset.
Definition trace_session.hpp:45
constexpr std::uint32_t min_autostart_ring_kb
Accepted bounds for an override: 1 MB to 4 GB, expressed in KB.
Definition trace_session.hpp:47
TraceAutostartConfig parse_trace_autostart(std::string_view text)
Parse the autostart file's text.
Definition trace_session.hpp:96
std::string trace_autostart_output_path(const std::string &path, std::string_view process_name, long pid)
The file a process writes for path: path itself, or, for a directory (ends with '/'),...
Definition trace_session.hpp:130
Definition generated_event_source.hpp:33
void log_tracing_reminder()
Emit — at most once for the whole process — a single dev-build reminder that Perfetto tracing is comp...
TraceStartStatus
Outcome of an exclusive attempt to start the process-global trace session.
Definition trace_session.hpp:152
@ AlreadyActive
Definition trace_session.hpp:154
@ Unavailable
Definition trace_session.hpp:155
@ Started
Definition trace_session.hpp:153
@ other
Definition udev_monitor.hpp:26
bool tracing_reminder_first_time(std::atomic< bool > &already_emitted)
One-shot gate for the "tracing compiled in" reminder.
Atomic view of the process-global session relative to one ownership token.
Definition trace_session.hpp:191
bool owned
Definition trace_session.hpp:193
bool active
Definition trace_session.hpp:192
Definition trace_session.hpp:184
TraceStartStatus status
Definition trace_session.hpp:185
std::optional< TraceOwnership > ownership
Capability returned only to the caller that started this generation.
Definition trace_session.hpp:187
Result of stopping a session: the flushed trace path + basic loss accounting so a caller can tell whe...
Definition trace_session.hpp:143
std::uint64_t trace_bytes
Definition trace_session.hpp:146
std::string path
Absolute path to the flushed .pftrace.
Definition trace_session.hpp:145
bool ok
A session was active and a trace was written.
Definition trace_session.hpp:144
A traced plug-in records when PULP_TRACE_PATH is set in its host's environment, but an out-of-process...
Definition trace_session.hpp:88
std::string ring_kb
Definition trace_session.hpp:91
std::string seconds
Definition trace_session.hpp:90
std::string path
Definition trace_session.hpp:89