Zth (libzth)
Loading...
Searching...
No Matches
perf.h
Go to the documentation of this file.
1#ifndef ZTH_PERF_H
2#define ZTH_PERF_H
3/*
4 * SPDX-FileCopyrightText: 2019-2026 Jochem Rutgers
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 */
8
22#include <libzth/macros.h>
23
24#include <libzth/util.h>
25
26typedef struct {
27 void* p;
29
31typedef void(zth_perf_dump_callback_t)(void const*, size_t);
32
33#ifdef __cplusplus
34
35# include <libzth/allocator.h>
36# include <libzth/config.h>
37# include <libzth/time.h>
38
39# include <cstdio>
40# include <cstdlib>
41# include <cstring>
42
43namespace zth {
44
45int perf_init();
46void perf_deinit();
47
48class Fiber;
49
50ZTH_EXPORT void perf_start(zth_perf_done_callback_t* f = nullptr) noexcept;
51ZTH_EXPORT void perf_stop() noexcept;
52ZTH_EXPORT void perf_mark(char const* marker, Timestamp const& t = Timestamp()) noexcept;
53ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 0))) void
54perf_logv(char const* fmt, va_list args, Timestamp const& t = Timestamp()) noexcept;
55ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 2))) void
56perf_log(char const* fmt, ...) noexcept;
57ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 2, 3))) void
58perf_log(Timestamp const& t, char const* fmt, ...) noexcept;
59ZTH_EXPORT void perf_dump(zth_perf_dump_callback_t* f) noexcept;
60ZTH_EXPORT void perf_async_handle(zth_perf_async_handle_t* handle) noexcept;
61ZTH_EXPORT void perf_mark_async(char const* marker, zth_perf_async_handle_t* handle) noexcept;
62ZTH_EXPORT void perf_run(zth_perf_dump_callback_t* f) noexcept;
63ZTH_EXPORT void perf_abort() noexcept;
64ZTH_EXPORT void perf_run_dump(char const* path = nullptr) noexcept;
65ZTH_EXPORT int perf_vcd(char const* perf = nullptr, char const* vcd = nullptr) noexcept;
66ZTH_EXPORT int perf_vcdf(FILE* perf, FILE* vcd) noexcept;
67
71inline void perf_syscall(char const* syscall, Timestamp const& t = Timestamp()) noexcept
72{
73 if(Config::EnablePerfEvent && zth_config(PerfSyscall))
74 perf_mark(syscall, t);
75}
76
77void perf_fiber(Fiber& f) noexcept;
78void perf_fiber_state(Fiber& f, int state = -1, Timestamp const& t = Timestamp()) noexcept;
79
90template <typename T = float>
91class Load {
93public:
94 typedef T type;
95
96 explicit Load(type rc = 1) noexcept
97 : m_rc(rc)
98 , m_active()
99 , m_current(Timestamp::now())
100 , m_load()
101 {}
102
103 type rc() const noexcept
104 {
105 return m_rc;
106 }
107
108 void setRc(type rc) noexcept
109 {
110 m_rc = rc;
111 }
112
113 void start(Timestamp const& now = Timestamp::now()) noexcept
114 {
115 if(isActive())
116 return;
117
118 idle((type)(now - m_current).s());
119 m_current = now;
120 m_active = true;
121 }
122
123 void stop(Timestamp const& now = Timestamp::now()) noexcept
124 {
125 if(!isActive())
126 return;
127
128 active((type)(now - m_current).s());
129 m_current = now;
130 m_active = false;
131 }
132
133 bool isActive() const noexcept
134 {
135 return m_active;
136 }
137
138 type load() const noexcept
139 {
140 return m_load;
141 }
142
143 type load(Timestamp const& now) const noexcept
144 {
145 type dt_s = (type)(now - m_current).s();
146 if(isActive())
147 return active(load(), dt_s);
148 else
149 return idle(load(), dt_s);
150 }
151
152 void idle(type dt_s) noexcept
153 {
154 m_load = idle(load(), dt_s);
155 }
156
157 void active(type dt_s) noexcept
158 {
159 m_load = active(load(), dt_s);
160 }
161
162protected:
163 type idle(type load, type dt_s) const noexcept
164 {
165 if(dt_s <= 0)
166 return load;
167
168 return ((type)1 - alpha(dt_s)) * load;
169 }
170
171 type active(type load, type dt_s) const noexcept
172 {
173 if(dt_s <= 0)
174 return load;
175
176 type a = alpha(dt_s);
177 return a + ((type)1 - a) * load;
178 }
179
180 type alpha(type dt_s) const noexcept
181 {
182 return dt_s / (rc() + dt_s);
183 }
184
185private:
186 type m_rc;
187 bool m_active;
188 Timestamp m_current;
189 type m_load;
190};
191
205template <typename T = float, size_t Bins = 2, typename Count = uint_fast32_t>
208public:
209 typedef T type;
210 typedef Count count_type;
211
212 explicit EventRate(type window = 1) noexcept
213 : m_window_s(window)
214 , m_window(window)
215 , m_binStart()
216 , m_bins()
217 , m_current()
218 {
219 static_assert(std::numeric_limits<decltype(m_current)>::max() >= Bins, "");
220 }
221
222 void event(Timestamp const& now = Timestamp::now()) noexcept
223 {
224 size_t b = 0;
225 for(; m_binStart + m_window < now && b < Bins; b++) {
226 // Proceed to next bin.
227 m_current = (m_current + 1U) % Bins;
228 m_bins[m_current] = 0;
229 m_binStart += m_window;
230 }
231
232 if(unlikely(b == Bins)) {
233 // Cleared all bins. Apparently, m_binStart was a long time ago.
234 m_binStart = now;
235 }
236
237 m_bins[m_current]++;
238 }
239
240 void operator()(Timestamp const& now = Timestamp::now()) noexcept
241 {
242 event(now);
243 }
244
245 type rate(Timestamp const& now = Timestamp::now()) const noexcept
246 {
247 type w = (type)(now - m_binStart).s() / m_window_s;
248
249 if(unlikely(w > 1)) {
250 if(w > 2)
251 return 0; // We are really late.
252
253 w = 1;
254 }
255
256 // Scale the first bin, such that it is gradually removed from the average.
257 type first_bin = ((type)1 - w) * (type)m_bins[(m_current + 1U) % Bins];
258 // Last bin only holds events from [m_binStart,now[, no scaling required.
259 type last_bin = (type)m_bins[m_current];
260
261 // Sum all intermediate bins.
262 type sum = first_bin + last_bin;
263 for(decltype(m_current + 0) i = 2; i < Bins; i++)
264 sum += (type)m_bins[(m_current + i) % Bins];
265
266 // As the first and last one are both partial, divide by Bins - 1.
267 return sum * ((type)1 / (type)(Bins - 1)) / m_window_s;
268 }
269
270 operator type() const noexcept
271 {
272 return rate();
273 }
274
275private:
276 type m_window_s;
277 TimeInterval m_window;
278 Timestamp m_binStart;
279 count_type m_bins[Bins];
280 uint8_t m_current;
281};
282
283} // namespace zth
284
290EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_perf_start(zth_perf_done_callback_t* f = nullptr) noexcept
291{
294}
295
301EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_perf_stop() noexcept
302{
305}
306
312EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_perf_run(zth_perf_dump_callback_t* f) noexcept
313{
315 zth::perf_run(f);
316}
317
323EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_perf_abort() noexcept
324{
327}
328
329EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_perf_mark_(char const* marker) noexcept
330{
332 zth::perf_mark(marker);
333}
334
335EXTERN_C ZTH_EXPORT ZTH_INLINE __attribute__((format(ZTH_ATTR_PRINTF, 1, 0))) void
336zth_perf_logv_(char const* fmt, va_list args) noexcept
337{
339 zth::perf_logv(fmt, args);
340}
341
342EXTERN_C ZTH_EXPORT ZTH_INLINE __attribute__((format(ZTH_ATTR_PRINTF, 1, 2))) void
343zth_perf_log_(char const* fmt, ...) noexcept
344{
346 return;
347
348 va_list args;
349 va_start(args, fmt);
350 zth::perf_logv(fmt, args);
351 va_end(args);
352}
353
359EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_perf_dump(zth_perf_dump_callback_t* f) noexcept
360{
363}
364
370EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_perf_async_handle(zth_perf_async_handle_t* handle) noexcept
371{
374}
375
376EXTERN_C ZTH_EXPORT ZTH_INLINE void
377zth_perf_mark_async_(char const* marker, zth_perf_async_handle_t* handle) noexcept
378{
380 zth::perf_mark_async(marker, handle);
381}
382
388EXTERN_C ZTH_EXPORT ZTH_INLINE int
389zth_perf_vcd(char const* perf = nullptr, char const* vcd = nullptr) noexcept
390{
392 return ENOSYS;
393
394 return zth::perf_vcd(perf, vcd);
395}
396
402EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_perf_vcdf(FILE* perf, FILE* vcd) noexcept
403{
405 return ENOSYS;
406
407 return zth::perf_vcdf(perf, vcd);
408}
409
410#else // !__cplusplus
411
412# include <stdarg.h>
413# include <stdio.h>
414
415ZTH_EXPORT void zth_perf_start(zth_perf_done_callback_t* f);
416ZTH_EXPORT void zth_perf_stop();
417ZTH_EXPORT void zth_perf_mark_(char const* marker);
418ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 0))) void
419zth_perf_logv(char const* fmt, va_list args);
420ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 2))) void zth_perf_log(char const* fmt, ...);
421ZTH_EXPORT void zth_perf_dump(zth_perf_dump_callback_t* f);
422ZTH_EXPORT void zth_perf_async_handle(zth_perf_async_handle_t* handle);
423ZTH_EXPORT void zth_perf_mark_async_(char const* marker, zth_perf_async_handle_t* handle);
424ZTH_EXPORT void zth_perf_run(zth_perf_dump_callback_t* f);
425ZTH_EXPORT void zth_perf_abort();
426ZTH_EXPORT int zth_perf_vcd(char const* perf, char const* vcd);
427ZTH_EXPORT int zth_perf_vcdf(FILE* perf, FILE* vcd);
428
429#endif // __cplusplus
430
437#define zth_perf_mark(marker) zth_perf_mark_("" marker)
438
445#define zth_perf_logv(fmt, args) zth_perf_logv_("" fmt, args)
446
453#define zth_perf_log(fmt, ...) zth_perf_log_("" fmt, ##__VA_ARGS__)
454
461#define zth_perf_mark_async(marker, handle) zth_perf_mark_async("" marker, (handle))
462
463#endif // ZTH_PERF_H
Measure the rate of some event in Hz.
Definition perf.h:206
Count count_type
Definition perf.h:210
void operator()(Timestamp const &now=Timestamp::now()) noexcept
Definition perf.h:240
void event(Timestamp const &now=Timestamp::now()) noexcept
Definition perf.h:222
type rate(Timestamp const &now=Timestamp::now()) const noexcept
Definition perf.h:245
EventRate(type window=1) noexcept
Definition perf.h:212
Measure the load of some activity.
Definition perf.h:91
void setRc(type rc) noexcept
Definition perf.h:108
Load(type rc=1) noexcept
Definition perf.h:96
type idle(type load, type dt_s) const noexcept
Definition perf.h:163
type active(type load, type dt_s) const noexcept
Definition perf.h:171
type load(Timestamp const &now) const noexcept
Definition perf.h:143
void idle(type dt_s) noexcept
Definition perf.h:152
void stop(Timestamp const &now=Timestamp::now()) noexcept
Definition perf.h:123
void start(Timestamp const &now=Timestamp::now()) noexcept
Definition perf.h:113
type load() const noexcept
Definition perf.h:138
void active(type dt_s) noexcept
Definition perf.h:157
type rc() const noexcept
Definition perf.h:103
type alpha(type dt_s) const noexcept
Definition perf.h:180
T type
Definition perf.h:94
bool isActive() const noexcept
Definition perf.h:133
Convenient wrapper around struct timespec that contains a time interval.
Definition time.h:82
Convenient wrapper around struct timespec that contains an absolute timestamp.
Definition time.h:629
static Timestamp now()
Definition time.h:656
#define zth_perf_log(fmt,...)
Put a formatted log string into the perf output.
Definition perf.h:453
#define zth_perf_logv(fmt, args)
Put a formatted log string into the perf output.
Definition perf.h:445
void zth_perf_start(zth_perf_done_callback_t *f=nullptr) noexcept
Starts recording perf events.
Definition perf.h:290
void zth_perf_abort() noexcept
Abort a zth::perf_run().
Definition perf.h:323
int zth_perf_vcdf(FILE *perf, FILE *vcd) noexcept
Convert a perf file into VCD.
Definition perf.h:402
int zth_perf_vcd(char const *perf=nullptr, char const *vcd=nullptr) noexcept
Convert a perf file into VCD.
Definition perf.h:389
void zth_perf_dump(zth_perf_dump_callback_t *f) noexcept
Passes collected perf data to f.
Definition perf.h:359
void zth_perf_run(zth_perf_dump_callback_t *f) noexcept
Setup the system to automatically perform perf event recording, dumping, and resuming.
Definition perf.h:312
void zth_perf_stop() noexcept
Stops recording perf events.
Definition perf.h:301
void zth_perf_async_handle(zth_perf_async_handle_t *handle) noexcept
Returns the handle of the current thread's perf buffer.
Definition perf.h:370
#define zth_config(name)
Checks if the given zth::Config field is enabled.
Definition config.h:46
void perf_stop() noexcept
Stops recording perf events.
Definition perf.cpp:276
void perf_async_handle(zth_perf_async_handle_t *handle) noexcept
Returns the handle of the current thread's perf buffer.
Definition perf.cpp:408
void perf_mark(char const *marker, Timestamp const &t=Timestamp()) noexcept
Put a string marker into the perf output.
Definition perf.cpp:394
void perf_abort() noexcept
Abort a zth::perf_run().
Definition perf.cpp:700
void perf_run(zth_perf_dump_callback_t *f) noexcept
Setup the system to automatically perform perf event recording, dumping, and resuming.
Definition perf.cpp:685
void perf_start(zth_perf_done_callback_t *f=nullptr) noexcept
Starts recording perf events.
Definition perf.cpp:263
void perf_dump(zth_perf_dump_callback_t *f) noexcept
Passes collected perf data to f.
Definition perf.cpp:572
void perf_logv(char const *fmt, va_list args, Timestamp const &t=Timestamp()) noexcept
Put a formatted log string into the perf output.
Definition perf.cpp:467
void perf_mark_async(char const *marker, zth_perf_async_handle_t *handle) noexcept
Async-/thread-safe zth::perf_mark().
Definition perf.cpp:424
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
Definition allocator.h:160
#define ZTH_ATTR_PRINTF
Definition macros.h:64
#define ZTH_INLINE
Definition macros.h:139
void now(struct timespec &ts)
Returns the current timestamp.
Definition time.h:59
void perf_syscall(char const *syscall, Timestamp const &t=Timestamp()) noexcept
Put a syscall into the perf output.
Definition perf.h:71
int perf_vcd(char const *perf=nullptr, char const *vcd=nullptr) noexcept
Convert a perf file into VCD.
Definition perf.cpp:860
string format(char const *fmt,...)
Format like sprintf(), but save the result in an zth::string.
Definition util.h:498
int perf_vcdf(FILE *perf, FILE *vcd) noexcept
Convert a perf file into VCD.
Definition perf.cpp:1440
void() zth_perf_dump_callback_t(void const *, size_t)
Definition perf.h:31
void zth_perf_logv_(char const *fmt, va_list args) noexcept
Definition perf.h:336
void zth_perf_mark_async_(char const *marker, zth_perf_async_handle_t *handle) noexcept
Definition perf.h:377
void() zth_perf_done_callback_t()
Definition perf.h:30
void zth_perf_log_(char const *fmt,...) noexcept
Definition perf.h:343
void zth_perf_mark_(char const *marker) noexcept
Definition perf.h:329
static bool const EnablePerfEvent
Enable (but not necessarily record) perf.
Definition config.h:265
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.
Definition util.h:60