Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
CPU.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. 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 qSupport_SystemPerformance_Instruments_CPU_LoadAverage
31#define qSupport_SystemPerformance_Instruments_CPU_LoadAverage \
32 (qStroika_Foundation_Common_Platform_Linux or qStroika_Foundation_Common_Platform_MacOS)
33#endif
34
35 using DataExchange::ObjectVariantMapper;
36
37 /**
38 *
39 */
40 struct Info {
41#if qSupport_SystemPerformance_Instruments_CPU_LoadAverage
42 struct LoadAverage {
43 double f1MinuteAve{};
44 double f5MinuteAve{};
45 double f15MinuteAve{};
46 };
47 optional<LoadAverage> fLoadAverage;
48#endif
49
50 /**
51 * This is natural number (typically, 4, or 8, or something like that). But this CAN change over time
52 * @see /sys/devices/system/cpu/online
53 * @see https://www.kernel.org/doc/Documentation/cpu-hotplug.txt
54 * Crazy - right?
55 *
56 * This is can be used to NORMALIZE the value of fTotalCPUUsage or fTotalProcessCPUUsage to be 0..1
57 */
58 optional<unsigned int> fTotalLogicalCores{};
59
60 /**
61 * This is a number from 0..fTotalLogicalCores, and is the weighted average across all CPU cores.
62 * If you have 4 logical cores, all fully occupied, this will return 4.0.
63 *
64 * @see GetTotalCPURatio
65 */
66 optional<double> fTotalCPUUsage{};
67
68 /**
69 * \brief like fTotalCPUUsage, but returns # 0..1 (so 'percentage' of all CPU available on that machine)
70 */
71 optional<double> GetTotalCPURatio () const
72 {
73 if (fTotalLogicalCores and fTotalCPUUsage) {
74 return *fTotalCPUUsage / *fTotalLogicalCores;
75 }
76 return nullopt;
77 }
78
79 /**
80 * \brief Same as fTotalCPUUsage, except not counting time spent handling interrupts
81 *
82 * This is a number from 0..fTotalLogicalCores, and is the weighted average across all CPU cores.
83 * If you have 4 logical cores, all fully occupied, this will return 4.0.
84 *
85 * This restricts to process usage identifyable attributed to a process (including system processes).
86 * It does not count time handling interupts.
87 *
88 * @see GetTotalProcessCPUUsage
89 */
90 optional<double> fTotalProcessCPUUsage{};
91
92 /**
93 * \brief like fTotalCPUUsage, but returns # 0..1 (so 'percentage' of all CPU available on that machine)
94 */
95 optional<double> GetTotalProcessCPUUsage () const
96 {
97 if (fTotalLogicalCores and fTotalProcessCPUUsage) {
98 return *fTotalProcessCPUUsage / *fTotalLogicalCores;
99 }
100 return nullopt;
101 }
102
103 /**
104 * This is the average number of threads waiting in the run-q (status runnable) / number of logical cores.
105 * If the system is not busy, it should be zero. When more than 4 or 5 (depends alot on system) - performance maybe degraded.
106 *
107 * \note On some systems, this may included threads in disk wait. We try to avoid that, but depend
108 * on low level data, and may not be able to avoid it.
109 *
110 * This is essentially the same as the UNIX 'load average' concept, except that the time frame
111 * is not 1/5/15 minutes, but the time frame over which you've sampled, and that we normalize the result
112 * to be if we had a single CPU core.
113 *
114 * \note This is scaled to the number of CPUs, so a load average of 4 on a 4 CPU system is like
115 * would produce a 'RunQLength' of 1.
116 *
117 * \note This is very similar to Windows System \ Processor Queue Length, except that that doesn't take
118 * into account running threads, and fRunQLength does.
119 *
120 * \note We chose to define this differently than 'windows Processor Queue Length' and UNIX 'loadave' so that
121 * o Same def on UNIX/Windows
122 * o Largely independent measure of CPU load regardless of how many logical cores machine has
123 * (0 means no use, 1 means ALL cores fully used with no Q, and 2 means all cores fully utilized and
124 * each core with a Q length of 1).
125 */
126 optional<double> fRunQLength{};
127
128 /**
129 * @see Characters::ToString ();
130 */
131 nonvirtual String ToString () const;
132 };
133
134 /**
135 * To control the behavior of the instrument.
136 */
137 struct Options {
138 /**
139 * To compute averages, the instrument may keep around some earlier snapshots of data. This time interval is regulated by how often
140 * the capture is called (typically the Captureset::'run interval'. However, this value can be used to override that partly, and provide
141 * a minimum time for averaging.
142 *
143 * If you call capture more frequently than this interval, some (averaged) items maybe missing from the result.
144 *
145 * \pre fMinimumAveragingInterval > 0
146 */
148 };
149
150 /**
151 * This class is designed to be object-sliced into just the SystemPerformance::Instrument
152 *
153 * \note Constructing the instrument does no capturing (so sb quick/cheap) - capturing starts when you
154 * first call i.Capture()
155 */
157 public:
158 Instrument (const Options& options = Options{});
159
160 public:
161 /**
162 * For Instruments::CPU::Info, etc types.
163 */
165 };
166
167}
168
169namespace Stroika::Frameworks::SystemPerformance {
170
171 /*
172 * Specialization to improve performance
173 */
174 template <>
175 Instruments::CPU::Info Instrument::CaptureOneMeasurement (Range<Time::TimePointSeconds>* measurementTimeOut);
176
177}
178
179/*
180 ********************************************************************************
181 ***************************** Implementation Details ***************************
182 ********************************************************************************
183 */
184
185#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:69
nonvirtual T CaptureOneMeasurement(Range< TimePointSeconds > *measurementTimeOut=nullptr)
STRING_TYPE ToString(FLOAT_TYPE f, const ToStringOptions &options={})