xosview  1.23
About: xosview is an X Windows based system monitor (cpu, memory, swap and network usage; interrupt and serial activities; load average).
  Fossies Dox: xosview-1.23.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

cpumeter.cc
Go to the documentation of this file.
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;
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 ){
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.
256  // Same applies to niced guest time.
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.
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 
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, &micro);
343  }
344  return (major*1000000 + minor*1000 + micro);
345 }
void checkevent(void)
Definition: cpumeter.cc:53
static int getkernelversion(void)
Definition: cpumeter.cc:337
int statfields_
Definition: cpumeter.h:32
CPUMeter(XOSView *parent, unsigned int nbr)
Definition: cpumeter.cc:23
static int countCPUs(void)
Definition: cpumeter.cc:300
uint64_t cputime_[2][CPUSTATES]
Definition: cpumeter.h:44
int _lineNum
Definition: cpumeter.h:28
void checkResources(void)
Definition: cpumeter.cc:39
~CPUMeter(void)
Definition: cpumeter.cc:36
void getcputime(void)
Definition: cpumeter.cc:58
static const char * cpuStr(int num)
Definition: cpumeter.cc:93
const char * toUpper(const char *str)
Definition: cpumeter.cc:83
int findLine(const char *cpuID)
Definition: cpumeter.cc:277
int kernel_
Definition: cpumeter.h:31
unsigned int cpuindex_
Definition: cpumeter.h:45
virtual void checkResources(void)
virtual void drawfields(int mandatory=0)
double total_
Definition: fieldmeter.h:41
void setfieldcolor(int field, const char *color)
Definition: fieldmeter.cc:108
void setUsed(double val, double total)
Definition: fieldmeter.cc:76
int numfields_
Definition: fieldmeter.h:39
double * fields_
Definition: fieldmeter.h:40
void SetUsedFormat(const char *const str)
Definition: fieldmeter.cc:60
int priority_
Definition: meter.h:54
const char * legend(void)
Definition: meter.h:27
XOSView * parent_
Definition: meter.h:52
unsigned long allocColor(const char *name)
Definition: xwin.cc:383
int isResourceTrue(const char *name)
Definition: xwin.h:89
const char * getResource(const char *name)
Definition: xwin.cc:362
static int cputime_to_field[10]
Definition: cpumeter.cc:18
#define MAX_PROCSTAT_LENGTH
Definition: cpumeter.cc:20
static const char STATFILENAME[]
Definition: cpumeter.cc:17