--- /dev/null
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <dbDefs.h>
+#include <registryFunction.h>
+#include <subRecord.h>
+#include <epicsExport.h>
+#include <genSubRecord.h>
+#include <stringinRecord.h>
+
+#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("<E> 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("<E> 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("<E> 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("<E> 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);