CS431 - Homework #2
/******************************************
Name: Thomas Heffron (tehqnf@umkc.edu)
Section: CS431 NET
Program: Program #2
Due Date: Oct. 1, 2002
Desc: Write a small program to pull information
from the /proc directory on a Linux system
Inputs: No input from user.
All info is read from /proc directory
Outputs: Well formatted information about:
- machine name
- system time
- kernel version
- memory usage
- uptime/idletime before and after a load
*******************************************/
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
int main()
{
/* Type declarations */
char hostname[50];
char kernel[100];
time_t now;
unsigned long start_uptime_int = 0, start_idle_int = 0;
unsigned long end_uptime_int = 0, end_idle_int = 0;
float start_uptime_frac = 0.0, start_idle_frac = 0.0;
float end_uptime_frac = 0.0, end_idle_frac = 0.0;
float idle_percent, total_real_time, total_idle_time;
char TOTAL_STR[] = "TOTAL";
char IDLE_STR[] = "IDLE";
/* Function declarations */
void get_hostname(char *value);
void get_kernel_info(char *value);
void show_memory_info();
void get_time_stats(unsigned long *up_int,
float *up_frac,
unsigned long *id_int, float *id_frac);
void format_seconds(unsigned long secs, float frac);
void work(int loops);
float get_time_diff(unsigned long start_int,
float start_frac,
unsigned long end_int, float end_frac);
/* Start of processing */
printf("\nHere's some general info on this system:\n");
/* Hostname information */
get_hostname(hostname);
printf("Hostname: %s\n", hostname);
/* System time */
time(&now);
printf("System Time: %s", ctime(&now));
/* Kernel version */
get_kernel_info(kernel);
printf("You are working in the %s kernel\n", kernel);
/* Memory usage */
show_memory_info();
/* Load average since LAST REBOOT */
printf("\nStatistics on busy/idle time:\n");
get_time_stats(&start_uptime_int,
&start_uptime_frac, &start_idle_int, &start_idle_frac);
printf("Uptime: %lu seconds - or ", start_uptime_int);
format_seconds(start_uptime_int, start_uptime_frac);
printf("Idle: %lu seconds - or ", start_idle_int);
format_seconds(start_idle_int, start_idle_frac);
idle_percent = ((float) start_idle_int /
(float) start_uptime_int) * 100.0;
printf("This system has been idle %.2f%c of the time.\n\n",
idle_percent, '%');
/********************************
/ Place a load on the CPU
/ !!! Make sure that stats are gathered
/ immediately before and after work
/ is performed.!!!
/ Additional statements may skew data.
********************************/
printf("Let's do some work...\n");
get_time_stats(&start_uptime_int,
&start_uptime_frac, &start_idle_int, &start_idle_frac);
work(5);
get_time_stats(&end_uptime_int,
&end_uptime_frac, &end_idle_int, &end_idle_frac);
/* Calculate elapsed real time */
total_real_time = get_time_diff(start_uptime_int,
start_uptime_frac,
end_uptime_int, end_uptime_frac);
/* Calulate elapsed idle time */
total_idle_time = get_time_diff(start_idle_int,
start_idle_frac,
end_idle_int, end_idle_frac);
/* Finally, display formatted results */
printf("Done!!!\n\n");
printf("%20s%15s\n", TOTAL_STR, IDLE_STR);
printf("Start: %9lu%.2f %9lu%.2f\n", (start_uptime_int / 10),
((float) (start_uptime_int % 10) + start_uptime_frac),
(start_idle_int / 10),
((float) (start_idle_int % 10) + start_idle_frac));
printf("End: %9lu%.2f %9lu%.2f\n", (end_uptime_int / 10),
((float) (end_uptime_int % 10) + end_uptime_frac),
(end_idle_int / 10),
((float) (end_idle_int % 10) + end_idle_frac));
printf("Diff: %13.2f %13.2f\n", total_real_time, total_idle_time);
printf("That work cycle kept the system busy %4.2f%c of the time.\n",
(((total_real_time - total_idle_time) / total_real_time) * 100),
'%');
} /* End of main() */
/* Function to remove all newline chars */
/* from a string (char array) by replacing */
/* it with at blank if not at end of string */
/* or removing it if at the end. */
void remove_crln(char *value)
{
int str_len, i = 0;
str_len = strlen(value);
while (value[i] != '\0') {
if (value[i] == '\n') {
if (value[i + 1] == '\0') {
value[i] = '\0';
} else {
value[i] = ' ';
}
}
i++;
}
}
/* Subroutine to return a float calculated */
/* from the difference in seconds held in the */
/* four different variables as returned from the */
/* get_time_stats function. It will automatically */
/* carry a one from the whole second value */
/* if needed for proper subtraction */
float get_time_diff(unsigned long start_int,
float start_frac,
unsigned long end_int, float end_frac)
{
if ((end_frac - start_frac) < 0.0) {
return (((1.0 + end_frac) - start_frac) +
(float) ((end_int - 1) - start_int));
} else {
return ((end_frac - start_frac) + (float) (end_int - start_int));
}
}
/* Subroutine to manipulate the actual variable */
/* passed to a more readable form in less than */
/* three digits as well as returning a char that */
/* represents the magnitude of new value. */
char format_memory(unsigned long *mem_val)
{
int mem_pow = 0;
char byte_val;
unsigned long temp_val;
temp_val = *mem_val;
while ((temp_val / 1024) > 0) {
temp_val /= 1024;
mem_pow += 1;
}
*mem_val = temp_val;
switch (mem_pow) {
case 0:
byte_val = 'B';
break;
case 1:
byte_val = 'K';
break;
case 2:
byte_val = 'M';
break;
case 3:
byte_val = 'G';
break;
}
return byte_val;
}
/* Function to display the two parts (whole */
/* and fraction) of a large value seconds */
/* in a more readable form including days, */
/* hours, minutes, and seconds. */
void format_seconds(unsigned long secs, float fracs)
{
unsigned long temp_sec = secs;
float temp_frac = fracs;
int form_sec, form_min, form_hrs, form_day;
form_sec = temp_sec % 60;
temp_sec /= 60;
form_min = temp_sec % 60;
temp_sec /= 60;
form_hrs = temp_sec % 24;
temp_sec /= 24;
form_day = temp_sec;
temp_frac += form_sec;
if (temp_frac < 10.0) {
printf("%03dD %02d:%02d:0%.2f(H:M:S)\n",
form_day, form_hrs, form_min, temp_frac);
} else {
printf("%03dD %02d:%02d:%.2f(H:M:S)\n",
form_day, form_hrs, form_min, temp_frac);
}
}
/* Function to gather the values read from */
/* /proc/uptime file. These values are stored */
/* in separate parts as a large integer and */
/* fractional portion. This is necessary because */
/* uptime reports in seconds that will always be */
/* positive and large. A double variable may */
/* cause unwanted rounding. */
void get_time_stats(unsigned long *up_int,
float *up_frac, unsigned long *id_int, float *id_frac)
{
FILE *in_file;
float trash;
in_file = fopen("/proc/uptime", "r");
fscanf(in_file, "%lu%f%lu%f",
&(*up_int), &(*up_frac), &(*id_int), &(*id_frac));
fclose(in_file);
}
/* Function to display the current memory */
/* in raw form from the /proc/meminfo file */
/* and in a more readable form using the */
/* format_memory() function. Again, unsigned */
/* long integer is used bacause values are */
/* positive, very large, and rounding is not */
/* acceptable. */
void show_memory_info()
{
FILE *in_file;
char temp_str[200];
unsigned long mem_avail, mem_free, mem_used;
unsigned long kmem_avail, kmem_free, kmem_used;
int i;
char avail_unit, free_unit, used_unit;
in_file = fopen("/proc/meminfo", "r");
fgets(temp_str, 200, in_file);
fscanf(in_file, "%s", temp_str);
fscanf(in_file, "%lu %lu %lu", &mem_avail, &mem_used, &mem_free);
kmem_avail = mem_avail;
kmem_used = mem_used;
kmem_free = mem_free;
avail_unit = format_memory(&kmem_avail);
free_unit = format_memory(&kmem_free);
used_unit = format_memory(&kmem_used);
printf("Mem Used: %10lu (~%3lu%c)\n", mem_used, kmem_used, used_unit);
printf("Mem Free: %10lu (~%3lu%c)\n", mem_free, kmem_free, free_unit);
fclose(in_file);
}
/* Function to read the O/S type and */
/* version number in the /proc directory */
/* then storing them in the char array */
/* passed by reference */
void get_kernel_info(char *value)
{
FILE *in_file1, *in_file2;
char string_val1[20], string_val2[20];
int str_len, i = 0;
in_file1 = fopen("/proc/sys/kernel/ostype", "r");
fgets(string_val1, 20, in_file1);
fclose(in_file1);
in_file2 = fopen("/proc/sys/kernel/osrelease", "r");
fgets(string_val2, 20, in_file2);
fclose(in_file2);
remove_crln(string_val1);
remove_crln(string_val2);
strcpy(value, string_val1);
strcat(value, " ver. ");
strcat(value, string_val2);
}
/* Function to read the system name */
/* from the /proc/sys/kernel/hostname */
/* file then stored in the char array */
/* passed by reference */
void get_hostname(char *value)
{
FILE *in_file;
char string_val1[200];
int str_len, i = 0;
in_file = fopen("/proc/sys/kernel/hostname", "r");
fgets(string_val1, 200, in_file);
remove_crln(string_val1);
strcpy(value, string_val1);
fclose(in_file);
}
/* Function to produce a load on the */
/* system. Iterates number of times */
/* passed into the value loops */
void work(int loops)
{
double y;
double x = 3.0;
double e = 2.0;
int i, j;
for (i = 0; i < loops; i++) {
for (j = 0; j < 400000; j++) {
y = pow(x, e);
}
sleep(1);
}
}