I'm trying to extract the long int data only from /proc/meminfo. A sample of the file is below. I can do this, but a long known mantra in Linux is, do one thing, and do it well. It irks me that I'm not doing this as efficiently as I could be.
I don't want to be reading/collecting/storing the char data before and after the long ints. I don't want the program to check for characters to make sure they are or are not such and such. I only want the long int data to be processed and stored as a variable, and I want it to be done via file positions which simply skip all the useless char data.
Also, I want the data to be grabbed as a long int and stored as a long int. There are several programs doing all that I've said, but they start out storing the information as a character string. That string would have to be converted back, negating much of the benefit.
The way I'd like to do this is by moving the file position to right in front of the long int, and then storing it, but I haven't figured out how to do it efficiently. The only way I could get that to work was to always start from the beginning of the file and use bigger and bigger file positions to get to each successive long int. The result was very slow execution—much slower than my code below (~30% slower). Perhaps the program had to restart from the beginning and go through the entire file to find its position?
I want to jump to 766744, grab it, store it, and then jump (starting from this new current position) to 191680, grab it, store it, and jump to 468276... You get the idea.
The file position jumps (aside from the very first jump to 766744, which is 18 characters), starting from the end of the long int, going past the 'kB', down a line, and ending at the next number, are always 22 characters.
/proc/meminfo:
MemTotal: 766744 kB
MemFree: 191680 kB
MemAvailable: 468276 kB
Buffers: 30180 kB
Cached: 272476 kB
Here are two of my best attempts to do this. They work fine, but they are not as efficient as they can be; they scan and check for particular data, and they waste resources doing so:
mem.cpp:
/*
Compile using:
g++ -Wall -O2 mem.cpp -o mem
*/
#include<fstream>
#include<unistd.h> // Needed for usleep func.
#include<limits>
int mem()
{
unsigned int memTotal, memFree, buffers, cached;
std::ifstream file("/proc/meminfo");
file.ignore(18, ' ');
file >> memTotal;
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
file.ignore(18, ' ');
file >> memFree;
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Skip 'MemAvailable:' line:
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
file.ignore(18, ' ');
file >> buffers;
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
file.ignore(18, ' ');
file >> cached;
file.close();
return ((memTotal - memFree) - (buffers + cached)) / 1024;
}
int main()
{
do{
// Everyday use:
printf("mem: %im\n", mem());
sleep(1);
// For benchmarking:
// mem();
// usleep(55);
}while(1);
return 0;
}
Compile using: [code]g++ -Wall -O2 mem.cpp -o mem[/code]
mem.c
/*
Compile using:
g++ -Wall -O2 mem.c -o mem
*/
#include<fstream>
#include<unistd.h> // Needed for 'usleep' func.
unsigned int mem()
{
unsigned int memTotal, memFree, buffers, cached;
FILE * const file = fopen( "/proc/meminfo", "r" );
fscanf(file, "%*19s %i %*2s %*19s %i %*2s %*19s %*i %*2s %*19s %i %*2s %*19s %i", &memTotal, &memFree, &buffers, &cached);
fclose(file);
return ((memTotal - memFree) - (buffers + cached)) / 1024;
}
int main()
{
do{
printf("mem: %im\n", mem());
sleep(1);
//For benchmarking:
//mem();
//usleep(55);
}while(1);
return 0;
}
Compile using: g++ -Wall -O2 mem.c -o mem
* EDIT *
In trying to recreate my code that I originally had using file positions, I did get it to work as asked, but the code is actually SLOWER (by 2%) than both codes above:
mem3.c
/*
// -O3 seems to be .6% more efficient
g++ -Wall -O3 mem3.c -o mem3
cpu 47.7% @ 55 microseconds
*/
#include<fstream>
#include<unistd.h> // Needed for usleep func.
int mem()
{
unsigned long memTotal, memFree, buffers, cached;
FILE * file;
file = fopen("/proc/meminfo", "r");
fseek(file, 18, SEEK_SET);
fscanf(file, "%lu", &memTotal);
fseek(file, 22, SEEK_CUR);
fscanf(file, "%lu", &memFree);
fseek(file, 40, SEEK_CUR);
fscanf(file, "%lu", &buffers);
fseek(file, 22, SEEK_CUR);
fscanf(file, "%lu", &cached);
fclose (file);
return ((memTotal - memFree) - (buffers + cached)) / 1024;
}
int main()
{
do{
printf("mem: %im\n", mem());
sleep(1);
// For testing:
// mem();
// usleep(55);
}while(1);
return 0;
}
No storing useless data. No extra checking, but the code above is slower?? Clearly I'm not doing something right, and I'm somehow causing an increased workload.
Thanks for reading. Looking for suggestions.
* EDIT 2 *
I was able to get a decent efficiency gain of 7% through the use of making a custom function. Notes are in code.
mem.c:
/*
// -O3 seems to give .6% increased efficiency
g++ -Wall -O3 mem.c -o mem
43.7% CPU usage @ usleep(55)
*/
#include<fstream>
#include<unistd.h> // Needed for 'usleep' func.
/* Function courtesy of: https://stackoverflow.com/questions/16826422/c-most-efficient-way-to-convert-string-to-int-faster-than-atoi. With a personal modification to allow for conversion of an int between strings. */
void naive(const char *p, unsigned int &x)
{
x = 0;
do{
// Nifty little trick with uint8_t... which I saw on stack! :D
if (uint8_t(*p - '0') < 10)
x = (x*10) + (*p - '0');
}while(*++p != '\0');
}
unsigned int mem()
{
unsigned int memTotal, memFree, buffers, cached;
FILE * file;
char str [30]; // Length of each file line
file = fopen ("/proc/meminfo" , "r");
/* Looking into finding a way to gather all the below info at once; likely, the 5 'fget' file calls are slowing things down. */
fgets(str, 30, file);
naive(str, memTotal);
fgets(str, 30, file);
naive(str, memFree);
fgets(str, 30, file);
fgets(str, 30, file);
naive(str, buffers);
fgets(str, 30 , file);
naive(str, cached);
fclose(file);
return ((memTotal - memFree) - (buffers + cached)) / 1024;
}
int main()
{
do{
// Everyday usage:
//printf("mem: %im\n", mem());
//sleep(1);
// For testing:
mem();
usleep(55);
}while(1);
return 0;
}