From: Jo-Philipp Wich Date: Fri, 29 Apr 2011 15:45:52 +0000 (+0000) Subject: [PATCH] New package CPUsage X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=commitdiff_plain;h=ca300f565852d7f07888aaae61b8642771e29eb9;hp=2481d934602e4112ef3d4e4018710128dabf6554;ds=sidebyside [PATCH] New package CPUsage 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 SVN-Revision: 26792 --- diff --git a/utils/cpusage/Makefile b/utils/cpusage/Makefile new file mode 100644 index 0000000000..a02744bd35 --- /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 0000000000..a027e4f366 --- /dev/null +++ b/utils/cpusage/src/cpusage.c @@ -0,0 +1,426 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#else +#include +#include +#include +#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 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; +} + + +