better indentation.
[collectd.git] / src / cpu.c
1 /**
2  * collectd - src/cpu.c
3  * Copyright (C) 2005-2010  Florian octo Forster
4  * Copyright (C) 2008       Oleg King
5  * Copyright (C) 2009       Simon Kuhnle
6  * Copyright (C) 2009       Manuel Sanmartin
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; only version 2 of the License is applicable.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20  *
21  * Authors:
22  *   Florian octo Forster <octo at verplant.org>
23  *   Oleg King <king2 at kaluga.ru>
24  *   Simon Kuhnle <simon at blarzwurst.de>
25  *   Manuel Sanmartin
26  **/
27
28 #include "collectd.h"
29 #include "common.h"
30 #include "plugin.h"
31
32 #ifdef HAVE_MACH_KERN_RETURN_H
33 # include <mach/kern_return.h>
34 #endif
35 #ifdef HAVE_MACH_MACH_INIT_H
36 # include <mach/mach_init.h>
37 #endif
38 #ifdef HAVE_MACH_HOST_PRIV_H
39 # include <mach/host_priv.h>
40 #endif
41 #if HAVE_MACH_MACH_ERROR_H
42 #  include <mach/mach_error.h>
43 #endif
44 #ifdef HAVE_MACH_PROCESSOR_INFO_H
45 # include <mach/processor_info.h>
46 #endif
47 #ifdef HAVE_MACH_PROCESSOR_H
48 # include <mach/processor.h>
49 #endif
50 #ifdef HAVE_MACH_VM_MAP_H
51 # include <mach/vm_map.h>
52 #endif
53
54 #ifdef HAVE_LIBKSTAT
55 # include <sys/sysinfo.h>
56 #endif /* HAVE_LIBKSTAT */
57
58 #if (defined(HAVE_SYSCTL) && HAVE_SYSCTL) \
59         || (defined(HAVE_SYSCTLBYNAME) && HAVE_SYSCTLBYNAME)
60 # ifdef HAVE_SYS_SYSCTL_H
61 #  include <sys/sysctl.h>
62 # endif
63
64 # ifdef HAVE_SYS_DKSTAT_H
65 #  include <sys/dkstat.h>
66 # endif
67
68 # if !defined(CP_USER) || !defined(CP_NICE) || !defined(CP_SYS) || !defined(CP_INTR) || !defined(CP_IDLE) || !defined(CPUSTATES)
69 #  define CP_USER   0
70 #  define CP_NICE   1
71 #  define CP_SYS    2
72 #  define CP_INTR   3
73 #  define CP_IDLE   4
74 #  define CPUSTATES 5
75 # endif
76 #endif /* HAVE_SYSCTL || HAVE_SYSCTLBYNAME */
77
78 #if HAVE_SYSCTL
79 # if defined(CTL_HW) && defined(HW_NCPU) \
80         && defined(CTL_KERN) && defined(KERN_CPTIME) && defined(CPUSTATES)
81 #  define CAN_USE_SYSCTL 1
82 # else
83 #  define CAN_USE_SYSCTL 0
84 # endif
85 #else
86 # define CAN_USE_SYSCTL 0
87 #endif
88
89 #define CPU_SUBMIT_USER 0
90 #define CPU_SUBMIT_SYSTEM 1
91 #define CPU_SUBMIT_WAIT 2
92 #define CPU_SUBMIT_NICE 3
93 #define CPU_SUBMIT_SWAP 4
94 #define CPU_SUBMIT_INTERRUPT 5
95 #define CPU_SUBMIT_SOFTIRQ 6
96 #define CPU_SUBMIT_STEAL 7
97 #define CPU_SUBMIT_IDLE 8
98 #define CPU_SUBMIT_ACTIVE 9
99 #define CPU_SUBMIT_MAX 10
100
101 #if HAVE_STATGRAB_H
102 # include <statgrab.h>
103 #endif
104
105 # ifdef HAVE_PERFSTAT
106 #  include <sys/protosw.h>
107 #  include <libperfstat.h>
108 # endif /* HAVE_PERFSTAT */
109
110 #if !PROCESSOR_CPU_LOAD_INFO && !KERNEL_LINUX && !HAVE_LIBKSTAT \
111         && !CAN_USE_SYSCTL && !HAVE_SYSCTLBYNAME && !HAVE_LIBSTATGRAB && !HAVE_PERFSTAT
112 # error "No applicable input method."
113 #endif
114
115 static const char *cpu_state_names[] = {
116         "user",
117         "system",
118         "wait",
119         "nice",
120         "swap",
121         "interrupt",
122         "softirq",
123         "steal",
124         "idle",
125         "active"
126 };
127
128 #ifdef PROCESSOR_CPU_LOAD_INFO
129 static mach_port_t port_host;
130 static processor_port_array_t cpu_list;
131 static mach_msg_type_number_t cpu_list_len;
132
133 #if PROCESSOR_TEMPERATURE
134 static int cpu_temp_retry_counter = 0;
135 static int cpu_temp_retry_step    = 1;
136 static int cpu_temp_retry_max     = 1;
137 #endif /* PROCESSOR_TEMPERATURE */
138 /* #endif PROCESSOR_CPU_LOAD_INFO */
139
140 #elif defined(KERNEL_LINUX)
141 /* no variables needed */
142 /* #endif KERNEL_LINUX */
143
144 #elif defined(HAVE_LIBKSTAT)
145 /* colleague tells me that Sun doesn't sell systems with more than 100 or so CPUs.. */
146 # define MAX_NUMCPU 256
147 extern kstat_ctl_t *kc;
148 static kstat_t *ksp[MAX_NUMCPU];
149 static int numcpu;
150 /* #endif HAVE_LIBKSTAT */
151
152 #elif CAN_USE_SYSCTL
153 static int numcpu;
154 /* #endif CAN_USE_SYSCTL */
155
156 #elif defined(HAVE_SYSCTLBYNAME)
157 static int numcpu;
158 #  ifdef HAVE_SYSCTL_KERN_CP_TIMES
159 static int maxcpu;
160 #  endif /* HAVE_SYSCTL_KERN_CP_TIMES */
161 /* #endif HAVE_SYSCTLBYNAME */
162
163 #elif defined(HAVE_LIBSTATGRAB)
164 /* no variables needed */
165 /* #endif  HAVE_LIBSTATGRAB */
166
167 #elif defined(HAVE_PERFSTAT)
168 static perfstat_cpu_t *perfcpu;
169 static int numcpu;
170 static int pnumcpu;
171 #endif /* HAVE_PERFSTAT */
172
173 static value_to_rate_state_t *percents = NULL;
174 static gauge_t agg_percents[CPU_SUBMIT_MAX] = {
175         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
176
177 };
178 static int percents_cells = 0;
179 static int cpu_count = 0;
180
181
182 static _Bool report_by_cpu = 1;
183 static _Bool report_percent = 0;
184 static _Bool report_active = 0;
185
186 static const char *config_keys[] =
187 {
188         "ReportByCpu",
189         "ReportActive",
190         "ValuesPercentage"
191 };
192 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
193
194
195 static int cpu_config (const char *key, const char *value)
196 {
197         if (strcasecmp (key, "ReportByCpu") == 0) {
198                 report_by_cpu = IS_TRUE (value) ? 1 : 0;
199                 if (!report_by_cpu)
200                         report_percent = 1;
201         }
202         if (strcasecmp (key, "ValuesPercentage") == 0) {
203                 report_percent = IS_TRUE (value) ? 1 : 0;
204                 if (!report_percent)
205                         report_by_cpu = 1;
206         }
207         if (strcasecmp (key, "ReportActive") == 0)
208                 report_active = IS_TRUE (value) ? 1 : 0;
209         return (-1);
210 }
211
212 static int cpu_states_grow (void)
213 {
214   void *tmp;
215   int size;
216   int i;
217
218   size = cpu_count * CPU_SUBMIT_MAX; /* always alloc for all states */
219
220   if (size <= 0)
221           return 0;
222
223   if (percents_cells >= size)
224           return 0;
225
226   if (percents == NULL) {
227           percents = malloc(size * sizeof(*percents));
228           if (percents == NULL)
229                   return -1;
230           for (i = 0; i < size; i++)
231                   memset(&percents[i], 0, sizeof(*percents));
232           percents_cells = size;
233           return 0;
234   }
235
236   tmp = realloc(percents, size * sizeof(*percents));
237
238   if (tmp == NULL) {
239           ERROR ("cpu plugin: could not reserve enough space to hold states");
240           percents = NULL;
241           return -1;
242   }
243
244   for (i = percents_cells; i < size; i++)
245           memset(&percents[i], 0, sizeof(*percents));
246
247   percents = tmp;
248   percents_cells = size;
249   return 0;
250 } /* cpu_states_grow */
251
252
253 static int init (void)
254 {
255 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
256         kern_return_t status;
257
258         port_host = mach_host_self ();
259
260         /* FIXME: Free `cpu_list' if it's not NULL */
261         if ((status = host_processors (port_host, &cpu_list, &cpu_list_len)) != KERN_SUCCESS)
262         {
263                 ERROR ("cpu plugin: host_processors returned %i", (int) status);
264                 cpu_list_len = 0;
265                 return (-1);
266         }
267
268         DEBUG ("host_processors returned %i %s", (int) cpu_list_len, cpu_list_len == 1 ? "processor" : "processors");
269         INFO ("cpu plugin: Found %i processor%s.", (int) cpu_list_len, cpu_list_len == 1 ? "" : "s");
270
271         cpu_temp_retry_max = 86400 / CDTIME_T_TO_TIME_T (plugin_get_interval ());
272 /* #endif PROCESSOR_CPU_LOAD_INFO */
273
274 #elif defined(HAVE_LIBKSTAT)
275         kstat_t *ksp_chain;
276
277         numcpu = 0;
278
279         if (kc == NULL)
280                 return (-1);
281
282         /* Solaris doesn't count linear.. *sigh* */
283         for (numcpu = 0, ksp_chain = kc->kc_chain;
284                         (numcpu < MAX_NUMCPU) && (ksp_chain != NULL);
285                         ksp_chain = ksp_chain->ks_next)
286                 if (strncmp (ksp_chain->ks_module, "cpu_stat", 8) == 0)
287                         ksp[numcpu++] = ksp_chain;
288 /* #endif HAVE_LIBKSTAT */
289
290 #elif CAN_USE_SYSCTL
291         size_t numcpu_size;
292         int mib[2] = {CTL_HW, HW_NCPU};
293         int status;
294
295         numcpu = 0;
296         numcpu_size = sizeof (numcpu);
297
298         status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
299                         &numcpu, &numcpu_size, NULL, 0);
300         if (status == -1)
301         {
302                 char errbuf[1024];
303                 WARNING ("cpu plugin: sysctl: %s",
304                                 sstrerror (errno, errbuf, sizeof (errbuf)));
305                 return (-1);
306         }
307 /* #endif CAN_USE_SYSCTL */
308
309 #elif defined (HAVE_SYSCTLBYNAME)
310         size_t numcpu_size;
311
312         numcpu_size = sizeof (numcpu);
313
314         if (sysctlbyname ("hw.ncpu", &numcpu, &numcpu_size, NULL, 0) < 0)
315         {
316                 char errbuf[1024];
317                 WARNING ("cpu plugin: sysctlbyname(hw.ncpu): %s",
318                                 sstrerror (errno, errbuf, sizeof (errbuf)));
319                 return (-1);
320         }
321
322 #ifdef HAVE_SYSCTL_KERN_CP_TIMES
323         numcpu_size = sizeof (maxcpu);
324
325         if (sysctlbyname("kern.smp.maxcpus", &maxcpu, &numcpu_size, NULL, 0) < 0)
326         {
327                 char errbuf[1024];
328                 WARNING ("cpu plugin: sysctlbyname(kern.smp.maxcpus): %s",
329                                 sstrerror (errno, errbuf, sizeof (errbuf)));
330                 return (-1);
331         }
332 #else
333         if (numcpu != 1)
334                 NOTICE ("cpu: Only one processor supported when using `sysctlbyname' (found %i)", numcpu);
335 #endif
336 /* #endif HAVE_SYSCTLBYNAME */
337
338 #elif defined(HAVE_LIBSTATGRAB)
339         /* nothing to initialize */
340 /* #endif HAVE_LIBSTATGRAB */
341
342 #elif defined(HAVE_PERFSTAT)
343         /* nothing to initialize */
344 #endif /* HAVE_PERFSTAT */
345
346         return (0);
347 } /* int init */
348
349 static void submit_value (int cpu_num, int cpu_state, const char *type, value_t value)
350 {
351         value_t values[1];
352         value_list_t vl = VALUE_LIST_INIT;
353
354         memcpy(&values[0], &value, sizeof(value));
355
356         vl.values = values;
357         vl.values_len = 1;
358
359         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
360         sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
361         sstrncpy (vl.type, type, sizeof (vl.type));
362         sstrncpy (vl.type_instance, cpu_state_names[cpu_state],
363                   sizeof (vl.type_instance));
364
365         if (cpu_num >= 0) {
366                 ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
367                            "%i", cpu_num);
368         }
369         plugin_dispatch_values (&vl);
370 }
371
372 static void submit_percent(int cpu_num, int cpu_state, gauge_t percent)
373 {
374         value_t value;
375
376         value.gauge = percent;
377         submit_value (cpu_num, cpu_state, "percent", value);
378 }
379
380 static void submit_derive(int cpu_num, int cpu_state, derive_t derive)
381 {
382         value_t value;
383
384         value.derive = derive;
385         submit_value (cpu_num, cpu_state, "cpu", value);
386 }
387
388 static void submit_flush (void)
389 {
390         int i = 0;
391
392         if (report_by_cpu) {
393                 cpu_count = 0;
394                 return;
395         }
396
397         for (i = 0; i < CPU_SUBMIT_MAX; i++) {
398                 if (agg_percents[i] == -1)
399                         continue;
400
401                 submit_percent(-1, i, agg_percents[i] / cpu_count);
402                 agg_percents[i] = -1;
403         }
404         cpu_count = 0;
405 }
406
407 static void submit (int cpu_num, derive_t *derives)
408 {
409
410         int i = 0;
411
412         if (!report_percent && report_by_cpu) {
413                 derive_t cpu_active = 0;
414                 for (i = 0; i < CPU_SUBMIT_ACTIVE; i++)
415                 {
416                         if (derives[i] == -1)
417                                 continue;
418
419                         if (i != CPU_SUBMIT_IDLE)
420                                 cpu_active += derives[i];
421
422                         submit_derive(cpu_num, i, derives[i]);
423                 }
424                 if (report_active)
425                         submit_derive(cpu_num, CPU_SUBMIT_ACTIVE, cpu_active);
426         }
427         else /* we are reporting percents */
428         {
429                 cdtime_t cdt;
430                 gauge_t percent;
431                 gauge_t cpu_total = 0;
432                 gauge_t cpu_active = 0;
433                 gauge_t local_rates[CPU_SUBMIT_MAX];
434
435                 cpu_count++;
436                 if (cpu_states_grow())
437                         return;
438
439                 memset(local_rates, 0, sizeof(local_rates));
440
441                 cdt = cdtime();
442                 for (i = 0; i < CPU_SUBMIT_ACTIVE; i++) {
443                         value_t rate;
444                         int index;
445
446                         if (derives[i] == -1)
447                                 continue;
448
449                         index = (cpu_num * CPU_SUBMIT_MAX) + i;
450                         if (value_to_rate(&rate, derives[i], &percents[index],
451                                           DS_TYPE_DERIVE, cdt) != 0) {
452                                 local_rates[i] = -1;
453                                 continue;
454                         }
455
456                         local_rates[i] = rate.gauge;
457                         cpu_total += rate.gauge;
458                         if (i != CPU_SUBMIT_IDLE)
459                                 cpu_active += rate.gauge;
460                 }
461                 if (cpu_total == 0.0)
462                         return;
463
464                 if (report_active)
465                         local_rates[CPU_SUBMIT_ACTIVE] = cpu_active;
466
467                 for (i = 0; i < CPU_SUBMIT_MAX; i++) {
468                         if (local_rates[i] == -1)
469                                 continue;
470
471                         percent = (local_rates[i] / cpu_total) * 100;
472                         if (report_by_cpu)
473                                 submit_percent (cpu_num, i, percent);
474                         else {
475                                 if (agg_percents[i] == -1)
476                                         agg_percents[i] = percent;
477                                 else
478                                         agg_percents[i] += percent;
479                         }
480
481                 }
482         }
483 }
484
485 static int cpu_read (void)
486 {
487 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
488         int cpu;
489
490         kern_return_t status;
491
492 #if PROCESSOR_CPU_LOAD_INFO
493         processor_cpu_load_info_data_t cpu_info;
494         mach_msg_type_number_t         cpu_info_len;
495 #endif
496 #if PROCESSOR_TEMPERATURE
497         processor_info_data_t          cpu_temp;
498         mach_msg_type_number_t         cpu_temp_len;
499 #endif
500
501         host_t cpu_host;
502
503         for (cpu = 0; cpu < cpu_list_len; cpu++)
504         {
505 #if PROCESSOR_CPU_LOAD_INFO
506                 derive_t derives[CPU_SUBMIT_MAX] = {
507                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
508                 };
509                 memset(derives, -1, sizeof(derives));
510                 cpu_host = 0;
511                 cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
512
513                 if ((status = processor_info (cpu_list[cpu],
514                                                 PROCESSOR_CPU_LOAD_INFO, &cpu_host,
515                                                 (processor_info_t) &cpu_info, &cpu_info_len)) != KERN_SUCCESS)
516                 {
517                         ERROR ("cpu plugin: processor_info failed with status %i", (int) status);
518                         continue;
519                 }
520
521                 if (cpu_info_len < CPU_STATE_MAX)
522                 {
523                         ERROR ("cpu plugin: processor_info returned only %i elements..", cpu_info_len);
524                         continue;
525                 }
526
527                 derives[CPU_SUBMIT_USER] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_USER];
528                 derives[CPU_SUBMIT_NICE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE];
529                 derives[CPU_SUBMIT_SYSTEM] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM];
530                 derives[CPU_SUBMIT_IDLE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE];
531                 submit (cpu, derives);
532
533 #endif /* PROCESSOR_CPU_LOAD_INFO */
534 #if PROCESSOR_TEMPERATURE
535                 /*
536                  * Not all Apple computers do have this ability. To minimize
537                  * the messages sent to the syslog we do an exponential
538                  * stepback if `processor_info' fails. We still try ~once a day
539                  * though..
540                  */
541                 if (cpu_temp_retry_counter > 0)
542                 {
543                         cpu_temp_retry_counter--;
544                         continue;
545                 }
546
547                 cpu_temp_len = PROCESSOR_INFO_MAX;
548
549                 status = processor_info (cpu_list[cpu],
550                                 PROCESSOR_TEMPERATURE,
551                                 &cpu_host,
552                                 cpu_temp, &cpu_temp_len);
553                 if (status != KERN_SUCCESS)
554                 {
555                         ERROR ("cpu plugin: processor_info failed: %s",
556                                         mach_error_string (status));
557
558                         cpu_temp_retry_counter = cpu_temp_retry_step;
559                         cpu_temp_retry_step *= 2;
560                         if (cpu_temp_retry_step > cpu_temp_retry_max)
561                                 cpu_temp_retry_step = cpu_temp_retry_max;
562
563                         continue;
564                 }
565
566                 if (cpu_temp_len != 1)
567                 {
568                         DEBUG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
569                                         (int) cpu_temp_len);
570                         continue;
571                 }
572
573                 cpu_temp_retry_counter = 0;
574                 cpu_temp_retry_step    = 1;
575 #endif /* PROCESSOR_TEMPERATURE */
576         }
577         submit_flush ();
578 /* #endif PROCESSOR_CPU_LOAD_INFO */
579
580 #elif defined(KERNEL_LINUX)
581         int cpu;
582         FILE *fh;
583         char buf[1024];
584
585         char *fields[9];
586         int numfields;
587
588         if ((fh = fopen ("/proc/stat", "r")) == NULL)
589         {
590                 char errbuf[1024];
591                 ERROR ("cpu plugin: fopen (/proc/stat) failed: %s",
592                                 sstrerror (errno, errbuf, sizeof (errbuf)));
593                 return (-1);
594         }
595
596         while (fgets (buf, 1024, fh) != NULL)
597         {
598                 derive_t derives[CPU_SUBMIT_MAX] = {
599                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
600                 };
601
602                 if (strncmp (buf, "cpu", 3))
603                         continue;
604                 if ((buf[3] < '0') || (buf[3] > '9'))
605                         continue;
606
607                 numfields = strsplit (buf, fields, 9);
608                 if (numfields < 5)
609                         continue;
610
611                 cpu = atoi (fields[0] + 3);
612                 derives[CPU_SUBMIT_USER] = atoll(fields[1]);
613                 derives[CPU_SUBMIT_NICE] = atoll(fields[2]);
614                 derives[CPU_SUBMIT_SYSTEM] = atoll(fields[3]);
615                 derives[CPU_SUBMIT_IDLE] = atoll(fields[4]);
616
617                 if (numfields >= 8)
618                 {
619                         derives[CPU_SUBMIT_WAIT] = atoll(fields[5]);
620                         derives[CPU_SUBMIT_INTERRUPT] = atoll(fields[6]);
621                         derives[CPU_SUBMIT_SOFTIRQ] = atoll(fields[6]);
622
623                         if (numfields >= 9)
624                                 derives[CPU_SUBMIT_STEAL] = atoll(fields[8]);
625                 }
626                 submit(cpu, derives);
627         }
628         submit_flush();
629
630         fclose (fh);
631 /* #endif defined(KERNEL_LINUX) */
632
633 #elif defined(HAVE_LIBKSTAT)
634         int cpu;
635         static cpu_stat_t cs;
636
637         if (kc == NULL)
638                 return (-1);
639
640         for (cpu = 0; cpu < numcpu; cpu++)
641         {
642                 derive_t derives[CPU_SUBMIT_MAX] = {
643                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
644                 };
645
646                 if (kstat_read (kc, ksp[cpu], &cs) == -1)
647                         continue; /* error message? */
648
649                 memset(derives, -1, sizeof(derives));
650                 derives[CPU_SUBMIT_IDLE] = cs.cpu_sysinfo.cpu[CPU_IDLE];
651                 derives[CPU_SUBMIT_USER] = cs.cpu_sysinfo.cpu[CPU_USER];
652                 derives[CPU_SUBMIT_SYSTEM] = cs.cpu_sysinfo.cpu[CPU_KERNEL];
653                 derives[CPU_SUBMIT_WAIT] = cs.cpu_sysinfo.cpu[CPU_WAIT];
654                 submit (ksp[cpu]->ks_instance, derives);
655         }
656         submit_flush ();
657 /* #endif defined(HAVE_LIBKSTAT) */
658
659 #elif CAN_USE_SYSCTL
660         uint64_t cpuinfo[numcpu][CPUSTATES];
661         size_t cpuinfo_size;
662         int status;
663         int i;
664
665         if (numcpu < 1)
666         {
667                 ERROR ("cpu plugin: Could not determine number of "
668                                 "installed CPUs using sysctl(3).");
669                 return (-1);
670         }
671
672         memset (cpuinfo, 0, sizeof (cpuinfo));
673
674 #if defined(KERN_CPTIME2)
675         if (numcpu > 1) {
676                 for (i = 0; i < numcpu; i++) {
677                         int mib[] = {CTL_KERN, KERN_CPTIME2, i};
678
679                         cpuinfo_size = sizeof (cpuinfo[0]);
680
681                         status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
682                                         cpuinfo[i], &cpuinfo_size, NULL, 0);
683                         if (status == -1) {
684                                 char errbuf[1024];
685                                 ERROR ("cpu plugin: sysctl failed: %s.",
686                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
687                                 return (-1);
688                         }
689                 }
690         }
691         else
692 #endif /* defined(KERN_CPTIME2) */
693         {
694                 int mib[] = {CTL_KERN, KERN_CPTIME};
695                 long cpuinfo_tmp[CPUSTATES];
696
697                 cpuinfo_size = sizeof(cpuinfo_tmp);
698
699                 status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
700                                         &cpuinfo_tmp, &cpuinfo_size, NULL, 0);
701                 if (status == -1)
702                 {
703                         char errbuf[1024];
704                         ERROR ("cpu plugin: sysctl failed: %s.",
705                                         sstrerror (errno, errbuf, sizeof (errbuf)));
706                         return (-1);
707                 }
708
709                 for(i = 0; i < CPUSTATES; i++) {
710                         cpuinfo[0][i] = cpuinfo_tmp[i];
711                 }
712         }
713
714         for (i = 0; i < numcpu; i++) {
715                 derive_t derives[CPU_SUBMIT_MAX] = {
716                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
717                 };
718
719                 derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
720                 derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
721                 derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
722                 derives[CPU_SUBMIT_IDLE] = cpuinfo[i][CP_IDLE];
723                 derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
724                 submit(i, derives);
725         }
726         submit_flush();
727 /* #endif CAN_USE_SYSCTL */
728 #elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES)
729         long cpuinfo[maxcpu][CPUSTATES];
730         size_t cpuinfo_size;
731         int i;
732
733         memset (cpuinfo, 0, sizeof (cpuinfo));
734
735         cpuinfo_size = sizeof (cpuinfo);
736         if (sysctlbyname("kern.cp_times", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
737         {
738                 char errbuf[1024];
739                 ERROR ("cpu plugin: sysctlbyname failed: %s.",
740                                 sstrerror (errno, errbuf, sizeof (errbuf)));
741                 return (-1);
742         }
743
744         for (i = 0; i < numcpu; i++) {
745                 derive_t derives[CPU_SUBMIT_MAX] = {
746                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
747                 };
748
749                 derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
750                 derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
751                 derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
752                 derives[CPU_SUBMIT_IDLE] = cpuinfo[i][CP_IDLE];
753                 derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
754                 submit(i, derives);
755         }
756         submit_flush();
757
758 /* #endif HAVE_SYSCTL_KERN_CP_TIMES */
759 #elif defined(HAVE_SYSCTLBYNAME)
760         long cpuinfo[CPUSTATES];
761         size_t cpuinfo_size;
762         derive_t derives[CPU_SUBMIT_MAX] = {
763                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
764         };
765
766         cpuinfo_size = sizeof (cpuinfo);
767
768         if (sysctlbyname("kern.cp_time", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
769         {
770                 char errbuf[1024];
771                 ERROR ("cpu plugin: sysctlbyname failed: %s.",
772                                 sstrerror (errno, errbuf, sizeof (errbuf)));
773                 return (-1);
774         }
775
776         derives[CPU_SUBMIT_USER] = cpuinfo[CP_USER];
777         derives[CPU_SUBMIT_SYSTEM] = cpuinfo[CP_SYS];
778         derives[CPU_SUBMIT_NICE] = cpuinfo[CP_NICE];
779         derives[CPU_SUBMIT_IDLE] = cpuinfo[CP_IDLE];
780         derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[CP_INTR];
781         submit(0, derives);
782         submit_flush();
783
784 /* #endif HAVE_SYSCTLBYNAME */
785
786 #elif defined(HAVE_LIBSTATGRAB)
787         sg_cpu_stats *cs;
788         derive_t derives[CPU_SUBMIT_MAX] = {
789                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
790         };
791         cs = sg_get_cpu_stats ();
792
793         if (cs == NULL)
794         {
795                 ERROR ("cpu plugin: sg_get_cpu_stats failed.");
796                 return (-1);
797         }
798
799         derives[CPU_SUBMIT_IDLE] = (derive_t) cs->idle;
800         derives[CPU_SUBMIT_NICE] = (derive_t) cs->nice;
801         derives[CPU_SUBMIT_SWAP] = (derive_t) cs->swap;
802         derives[CPU_SUBMIT_SYSTEM] = (derive_t) cs->kernel;
803         derives[CPU_SUBMIT_USER] = (derive_t) cs->user;
804         derives[CPU_SUBMIT_WAIT] = (derive_t) cs->iowait;
805         submit(0, derives);
806         submit_flush();
807 /* #endif HAVE_LIBSTATGRAB */
808
809 #elif defined(HAVE_PERFSTAT)
810         perfstat_id_t id;
811         int i, cpus;
812
813         numcpu =  perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
814         if(numcpu == -1)
815         {
816                 char errbuf[1024];
817                 WARNING ("cpu plugin: perfstat_cpu: %s",
818                         sstrerror (errno, errbuf, sizeof (errbuf)));
819                 return (-1);
820         }
821
822         if (pnumcpu != numcpu || perfcpu == NULL)
823         {
824                 if (perfcpu != NULL)
825                         free(perfcpu);
826                 perfcpu = malloc(numcpu * sizeof(perfstat_cpu_t));
827         }
828         pnumcpu = numcpu;
829
830         id.name[0] = '\0';
831         if ((cpus = perfstat_cpu(&id, perfcpu, sizeof(perfstat_cpu_t), numcpu)) < 0)
832         {
833                 char errbuf[1024];
834                 WARNING ("cpu plugin: perfstat_cpu: %s",
835                         sstrerror (errno, errbuf, sizeof (errbuf)));
836                 return (-1);
837         }
838
839         for (i = 0; i < cpus; i++)
840         {
841                 derive_t derives[CPU_SUBMIT_MAX] = {
842                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
843                 };
844                 derives[CPU_SUBMIT_IDLE] = perfcpu[i].idle;
845                 derives[CPU_SUBMIT_SYSTEM] = perfcpu[i].sys;
846                 derives[CPU_SUBMIT_USER] = perfcpu[i].user;
847                 derives[CPU_SUBMIT_WAIT] = perfcpu[i].wait;
848                 submit(i, derives);
849         }
850         submit_flush();
851 #endif /* HAVE_PERFSTAT */
852
853         return (0);
854 }
855
856 void module_register (void)
857 {
858         plugin_register_init ("cpu", init);
859         plugin_register_config ("cpu", cpu_config, config_keys, config_keys_num);
860         plugin_register_read ("cpu", cpu_read);
861 } /* void module_register */