1 #include <net-snmp/net-snmp-config.h>
2 #include <net-snmp/net-snmp-features.h>
3 #include <net-snmp/net-snmp-includes.h>
4 #include <net-snmp/agent/net-snmp-agent-includes.h>
5 #include <net-snmp/agent/hardware/cpu.h>
6 #include "cpu.h"
7
8 netsnmp_feature_child_of(hardware_cpu, libnetsnmpmibs);
9
10 netsnmp_feature_child_of(hardware_cpu_copy_stats, hardware_cpu);
11 netsnmp_feature_child_of(hardware_cpu_load, hardware_cpu);
12 netsnmp_feature_child_of(hardware_cpu_get_cache, hardware_cpu);
13 netsnmp_feature_child_of(hardware_cpu_get_byName, hardware_cpu);
14
15 static void _cpu_update_stats( unsigned int, void* );
16
17 static int _cpuAutoUpdate = 5;
18 static int _cpuHistoryLen;
19 int cpu_num = 0;
20
21 static netsnmp_cpu_info *_cpu_head = NULL;
22 static netsnmp_cpu_info *_cpu_tail = NULL;
23 static netsnmp_cache *_cpu_cache = NULL;
24
init_cpu(void)25 void init_cpu( void ) {
26 oid nsCPU[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 33 };
27 /*
28 * If we're sampling the CPU statistics automatically,
29 * then arrange for this to be triggered regularly,
30 * keeping sufficient samples to cover the last minute.
31 * If the system-specific code has already initialised
32 * the list of CPU entries, then retrieve the first set
33 * of stats immediately.
34 * Otherwise, wait until the regular sampling kicks in.
35 *
36 * If we're not sampling these statistics regularly,
37 * create a suitable cache handler instead.
38 */
39 if ( _cpuAutoUpdate ) {
40
41 _cpuHistoryLen = 60/_cpuAutoUpdate;
42 snmp_alarm_register( _cpuAutoUpdate, SA_REPEAT, _cpu_update_stats,
43 NULL );
44 if ( _cpu_head )
45 _cpu_update_stats( 0, NULL );
46 } else
47 _cpu_cache = netsnmp_cache_create( 5, netsnmp_cpu_arch_load, NULL,
48 nsCPU, OID_LENGTH(nsCPU));
49 }
50
shutdown_cpu(void)51 void shutdown_cpu( void ) {
52 while ( _cpu_head ) {
53 netsnmp_cpu_info *tmp = _cpu_head;
54 _cpu_head = _cpu_head->next;
55 SNMP_FREE(tmp->history);
56 SNMP_FREE(tmp);
57 }
58 _cpu_tail = NULL;
59 }
60
61
netsnmp_cpu_get_first(void)62 netsnmp_cpu_info *netsnmp_cpu_get_first( void ) {
63 return _cpu_head;
64 }
netsnmp_cpu_get_next(netsnmp_cpu_info * this_ptr)65 netsnmp_cpu_info *netsnmp_cpu_get_next( netsnmp_cpu_info *this_ptr ) {
66 return ( this_ptr ? this_ptr->next : NULL );
67 }
68
69 /*
70 * Work with a list of CPU entries, indexed numerically
71 */
netsnmp_cpu_get_byIdx(int idx,int create)72 netsnmp_cpu_info *netsnmp_cpu_get_byIdx( int idx, int create ) {
73 netsnmp_cpu_info *cpu, *cpu2;
74
75 /*
76 * Find the specified CPU entry
77 */
78 DEBUGMSGTL(("cpu", "cpu_get_byIdx %d ", idx));
79 for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
80 if ( cpu->idx == idx ) {
81 DEBUGMSG(("cpu", "(found)\n"));
82 return cpu;
83 }
84 }
85 if (!create) {
86 DEBUGMSG(("cpu", "(not found)\n"));
87 return NULL;
88 }
89
90 /*
91 * Create a new CPU entry, and insert it into the list....
92 */
93 cpu = SNMP_MALLOC_TYPEDEF( netsnmp_cpu_info );
94 if (!cpu) {
95 DEBUGMSG(("cpu", "(failed)\n"));
96 return NULL;
97 }
98 DEBUGMSG(("cpu", "(created)\n"));
99 cpu->idx = idx;
100 /* ... either as the first (or only) entry.... */
101 if ( !_cpu_head || _cpu_head->idx > idx ) {
102 cpu->next = _cpu_head;
103 _cpu_head = cpu;
104 if (!_cpu_tail)
105 _cpu_tail = cpu;
106 return cpu;
107 }
108 /* ... or in the appropriate position */
109 for ( cpu2=_cpu_head; cpu2; cpu2=cpu2->next ) {
110 if ( !cpu2->next || cpu2->next->idx > idx ) {
111 cpu->next = cpu2->next;
112 cpu2->next = cpu;
113 if (!cpu->next)
114 _cpu_tail = cpu;
115 return cpu;
116 }
117 }
118 SNMP_FREE(cpu); /* just in case */
119 return NULL; /* Shouldn't happen! */
120 }
121
122 /*
123 * Work with a list of CPU entries, indexed by name
124 */
125 #ifndef NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_GET_BYNAME
netsnmp_cpu_get_byName(char * name,int create)126 netsnmp_cpu_info *netsnmp_cpu_get_byName( char *name, int create ) {
127 netsnmp_cpu_info *cpu;
128
129 /*
130 * Find the specified CPU entry
131 */
132 for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
133 if ( !strcmp(cpu->name, name))
134 return cpu;
135 }
136 if (!create)
137 return NULL;
138
139 /*
140 * Create a new CPU entry, and append it to the list
141 */
142 cpu = SNMP_MALLOC_TYPEDEF( netsnmp_cpu_info );
143 if (!cpu)
144 return NULL;
145 if (strlen(name) >= sizeof(cpu->name)) {
146 free(cpu);
147 snmp_log(LOG_ERR, "Name of CPU is too large: %s\n", name);
148 return NULL;
149 }
150
151 strlcpy(cpu->name, name, sizeof(cpu));
152 if ( _cpu_tail ) {
153 cpu->idx = _cpu_tail->idx+1;
154 _cpu_tail->next = cpu;
155 _cpu_tail = cpu;
156 } else {
157 cpu->idx = 0;
158 _cpu_head = cpu;
159 _cpu_tail = cpu;
160 }
161 return cpu;
162 }
163 #endif /* NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_GET_BYNAME */
164
165 #ifndef NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_GET_CACHE
netsnmp_cpu_get_cache(void)166 netsnmp_cache *netsnmp_cpu_get_cache( void ) {
167 return _cpu_cache;
168 }
169 #endif /* NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_GET_CACHE */
170
171 #ifndef NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_LOAD
netsnmp_cpu_load(void)172 int netsnmp_cpu_load( void ) {
173 /*
174 * If we're automatically updating the stats regularly,
175 * then don't invoke the cache handling.
176 */
177 return ( _cpuAutoUpdate ? 1
178 : netsnmp_cache_check_and_reload( _cpu_cache ));
179 }
180 #endif /* NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_LOAD */
181
182 /*
183 * Call the system-specific load routine regularly,
184 * keeping track of the relevant earlier results.
185 */
186 static void
_cpu_update_stats(unsigned int reg,void * magic)187 _cpu_update_stats( unsigned int reg, void* magic ) {
188 netsnmp_cpu_info *cpu;
189 int i;
190
191 for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
192 if ( !cpu->history ) {
193 /*
194 * First time through, we need to create buffers
195 * for the historical stats
196 */
197 cpu->history = (struct netsnmp_cpu_history *)calloc( _cpuHistoryLen, sizeof(struct netsnmp_cpu_history));
198 } else {
199 /*
200 * Otherwise, rotate these values - in descending order
201 * with the earliest (relevant) statistics in entry 0.
202 * This means that the code to calculate the rolling averages
203 * is independent of the number of historical samples saved.
204 */
205 for (i=0; i<_cpuHistoryLen-2; i++) {
206 cpu->history[i] = cpu->history[i+1];
207 }
208 cpu->history[i].user_hist = cpu->user_ticks;
209 cpu->history[i].sys_hist = cpu->sys_ticks;
210 cpu->history[i].idle_hist = cpu->idle_ticks;
211 cpu->history[i].nice_hist = cpu->nice_ticks;
212 cpu->history[i].total_hist = cpu->total_ticks;
213
214 cpu->history[i].ctx_hist = cpu->nCtxSwitches;
215 cpu->history[i].intr_hist = cpu->nInterrupts;
216 cpu->history[i].swpi_hist = cpu->swapIn;
217 cpu->history[i].swpo_hist = cpu->swapOut;
218 cpu->history[i].pagei_hist = cpu->pageIn;
219 cpu->history[i].pageo_hist = cpu->pageOut;
220 }
221 }
222
223 /*
224 * Now call the system-specific load routine, to
225 * retrieve the latest set of data.
226 */
227 netsnmp_cpu_arch_load( NULL, NULL );
228 for ( cpu=_cpu_head; cpu; cpu=cpu->next ) {
229 cpu->total_ticks = cpu->user_ticks +
230 cpu->nice_ticks +
231 cpu->sys_ticks +
232 cpu->idle_ticks +
233 cpu->wait_ticks +
234 cpu->kern_ticks +
235 cpu->intrpt_ticks +
236 cpu->sirq_ticks +
237 cpu->steal_ticks +
238 cpu->guest_ticks +
239 cpu->guestnice_ticks;
240 }
241 }
242
243 #ifndef NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_COPY_STATS
_cpu_copy_stats(netsnmp_cpu_info * cpu)244 void _cpu_copy_stats( netsnmp_cpu_info *cpu )
245 {
246 netsnmp_cpu_info *cpu2;
247
248 /*
249 * Copy "overall" statistics to the 'cpu0' entry
250 * on single CPU systems where this isn't done automatically
251 */
252 cpu2 = netsnmp_cpu_get_byIdx( 0, 1 );
253 if (!cpu || !cpu2) return;
254 cpu2->user_ticks = cpu->user_ticks;
255 cpu2->nice_ticks = cpu->nice_ticks;
256 cpu2->sys_ticks = cpu->sys_ticks;
257 cpu2->sys2_ticks = cpu->sys2_ticks;
258 cpu2->idle_ticks = cpu->idle_ticks;
259 cpu2->wait_ticks = cpu->wait_ticks;
260 cpu2->kern_ticks = cpu->kern_ticks;
261 cpu2->intrpt_ticks = cpu->intrpt_ticks;
262 cpu2->sirq_ticks = cpu->sirq_ticks;
263 cpu2->steal_ticks = cpu->steal_ticks;
264 cpu2->guest_ticks = cpu->guest_ticks;
265 cpu2->guestnice_ticks = cpu->guestnice_ticks;
266
267 cpu2->nInterrupts = cpu->nInterrupts;
268 cpu2->nCtxSwitches = cpu->nCtxSwitches;
269 cpu2->swapIn = cpu->swapIn;
270 cpu2->swapOut = cpu->swapOut;
271 cpu2->pageIn = cpu->pageIn;
272 cpu2->pageOut = cpu->pageOut;
273 }
274 #endif /* NETSNMP_FEATURE_REMOVE_HARDWARE_CPU_COPY_STATS */
275