Drop Qt foreach.
[lxde/libsysstat.git] / cpustat.cpp
1 /* BEGIN_COMMON_COPYRIGHT_HEADER
2 * (c)LGPL2+
3 **
4 ** SysStat is a Qt-based interface to system statistics
5 **
6 ** Authors:
7 ** Copyright (c) 2009 - 2012 Kuzma Shapran <Kuzma.Shapran@gmail.com>
8 **
9 ** This library is free software; you can redistribute it and/or
10 ** modify it under the terms of the GNU Lesser General Public
11 ** License as published by the Free Software Foundation; either
12 ** version 2.1 of the License, or (at your option) any later version.
13 **
14 ** This library is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ** Lesser General Public License for more details.
18 **
19 ** You should have received a copy of the GNU Lesser General Public
20 ** License along with this library;
21 ** if not, write to the Free Software Foundation, Inc.,
22 ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 **
24 ** END_COMMON_COPYRIGHT_HEADER */
25
26
27 #include <unistd.h>
28
29 #include "cpustat.h"
30 #include "cpustat_p.h"
31
32
33 namespace SysStat {
34
35 CpuStatPrivate::CpuStatPrivate(CpuStat *parent)
36 : BaseStatPrivate(parent)
37 , mMonitoring(CpuStat::LoadAndFrequency)
38 {
39 mSource = defaultSource();
40
41 connect(mTimer, SIGNAL(timeout()), SLOT(timeout()));
42
43 mUserHz = sysconf(_SC_CLK_TCK);
44
45 updateSources();
46 }
47
48 void CpuStatPrivate::addSource(const QString &source)
49 {
50 bool ok;
51
52 uint min = readAllFile(qPrintable(QString("/sys/devices/system/cpu/%1/cpufreq/scaling_min_freq").arg(source))).toUInt(&ok);
53 if (ok)
54 {
55 uint max = readAllFile(qPrintable(QString("/sys/devices/system/cpu/%1/cpufreq/scaling_max_freq").arg(source))).toUInt(&ok);
56 if (ok)
57 mBounds[source] = qMakePair(min, max);
58 }
59 }
60
61 void CpuStatPrivate::updateSources()
62 {
63 mSources.clear();
64
65 const QStringList rows = readAllFile("/proc/stat").split(QChar('\n'), QString::SkipEmptyParts);
66 for (const QString &row : rows)
67 {
68 QStringList tokens = row.split(QChar(' '), QString::SkipEmptyParts);
69 if( (tokens.size() < 5)
70 || (!tokens[0].startsWith("cpu")) )
71 continue;
72
73 mSources.append(tokens[0]);
74 }
75
76 mBounds.clear();
77
78 bool ok;
79
80 const QStringList ranges = readAllFile("/sys/devices/system/cpu/online").split(QChar(','), QString::SkipEmptyParts);
81 for (const QString &range : ranges)
82 {
83 int dash = range.indexOf('-');
84 if (dash != -1)
85 {
86 uint min = range.leftRef(dash).toUInt(&ok);
87 if (ok)
88 {
89 uint max = range.midRef(dash + 1).toUInt(&ok);
90 if (ok)
91 for (uint number = min; number <= max; ++number)
92 addSource(QString("cpu%1").arg(number));
93 }
94 }
95 else
96 {
97 uint number = range.toUInt(&ok);
98 if (ok)
99 addSource(QString("cpu%1").arg(number));
100 }
101 }
102 }
103
104 CpuStatPrivate::~CpuStatPrivate()
105 {
106 }
107
108 void CpuStatPrivate::intervalChanged()
109 {
110 recalculateMinMax();
111 }
112
113 void CpuStatPrivate::sourceChanged()
114 {
115 recalculateMinMax();
116 }
117
118 void CpuStatPrivate::recalculateMinMax()
119 {
120 int cores = 1;
121 if (mSource == "cpu")
122 cores = mSources.size() - 1;
123
124 mIntervalMin = static_cast<float>(mTimer->interval()) / 1000 * static_cast<float>(mUserHz) * static_cast<float>(cores) / 1.25; // -25%
125 mIntervalMax = static_cast<float>(mTimer->interval()) / 1000 * static_cast<float>(mUserHz) * static_cast<float>(cores) * 1.25; // +25%
126 }
127
128 void CpuStatPrivate::timeout()
129 {
130 if ( (mMonitoring == CpuStat::LoadOnly)
131 || (mMonitoring == CpuStat::LoadAndFrequency) )
132 {
133 const QStringList rows = readAllFile("/proc/stat").split(QChar('\n'), QString::SkipEmptyParts);
134 for (const QString &row : rows)
135 {
136 if (!row.startsWith("cpu"))
137 continue;
138
139 if (row.startsWith(mSource + " "))
140 {
141 QStringList tokens = row.split(QChar(' '), QString::SkipEmptyParts);
142 if (tokens.size() < 5)
143 continue;
144
145 Values current;
146 current.user = tokens[1].toULongLong();
147 current.nice = tokens[2].toULongLong();
148 current.system = tokens[3].toULongLong();
149 current.idle = tokens[4].toULongLong();
150 current.other = 0;
151 int m = tokens.size();
152 for (int i = 5; i < m; ++i)
153 current.other += tokens[i].toULongLong();
154 current.sum();
155
156 float sumDelta = static_cast<float>(current.total - mPrevious.total);
157
158 if ((mPrevious.total != 0) && ((sumDelta < mIntervalMin) || (sumDelta > mIntervalMax)))
159 {
160 if (mMonitoring == CpuStat::LoadAndFrequency)
161 emit update(0.0, 0.0, 0.0, 0.0, 0.0, 0);
162 else
163 emit update(0.0, 0.0, 0.0, 0.0);
164
165 mPrevious.clear(); // make sure it won't keep crazy values.
166 }
167 else
168 {
169 if (mMonitoring == CpuStat::LoadAndFrequency)
170 {
171 float freqRate = 1.0;
172 uint freq = 0;
173
174 bool ok;
175
176 if (mSource == "cpu")
177 {
178 uint count = 0;
179 freqRate = 0.0;
180
181 for (Bounds::ConstIterator I = mBounds.constBegin(); I != mBounds.constEnd(); ++I)
182 {
183 uint thisFreq = readAllFile(qPrintable(QString("/sys/devices/system/cpu/%1/cpufreq/scaling_cur_freq").arg(I.key()))).toUInt(&ok);
184
185 if (ok)
186 {
187 freq += thisFreq;
188 freqRate += static_cast<float>(thisFreq) / static_cast<float>(I.value().second);
189 ++count;
190 }
191 }
192 if (!count)
193 freqRate = 1.0;
194 else
195 {
196 freq /= count;
197 freqRate /= count;
198 }
199 }
200 else
201 {
202 freq = readAllFile(qPrintable(QString("/sys/devices/system/cpu/%1/cpufreq/scaling_cur_freq").arg(mSource))).toUInt(&ok);
203
204 if (ok)
205 {
206 Bounds::ConstIterator I = mBounds.constFind(mSource);
207 if (I != mBounds.constEnd())
208 freqRate = static_cast<float>(freq) / static_cast<float>(I.value().second);
209 }
210 }
211
212 emit update(
213 static_cast<float>(current.user - mPrevious.user ) / sumDelta,
214 static_cast<float>(current.nice - mPrevious.nice ) / sumDelta,
215 static_cast<float>(current.system - mPrevious.system) / sumDelta,
216 static_cast<float>(current.other - mPrevious.other ) / sumDelta,
217 freqRate,
218 freq);
219 }
220 else
221 {
222 emit update(
223 static_cast<float>(current.user - mPrevious.user ) / sumDelta,
224 static_cast<float>(current.nice - mPrevious.nice ) / sumDelta,
225 static_cast<float>(current.system - mPrevious.system) / sumDelta,
226 static_cast<float>(current.other - mPrevious.other ) / sumDelta);
227 }
228
229 mPrevious = current;
230 }
231 }
232 }
233 }
234 else
235 {
236 bool ok;
237 uint freq = 0;
238
239 if (mSource == "cpu")
240 {
241 uint count = 0;
242
243 for (Bounds::ConstIterator I = mBounds.constBegin(); I != mBounds.constEnd(); ++I)
244 {
245 uint thisFreq = readAllFile(qPrintable(QString("/sys/devices/system/cpu/%1/cpufreq/scaling_cur_freq").arg(I.key()))).toUInt(&ok);
246
247 if (ok)
248 {
249 freq += thisFreq;
250 ++count;
251 }
252 }
253 if (count)
254 {
255 freq /= count;
256 }
257 }
258 else
259 {
260 freq = readAllFile(qPrintable(QString("/sys/devices/system/cpu/%1/cpufreq/scaling_cur_freq").arg(mSource))).toUInt(&ok);
261 }
262 emit update(freq);
263 }
264 }
265
266 QString CpuStatPrivate::defaultSource()
267 {
268 return "cpu";
269 }
270
271 CpuStatPrivate::Values::Values()
272 : user(0)
273 , nice(0)
274 , system(0)
275 , idle(0)
276 , other(0)
277 , total(0)
278 {
279 }
280
281 void CpuStatPrivate::Values::sum()
282 {
283 total = user + nice + system + idle + other;
284 }
285
286 void CpuStatPrivate::Values::clear()
287 {
288 total = user = nice = system = idle = other = 0;
289 }
290
291 CpuStat::Monitoring CpuStatPrivate::monitoring() const
292 {
293 return mMonitoring;
294 }
295
296 void CpuStatPrivate::setMonitoring(CpuStat::Monitoring value)
297 {
298 mPrevious.clear();
299 mMonitoring = value;
300 }
301
302 CpuStat::CpuStat(QObject *parent)
303 : BaseStat(parent)
304 {
305 impl = new CpuStatPrivate(this);
306 baseimpl = impl;
307
308 connect(impl, SIGNAL(update(float,float,float,float,float,uint)), this, SIGNAL(update(float,float,float,float,float,uint)));
309 connect(impl, SIGNAL(update(float,float,float,float)), this, SIGNAL(update(float,float,float,float)));
310 connect(impl, SIGNAL(update(uint)), this, SIGNAL(update(uint)));
311 }
312
313 CpuStat::~CpuStat()
314 {
315 }
316
317 void CpuStat::updateSources()
318 {
319 dynamic_cast<CpuStatPrivate*>(impl)->updateSources();
320 }
321
322 CpuStat::Monitoring CpuStat::monitoring() const
323 {
324 return impl->monitoring();
325 }
326
327 void CpuStat::setMonitoring(CpuStat::Monitoring value)
328 {
329 if (impl->monitoring() != value)
330 {
331 impl->setMonitoring(value);
332 emit monitoringChanged(value);
333 }
334 }
335
336 }