"Fossies" - the Fresh Open Source Software Archive 
Member "xosview-1.23/linux/cpumeter.cc" (11 Jul 2020, 11573 Bytes) of package /linux/misc/xosview-1.23.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "cpumeter.cc" see the
Fossies "Dox" file reference documentation.
1 //
2 // Copyright (c) 1994, 1995, 2002, 2006 by Mike Romberg ( mike.romberg@noaa.gov )
3 //
4 // This file may be distributed under terms of the GPL
5 //
6
7 #include "cpumeter.h"
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <sys/utsname.h>
13 #include <string>
14 #include <iostream>
15 #include <fstream>
16
17 static const char STATFILENAME[] = "/proc/stat";
18 static int cputime_to_field[10] = { 0, 1, 2, 9, 5, 4, 3, 8, 6, 7 };
19
20 #define MAX_PROCSTAT_LENGTH 4096
21
22 CPUMeter::CPUMeter(XOSView *parent, const char *cpuID)
23 : FieldMeterGraph( parent, 10, toUpper(cpuID), "USR/NIC/SYS/SI/HI/WIO/GST/NGS/STL/IDLE" ) {
24 _lineNum = findLine(cpuID);
25 for ( int i = 0 ; i < 2 ; i++ )
26 for ( int j = 0 ; j < 10 ; j++ )
27 cputime_[i][j] = 0;
28 cpuindex_ = 0;
29 kernel_ = getkernelversion();
30 if (kernel_ < 2006000)
31 statfields_ = 4;
32 else if (kernel_ < 2006011)
33 statfields_ = 7;
34 else if (kernel_ < 2006024)
35 statfields_ = 8;
36 else if (kernel_ < 2006032)
37 statfields_ = 9;
38 else
39 statfields_ = 10;
40 }
41
42 CPUMeter::~CPUMeter( void ){
43 }
44
45 void CPUMeter::checkResources( void ){
46 FieldMeterGraph::checkResources();
47
48 unsigned long usercolor = parent_->allocColor(parent_->getResource( "cpuUserColor" ) );
49 unsigned long nicecolor = parent_->allocColor(parent_->getResource( "cpuNiceColor" ) );
50 unsigned long syscolor = parent_->allocColor(parent_->getResource( "cpuSystemColor" ) );
51 unsigned long sintcolor = parent_->allocColor(parent_->getResource( "cpuSInterruptColor" ) );
52 unsigned long intcolor = parent_->allocColor(parent_->getResource( "cpuInterruptColor" ) );
53 unsigned long waitcolor = parent_->allocColor(parent_->getResource( "cpuWaitColor" ) );
54 unsigned long gstcolor = parent_->allocColor(parent_->getResource( "cpuGuestColor" ) );
55 unsigned long ngstcolor = parent_->allocColor(parent_->getResource( "cpuNiceGuestColor" ) );
56 unsigned long stealcolor= parent_->allocColor(parent_->getResource( "cpuStolenColor" ) );
57 unsigned long idlecolor = parent_->allocColor(parent_->getResource( "cpuFreeColor" ) );
58
59 priority_ = atoi(parent_->getResource( "cpuPriority" ) );
60 dodecay_ = parent_->isResourceTrue( "cpuDecay" );
61 useGraph_ = parent_->isResourceTrue( "cpuGraph" );
62 SetUsedFormat(parent_->getResource("cpuUsedFormat") );
63
64 /* Use user-defined fields.
65 * Fields Including if not its own field
66 * --------------|------------------------------
67 * USED all used time, including user and system times
68 * USR user time, including nice and guest times
69 * NIC niced time, including niced guest unless guest is present
70 * GST guest time, including niced guest time
71 * NGS niced guest time
72 * SYS system time, including interrupt and stolen times
73 * INT interrupt time, including soft and hard interrupt times
74 * HI hard interrupt time
75 * SI soft interrupt time
76 * STL stolen time
77 * IDLE idle time, including io wait time
78 * WIO io wait time
79 *
80 * Stolen time is a class of its own in kernel scheduler, in cpufreq it is
81 * considered used time. Here it is part of used and system time, but can be
82 * separate field as well.
83 * Idle field is always present.
84 * Either USED or at least USR+SYS must be included.
85 */
86
87 const char *f = parent_->getResource( "cpuFields" );
88 std::string lgnd, fields(f);
89 int field = 0;
90
91 /* Check for possible fields and define field mapping. Assign colors and
92 * build legend on the way.
93 */
94 if (fields.find("USED") != fields.npos) { // USED = USR+NIC+SYS+SI+HI+GST+NGS(+STL)
95 if (fields.find("USR") != fields.npos || fields.find("NIC") != fields.npos ||
96 fields.find("SYS") != fields.npos || fields.find("INT") != fields.npos ||
97 fields.find("HI") != fields.npos || fields.find("SI") != fields.npos ||
98 fields.find("GST") != fields.npos || fields.find("NGS") != fields.npos) {
99 std::cerr << "'USED' cannot be in cpuFields together with either 'USR', "
100 << "'NIC', 'SYS', 'INT', 'HI', 'SI', 'GST' or 'NGS'." << std::endl;
101 exit(1);
102 }
103 setfieldcolor(field, usercolor);
104 if (kernel_ >= 2006000) // SI and HI
105 cputime_to_field[5] = cputime_to_field[6] = field;
106 if (kernel_ >= 2006024) // GST
107 cputime_to_field[8] = field;
108 if (kernel_ >= 2006032) // NGS
109 cputime_to_field[9] = field;
110 if (kernel_ >= 2006011 && fields.find("STL") == fields.npos)
111 cputime_to_field[7] = field; // STL can be separate as well
112 // USR, NIC and SYS
113 cputime_to_field[0] = cputime_to_field[1] = cputime_to_field[2] = field++;
114 lgnd = "USED";
115 }
116 if (fields.find("USR") != fields.npos) {
117 setfieldcolor(field, usercolor);
118 // add NIC if not on its own
119 if (fields.find("NIC") == fields.npos)
120 cputime_to_field[1] = field;
121 // add GST if not on its own
122 if (kernel_ >= 2006024 && fields.find("GST") == fields.npos)
123 cputime_to_field[8] = field;
124 // add NGS if not on its own and neither NIC or GST is present
125 if (kernel_ >= 2006032 && fields.find("NGS") == fields.npos &&
126 fields.find("NIC") == fields.npos && fields.find("GST") == fields.npos)
127 cputime_to_field[9] = field;
128 cputime_to_field[0] = field++;
129 lgnd = "USR";
130 }
131 else {
132 if (fields.find("USED") == fields.npos) {
133 std::cerr << "Either 'USED' or 'USR' is mandatory in cpuFields." << std::endl;
134 exit(1);
135 }
136 }
137 if (fields.find("NIC") != fields.npos) {
138 setfieldcolor(field, nicecolor);
139 // add NGS if not on its own and GST is not present
140 if (kernel_ >= 2006032 && fields.find("NGS") == fields.npos &&
141 fields.find("GST") == fields.npos)
142 cputime_to_field[9] = field;
143 cputime_to_field[1] = field++;
144 lgnd += "/NIC";
145 }
146 if (fields.find("SYS") != fields.npos) {
147 setfieldcolor(field, syscolor);
148 // add SI if not on its own and INT is not present
149 if (kernel_ >= 2006000 && fields.find("SI") == fields.npos &&
150 fields.find("INT") == fields.npos)
151 cputime_to_field[6] = field;
152 // add HI if not on its own and INT is not present
153 if (kernel_ >= 2006000 && fields.find("HI") == fields.npos &&
154 fields.find("INT") == fields.npos)
155 cputime_to_field[5] = field;
156 // add STL if not on its own
157 if (kernel_ >= 2006011 && fields.find("STL") == fields.npos)
158 cputime_to_field[7] = field;
159 cputime_to_field[2] = field++;
160 lgnd += "/SYS";
161 }
162 else {
163 if (fields.find("USED") == fields.npos) {
164 std::cerr << "Either 'USED' or 'SYS' is mandatory in cpuFields." << std::endl;
165 exit(1);
166 }
167 }
168 if (kernel_ >= 2006000) {
169 if (fields.find("INT") != fields.npos) { // combine soft and hard interrupt times
170 setfieldcolor(field, intcolor);
171 cputime_to_field[5] = cputime_to_field[6] = field++;
172 lgnd += "/INT";
173 } // Maybe should warn if both INT and HI/SI are requested ???
174 else { // separate soft and hard interrupt times
175 if (fields.find("SI") != fields.npos) {
176 setfieldcolor(field, sintcolor);
177 cputime_to_field[5] = field++;
178 lgnd += "/SI";
179 }
180 if (fields.find("HI") != fields.npos) {
181 setfieldcolor(field, intcolor);
182 cputime_to_field[6] = field++;
183 lgnd += "/HI";
184 }
185 }
186 if (fields.find("WIO") != fields.npos) {
187 setfieldcolor(field, waitcolor);
188 cputime_to_field[4] = field++;
189 lgnd += "/WIO";
190 }
191 if (kernel_ >= 2006024 && fields.find("GST") != fields.npos) {
192 setfieldcolor(field, gstcolor);
193 // add NGS if not on its own
194 if (kernel_ >= 2006032 && fields.find("NGS") == fields.npos)
195 cputime_to_field[9] = field;
196 cputime_to_field[8] = field++;
197 lgnd += "/GST";
198 }
199 if (kernel_ >= 2006032 && fields.find("NGS") != fields.npos) {
200 setfieldcolor(field, ngstcolor);
201 cputime_to_field[9] = field++;
202 lgnd += "/NGS";
203 }
204 if (kernel_ >= 2006011 && fields.find("STL") != fields.npos) {
205 setfieldcolor(field, stealcolor);
206 cputime_to_field[7] = field++;
207 lgnd += "/STL";
208 }
209 }
210 // always add IDLE field
211 setfieldcolor(field, idlecolor);
212 // add WIO if not on its own
213 if (kernel_ >= 2006000 && fields.find("WIO") == fields.npos)
214 cputime_to_field[4] = field;
215 cputime_to_field[3] = field++;
216 lgnd += "/IDLE";
217
218 legend(lgnd.c_str());
219 numfields_ = field; // can't use setNumFields as it destroys the color mapping
220 }
221
222 void CPUMeter::checkevent( void ){
223 getcputime();
224 drawfields();
225 }
226
227 void CPUMeter::getcputime( void ){
228 total_ = 0;
229 std::string tmp;
230 std::ifstream stats( STATFILENAME );
231 char *end = NULL;
232
233 if ( !stats ){
234 std::cerr <<"Can not open file : " <<STATFILENAME << std::endl;
235 exit( 1 );
236 }
237
238 // read until we are at the right line.
239 for (int i = 0 ; i < _lineNum ; i++) {
240 if (stats.eof())
241 return;
242 stats.ignore(1024, '\n');
243 }
244 std::getline(stats, tmp);
245
246 int col = 0;
247 std::string l = tmp.substr(tmp.find_first_of(' ') + 1);
248 const char *line = l.c_str();
249 while (*line) {
250 cputime_[cpuindex_][col++] = strtoull(line, &end, 10);
251 line = end;
252 }
253
254 // Guest time already included in user time.
255 cputime_[cpuindex_][0] -= cputime_[cpuindex_][8];
256 // Same applies to niced guest time.
257 cputime_[cpuindex_][1] -= cputime_[cpuindex_][9];
258
259 int oldindex = (cpuindex_+1)%2;
260 // zero all the fields
261 memset(fields_, 0, numfields_*sizeof(fields_[0]));
262 for ( int i = 0 ; i < statfields_ ; i++ ){
263 int time = cputime_[cpuindex_][i] - cputime_[oldindex][i];
264 if (time < 0) // counters in /proc/stat do sometimes go backwards
265 time = 0;
266 fields_[cputime_to_field[i]] += time;
267 total_ += time;
268 // XOSDEBUG("cputime_[%d] = %2d fields_[%d] = %d\n", i, time, cputime_to_field[i], (int)fields_[cputime_to_field[i]]);
269 }
270
271 if (total_){
272 setUsed (total_ - fields_[numfields_ - 1], total_); // any non-idle time
273 cpuindex_ = (cpuindex_ + 1) % 2;
274 }
275 }
276
277 int CPUMeter::findLine(const char *cpuID){
278 std::ifstream stats( STATFILENAME );
279
280 if ( !stats ){
281 std::cerr <<"Can not open file : " <<STATFILENAME << std::endl;
282 exit( 1 );
283 }
284
285 int line = -1;
286 std::string buf;
287 while (!stats.eof()){
288 getline(stats, buf);
289 if (!stats.eof()){
290 line++;
291 if (!strncmp(cpuID, buf.data(), strlen(cpuID))
292 && buf[strlen(cpuID)] == ' ')
293 return line;
294 }
295 }
296 return -1;
297 }
298
299 // Returns the number of cpus that are on this machine.
300 int CPUMeter::countCPUs(void){
301 std::ifstream stats( STATFILENAME );
302
303 if ( !stats ){
304 std::cerr <<"Can not open file : " <<STATFILENAME << std::endl;
305 exit( 1 );
306 }
307
308 int cpuCount = 0;
309 std::string buf;
310 while (getline(stats, buf))
311 if (!strncmp(buf.data(), "cpu", 3) && buf[3] != ' ')
312 cpuCount++;
313
314 return cpuCount;
315 }
316
317 const char *CPUMeter::cpuStr(int num){
318 static char buffer[32];
319
320 if (num != 0)
321 snprintf(buffer, sizeof(buffer), "cpu%d", num - 1);
322 else
323 strcpy(buffer, "cpu");
324
325 return buffer;
326 }
327
328 const char *CPUMeter::toUpper(const char *str){
329 static char buffer[MAX_PROCSTAT_LENGTH];
330 strncpy(buffer, str, MAX_PROCSTAT_LENGTH);
331 for (char *tmp = buffer ; *tmp != '\0' ; tmp++)
332 *tmp = toupper(*tmp);
333
334 return buffer;
335 }
336
337 int CPUMeter::getkernelversion(void){
338 static int major = 0, minor = 0, micro = 0;
339 if (!major) {
340 struct utsname myosrelease;
341 uname(&myosrelease);
342 sscanf(myosrelease.release, "%d.%d.%d", &major, &minor, µ);
343 }
344 return (major*1000000 + minor*1000 + micro);
345 }