1

I'am new to c++ and a little bit in Linux. I have simple project that need to parse CPU stat from /proc/stat file and compute CPU usage. I have tried doing it on full bash script. but what i need is c++. I just need a little help. /proc/stat gives a lot of numbers and i know different column represent on something. like User,Nice,System,Idle etc. For example i just want to get the Idle value, and store it as Integer using c++, how would i do it? Please Help. What I tried right now is just getting the whole line i need using ifstream and getline()

std::ifstream filestat("/proc/stat");
std::string line;
std::getline(filestat,line);

and what i get is this.

cpu  349585 0 30513 875546 0 935 0 0 0 0

To clarify my question, for example i want to get the 875546 value and store it to an integer using c++. how would i do it? thank you

Karl Cepillo
  • 13
  • 1
  • 3
  • 2
    There is [this](https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string) but if you only want to extract a particular column you can just use a regex to get it. – NathanOliver Feb 21 '19 at 14:12
  • 3
    Possible duplicate of [How do I iterate over the words of a string?](https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string) – Valentino Feb 21 '19 at 14:44

3 Answers3

3

The format of stat is described in detail under the proc(5) manual page. You can see it either by running the command man 5 proc from a Linux terminal or online.

The methods described above for parsing the stat file are fine for academic purposes, but a production grade parser should take extra precaution when using these methods.

If you need a production grade parser in C++ for files in /proc, you can check out pfs - A library for parsing the procfs. (Disclaimer: I'm the author of the library)

The biggest issue is usually the comm field (The second field in the file). According to the man pages, this field is a string that should be "scanned" using some scanf flavor and the formatter %s. But that is wrong!

The comm field is controlled by the application (Can be set using prctl(PR_SET_NAME, ...)) and can easily include spaces or brackets, easily causing 99% of the parsers out there to fail. And a simple change like that won't just return a bad comm value, it will screw up with all the values that come after it.

The right way to parse the file are one of the following:

  1. Option #1:

    1. Read the entire content of the file
    2. Find the first occurrence of '('
    3. Find the last occurrence of ')'
    4. Assign to comm the string between those indices
    5. Parse the rest of the file after the last occurrence of ')'
  2. Option #2:

    1. Read the PID (the first value in the file)
    2. Read 18 bytes (16 is the largest comm value + 2 for the wrapping brackets)
    3. Extract the comm value from that buffer just like we did for option #1
    4. Find out the actual length of the value, fix your stream and continue reading from there
Daniel Trugman
  • 8,186
  • 20
  • 41
1

You really need to study up on how file input works. This should be simple enough. You just need to ignore the first 3 characters "cpu" and then read through 4 integer values:

unsigned n;
if(std::ifstream("/proc/stat").ignore(3) >> n >> n >> n >> n)
{
    // use n here...
    std::cout << n << '\n';
}

Alternatively if you already have the line (maybe you are reading the file one line at a time) you can use std::istringstream to turn the line into a new input stream:

std::ifstream filestat("/proc/stat");

std::string line;
std::getline(filestat, line);

unsigned n;
if(std::istringstream(line).ignore(3) >> n >> n >> n >> n)
{
    // use n here...
    std::cout << n << '\n';
}
Galik
  • 47,303
  • 4
  • 80
  • 117
0

There are several ways to the problem. You can use regular expression library to get the part of the string or if you know this is always going to the 5th element then you can use this:

std::string text = "cpu  349585 0 30513 875546 0 935 0 0 0 0";
std::istringstream iss(text);
std::vector<std::string> results(std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>());
int data = std::stoi( results[4] ); //check size before accessing 
std::cout << data << std::endl;

I hope it helps.

Sumit Jha
  • 1,601
  • 11
  • 18