typo fixes.
[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 (strcasecmp (key, "ReportActive") == 0)
205                 report_active = IS_TRUE (value) ? 1 : 0;
206         return (-1);
207 }
208
209 static int cpu_states_grow (void)
210 {
211   void *tmp;
212   int size;
213   int i;
214
215   size = cpu_count * CPU_SUBMIT_MAX; /* always alloc for all states */
216
217   if (size <= 0)
218           return 0;
219
220   if (percents_cells >= size)
221           return 0;
222
223   if (percents == NULL) {
224           percents = malloc(size * sizeof(*percents));
225           if (percents == NULL)
226                   return -1;
227           for (i = 0; i < size; i++)
228                   memset(&percents[i], 0, sizeof(*percents));
229           percents_cells = size;
230           return 0;
231   }
232
233   tmp = realloc(percents, size * sizeof(*percents));
234
235   if (tmp == NULL) {
236           ERROR ("cpu plugin: could not reserve enough space to hold states");
237           percents = NULL;
238           return -1;
239   }
240
241   for (i = percents_cells; i < size; i++)
242           memset(&percents[i], 0, sizeof(*percents));
243
244   percents = tmp;
245   percents_cells = size;
246   return 0;
247 } /* cpu_states_grow */
248
249
250 static int init (void)
251 {
252 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
253         kern_return_t status;
254
255         port_host = mach_host_self ();
256
257         /* FIXME: Free `cpu_list' if it's not NULL */
258         if ((status = host_processors (port_host, &cpu_list, &cpu_list_len)) != KERN_SUCCESS)
259         {
260                 ERROR ("cpu plugin: host_processors returned %i", (int) status);
261                 cpu_list_len = 0;
262                 return (-1);
263         }
264
265         DEBUG ("host_processors returned %i %s", (int) cpu_list_len, cpu_list_len == 1 ? "processor" : "processors");
266         INFO ("cpu plugin: Found %i processor%s.", (int) cpu_list_len, cpu_list_len == 1 ? "" : "s");
267
268         cpu_temp_retry_max = 86400 / CDTIME_T_TO_TIME_T (plugin_get_interval ());
269 /* #endif PROCESSOR_CPU_LOAD_INFO */
270
271 #elif defined(HAVE_LIBKSTAT)
272         kstat_t *ksp_chain;
273
274         numcpu = 0;
275
276         if (kc == NULL)
277                 return (-1);
278
279         /* Solaris doesn't count linear.. *sigh* */
280         for (numcpu = 0, ksp_chain = kc->kc_chain;
281                         (numcpu < MAX_NUMCPU) && (ksp_chain != NULL);
282                         ksp_chain = ksp_chain->ks_next)
283                 if (strncmp (ksp_chain->ks_module, "cpu_stat", 8) == 0)
284                         ksp[numcpu++] = ksp_chain;
285 /* #endif HAVE_LIBKSTAT */
286
287 #elif CAN_USE_SYSCTL
288         size_t numcpu_size;
289         int mib[2] = {CTL_HW, HW_NCPU};
290         int status;
291
292         numcpu = 0;
293         numcpu_size = sizeof (numcpu);
294
295         status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
296                         &numcpu, &numcpu_size, NULL, 0);
297         if (status == -1)
298         {
299                 char errbuf[1024];
300                 WARNING ("cpu plugin: sysctl: %s",
301                                 sstrerror (errno, errbuf, sizeof (errbuf)));
302                 return (-1);
303         }
304 /* #endif CAN_USE_SYSCTL */
305
306 #elif defined (HAVE_SYSCTLBYNAME)
307         size_t numcpu_size;
308
309         numcpu_size = sizeof (numcpu);
310
311         if (sysctlbyname ("hw.ncpu", &numcpu, &numcpu_size, NULL, 0) < 0)
312         {
313                 char errbuf[1024];
314                 WARNING ("cpu plugin: sysctlbyname(hw.ncpu): %s",
315                                 sstrerror (errno, errbuf, sizeof (errbuf)));
316                 return (-1);
317         }
318
319 #ifdef HAVE_SYSCTL_KERN_CP_TIMES
320         numcpu_size = sizeof (maxcpu);
321
322         if (sysctlbyname("kern.smp.maxcpus", &maxcpu, &numcpu_size, NULL, 0) < 0)
323         {
324                 char errbuf[1024];
325                 WARNING ("cpu plugin: sysctlbyname(kern.smp.maxcpus): %s",
326                                 sstrerror (errno, errbuf, sizeof (errbuf)));
327                 return (-1);
328         }
329 #else
330         if (numcpu != 1)
331                 NOTICE ("cpu: Only one processor supported when using `sysctlbyname' (found %i)", numcpu);
332 #endif
333 /* #endif HAVE_SYSCTLBYNAME */
334
335 #elif defined(HAVE_LIBSTATGRAB)
336         /* nothing to initialize */
337 /* #endif HAVE_LIBSTATGRAB */
338
339 #elif defined(HAVE_PERFSTAT)
340         /* nothing to initialize */
341 #endif /* HAVE_PERFSTAT */
342
343         return (0);
344 } /* int init */
345
346 static void submit_value (int cpu_num, int cpu_state, const char *type, value_t value)
347 {
348         value_t values[1];
349         value_list_t vl = VALUE_LIST_INIT;
350
351         memcpy(&values[0], &value, sizeof(value));
352
353         vl.values = values;
354         vl.values_len = 1;
355
356         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
357         sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
358         sstrncpy (vl.type, type, sizeof (vl.type));
359         sstrncpy (vl.type_instance, cpu_state_names[cpu_state],
360                   sizeof (vl.type_instance));
361
362         if (cpu_num >= 0) {
363                 ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
364                            "%i", cpu_num);
365         }
366         plugin_dispatch_values (&vl);
367 }
368
369 static void submit_percent(int cpu_num, int cpu_state, gauge_t percent)
370 {
371         value_t value;
372
373         value.gauge = percent;
374         submit_value (cpu_num, cpu_state, "percent", value);
375 }
376
377 static void submit_derive(int cpu_num, int cpu_state, derive_t derive)
378 {
379         value_t value;
380
381         value.derive = derive;
382         submit_value (cpu_num, cpu_state, "cpu", value);
383 }
384
385 static void submit_flush (void)
386 {
387         int i = 0;
388
389         if (report_by_cpu) {
390                 cpu_count = 0;
391                 return;
392         }
393
394         for (i = 0; i < CPU_SUBMIT_MAX; i++) {
395                 if (agg_percents[i] == -1)
396                         continue;
397
398                 submit_percent(-1, i, agg_percents[i] / cpu_count);
399                 agg_percents[i] = -1;
400         }
401         cpu_count = 0;
402 }
403
404 static void submit (int cpu_num, derive_t *derives)
405 {
406
407         int i = 0;
408
409         if (!report_percent && report_by_cpu) {
410                 derive_t cpu_active = 0;
411                 for (i = 0; i < CPU_SUBMIT_ACTIVE; i++)
412                 {
413                         if (derives[i] == -1)
414                                 continue;
415
416                         if (i != CPU_SUBMIT_IDLE)
417                                 cpu_active += derives[i];
418
419                         submit_derive(cpu_num, i, derives[i]);
420                 }
421                 if (report_active)
422                         submit_derive(cpu_num, CPU_SUBMIT_ACTIVE, cpu_active);
423         }
424         else /* we are reporting percents */
425         {
426                 cdtime_t cdt;
427                 gauge_t percent;
428                 gauge_t cpu_total = 0;
429                 gauge_t cpu_active = 0;
430                 gauge_t local_rates[CPU_SUBMIT_MAX];
431
432                 cpu_count++;
433                 if (cpu_states_grow())
434                         return;
435
436                 memset(local_rates, 0, sizeof(local_rates));
437
438                 cdt = cdtime();
439                 for (i = 0; i < CPU_SUBMIT_ACTIVE; i++) {
440                         value_t rate;
441                         int index;
442
443                         if (derives[i] == -1)
444                                 continue;
445
446                         index = (cpu_num * CPU_SUBMIT_MAX) + i;
447                         if (value_to_rate(&rate, derives[i], &percents[index],
448                                           DS_TYPE_DERIVE, cdt) != 0) {
449                                 local_rates[i] = -1;
450                                 continue;
451                         }
452
453                         local_rates[i] = rate.gauge;
454                         cpu_total += rate.gauge;
455                         if (i != CPU_SUBMIT_IDLE)
456                                 cpu_active += rate.gauge;
457                 }
458                 if (cpu_total == 0.0)
459                         return;
460
461                 if (report_active)
462                         local_rates[CPU_SUBMIT_ACTIVE] = cpu_active;
463
464                 for (i = 0; i < CPU_SUBMIT_MAX; i++) {
465                         if (local_rates[i] == -1)
466                                 continue;
467
468                         percent = (local_rates[i] / cpu_total) * 100;
469                         if (report_by_cpu)
470                                 submit_percent (cpu_num, i, percent);
471                         else {
472                                 if (agg_percents[i] == -1)
473                                         agg_percents[i] = percent;
474                                 else
475                                         agg_percents[i] += percent;
476                         }
477
478                 }
479         }
480 }
481
482 static int cpu_read (void)
483 {
484 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
485         int cpu;
486
487         kern_return_t status;
488
489 #if PROCESSOR_CPU_LOAD_INFO
490         processor_cpu_load_info_data_t cpu_info;
491         mach_msg_type_number_t         cpu_info_len;
492 #endif
493 #if PROCESSOR_TEMPERATURE
494         processor_info_data_t          cpu_temp;
495         mach_msg_type_number_t         cpu_temp_len;
496 #endif
497
498         host_t cpu_host;
499
500         for (cpu = 0; cpu < cpu_list_len; cpu++)
501         {
502 #if PROCESSOR_CPU_LOAD_INFO
503                 derive_t derives[CPU_SUBMIT_MAX] = {
504                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
505                 };
506                 memset(derives, -1, sizeof(derives));
507                 cpu_host = 0;
508                 cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
509
510                 if ((status = processor_info (cpu_list[cpu],
511                                                 PROCESSOR_CPU_LOAD_INFO, &cpu_host,
512                                                 (processor_info_t) &cpu_info, &cpu_info_len)) != KERN_SUCCESS)
513                 {
514                         ERROR ("cpu plugin: processor_info failed with status %i", (int) status);
515                         continue;
516                 }
517
518                 if (cpu_info_len < CPU_STATE_MAX)
519                 {
520                         ERROR ("cpu plugin: processor_info returned only %i elements..", cpu_info_len);
521                         continue;
522                 }
523
524                 derives[CPU_SUBMIT_USER] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_USER];
525                 derives[CPU_SUBMIT_NICE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE];
526                 derives[CPU_SUBMIT_SYSTEM] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM];
527                 derives[CPU_SUBMIT_IDLE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE];
528                 submit (cpu, derives);
529
530 #endif /* PROCESSOR_CPU_LOAD_INFO */
531 #if PROCESSOR_TEMPERATURE
532                 /*
533                  * Not all Apple computers do have this ability. To minimize
534                  * the messages sent to the syslog we do an exponential
535                  * stepback if `processor_info' fails. We still try ~once a day
536                  * though..
537                  */
538                 if (cpu_temp_retry_counter > 0)
539                 {
540                         cpu_temp_retry_counter--;
541                         continue;
542                 }
543
544                 cpu_temp_len = PROCESSOR_INFO_MAX;
545
546                 status = processor_info (cpu_list[cpu],
547                                 PROCESSOR_TEMPERATURE,
548                                 &cpu_host,
549                                 cpu_temp, &cpu_temp_len);
550                 if (status != KERN_SUCCESS)
551                 {
552                         ERROR ("cpu plugin: processor_info failed: %s",
553                                         mach_error_string (status));
554
555                         cpu_temp_retry_counter = cpu_temp_retry_step;
556                         cpu_temp_retry_step *= 2;
557                         if (cpu_temp_retry_step > cpu_temp_retry_max)
558                                 cpu_temp_retry_step = cpu_temp_retry_max;
559
560                         continue;
561                 }
562
563                 if (cpu_temp_len != 1)
564                 {
565                         DEBUG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
566                                         (int) cpu_temp_len);
567                         continue;
568                 }
569
570                 cpu_temp_retry_counter = 0;
571                 cpu_temp_retry_step    = 1;
572 #endif /* PROCESSOR_TEMPERATURE */
573         }
574         submit_flush ();
575 /* #endif PROCESSOR_CPU_LOAD_INFO */
576
577 #elif defined(KERNEL_LINUX)
578         int cpu;
579         FILE *fh;
580         char buf[1024];
581
582         char *fields[9];
583         int numfields;
584
585         if ((fh = fopen ("/proc/stat", "r")) == NULL)
586         {
587                 char errbuf[1024];
588                 ERROR ("cpu plugin: fopen (/proc/stat) failed: %s",
589                                 sstrerror (errno, errbuf, sizeof (errbuf)));
590                 return (-1);
591         }
592
593         while (fgets (buf, 1024, fh) != NULL)
594         {
595                 derive_t derives[CPU_SUBMIT_MAX] = {
596                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
597                 };
598
599                 if (strncmp (buf, "cpu", 3))
600                         continue;
601                 if ((buf[3] < '0') || (buf[3] > '9'))
602                         continue;
603
604                 numfields = strsplit (buf, fields, 9);
605                 if (numfields < 5)
606                         continue;
607
608                 cpu = atoi (fields[0] + 3);
609                 derives[CPU_SUBMIT_USER] = atoll(fields[1]);
610                 derives[CPU_SUBMIT_NICE] = atoll(fields[2]);
611                 derives[CPU_SUBMIT_SYSTEM] = atoll(fields[3]);
612                 derives[CPU_SUBMIT_IDLE] = atoll(fields[4]);
613
614                 if (numfields >= 8)
615                 {
616                         derives[CPU_SUBMIT_WAIT] = atoll(fields[5]);
617                         derives[CPU_SUBMIT_INTERRUPT] = atoll(fields[6]);
618                         derives[CPU_SUBMIT_SOFTIRQ] = atoll(fields[6]);
619
620                         if (numfields >= 9)
621                                 derives[CPU_SUBMIT_STEAL] = atoll(fields[8]);
622                 }
623                 submit(cpu, derives);
624         }
625         submit_flush();
626
627         fclose (fh);
628 /* #endif defined(KERNEL_LINUX) */
629
630 #elif defined(HAVE_LIBKSTAT)
631         int cpu;
632         static cpu_stat_t cs;
633
634         if (kc == NULL)
635                 return (-1);
636
637         for (cpu = 0; cpu < numcpu; cpu++)
638         {
639                 derive_t derives[CPU_SUBMIT_MAX] = {
640                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
641                 };
642
643                 if (kstat_read (kc, ksp[cpu], &cs) == -1)
644                         continue; /* error message? */
645
646                 memset(derives, -1, sizeof(derives));
647                 derives[CPU_SUBMIT_IDLE] = cs.cpu_sysinfo.cpu[CPU_IDLE];
648                 derives[CPU_SUBMIT_USER] = cs.cpu_sysinfo.cpu[CPU_USER];
649                 derives[CPU_SUBMIT_SYSTEM] = cs.cpu_sysinfo.cpu[CPU_KERNEL];
650                 derives[CPU_SUBMIT_WAIT] = cs.cpu_sysinfo.cpu[CPU_WAIT];
651                 submit (ksp[cpu]->ks_instance, derives);
652         }
653         submit_flush ();
654 /* #endif defined(HAVE_LIBKSTAT) */
655
656 #elif CAN_USE_SYSCTL
657         uint64_t cpuinfo[numcpu][CPUSTATES];
658         size_t cpuinfo_size;
659         int status;
660         int i;
661
662         if (numcpu < 1)
663         {
664                 ERROR ("cpu plugin: Could not determine number of "
665                                 "installed CPUs using sysctl(3).");
666                 return (-1);
667         }
668
669         memset (cpuinfo, 0, sizeof (cpuinfo));
670
671 #if defined(KERN_CPTIME2)
672         if (numcpu > 1) {
673                 for (i = 0; i < numcpu; i++) {
674                         int mib[] = {CTL_KERN, KERN_CPTIME2, i};
675
676                         cpuinfo_size = sizeof (cpuinfo[0]);
677
678                         status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
679                                         cpuinfo[i], &cpuinfo_size, NULL, 0);
680                         if (status == -1) {
681                                 char errbuf[1024];
682                                 ERROR ("cpu plugin: sysctl failed: %s.",
683                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
684                                 return (-1);
685                         }
686                 }
687         }
688         else
689 #endif /* defined(KERN_CPTIME2) */
690         {
691                 int mib[] = {CTL_KERN, KERN_CPTIME};
692                 long cpuinfo_tmp[CPUSTATES];
693
694                 cpuinfo_size = sizeof(cpuinfo_tmp);
695
696                 status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
697                                         &cpuinfo_tmp, &cpuinfo_size, NULL, 0);
698                 if (status == -1)
699                 {
700                         char errbuf[1024];
701                         ERROR ("cpu plugin: sysctl failed: %s.",
702                                         sstrerror (errno, errbuf, sizeof (errbuf)));
703                         return (-1);
704                 }
705
706                 for(i = 0; i < CPUSTATES; i++) {
707                         cpuinfo[0][i] = cpuinfo_tmp[i];
708                 }
709         }
710
711         for (i = 0; i < numcpu; i++) {
712                 derive_t derives[CPU_SUBMIT_MAX] = {
713                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
714                 };
715
716                 derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
717                 derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
718                 derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
719                 derives[CPU_SUBMIT_IDLE] = cpuinfo[i][CP_IDLE];
720                 derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
721                 submit(i, derives);
722         }
723         submit_flush();
724 /* #endif CAN_USE_SYSCTL */
725 #elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES)
726         long cpuinfo[maxcpu][CPUSTATES];
727         size_t cpuinfo_size;
728         int i;
729
730         memset (cpuinfo, 0, sizeof (cpuinfo));
731
732         cpuinfo_size = sizeof (cpuinfo);
733         if (sysctlbyname("kern.cp_times", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
734         {
735                 char errbuf[1024];
736                 ERROR ("cpu plugin: sysctlbyname failed: %s.",
737                                 sstrerror (errno, errbuf, sizeof (errbuf)));
738                 return (-1);
739         }
740
741         for (i = 0; i < numcpu; i++) {
742                 derive_t derives[CPU_SUBMIT_MAX] = {
743                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
744                 };
745
746                 derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
747                 derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
748                 derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
749                 derives[CPU_SUBMIT_IDLE] = cpuinfo[i][CP_IDLE];
750                 derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
751                 submit(i, derives);
752         }
753         submit_flush();
754
755 /* #endif HAVE_SYSCTL_KERN_CP_TIMES */
756 #elif defined(HAVE_SYSCTLBYNAME)
757         long cpuinfo[CPUSTATES];
758         size_t cpuinfo_size;
759         derive_t derives[CPU_SUBMIT_MAX] = {
760                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
761         };
762
763         cpuinfo_size = sizeof (cpuinfo);
764
765         if (sysctlbyname("kern.cp_time", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
766         {
767                 char errbuf[1024];
768                 ERROR ("cpu plugin: sysctlbyname failed: %s.",
769                                 sstrerror (errno, errbuf, sizeof (errbuf)));
770                 return (-1);
771         }
772
773         derives[CPU_SUBMIT_USER] = cpuinfo[CP_USER];
774         derives[CPU_SUBMIT_SYSTEM] = cpuinfo[CP_SYS];
775         derives[CPU_SUBMIT_NICE] = cpuinfo[CP_NICE];
776         derives[CPU_SUBMIT_IDLE] = cpuinfo[CP_IDLE];
777         derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[CP_INTR];
778         submit(0, derives);
779         submit_flush();
780
781 /* #endif HAVE_SYSCTLBYNAME */
782
783 #elif defined(HAVE_LIBSTATGRAB)
784         sg_cpu_stats *cs;
785         derive_t derives[CPU_SUBMIT_MAX] = {
786                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
787         };
788         cs = sg_get_cpu_stats ();
789
790         if (cs == NULL)
791         {
792                 ERROR ("cpu plugin: sg_get_cpu_stats failed.");
793                 return (-1);
794         }
795
796         derives[CPU_SUBMIT_IDLE] = (derive_t) cs->idle;
797         derives[CPU_SUBMIT_NICE] = (derive_t) cs->nice;
798         derives[CPU_SUBMIT_SWAP] = (derive_t) cs->swap;
799         derives[CPU_SUBMIT_SYSTEM] = (derive_t) cs->kernel;
800         derives[CPU_SUBMIT_USER] = (derive_t) cs->user;
801         derives[CPU_SUBMIT_WAIT] = (derive_t) cs->iowait;
802         submit(0, derives);
803         submit_flush();
804 /* #endif HAVE_LIBSTATGRAB */
805
806 #elif defined(HAVE_PERFSTAT)
807         perfstat_id_t id;
808         int i, cpus;
809
810         numcpu =  perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
811         if(numcpu == -1)
812         {
813                 char errbuf[1024];
814                 WARNING ("cpu plugin: perfstat_cpu: %s",
815                         sstrerror (errno, errbuf, sizeof (errbuf)));
816                 return (-1);
817         }
818
819         if (pnumcpu != numcpu || perfcpu == NULL)
820         {
821                 if (perfcpu != NULL)
822                         free(perfcpu);
823                 perfcpu = malloc(numcpu * sizeof(perfstat_cpu_t));
824         }
825         pnumcpu = numcpu;
826
827         id.name[0] = '\0';
828         if ((cpus = perfstat_cpu(&id, perfcpu, sizeof(perfstat_cpu_t), numcpu)) < 0)
829         {
830                 char errbuf[1024];
831                 WARNING ("cpu plugin: perfstat_cpu: %s",
832                         sstrerror (errno, errbuf, sizeof (errbuf)));
833                 return (-1);
834         }
835
836         for (i = 0; i < cpus; i++)
837         {
838                 derive_t derives[CPU_SUBMIT_MAX] = {
839                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
840                 };
841                 derives[CPU_SUBMIT_IDLE] = perfcpu[i].idle;
842                 derives[CPU_SUBMIT_SYSTEM] = perfcpu[i].sys;
843                 derives[CPU_SUBMIT_USER] = perfcpu[i].user;
844                 derives[CPU_SUBMIT_WAIT] = perfcpu[i].wait;
845                 submit(i, derives);
846         }
847         submit_flush();
848 #endif /* HAVE_PERFSTAT */
849
850         return (0);
851 }
852
853 void module_register (void)
854 {
855         plugin_register_init ("cpu", init);
856         plugin_register_config ("cpu", cpu_config, config_keys, config_keys_num);
857         plugin_register_read ("cpu", cpu_read);
858 } /* void module_register */