431439: CRM #1765368 HOST-RESOURCES-MIB::hrProcessorLoad Author: cpu_linux.c: upstream, svn diff -r 15025:15026 + 17191 hr_proc.c: Jan Safranek <jsafrane@redhat.com> (inspired by svn ver. 15026) - just move the computation to the 'old' place This patch fixes reading of CPU stats on multi-CPU machines + computes the load in proper way (was: based on load average, now: based on real tick counts). diff -ur --exclude '*.o' --exclude .libs --exclude '*.lo' --exclude man --exclude perl --exclude apps --exclude local --exclude '*.la' --exclude snmpd --exclude net-snmp-config-x --exclude net-snmp-config.h --exclude Makefile --exclude config.log --exclude config.sub --exclude config.status --exclude config.guess --exclude '*.orig' orig/agent/mibgroup/hardware/cpu/cpu_linux.c net-snmp-5.3.1/agent/mibgroup/hardware/cpu/cpu_linux.c --- orig/agent/mibgroup/hardware/cpu/cpu_linux.c 2005-07-21 00:07:41.000000000 +0200 +++ net-snmp-5.3.1/agent/mibgroup/hardware/cpu/cpu_linux.c 2008-02-07 12:56:16.000000000 +0100 @@ -46,7 +46,7 @@ #endif } -#ifdef DESCR2_FIELD +#ifdef DESCR_FIELD if (!strncmp( buf, DESCR_FIELD, strlen(DESCR_FIELD))) { cp = strchr( buf, ':' ); strcpy( cpu->descr, cp+2 ); @@ -76,18 +76,12 @@ static int bsize = 0; static int first = 1; static int has_cpu_26 = 1; - int statfd; - char *b; + int statfd, i; + char *b1, *b2; unsigned long long cusell = 0, cicell = 0, csysll = 0, cidell = 0, ciowll = 0, cirqll = 0, csoftll = 0; netsnmp_cpu_info* cpu; - cpu = netsnmp_cpu_get_byIdx( -1, 0 ); - if (!cpu) { - snmp_log_perror("No CPU info entry"); - return -1; - } - if ((statfd = open(STAT_FILE, O_RDONLY, 0)) == -1) { snmp_log_perror(STAT_FILE); return -1; @@ -106,15 +100,32 @@ close(statfd); /* - * Overall CPU statistics + * CPU statistics (overall and per-CPU) */ - b = strstr(buff, "cpu "); - if (b) { + b1 = buff; + while ( b2 = strstr( b1, "cpu" )) { + if (b2[3] == ' ') { + cpu = netsnmp_cpu_get_byIdx( -1, 0 ); + if (!cpu) { + snmp_log_perror("No (overall) CPU info entry"); + return -1; + } + b1 = b2+4; /* Skip "cpu " */ + } else { + sscanf( b2, "cpu%d", &i ); + cpu = netsnmp_cpu_get_byIdx( i, 0 ); + if (!cpu) { + snmp_log_perror("Missing CPU info entry"); + break; + } + b1 = b2+5; /* Skip "cpuN " */ + } + if (!has_cpu_26 || - sscanf(b, "cpu %llu %llu %llu %llu %llu %llu %llu", &cusell, + sscanf(b1, "%llu %llu %llu %llu %llu %llu %llu", &cusell, &cicell, &csysll, &cidell, &ciowll, &cirqll, &csoftll) != 7) { has_cpu_26 = 0; - sscanf(b, "cpu %llu %llu %llu %llu", &cusell, &cicell, &csysll, + sscanf(b1, "%llu %llu %llu %llu", &cusell, &cicell, &csysll, &cidell); } else { @@ -126,7 +137,8 @@ cpu->nice_ticks = (unsigned long)cicell; cpu->sys_ticks = (unsigned long)csysll; cpu->idle_ticks = (unsigned long)cidell; - } else { + } + if ( b1 == buff ) { if (first) snmp_log(LOG_ERR, "No cpu line in %s\n", STAT_FILE); } @@ -135,6 +147,7 @@ * Interrupt/Context Switch statistics * XXX - Do these really belong here ? */ + cpu = netsnmp_cpu_get_byIdx( -1, 0 ); _cpu_load_swap_etc( buff, cpu ); /* @@ -181,7 +194,7 @@ b = strstr(vmbuff, "pgpgin "); if (b) { sscanf(b, "pgpgin %llu", &pin); - cpu->pageIn = (unsigned long)pin; + cpu->pageIn = (unsigned long)pin*2; /* ??? */ } else { if (first) snmp_log(LOG_ERR, "No pgpgin line in %s\n", VMSTAT_FILE); @@ -190,7 +203,7 @@ b = strstr(vmbuff, "pgpgout "); if (b) { sscanf(b, "pgpgout %llu", &pout); - cpu->pageOut = (unsigned long)pout; + cpu->pageOut = (unsigned long)pout*2; /* ??? */ } else { if (first) snmp_log(LOG_ERR, "No pgpgout line in %s\n", VMSTAT_FILE); diff -ur --exclude '*.o' --exclude .libs --exclude '*.lo' --exclude man --exclude perl --exclude apps --exclude local --exclude '*.la' --exclude snmpd --exclude net-snmp-config-x --exclude net-snmp-config.h --exclude Makefile --exclude config.log --exclude config.sub --exclude config.status --exclude config.guess --exclude '*.orig' orig/agent/mibgroup/host/hr_proc.c net-snmp-5.3.1/agent/mibgroup/host/hr_proc.c --- orig/agent/mibgroup/host/hr_proc.c 2006-05-19 19:02:22.000000000 +0200 +++ net-snmp-5.3.1/agent/mibgroup/host/hr_proc.c 2008-02-07 12:56:35.000000000 +0100 @@ -199,26 +199,36 @@ { int proc_idx; double avenrun[3]; + netsnmp_cpu_info *cpu; + long cpu_total_ticks; proc_idx = header_hrproc(vp, name, length, exact, var_len, write_method); if (proc_idx == MATCH_FAILED) return NULL; - if (try_getloadavg(&avenrun[0], sizeof(avenrun) / sizeof(avenrun[0])) - == -1) - return NULL; switch (vp->magic) { case HRPROC_ID: *var_len = nullOidLen; return (u_char *) nullOid; case HRPROC_LOAD: -#if NO_DUMMY_VALUES - return NULL; -#endif - long_return = avenrun[0] * 100; /* 1 minute average */ - if (long_return > 100) - long_return = 100; + cpu = netsnmp_cpu_get_byIdx( proc_idx & HRDEV_TYPE_MASK, 0 ); + if ( !cpu || !cpu->history[0].total_hist ) + return NULL; + cpu_total_ticks = cpu->user_ticks + + cpu->nice_ticks + + cpu->sys_ticks + + cpu->idle_ticks + + cpu->wait_ticks + + cpu->kern_ticks + + cpu->intrpt_ticks + + cpu->sirq_ticks; + *var_len = sizeof(long_return); + long_return = (cpu->idle_ticks - cpu->history[0].idle_hist)*100; + long_return /= (cpu_total_ticks - cpu->history[0].total_hist); + long_return = 100 - long_return; + if (long_return < 0) + long_return = 0; return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrproc\n", diff --git a/net-snmp/agent/mibgroup/hardware/cpu/cpu_linux.c b/net-snmp/agent/mibgroup/hardware/cpu/cpu_linux.c --- orig/agent/mibgroup/hardware/cpu/cpu_linux.c +++ net-snmp/agent/mibgroup/hardware/cpu/cpu_linux.c @@ -56,6 +56,15 @@ void init_cpu_linux( void ) { strcat( cpu->descr, "An S/390 CPU" ); #endif } +#if defined(__s390__) || defined(__s390x__) + else { /* s390 has different format of CPU_FILE */ + if (sscanf( buf, "processor %d:", &i ) == 1) { + cpu = netsnmp_cpu_get_byIdx( i, 1 ); + sprintf( cpu->name, "cpu%d", i ); + strcat( cpu->descr, "An S/390 CPU" ); + } + } +#endif #ifdef DESCR_FIELD if (!strncmp( buf, DESCR_FIELD, strlen(DESCR_FIELD))) {