* =====================================================================================
*
* Filename: util_sysinfo.c
*
* Description: get cpu load and memory state
*
* Version: 1.0
* Created: 2016年01月23日
* Revision: none
* Compiler: gcc
*
* Author: Dr. Clement.Huang
* Organization:
*
* =====================================================================================
*/
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "util_sysinfo.h"
//#define DEBUG
#define PROCFS "/proc"
#define NPROCSTATES 7
#define NCPUSTATES 7
#ifdef DEBUG
double load_avg[NUM_AVERAGES];
#endif
/* these are for calculating cpu state percentages */
static long cp_time[NCPUSTATES];
static long cp_old[NCPUSTATES];
static long cp_diff[NCPUSTATES];
/* for calculating the exponential average */
static struct timeval lasttime = { 0, 0 };
static struct timeval timediff = { 0, 0 };
static long elapsed_msecs;
/* these are counters that need to be track */
static unsigned long last_ctxt = 0;
static unsigned long last_intr = 0;
static unsigned long last_newproc = 0;
static unsigned long last_flt = 0;
/* these are for passing data back to the machine independant portion */
/* cpu states name:"user", "nice", "system", "idle", "iowait", "irq", "sirq",*/
static int cpu_states[NCPUSTATES];
/* process states name:"", "run", "sleep", "disk", "zomb", "stop", "swap", */
static int process_states[NPROCSTATES];
/* kernelnames:" ctxsw, ", " flt, ", " intr, ", " newproc",*/
static int kernel_stats[NKERNELSTATS];
/* memorynames:"K used, ", "K free, ", "K shared, ", "K buffers, ", "K cached",*/
static long memory_stats[NMEMSTATS];
/* swapnames:"K used, ", "K free, ", "K cached",*/
static long swap_stats[NSWAPSTATS];
/* useful macros */
#define bytetok(bytes) ((bytes) >> 10)
/* calculate a per-second rate using milliseconds */
#define per_second(n, msec) (((n) * 1000) / (msec))
/* inline function */
static inline char * skip_ws(const char *p)
{
while (isspace(*p)) p++;
return (char *)p;
}
static inline char * skip_token(const char *p)
{
while (isspace(*p)) p++;
while (*p && !isspace(*p)) p++;
return (char *)p;
}
/*
* percentages(cnt, out, new, old, diffs) - calculate percentage change
* between array "old" and "new", putting the percentages i "out".
* "cnt" is size of each array and "diffs" is used for scratch space.
* The array "old" is updated on each call.
* The routine assumes modulo arithmetic. This function is especially
* useful on BSD mchines for calculating cpu state percentages.
*/
static long percentages(int cnt, int *out, long *new, long *old, long *diffs)
{
register int i;
register long change;
register long total_change;
register long *dp;
long half_total;
/* initialization */
total_change = 0;
dp = diffs;
/* calculate changes for each state and the overall change */
for (i = 0; i < cnt; i++)
{
if ((change = *new - *old) < 0)
{
/* this only happens when the counter wraps */
change = (int)
((unsigned long)*new-(unsigned long)*old);
}
total_change += (*dp++ = change);
*old++ = *new++;
}
/* avoid divide by zero potential */
if (total_change == 0)
{
total_change = 1;
}
/* calculate percentages based on overall change, rounding up */
half_total = total_change / 2l;
for (i = 0; i < cnt; i++)
{
*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
}
/* return the total in case the caller wants to use it */
return(total_change);
}
void get_system_info(struct system_info *info)
{
char buffer[4096+1];
int fd, len;
char *p;
struct timeval thistime;
unsigned long intr = 0;
unsigned long ctxt = 0;
unsigned long newproc = 0;
unsigned long flt = 0;
/* timestamp and time difference */
gettimeofday(&thistime, 0);
timersub(&thistime, &lasttime, &timediff);
elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000;
lasttime = thistime;
/* get load averages */
if ((fd = open("/proc/loadavg", O_RDONLY)) != -1)
{
if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
{
buffer[len] = '\0';
info->load_avg[0] = strtod(buffer, &p);
info->load_avg[1] = strtod(p, &p);
info->load_avg[2] = strtod(p, &p);
p = skip_token(p); /* skip running/tasks */
p = skip_ws(p);
if (*p)
{
info->last_pid = atoi(p);
}
else
{
info->last_pid = -1;
}
}
close(fd);
}
/* get the cpu time info */
if ((fd = open("/proc/stat", O_RDONLY)) != -1)
{
if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
{
buffer[len] = '\0';
p = skip_token(buffer); /* "cpu" */
cp_time[0] = strtoul(p, &p, 0);
cp_time[1] = strtoul(p, &p, 0);
cp_time[2] = strtoul(p, &p, 0);
cp_time[3] = strtoul(p, &p, 0);
cp_time[4] = strtoul(p, &p, 0);
cp_time[5] = strtoul(p, &p, 0);
cp_time[6] = strtoul(p, &p, 0);
/* convert cp_time counts to percentages */
percentages(NCPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
/* get the rest of it */
p = strchr(p, '\n');
while (p != NULL)
{
p++;
if (strncmp(p, "intr ", 5) == 0)
{
p = skip_token(p);
intr = strtoul(p, &p, 10);
}
else if (strncmp(p, "ctxt ", 5) == 0)
{
p = skip_token(p);
ctxt = strtoul(p, &p, 10);
}
else if (strncmp(p, "processes ", 10) == 0)
{
p = skip_token(p);
newproc = strtoul(p, &p, 10);
}
p = strchr(p, '\n');
}
kernel_stats[KERNELINTR] = per_second(intr - last_intr, elapsed_msecs);
kernel_stats[KERNELCTXT] = per_second(ctxt - last_ctxt, elapsed_msecs);
kernel_stats[KERNELNEWPROC] = per_second(newproc - last_newproc, elapsed_msecs);
last_intr = intr;
last_ctxt = ctxt;
last_newproc = newproc;
}
close(fd);
}
/* get system wide memory usage */
if ((fd = open("/proc/meminfo", O_RDONLY)) != -1)
{
char *p;
int mem = 0;
int swap = 0;
unsigned long memtotal = 0;
unsigned long memfree = 0;
unsigned long swaptotal = 0;
if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
{
buffer[len] = '\0';
p = buffer-1;
/* iterate thru the lines */
while (p != NULL)
{
p++;
if (p[0] == ' ' || p[0] == '\t')
{
/* skip */
}
else if (strncmp(p, "Mem:", 4) == 0)
{
p = skip_token(p); /* "Mem:" */
p = skip_token(p); /* total memory */
memory_stats[MEMUSED] = strtoul(p, &p, 10);
memory_stats[MEMFREE] = strtoul(p, &p, 10);
memory_stats[MEMSHARED] = strtoul(p, &p, 10);
memory_stats[MEMBUFFERS] = strtoul(p, &p, 10);
memory_stats[MEMCACHED] = strtoul(p, &p, 10);
memory_stats[MEMUSED] = bytetok(memory_stats[MEMUSED]);
memory_stats[MEMFREE] = bytetok(memory_stats[MEMFREE]);
memory_stats[MEMSHARED] = bytetok(memory_stats[MEMSHARED]);
memory_stats[MEMBUFFERS] = bytetok(memory_stats[MEMBUFFERS]);
memory_stats[MEMCACHED] = bytetok(memory_stats[MEMCACHED]);
mem = 1;
}
else if (strncmp(p, "Swap:", 5) == 0)
{
p = skip_token(p); /* "Swap:" */
p = skip_token(p); /* total swap */
swap_stats[SWAPUSED] = strtoul(p, &p, 10);
swap_stats[SWAPFREE] = strtoul(p, &p, 10);
swap_stats[SWAPUSED] = bytetok(swap_stats[SWAPUSED]);
swap_stats[SWAPFREE] = bytetok(swap_stats[SWAPFREE]);
swap = 1;
}
else if (!mem && strncmp(p, "MemTotal:", 9) == 0)
{
p = skip_token(p);
memtotal = strtoul(p, &p, 10);
}
else if (!mem && memtotal > 0 && strncmp(p, "MemFree:", 8) == 0)
{
p = skip_token(p);
memfree = strtoul(p, &p, 10);
memory_stats[MEMUSED] = memtotal - memfree;
memory_stats[MEMFREE] = memfree;
}
else if (!mem && strncmp(p, "MemShared:", 10) == 0)
{
p = skip_token(p);
memory_stats[MEMSHARED] = strtoul(p, &p, 10);
}
else if (!mem && strncmp(p, "Buffers:", 8) == 0)
{
p = skip_token(p);
memory_stats[MEMBUFFERS] = strtoul(p, &p, 10);
}
else if (!mem && strncmp(p, "Cached:", 7) == 0)
{
p = skip_token(p);
memory_stats[MEMCACHED] = strtoul(p, &p, 10);
}
else if (!swap && strncmp(p, "SwapTotal:", 10) == 0)
{
p = skip_token(p);
swaptotal = strtoul(p, &p, 10);
}
else if (!swap && swaptotal > 0 && strncmp(p, "SwapFree:", 9) == 0)
{
p = skip_token(p);
memfree = strtoul(p, &p, 10);
swap_stats[SWAPUSED] = swaptotal - memfree;
swap_stats[SWAPFREE] = memfree;
}
else if (!mem && strncmp(p, "SwapCached:", 11) == 0)
{
p = skip_token(p);
swap_stats[SWAPCACHED] = strtoul(p, &p, 10);
}
/* move to the next line */
p = strchr(p, '\n');
}
}
close(fd);
}
/* get vm related stuff */
if ((fd = open("/proc/vmstat", O_RDONLY)) != -1)
{
char *p;
if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
{
buffer[len] = '\0';
p = buffer;
/* iterate thru the lines */
while (p != NULL)
{
if (strncmp(p, "pgmajfault ", 11) == 0)
{
p = skip_token(p);
flt = strtoul(p, &p, 10);
kernel_stats[KERNELFLT] = per_second(flt - last_flt, elapsed_msecs);
last_flt = flt;
break;
}
/* move to the next line */
p = strchr(p, '\n');
p++;
}
}
close(fd);
}
/* set arrays and strings */
info->cpustates = cpu_states;
info->memory = memory_stats;
info->swap = swap_stats;
info->kernel = kernel_stats;
#ifdef DEBUG
load_avg[0] = info->load_avg[0];
load_avg[0] = info->load_avg[0];
load_avg[0] = info->load_avg[0];
#endif
}
#ifdef DEBUG
int main(int argc, char *argv[])
{
struct system_info system_info;
chdir(PROCFS);
get_system_info(&system_info);
printf("memused %ld;memfree %ld;memshared %ld;membuffers %ld;memcached %ld;\n",memory_stats[MEMUSED],memory_stats[MEMFREE],memory_stats[MEMSHARED],\
memory_stats[MEMSHARED],memory_stats[MEMCACHED]);
printf("user %4.1f%%,sys %4.1f%%,nice %4.1f%%,idle %4.1f%%,iowait %4.1f%%;\n",((float)cpu_states[0])/10,\
((float)cpu_states[1])/10,((float)cpu_states[2])/10,((float)cpu_states[3])/10,((float)cpu_states[4])/10);
printf("load average: %.2lf, %.2lf, %.2lf\n",load_avg[0],load_avg[1],load_avg[2]);
return 0;
}
#endif
/*
* =====================================================================================
*
* Filename: util_sysinfo.h
*
* Description: get cpu load and memory state
*
* Version: 1.0
* Created: 2016年01月23日
* Revision: none
* Compiler: gcc
*
* Author: Dr. Clement.Huang
* Organization:
*
* =====================================================================================
*/
#ifndef __UTIL_SYSINFO_H__
#define __UTIL_SYSINFO_H__
#define KERNELCTXT 0
#define KERNELFLT 1
#define KERNELINTR 2
#define KERNELNEWPROC 3
#define NKERNELSTATS 4
#define MEMUSED 0
#define MEMFREE 1
#define MEMSHARED 2
#define MEMBUFFERS 3
#define MEMCACHED 4
#define NMEMSTATS 5
#define SWAPUSED 0
#define SWAPFREE 1
#define SWAPCACHED 2
#define NSWAPSTATS 3
#define NUM_AVERAGES 3
struct system_info
{
int last_pid;
double load_avg[NUM_AVERAGES];
int p_total;
int P_ACTIVE; /* number of procs considered "active" */
int *procstates;
int *cpustates;
int *kernel;
long *memory;
long *swap;
};
void get_system_info(struct system_info *info);
#endif