VLink  2.0.0
A high-performance communication middleware
cpu_profiler.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file cpu_profiler.h
26  * @brief Per-instance CPU utilisation sampler with an env-driven global enable gate.
27  *
28  * @details
29  * @c CpuProfiler measures the fraction of wall-clock time spent inside paired
30  * @c begin / @c end intervals. Two @c ElapsedTimer instances back the computation: one accrues
31  * active intervals; the other captures the total wall-clock span since the first @c begin. The
32  * reported utilisation is therefore the ratio of accumulated active time to elapsed wall time.
33  *
34  * @par Phases and events
35  *
36  * | Phase / event | Source | Effect on counters |
37  * | ------------------- | ------------------------------ | --------------------------------------- |
38  * | First @c begin | active timer + timestamp timer | Both timers start |
39  * | Subsequent @c begin | active timer @c restart | Resets the active baseline |
40  * | @c end | active timer elapsed | Adds positive delta to @c total_active_ |
41  * | @c get | read-only | Returns @c (active / elapsed) * 100 |
42  * | @c restart | read + reset | Returns the value then zeroes counters |
43  *
44  * @par RAII guard pattern
45  *
46  * @verbatim
47  * vlink::CpuProfiler profiler;
48  * --------------------------------------------------------
49  * {
50  * vlink::CpuProfilerGuard guard(&profiler); // begin()
51  * do_work();
52  * } // end()
53  * const double percent = profiler.get();
54  * --------------------------------------------------------
55  * @endverbatim
56  *
57  * @par Global enable gate
58  * @c VLINK_PROFILER_ENABLE is read on the first call to @c is_global_enabled and cached for the
59  * remainder of the process lifetime. Set it to @c "1" to enable; any other value disables.
60  *
61  * @par Example
62  * @code
63  * if (vlink::CpuProfiler::is_global_enabled()) {
64  * for (auto& item : work_items) {
65  * profiler.begin();
66  * process(item);
67  * profiler.end();
68  * }
69  * const double pct = profiler.restart();
70  * publish(pct);
71  * }
72  * @endcode
73  */
74 
75 #pragma once
76 
77 #include <atomic>
78 #include <cstdint>
79 
80 #include "./elapsed_timer.h"
81 #include "./macros.h"
82 #include "./spin_lock.h"
83 
84 namespace vlink {
85 
86 /**
87  * @class CpuProfiler
88  * @brief Tracks active CPU time as a percentage of wall-clock time using a @c SpinLock guard.
89  *
90  * @details
91  * Each @c begin / @c end pair contributes one active interval to the running total. @c get
92  * returns the ratio of active to elapsed time; @c restart returns the same value and clears the
93  * accumulators atomically. Non-copyable; each profiler tracks a single logical stream.
94  */
96  public:
97  /**
98  * @brief Constructs a profiler with zeroed accumulators and no active interval.
99  */
100  CpuProfiler() noexcept;
101 
102  /**
103  * @brief Destructor.
104  */
105  ~CpuProfiler() noexcept;
106 
107  /**
108  * @brief Reports whether profiling is enabled via the @c VLINK_PROFILER_ENABLE environment variable.
109  *
110  * @details
111  * The environment is sampled lazily on the first call and cached for the process lifetime.
112  * Use the return value to gate expensive sampling around @c begin / @c end pairs.
113  *
114  * @return @c true when @c VLINK_PROFILER_ENABLE is set to @c "1".
115  */
116  [[nodiscard]] static bool is_global_enabled() noexcept;
117 
118  /**
119  * @brief Opens a new active interval.
120  *
121  * @details
122  * Restarts the internal active timer and, on the first call, also starts the wall-clock timer
123  * used as the denominator in @c get. Acquires the internal @c SpinLock briefly.
124  */
125  void begin() noexcept;
126 
127  /**
128  * @brief Closes the current active interval and accrues its elapsed time.
129  *
130  * @details
131  * Reads the active timer's elapsed value and adds non-negative deltas to @c total_active_.
132  * Acquires the internal @c SpinLock briefly.
133  */
134  void end() noexcept;
135 
136  /**
137  * @brief Returns the current CPU utilisation ratio as a percentage.
138  *
139  * @details
140  * Computed as @c (total_active_ns @c / @c total_elapsed_ns) @c * @c 100.0. Returns @c 0.0
141  * when no time has elapsed yet. Values can exceed @c 100 on multi-core systems where the
142  * sum of active intervals outruns wall-clock time on one core.
143  *
144  * @return Utilisation percentage; @c 0.0 when no data has accrued.
145  */
146  [[nodiscard]] double get() const noexcept;
147 
148  /**
149  * @brief Returns the current utilisation and atomically zeroes all accumulators.
150  *
151  * @details
152  * Equivalent to reading @c get and then resetting both timers. Acquires the internal
153  * @c SpinLock briefly.
154  *
155  * @return Utilisation percentage accrued since construction or the last @c restart.
156  */
157  double restart() noexcept;
158 
159  private:
160  alignas(64) std::atomic<uint64_t> total_active_{0};
162  ElapsedTimer cpu_timestamp_timer_{ElapsedTimer::kCpuTimestamp, ElapsedTimer::kNano};
163  SpinLock spin_;
164 
165  VLINK_DISALLOW_COPY_AND_ASSIGN(CpuProfiler)
166 };
167 
168 } // namespace vlink
Lowest-level elapsed-time primitive used by deadline tracking, profilers and task metrics.
Cross-platform macros for visibility, branch hints, copy prevention, singletons and string helpers.
#define VLINK_EXPORT
Definition: macros.h:81
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174
Cache-line aligned adaptive spin lock with exponential back-off.