CPUsage is a small utility to dump the CPU usage every second. This version can write CSV output.
I used it to track CPU usage on the wireless routers I used in my diploma thesis. To get a quick overview if the nodes suffered from CPU overload (and thus are more likely to drop packets) I plotted the CSV files with Gnu R. See [1] for an example image (of a constantly overloaded node, in that case). For convenience, [2] has the Gnu R script I created the plots with. [1] http://bayimg.com/IaGcpAadj [2] http://pastebin.com/rjU6juc9
commit 36104b169a44f48f623c1916dcda9cb790b25eee Author: Florian Sesser <ses...@in.tum.de> Date: Tue Apr 5 13:09:12 2011 +0200 Add CPUsage to /utils CPUsage is a small utility to dump the CPU usage every second. This version can write CSV output. Signed-off-by: Florian Sesser <ses...@in.tum.de> diff --git a/utils/cpusage/Makefile b/utils/cpusage/Makefile new file mode 100644 index 0000000..a02744b --- /dev/null +++ b/utils/cpusage/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2005 Fabian Schneider, 2010 Florian Sesser, TU Muenchen +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=cpusage +PKG_VERSION:=0.31 + +PKG_BUILD_DIR:=$(BUILD_DIR)/cpusage + +include $(INCLUDE_DIR)/package.mk + +define Package/cpusage + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Outputs CPU usage statistics once per second + URL:=http://www.net.t-labs.tu-berlin.de/~fabian/proj_en.html\#cpusage +endef + +define Package/cpusage/description + CPUsage outputs CPU usage statistics once per second. + Optionally writes CSV output (see '-o' option). + Written by Fabian Schneider (TUM, TUB) in 2005. + Timestamp and CSV-compliance by Florian Sesser (TUM), 2010. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) src/* $(PKG_BUILD_DIR)/ +endef + +TARGET_CFLAGS += $(FPIC) + +define Build/Compile + $(TARGET_CC) $(TARGET_CFLAGS) -D__Linux26__ -D_BSD_SOURCE=1 -c -I$(PKG_BUILD_DIR) -I$(STAGING_DIR)/usr/include -o $(PKG_BUILD_DIR)/cpusage.o $(PKG_BUILD_DIR)/cpusage.c + $(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/cpusage -L$(STAGING_DIR)/usr/lib $(PKG_BUILD_DIR)/cpusage.o +endef + +define Package/cpusage/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/cpusage $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,cpusage)) diff --git a/utils/cpusage/src/cpusage.c b/utils/cpusage/src/cpusage.c new file mode 100644 index 0000000..a027e4f --- /dev/null +++ b/utils/cpusage/src/cpusage.c @@ -0,0 +1,426 @@ +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <time.h> + +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#else +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#endif + +#ifdef __FreeBSD__ +static void getsysctl(char *, void *, size_t); +#define CPUSTATES 5 +#define IDLEI 3 +char *cpustatenames[] = { + "user", "nice", "system", "idle", "interrupt", NULL +}; +#endif + +#ifdef __Linux24__ +#define CPUSTATES 4 +#define IDLEI 3 +char *cpustatenames[] = { + "user", "nice", "system", "idle", NULL +}; +#endif + +#ifdef __Linux26__ +#define CPUSTATES 7 +#define IDLEI 3 +/* long names: + * user - nice - system - idle - iowait - irq - soft irq */ +char *cpustatenames[] = { + "user", "nice", "system", "idle", "iowait", "irq", "softirq", NULL +}; +#endif + +#define LIMIT 95 + +static const char usage[] = + "\n usage: cpusage [ -hos ] [ -a | -l limit ] [ -c CPU ]\n"; + +char* appname; + +static float cpu_perc[CPUSTATES]; +static float cpu_max[CPUSTATES]; +static float cpu_min[CPUSTATES]; + +int cpunum; /* -1 all, 0-n CPU/Core 0-n */ + +int output; + +int breakloop; + +/* returns 1-n yielding the number of CPU's/Cores */ +int getNumCPU() +{ +#ifdef __FreeBSD__ + return 0; +#else + + char buffer[32768]; + int fd, len, i; + char * test; + + fd = open("/proc/stat", O_RDONLY); + if(fd<=0) + fprintf(stderr, "%s: cannot open /proc/stat \n", appname); + + len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + buffer[len] = '\0'; + + i=0; + + test = strstr(buffer, "cpu"); + if (test != NULL ) { + test += sizeof("cpu"); + test = strstr(test, "cpu"); + } + + while ( test != NULL ) { + test += sizeof("cpu"); + /* fprintf(stderr, "%s: DEBUG: %s\n", appname, test); */ + i++; + test = strstr(test, "cpu"); + } + return i; +#endif +} + +#ifdef __FreeBSD__ +static void getsysctl (char *name, void *ptr, size_t len) { + size_t nlen = len; + long save; + + if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { + fprintf(stderr, "%s: sysctl(%s...) failed: %s\n", + appname, name, strerror(errno)); + exit(1); + } + if (nlen != len) { + fprintf(stderr, "%s: sysctl(%s...) expected %lu, got %lu\n", + appname, name, (unsigned long)len, (unsigned long)nlen); + exit(1); + } + + /* swapping idle and interrupt to look like linux */ + save = ((long*) ptr)[4]; + ((long*) ptr)[4] = ((long*) ptr)[3]; + ((long*) ptr)[3] = save; +} +#else +void getSysinfo(unsigned long *ptr, size_t size) +{ + char buffer[4096]; + char match[100]; + char * start; + int fd, len, j; + + for (j = 0; j<size; j++) + ptr[j]=0; + + fd = open("/proc/stat", O_RDONLY); + if(fd<=0) + fprintf(stderr, "%s: cannot open /proc/stat\n", appname ); + + len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + buffer[len] = '\0'; + + + strcpy(match, "cpu "); + start = buffer; + if ( cpunum != -1 ) { + sprintf(match, "cpu%d ", cpunum); + start = strstr(buffer, match); + } + +#ifdef __Linux26__ + strcat(match, "%ld %ld %ld %ld %ld %ld %ld"); + if ( sscanf(start, match, &ptr[0], + &ptr[1], &ptr[2], &ptr[3], &ptr[4], &ptr[5], &ptr[6]) != 7 ) { + fprintf(stderr, "%s: wrong /proc/stat format\n", appname); + } +#else + strcat(match, "%ld %ld %ld %ld"); + if ( sscanf(start, match, + &ptr[0], &ptr[1], &ptr[2], &ptr[3]) != 4) { + fprintf(stderr, "%s: wrong /proc/stat format\n", appname); + } +#endif + +} +#endif + +long perc(int cpustates, long *cp_time, long *cp_old, long *cp_diff) { + + int i = 0; + long total = 0; + + for ( i = 0; i < cpustates; i++ ) { + cp_diff[i] = cp_time[i] - cp_old[i]; + total += cp_diff[i]; + } + + for ( i = 0; i < cpustates; i++) { + cpu_perc[i] = ((float)cp_diff[i]*100.0 / total); + /* new max ? */ + if ( cpu_perc[i] > cpu_max[i] ) + cpu_max[i] = cpu_perc[i]; + /* new min ? */ + if ( cpu_perc[i] < cpu_min[i] ) + cpu_min[i] = cpu_perc[i]; + } + + return total; +} + +void print_perc(float *perc, const char *head){ + int i; + time_t Zeitstempel; + struct tm *now; + + /* human readable */ + if ( (output == 0) && (head != "")) + printf("%s: ", head); + + /* machine readable */ + if ( (output == 1) && (head != "")) + printf("%s;", head); + + /* timestamp */ + time(&Zeitstempel); + now = localtime(&Zeitstempel); + if ( output == 0 ) + printf("timestamp: %04d-%02d-%02d %02d.%02d.%02d, ", now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + else + printf("%04d-%02d-%02d;%02d:%02d:%02d;", now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + + if ( output == 0 ) + printf("%s: %5.1f%%, ", cpustatenames[0], perc[0]); + else + printf("%.1f", perc[0]); + + /* print out calculated information in percentages */ + for ( i = 1; i < CPUSTATES; i++) { + if ( output == 0 ) + printf("%s: %5.1f%%, ", cpustatenames[i], perc[i]); + else + printf(";%.1f", perc[i]); + } + printf("\n"); +} + +/* to catch Strg+C when looping */ +void loop_term_handler (int signum) { + breakloop = 1; +} + +int main(int argc, char** argv) { + + appname = argv[0]; + + int i,c,limit; + int runonce; /* run just once and exit */ + int avg; /* is avg measurement allready running */ + int avg_run; /* did we allready had an avg measurement */ + static long cp_time1[CPUSTATES]; + static long cp_time2[CPUSTATES]; + static long cp_avg_start[CPUSTATES]; + static long cp_avg_stop[CPUSTATES]; + static long cp_diff[CPUSTATES]; + + struct sigaction sigold, signew; + + long *old = cp_time2; + long *new = cp_time1; + + long total; + limit = LIMIT; + output = 0; /* 0: human readable; 1: machine readable */ + runonce = 0; /* 0: run continuesly; 1: run once */ + + cpunum = -1; /* -1: all CPUs/Cores, 0-n: special CPU/Core */ + + /* reading commandline options */ + while (1) { + c = getopt(argc, argv, "saohl:c:"); + + if (c == -1){ + break; + } + + switch(c){ + /*run once and exit */ + case 's': + runonce = 1; + break; + /* use avg from begin to end -> same as "-l 100" */ + case 'a': + limit = 100; + break; + case 'o': + output = 1; /* machine readable */ + // header for CSV output + printf("date;time;user;nice;system;idle;iowait;irq;softirq\n"); + break; + /* print usage */ + case 'h': + fprintf(stderr, "%s: %s", appname, usage); + exit(0); + break; + /* set limit */ + case 'l': + if ( !(sscanf(optarg, "%d", &limit) == 1) ) { + fprintf(stderr, "%s: option for -l should be integer (is %s)\n", + appname, optarg); + exit(1); + } + break; + /* select CPU/Core */ + case 'c': + if ( !(sscanf(optarg, "%d", &cpunum) == 1) ) { + fprintf(stderr, "%s: option for -c should be integer (is %s)\n", + appname, optarg); + exit(1); + } + break; + + } + } + + if (cpunum != -1) { +#ifdef __FreeBSD__ + fprintf(stderr, "%s: No CPU/Core selection available for FreeBSD\n", + appname); + exit (1); +#else + int numcpu = getNumCPU(); + if ( cpunum < numcpu ) { + printf("-- Selected CPU %d\n", cpunum ); + } else { + if (numcpu == 1) { + fprintf(stderr, "%s: CPU %d not available (found %d CPU: [0])\n", + appname, cpunum, numcpu ); + } else { + fprintf(stderr, "%s: CPU %d not available (found %d CPU's: [0]-[%d])\n ", + appname, cpunum, numcpu, numcpu - 1 ); + } + exit(1); + } + +#endif + } + + breakloop = 0; + + for (i=0; i < CPUSTATES; i++){ + cpu_max[i] = 0; + cpu_min[i] = 100; + } + + /* get information */ +#ifdef __FreeBSD__ + getsysctl("kern.cp_time", new, sizeof(cp_time1)); +#else + getSysinfo((unsigned long*)new, CPUSTATES); +#endif + + /* catch Strg+C when capturing to call pcap_breakloop() */ + memset(&signew, 0, sizeof(signew)); + signew.sa_handler = loop_term_handler; + if (sigaction(SIGINT, &signew, &sigold) < 0 ){ + fprintf(stderr, "Could not set signal handler -> exiting"); + } + + avg = 0; + avg_run = 0; + + if ( runonce ) { + breakloop=1; + } + + while(1) { + usleep( 1000000 ); + + if ( new == cp_time1 ) { + new = cp_time2; + old = cp_time1; + } else{ + new = cp_time1; + old = cp_time2; + } + + /* get information again */ +#ifdef __FreeBSD__ + getsysctl("kern.cp_time", new, sizeof(cp_time1)); +#else + getSysinfo((unsigned long*)new, CPUSTATES); +#endif + + /* convert cp_time counts to percentages */ + total = perc(CPUSTATES, new, old, cp_diff); + + /* check for avg measurement start */ + if ( !avg_run && !avg && (cpu_perc[IDLEI] <= limit) ){ + avg = 1; + for ( i = 0; i < CPUSTATES; i++ ) + cp_avg_start[i] = new[i]; + } + + /* check for avg measurement stop */ + if ( !avg_run && avg && (cpu_perc[IDLEI] > limit) ){ + avg = 0; + for ( i = 0; i < CPUSTATES; i++ ) + cp_avg_stop[i] = new[i]; + avg_run = 1; + } + + print_perc(cpu_perc, ""); + + if (breakloop) { + if (avg) { + avg = 0; + for ( i = 0; i < CPUSTATES; i++ ) + cp_avg_stop[i] = new[i]; + } + break; + } + } + + /* Set default behaviour when loop is done */ + if (sigaction(SIGINT, &sigold, &signew) < 0 ){ + fprintf(stderr, "%s: Could not restore signal handler -> exiting", appname); + } + + if ( ! runonce && output == 0) { + // print avg only when not making a one-shot msg and + // when not writing CSV output + printf("---Summary----\n"); + + print_perc(cpu_min, "Min"); + + print_perc(cpu_max, "Max"); + + perc(CPUSTATES, cp_avg_start, cp_avg_stop, cp_diff); + + print_perc(cpu_perc, "Avg"); + } + + return 0; +} + + +
_______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel