diff options
Diffstat (limited to 'netcpu_procstat.c')
-rw-r--r-- | netcpu_procstat.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/netcpu_procstat.c b/netcpu_procstat.c new file mode 100644 index 0000000..5bdadea --- /dev/null +++ b/netcpu_procstat.c @@ -0,0 +1,265 @@ +char netcpu_procstat_id[]="\ +@(#)netcpu_procstat.c (c) Copyright 2005-2007 Version 2.4.3"; + +/* netcpu_procstat.c + + Implement the /proc/stat specific portions of netperf CPU + utilization measurements. These are broken-out into a separate file + to make life much nicer over in netlib.c which had become a maze of + twisty, CPU-util-related, #ifdefs, all different. raj 2005-01-26 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif +#if STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif + +#include <string.h> + +#include "netsh.h" +#include "netlib.h" + +/* the lib_start_count and lib_end_count arrays hold the starting + and ending values of whatever is counting when the system is + idle. The rate at which this increments during a test is compared + with a previous calibrarion to arrive at a CPU utilization + percentage. raj 2005-01-26 */ +static uint64_t lib_start_count[MAXCPUS]; +static uint64_t lib_end_count[MAXCPUS]; + + +/* The max. length of one line of /proc/stat cpu output */ +#define CPU_LINE_LENGTH ((8 * sizeof (long) / 3 + 1) * 4 + 8) +#define PROC_STAT_FILE_NAME "/proc/stat" +#define N_CPU_LINES(nr) (nr == 1 ? 1 : 1 + nr) + +static int proc_stat_fd = -1; +static char *proc_stat_buf = NULL; +static int proc_stat_buflen = 0; + +void +cpu_util_init(void) +{ + + if (debug) { + fprintf(where, + "cpu_util_init enter, proc_stat_fd %d proc_stat_buf %p\n", + proc_stat_fd, + proc_stat_buf); + fflush(where); + } + if (proc_stat_fd < 0) { + proc_stat_fd = open (PROC_STAT_FILE_NAME, O_RDONLY, NULL); + if (proc_stat_fd < 0) { + fprintf (stderr, "Cannot open %s!\n", PROC_STAT_FILE_NAME); + exit (1); + }; + }; + + if (!proc_stat_buf) { + proc_stat_buflen = N_CPU_LINES (lib_num_loc_cpus) * CPU_LINE_LENGTH; + if (debug) { + fprintf(where, + "lib_num_loc_cpus %d lines %d CPU_LINE_LENGTH %d proc_stat_buflen %d\n", + lib_num_loc_cpus, + N_CPU_LINES(lib_num_loc_cpus), + CPU_LINE_LENGTH, + proc_stat_buflen); + fflush(where); + } + proc_stat_buf = (char *)malloc (proc_stat_buflen); + if (!proc_stat_buf) { + fprintf (stderr, "Cannot allocate buffer memory!\n"); + exit (1); + } + } + return; +} + +void +cpu_util_terminate(void) +{ + close(proc_stat_fd); + proc_stat_fd = -1; + free(proc_stat_buf); + proc_stat_buf = NULL; + return; +} + +int +get_cpu_method() +{ + return PROC_STAT; +} + +float +calibrate_idle_rate (int iterations, int interval) +{ + if (proc_stat_fd < 0) { + proc_stat_fd = open (PROC_STAT_FILE_NAME, O_RDONLY, NULL); + if (proc_stat_fd < 0) { + fprintf (stderr, "Cannot open %s!\n", PROC_STAT_FILE_NAME); + exit (1); + }; + }; + + if (!proc_stat_buf) { + proc_stat_buflen = N_CPU_LINES (lib_num_loc_cpus) * CPU_LINE_LENGTH; + if (debug) { + fprintf(where, + "calibrate: lib_num_loc_cpus %d lines %d CPU_LINE_LENGTH %d proc_stat_buflen %d\n", + lib_num_loc_cpus, + N_CPU_LINES(lib_num_loc_cpus), + CPU_LINE_LENGTH, + proc_stat_buflen); + fflush(where); + } + proc_stat_buf = (char *)malloc (proc_stat_buflen); + if (!proc_stat_buf) { + fprintf (stderr, "Cannot allocate buffer memory!\n"); + exit (1); + }; + }; + + return sysconf (_SC_CLK_TCK); +} + +void +get_cpu_idle (uint64_t *res) +{ + int space; + int i; + int n = lib_num_loc_cpus; + char *p = proc_stat_buf; + + lseek (proc_stat_fd, 0, SEEK_SET); + read (proc_stat_fd, p, proc_stat_buflen); + + if (debug) { + fprintf(where,"proc_stat_buf '%.*s'\n",proc_stat_buflen,p); + fflush(where); + } + /* Skip first line (total) on SMP */ + if (n > 1) p = strchr (p, '\n'); + + /* Idle time is the 4th space-separated token */ + for (i = 0; i < n; i++) { + for (space = 0; space < 4; space ++) { + p = strchr (p, ' '); + while (*++p == ' '); + }; + res[i] = strtoul (p, &p, 10); + if (debug) { + fprintf(where,"res[%d] is %llu\n",i,res[i]); + fflush(where); + } + p = strchr (p, '\n'); + }; + +} + +/* take the initial timestamp and start collecting CPU utilization if + requested */ + +void +measure_cpu_start() +{ + cpu_method = PROC_STAT; + get_cpu_idle(lib_start_count); +} + +/* collect final CPU utilization raw data */ +void +measure_cpu_stop() +{ + get_cpu_idle(lib_end_count); +} + +float +calc_cpu_util_internal(float elapsed_time) +{ + int i; + + float actual_rate; + float correction_factor; + + lib_local_cpu_util = (float)0.0; + /* It is possible that the library measured a time other than */ + /* the one that the user want for the cpu utilization */ + /* calculations - for example, tests that were ended by */ + /* watchdog timers such as the udp stream test. We let these */ + /* tests tell up what the elapsed time should be. */ + + if (elapsed_time != 0.0) { + correction_factor = (float) 1.0 + + ((lib_elapsed - elapsed_time) / elapsed_time); + } + else { + correction_factor = (float) 1.0; + } + + for (i = 0; i < lib_num_loc_cpus; i++) { + + /* it would appear that on some systems, in loopback, nice is + *very* effective, causing the looper process to stop dead in its + tracks. if this happens, we need to ensure that the calculation + does not go south. raj 6/95 and if we run completely out of idle, + the same thing could in theory happen to the USE_KSTAT path. raj + 8/2000 */ + + if (lib_end_count[i] == lib_start_count[i]) { + lib_end_count[i]++; + } + + actual_rate = (lib_end_count[i] > lib_start_count[i]) ? + (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed : + (float)(lib_end_count[i] - lib_start_count[i] + + MAXLONG)/ lib_elapsed; + lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / + lib_local_maxrate * 100; + if (debug) { + fprintf(where, + "calc_cpu_util: actual_rate on processor %d is %f start %llx end %llx util %f\n", + i, + actual_rate, + lib_start_count[i], + lib_end_count[i], + lib_local_per_cpu_util[i]); + } + lib_local_cpu_util += lib_local_per_cpu_util[i]; + } + /* we want the average across all n processors */ + lib_local_cpu_util /= (float)lib_num_loc_cpus; + + lib_local_cpu_util *= correction_factor; + return lib_local_cpu_util; +} + +void +cpu_start_internal(void) +{ + get_cpu_idle(lib_start_count); + return; +} + +void +cpu_stop_internal(void) +{ + get_cpu_idle(lib_end_count); +} |