Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
CPU.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Framework_SystemPerformance_Instruments_CPU_h_
5#define _Stroika_Framework_SystemPerformance_Instruments_CPU_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
9#include <optional>
10
11#include "Stroika/Foundation/DataExchange/ObjectVariantMapper.h"
12
13#include "Stroika/Frameworks/SystemPerformance/Instrument.h"
14
15/*
16 * \file
17 *
18 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
19 *
20 * TODO:
21 * @todo Windows fRunQLength value is a point-in-time snapshot, and it SHOULD be (if we can find out how)
22 * an average over the measurement interval.
23 *
24 * Also - it appears strangely to be less than the
25 */
26
27namespace Stroika::Frameworks::SystemPerformance::Instruments::CPU {
28
29// @todo now we say iff Linux, but also available on BSD, Solaris, and could fetch with procfs
30#ifndef qStroika_Frameworks_SystemPerformance_CPU_SupportLoadAverage
31#if defined(qSupport_SystemPerformance_Instruments_CPU_LoadAverage)
32#define qStroika_Frameworks_SystemPerformance_CPU_SupportLoadAverage qSupport_SystemPerformance_Instruments_CPU_LoadAverage
33#else
34#define qStroika_Frameworks_SystemPerformance_CPU_SupportLoadAverage (qStroika_Platform_Linux or qStroika_Platform_MacOS)
35#endif
36#endif
37// DEPRECATED NAME - since 3.0d25 (to be removed in v3.0a1)
38#ifndef qSupport_SystemPerformance_Instruments_CPU_LoadAverage
39#define qSupport_SystemPerformance_Instruments_CPU_LoadAverage qStroika_Frameworks_SystemPerformance_CPU_SupportLoadAverage
40#endif
41
42 using DataExchange::ObjectVariantMapper;
43
44 /**
45 *
46 */
47 struct Info {
48#if qStroika_Frameworks_SystemPerformance_CPU_SupportLoadAverage
49 struct LoadAverage {
50 double f1MinuteAve{};
51 double f5MinuteAve{};
52 double f15MinuteAve{};
53 };
54 optional<LoadAverage> fLoadAverage;
55#endif
56
57 /**
58 * This is natural number (typically, 4, or 8, or something like that). But this CAN change over time
59 * @see /sys/devices/system/cpu/online
60 * @see https://www.kernel.org/doc/Documentation/cpu-hotplug.txt
61 * Crazy - right?
62 *
63 * This is can be used to NORMALIZE the value of fTotalCPUUsage or fTotalProcessCPUUsage to be 0..1
64 */
65 optional<unsigned int> fTotalLogicalCores{};
66
67 /**
68 * This is a number from 0..fTotalLogicalCores, and is the weighted average across all CPU cores.
69 * If you have 4 logical cores, all fully occupied, this will return 4.0.
70 *
71 * @see GetTotalCPURatio
72 */
73 optional<double> fTotalCPUUsage{};
74
75 /**
76 * \brief like fTotalCPUUsage, but returns # 0..1 (so 'percentage' of all CPU available on that machine)
77 */
78 optional<double> GetTotalCPURatio () const
79 {
80 if (fTotalLogicalCores and fTotalCPUUsage) {
81 return *fTotalCPUUsage / *fTotalLogicalCores;
82 }
83 return nullopt;
84 }
85
86 /**
87 * \brief Same as fTotalCPUUsage, except not counting time spent handling interrupts
88 *
89 * This is a number from 0..fTotalLogicalCores, and is the weighted average across all CPU cores.
90 * If you have 4 logical cores, all fully occupied, this will return 4.0.
91 *
92 * This restricts to process usage identifyable attributed to a process (including system processes).
93 * It does not count time handling interupts.
94 *
95 * @see GetTotalProcessCPUUsage
96 */
97 optional<double> fTotalProcessCPUUsage{};
98
99 /**
100 * \brief like fTotalCPUUsage, but returns # 0..1 (so 'percentage' of all CPU available on that machine)
101 */
102 optional<double> GetTotalProcessCPUUsage () const
103 {
104 if (fTotalLogicalCores and fTotalProcessCPUUsage) {
105 return *fTotalProcessCPUUsage / *fTotalLogicalCores;
106 }
107 return nullopt;
108 }
109
110 /**
111 * This is the average number of threads waiting in the run-q (status runnable) / number of logical cores.
112 * If the system is not busy, it should be zero. When more than 4 or 5 (depends alot on system) - performance maybe degraded.
113 *
114 * \note On some systems, this may included threads in disk wait. We try to avoid that, but depend
115 * on low level data, and may not be able to avoid it.
116 *
117 * This is essentially the same as the UNIX 'load average' concept, except that the time frame
118 * is not 1/5/15 minutes, but the time frame over which you've sampled, and that we normalize the result
119 * to be if we had a single CPU core.
120 *
121 * \note This is scaled to the number of CPUs, so a load average of 4 on a 4 CPU system is like
122 * would produce a 'RunQLength' of 1.
123 *
124 * \note This is very similar to Windows System \ Processor Queue Length, except that that doesn't take
125 * into account running threads, and fRunQLength does.
126 *
127 * \note We chose to define this differently than 'windows Processor Queue Length' and UNIX 'loadave' so that
128 * o Same def on UNIX/Windows
129 * o Largely independent measure of CPU load regardless of how many logical cores machine has
130 * (0 means no use, 1 means ALL cores fully used with no Q, and 2 means all cores fully utilized and
131 * each core with a Q length of 1).
132 */
133 optional<double> fRunQLength{};
134
135 /**
136 * @see Characters::ToString ();
137 */
138 nonvirtual String ToString () const;
139 };
140
141 /**
142 * To control the behavior of the instrument.
143 */
144 struct Options {
145 /**
146 * To compute averages, the instrument may keep around some earlier snapshots of data. This time interval is regulated by how often
147 * the capture is called (typically the Captureset::'run interval'. However, this value can be used to override that partly, and provide
148 * a minimum time for averaging.
149 *
150 * If you call capture more frequently than this interval, some (averaged) items maybe missing from the result.
151 *
152 * \pre fMinimumAveragingInterval > 0
153 */
155 };
156
157 /**
158 * This class is designed to be object-sliced into just the SystemPerformance::Instrument
159 *
160 * \note Constructing the instrument does no capturing (so sb quick/cheap) - capturing starts when you
161 * first call i.Capture()
162 */
164 public:
165 Instrument (const Options& options = Options{});
166
167 public:
168 /**
169 * For Instruments::CPU::Info, etc types.
170 */
172 };
173
174}
175
176namespace Stroika::Frameworks::SystemPerformance {
177
178 /*
179 * Specialization to improve performance
180 */
181 template <>
182 Instruments::CPU::Info Instrument::CaptureOneMeasurement (Range<Time::TimePointSeconds>* outMeasuredAt);
183
184}
185
186/*
187 ********************************************************************************
188 ***************************** Implementation Details ***************************
189 ********************************************************************************
190 */
191
192#endif /*_Stroika_Framework_SystemPerformance_Instruments_CPU_h_*/
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
An Instrument is a stateful object from which you can Capture () a series of measurements about a sys...
Definition Instrument.h:68
nonvirtual T CaptureOneMeasurement(Range< TimePointSeconds > *outMeasuredAt=nullptr)
STRING_TYPE ToString(FLOAT_TYPE f, const ToStringOptions &options={})