From 0fbf5bd623d7ca88c27e5fa73e3c1622d27d5ea0 Mon Sep 17 00:00:00 2001 From: hadaq Date: Fri, 10 Sep 2010 14:22:27 +0000 Subject: [PATCH] CPU usage. Sergey. --- ebctrl/ioc/ebctrlApp/src/cpu.c | 356 +++++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 ebctrl/ioc/ebctrlApp/src/cpu.c diff --git a/ebctrl/ioc/ebctrlApp/src/cpu.c b/ebctrl/ioc/ebctrlApp/src/cpu.c new file mode 100644 index 0000000..07c6017 --- /dev/null +++ b/ebctrl/ioc/ebctrlApp/src/cpu.c @@ -0,0 +1,356 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "worker.h" + +int cpuDebug; + +typedef struct TheStatS { + unsigned long utime; /* user time */ + unsigned long stime; /* system time */ + unsigned long cutime; /* children in user mode */ + unsigned long cstime; /* children in systme mode */ + unsigned long cputime; /* total CPU time */ + + unsigned long pwctime; /* wall clock time for process CPU usage */ + unsigned long cwctime; /* wall clock time for core CPU usage */ +} TheStat; + +static void initStat(TheStat *my) +{ + my->utime = 0; + my->stime = 0; + my->cutime = 0; + my->cstime = 0; + my->pwctime = 0; + + my->cputime = 0; + my->cwctime = 0; +} + +static void initProcStat(TheStat *my) +{ + my->utime = 0; + my->stime = 0; + my->cutime = 0; + my->cstime = 0; + my->pwctime = 0; +} + +static void parseCpuStat( TheStat *theStat, uint32_t coreNr ) +{ + int fd; + char filename[24]; + char arg_list[1024]; + size_t length; + char* next_arg; + + struct timeval wctime; + + /* Generate the name of the cmdline file for the process */ + snprintf(filename, sizeof (filename), "/proc/stat"); + + /* Read the contents of the file */ + fd = open(filename, O_RDONLY); + length = read(fd, arg_list, sizeof (arg_list)); + close(fd); + + /* Read does not NUL-terminate the buffer, so do it here*/ + arg_list[length] = '\0'; + + /* Loop over arguments. Arguments are separated by NULs */ + next_arg = arg_list; + + char cpu[6]; + char* match; + + unsigned long utime; /* time in user mode */ + unsigned long untime; /* time in user mode with low priority (nice) */ + unsigned long stime; /* time in system mode */ + + sprintf(cpu, "cpu%d", coreNr); + + while( next_arg < arg_list + length ){ + + match = strstr(next_arg, cpu); + + if(match == NULL) continue; + + sscanf(match, "%s %lu %lu %lu", cpu, &utime, &untime, &stime); + + /* Convert to micro seconds */ + theStat->cputime = (int) 1000. * (double) (utime + untime + stime) / (double) sysconf(_SC_CLK_TCK); + + gettimeofday(&wctime, NULL); + /* Convert to micro seconds */ + theStat->cwctime = (int) 1000. * (double)wctime.tv_sec + (double)wctime.tv_usec / 1000000.0; + + /* + * Advance to the next argument. + * Since each argument is NUL-terminated, + * strlen counts the length of the next argument, + * not the entire argument list. + */ + next_arg += strlen (next_arg) + 1; + } +} + +static int parseProcStat( TheStat *theStat, pid_t pid ) +{ + int fd; + char filename[24]; + char dir[24]; + char arg_list[1024]; + char tmp[1024]; + size_t length; + + struct timeval wctime; + + char *token; + const char space[] = " "; + + struct stat statBufS, *statBuf = &statBufS; + + snprintf (dir, sizeof(dir), "/proc/%d", (int) pid); + + stat(dir, statBuf); + + /* Return if the process is gone */ + if(S_ISDIR(statBuf->st_mode) == 0){ + initProcStat(theStat); + gettimeofday(&wctime, NULL); + /* Convert to micro seconds */ + theStat->pwctime = (int) 1000. * (double)wctime.tv_sec + (double)wctime.tv_usec / 1000000.0; + return 0; + } + + /* Generate the name of the cmdline file for the process */ + snprintf (filename, sizeof (filename), "/proc/%d/stat", (int) pid); + + /* Read the contents of the file */ + fd = open (filename, O_RDONLY); + length = read (fd, arg_list, sizeof (arg_list)); + close (fd); + + /* Split string by spaces */ + strcpy(tmp, arg_list); + + token = strtok(tmp, space); /* token => "pid" */ + token = strtok(NULL, space); /* token => "comm" */ + token = strtok(NULL, space); /* token => "state" */ + token = strtok(NULL, space); /* token => "ppid" */ + token = strtok(NULL, space); /* token => "pgrp" */ + token = strtok(NULL, space); /* token => "session" */ + token = strtok(NULL, space); /* token => "tty_nr" */ + token = strtok(NULL, space); /* token => "tpgid" */ + token = strtok(NULL, space); /* token => "flags" */ + token = strtok(NULL, space); /* token => "minflt" */ + token = strtok(NULL, space); /* token => "cminflt" */ + token = strtok(NULL, space); /* token => "majflt" */ + token = strtok(NULL, space); /* token => "cmajflt" */ + + /* Convert all the times to micro seconds */ + + token = strtok(NULL, space); /* token => "utime" */ + theStat->utime = (int) 1000. * (double) strtoul(token, NULL, 0) / (double) sysconf(_SC_CLK_TCK); + + token = strtok(NULL, space); /* token => "stime" */ + theStat->stime = (int) 1000. * (double) strtoul(token, NULL, 0) / (double) sysconf(_SC_CLK_TCK); + + token = strtok(NULL, space); /* token => "cutime" */ + theStat->cutime = (int) 1000. * (double) strtoul(token, NULL, 0) / (double) sysconf(_SC_CLK_TCK); + + token = strtok(NULL, space); /* token => "cstime" */ + theStat->cstime = (int) 1000. * (double) strtoul(token, NULL, 0) / (double) sysconf(_SC_CLK_TCK); + + gettimeofday(&wctime, NULL); + /* Convert to micro seconds */ + theStat->pwctime = (int) 1000. * (double)wctime.tv_sec + (double)wctime.tv_usec / 1000000.0; + + return 0; +} + +static int getProcCpuUsage(TheStat *theStat, TheStat *theStat_old) +{ + int procCPU = 100 * ((theStat->utime + theStat->stime + + theStat->cutime + theStat->cstime) - + (theStat_old->utime + theStat_old->stime + + theStat_old->cutime + theStat_old->cstime)) / + (theStat->pwctime - theStat_old->pwctime); + + return procCPU; +} + +static int getCoreCpuUsage(TheStat *theStat, TheStat * theStat_old) +{ + int coreCPU = 100 * (theStat->cputime - theStat_old->cputime) / + (theStat->cwctime - theStat_old->cwctime); + + return coreCPU; +} + +long cpu_init( struct genSubRecord *pgsub ) +{ + return(0); +} + +long cpu_proc( struct genSubRecord *pgsub ) +{ + + uint32_t *out[4]; + unsigned long tmp; + int i; + + out[0] = (uint32_t *)pgsub->vala; /* evtbuild: proc cpu usage */ + out[1] = (uint32_t *)pgsub->valb; /* evtbuild: core cpu usage */ + out[2] = (uint32_t *)pgsub->valc; /* netmem: proc cpu usage */ + out[3] = (uint32_t *)pgsub->vald; /* netmem: core cpu usage */ + + for( i=0; i<4; i++ ) + *out[i] = 0; + + /* + * ************** CPU usage for EvtBuild *************** + */ + + char buf[_POSIX_PATH_MAX]; + sprintf( buf, "%s%s", "daq_evtbuild", getenv("EBNUM") ); + + uint32_t eb_pid; + uint32_t eb_coreNr; + + /* Get PID of evtbuild */ + if( Worker_getStatistic( buf, "PID", &tmp ) == -1) { + eb_pid = 0; + + if(cpuDebug) + printf(" cpu.c: Worker_getStatistic failed for PID from %s\n", buf); + } + else { + eb_pid = (uint32_t)tmp; + } + + /* Get core number of evtbuild */ + if( Worker_getStatistic( buf, "coreNr", &tmp ) == -1) { + eb_coreNr = 0; + + if(cpuDebug) + printf(" cpu.c: Worker_getStatistic failed for coreNr from %s\n", buf); + } + else { + eb_coreNr = (uint32_t)tmp; + } + + static int once1 = 1; + static TheStat theStat1_oldS; + TheStat *theStat1_old = &theStat1_oldS; + TheStat theStat1S, *theStat1 = &theStat1S; + + initStat(theStat1); + if(once1){ + initStat(theStat1_old); + once1 = 0; + } + + /* Check core number */ + if(eb_coreNr == 0){ + *out[1] = 0; /* core CPU usage */ + } + else{ + parseCpuStat(theStat1, eb_coreNr); + *out[1] = (uint32_t) getCoreCpuUsage(theStat1, theStat1_old); + } + + /* Check PID */ + if(eb_pid == 0){ + *out[0] = 0; /* proc CPU usage */ + } + else{ + parseProcStat(theStat1, (pid_t) eb_pid); + *out[0] = (uint32_t) getProcCpuUsage(theStat1, theStat1_old); + } + + *theStat1_old = *theStat1; + + /* + * ************** CPU usage for EvtBuild *************** + */ + + sprintf( buf, "%s%s", "daq_netmem", getenv("EBNUM") ); + + uint32_t nm_pid; + uint32_t nm_coreNr; + + /* Get PID of evtbuild */ + if( Worker_getStatistic( buf, "PID", &tmp ) == -1) { + nm_pid = 0; + + if(cpuDebug) + printf(" cpu.c: Worker_getStatistic failed for PID from %s\n", buf); + } + else { + nm_pid = (uint32_t)tmp; + } + + /* Get core number of evtbuild */ + if( Worker_getStatistic( buf, "coreNr", &tmp ) == -1) { + nm_coreNr = 0; + + if(cpuDebug) + printf(" cpu.c: Worker_getStatistic failed for coreNr from %s\n", buf); + } + else { + nm_coreNr = (uint32_t)tmp; + } + + static int once2 = 1; + static TheStat theStat2_oldS; + TheStat *theStat2_old = &theStat2_oldS; + TheStat theStat2S, *theStat2 = &theStat2S; + + initStat(theStat2); + if(once2){ + initStat(theStat2_old); + once2 = 0; + } + + /* Check core number */ + if(nm_coreNr == 0){ + *out[3] = 0; /* core CPU usage */ + } + else{ + parseCpuStat(theStat2, nm_coreNr); + *out[3] = (uint32_t) getCoreCpuUsage(theStat2, theStat2_old); + } + + /* Check PID */ + if(nm_pid == 0){ + *out[2] = 0; /* proc CPU usage */ + } + else{ + parseProcStat(theStat2, (pid_t) nm_pid); + *out[2] = (uint32_t) getProcCpuUsage(theStat2, theStat2_old); + } + + *theStat2_old = *theStat2; + + return(0); +} + +/* Register these symbols for use by IOC code: */ + +epicsExportAddress(int, cpuDebug); +epicsRegisterFunction(cpu_init); +epicsRegisterFunction(cpu_proc); -- 2.43.0