summaryrefslogtreecommitdiff
path: root/agent/mibgroup/hardware/cpu/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/hardware/cpu/cpu.c')
-rw-r--r--agent/mibgroup/hardware/cpu/cpu.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/agent/mibgroup/hardware/cpu/cpu.c b/agent/mibgroup/hardware/cpu/cpu.c
new file mode 100644
index 0000000..0f66f47
--- /dev/null
+++ b/agent/mibgroup/hardware/cpu/cpu.c
@@ -0,0 +1,247 @@
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/agent/hardware/cpu.h>
+
+extern NetsnmpCacheLoad netsnmp_cpu_arch_load;
+static void _cpu_update_stats( unsigned int, void* );
+
+static int _cpuAutoUpdate = 5;
+static int _cpuHistoryLen;
+int cpu_num = 0;
+
+static netsnmp_cpu_info *_cpu_head = NULL;
+static netsnmp_cpu_info *_cpu_tail = NULL;
+static netsnmp_cache *_cpu_cache = NULL;
+
+void init_cpu( void ) {
+ oid nsCPU[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 33 };
+ /*
+ * If we're sampling the CPU statistics automatically,
+ * then arrange for this to be triggered regularly,
+ * keeping sufficient samples to cover the last minute.
+ * If the system-specific code has already initialised
+ * the list of CPU entries, then retrieve the first set
+ * of stats immediately.
+ * Otherwise, wait until the regular sampling kicks in.
+ *
+ * If we're not sampling these statistics regularly,
+ * create a suitable cache handler instead.
+ */
+ if ( _cpuAutoUpdate ) {
+
+ _cpuHistoryLen = 60/_cpuAutoUpdate;
+ snmp_alarm_register( _cpuAutoUpdate, SA_REPEAT, _cpu_update_stats,
+ NULL );
+ if ( _cpu_head )
+ _cpu_update_stats( 0, NULL );
+ } else
+ _cpu_cache = netsnmp_cache_create( 5, netsnmp_cpu_arch_load, NULL,
+ nsCPU, OID_LENGTH(nsCPU));
+}
+
+void shutdown_cpu( void ) {
+ while ( _cpu_head ) {
+ netsnmp_cpu_info *tmp = _cpu_head;
+ _cpu_head = _cpu_head->next;
+ SNMP_FREE(tmp->history);
+ SNMP_FREE(tmp);
+ }
+ _cpu_tail = NULL;
+}
+
+
+netsnmp_cpu_info *netsnmp_cpu_get_first( void ) {
+ return _cpu_head;
+}
+netsnmp_cpu_info *netsnmp_cpu_get_next( netsnmp_cpu_info *this_ptr ) {
+ return ( this_ptr ? this_ptr->next : NULL );
+}
+
+ /*
+ * Work with a list of CPU entries, indexed numerically
+ */
+netsnmp_cpu_info *netsnmp_cpu_get_byIdx( int idx, int create ) {
+ netsnmp_cpu_info *cpu, *cpu2;
+
+ /*
+ * Find the specified CPU entry
+ */
+ DEBUGMSGTL(("cpu", "cpu_get_byIdx %d ", idx));
+ for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
+ if ( cpu->idx == idx ) {
+ DEBUGMSG(("cpu", "(found)\n"));
+ return cpu;
+ }
+ }
+ if (!create) {
+ DEBUGMSG(("cpu", "(not found)\n"));
+ return NULL;
+ }
+
+ /*
+ * Create a new CPU entry, and insert it into the list....
+ */
+ cpu = SNMP_MALLOC_TYPEDEF( netsnmp_cpu_info );
+ if (!cpu) {
+ return NULL;
+ DEBUGMSG(("cpu", "(failed)\n"));
+ }
+ DEBUGMSG(("cpu", "(created)\n"));
+ cpu->idx = idx;
+ /* ... either as the first (or only) entry.... */
+ if ( !_cpu_head || _cpu_head->idx > idx ) {
+ cpu->next = _cpu_head;
+ _cpu_head = cpu;
+ if (!_cpu_tail)
+ _cpu_tail = cpu;
+ return cpu;
+ }
+ /* ... or in the appropriate position */
+ for ( cpu2=_cpu_head; cpu2; cpu2=cpu2->next ) {
+ if ( !cpu2->next || cpu2->next->idx > idx ) {
+ cpu->next = cpu2->next;
+ cpu2->next = cpu;
+ if (!cpu->next)
+ _cpu_tail = cpu;
+ return cpu;
+ }
+ }
+ if (cpu)
+ SNMP_FREE(cpu); /* just in case */
+ return NULL; /* Shouldn't happen! */
+}
+
+ /*
+ * Work with a list of CPU entries, indexed by name
+ */
+netsnmp_cpu_info *netsnmp_cpu_get_byName( char *name, int create ) {
+ netsnmp_cpu_info *cpu;
+
+ /*
+ * Find the specified CPU entry
+ */
+ for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
+ if ( !strcmp(cpu->name, name))
+ return cpu;
+ }
+ if (!create)
+ return NULL;
+
+ /*
+ * Create a new CPU entry, and append it to the list
+ */
+ cpu = SNMP_MALLOC_TYPEDEF( netsnmp_cpu_info );
+ if (!cpu)
+ return NULL;
+ strcpy(cpu->name, name);
+ if ( _cpu_tail ) {
+ cpu->idx = _cpu_tail->idx+1;
+ _cpu_tail->next = cpu;
+ _cpu_tail = cpu;
+ } else {
+ cpu->idx = 0;
+ _cpu_head = cpu;
+ _cpu_tail = cpu;
+ }
+ return cpu;
+}
+
+netsnmp_cache *netsnmp_cpu_get_cache( void ) {
+ return _cpu_cache;
+}
+
+int netsnmp_cpu_load( void ) {
+ /*
+ * If we're automatically updating the stats regularly,
+ * then don't invoke the cache handling.
+ */
+ return ( _cpuAutoUpdate ? 1
+ : netsnmp_cache_check_and_reload( _cpu_cache ));
+}
+
+ /*
+ * Call the system-specific load routine regularly,
+ * keeping track of the relevant earlier results.
+ */
+static void
+_cpu_update_stats( unsigned int reg, void* magic ) {
+ netsnmp_cpu_info *cpu;
+ int i;
+
+ for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
+ if ( !cpu->history ) {
+ /*
+ * First time through, we need to create buffers
+ * for the historical stats
+ */
+ cpu->history = calloc( _cpuHistoryLen, sizeof(struct netsnmp_cpu_history));
+ } else {
+ /*
+ * Otherwise, rotate these values - in descending order
+ * with the earliest (relevant) statistics in entry 0.
+ * This means that the code to calculate the rolling averages
+ * is independent of the number of historical samples saved.
+ */
+ for (i=0; i<_cpuHistoryLen-2; i++) {
+ cpu->history[i] = cpu->history[i+1];
+ }
+ cpu->history[i].user_hist = cpu->user_ticks;
+ cpu->history[i].sys_hist = cpu->sys_ticks;
+ cpu->history[i].idle_hist = cpu->idle_ticks;
+ cpu->history[i].nice_hist = cpu->nice_ticks;
+ cpu->history[i].total_hist = cpu->total_ticks;
+
+ cpu->history[i].ctx_hist = cpu->nCtxSwitches;
+ cpu->history[i].intr_hist = cpu->nInterrupts;
+ cpu->history[i].swpi_hist = cpu->swapIn;
+ cpu->history[i].swpo_hist = cpu->swapOut;
+ cpu->history[i].pagei_hist = cpu->pageIn;
+ cpu->history[i].pageo_hist = cpu->pageOut;
+ }
+ }
+
+ /*
+ * Now call the system-specific load routine, to
+ * retrieve the latest set of data.
+ */
+ netsnmp_cpu_arch_load( NULL, NULL );
+ for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
+ 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;
+ }
+}
+
+void _cpu_copy_stats( netsnmp_cpu_info *cpu )
+{
+ netsnmp_cpu_info *cpu2;
+
+ /*
+ * Copy "overall" statistics to the 'cpu0' entry
+ * on single CPU systems where this isn't done automatically
+ */
+ cpu2 = netsnmp_cpu_get_byIdx( 0, 1 );
+ if (!cpu || !cpu2) return;
+ cpu2->user_ticks = cpu->user_ticks;
+ cpu2->nice_ticks = cpu->nice_ticks;
+ cpu2->sys_ticks = cpu->sys_ticks;
+ cpu2->sys2_ticks = cpu->sys2_ticks;
+ cpu2->idle_ticks = cpu->idle_ticks;
+ cpu2->wait_ticks = cpu->wait_ticks;
+ cpu2->kern_ticks = cpu->kern_ticks;
+ cpu2->intrpt_ticks = cpu->intrpt_ticks;
+ cpu2->sirq_ticks = cpu->sirq_ticks;
+
+ cpu2->nInterrupts = cpu->nInterrupts;
+ cpu2->nCtxSwitches = cpu->nCtxSwitches;
+ cpu2->swapIn = cpu->swapIn;
+ cpu2->swapOut = cpu->swapOut;
+ cpu2->pageIn = cpu->pageIn;
+ cpu2->pageOut = cpu->pageOut;
+}