"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, &micro);
  343   }
  344   return (major*1000000 + minor*1000 + micro);
  345 }