Merge pull request #3339 from jkohen/patch-1
[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 collectd.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 *values = NULL;
174 static gauge_t agg_values[CPU_SUBMIT_MAX] = {
175         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
176
177 };
178 static int cpu_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         }
200         if (strcasecmp (key, "ValuesPercentage") == 0) {
201                 report_percent = IS_TRUE (value) ? 1 : 0;
202         }
203         if (strcasecmp (key, "ReportActive") == 0)
204                 report_active = IS_TRUE (value) ? 1 : 0;
205         return (-1);
206 }
207
208 static int cpu_states_grow (void)
209 {
210   void *tmp;
211   int size;
212   int i;
213
214   size = cpu_count * CPU_SUBMIT_MAX; /* always alloc for all states */
215
216   if (size <= 0)
217           return 0;
218
219   if (cpu_cells >= size)
220           return 0;
221
222   if (values == NULL) {
223           values = malloc(size * sizeof(*values));
224           if (values == NULL)
225                   return -1;
226           for (i = 0; i < size; i++)
227                   memset(&values[i], 0, sizeof(*values));
228           cpu_cells = size;
229           return 0;
230   }
231
232   tmp = realloc(values, size * sizeof(*values));
233
234   if (tmp == NULL) {
235           ERROR ("cpu plugin: could not reserve enough space to hold states");
236           values = NULL;
237           return -1;
238   }
239
240   values = tmp;
241
242   for (i = cpu_cells ; i < size; i++)
243           memset(&values[i], 0, sizeof(*values));
244
245   cpu_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         int cpu_submit_max = CPU_SUBMIT_MAX;
389
390         if (report_by_cpu) {
391                 cpu_count = 0;
392                 return;
393         }
394
395         if (report_active)
396                 cpu_submit_max = CPU_SUBMIT_MAX;
397         else
398                 cpu_submit_max = CPU_SUBMIT_ACTIVE;
399         for (i = 0; i < cpu_submit_max; i++) {
400                 if (agg_values[i] == -1)
401                         continue;
402
403                 if (report_percent)
404                         submit_percent(-1, i, agg_values[i] / cpu_count);
405                 else
406                         submit_derive(-1, i, agg_values[i]);
407                 agg_values[i] = -1;
408         }
409         cpu_count = 0;
410 }
411
412 static void submit (int cpu_num, derive_t *derives)
413 {
414
415         int i = 0;
416         int cpu_submit_max = CPU_SUBMIT_MAX;
417
418         if (report_active)
419                 cpu_submit_max = CPU_SUBMIT_MAX;
420         else
421                 cpu_submit_max = CPU_SUBMIT_ACTIVE;
422
423         if (!report_percent && report_by_cpu) {
424                 derive_t cpu_active = 0;
425                 for (i = 0; i < CPU_SUBMIT_ACTIVE; i++)
426                 {
427                         if (derives[i] == -1)
428                                 continue;
429
430                         if (i != CPU_SUBMIT_IDLE)
431                                 cpu_active += derives[i];
432
433                         submit_derive(cpu_num, i, derives[i]);
434                 }
435                 if (report_active)
436                         submit_derive(cpu_num, CPU_SUBMIT_ACTIVE, cpu_active);
437         }
438         else {
439                 cdtime_t cdt;
440                 gauge_t value;
441                 gauge_t cpu_total = 0;
442                 gauge_t cpu_active = 0;
443                 gauge_t local_rates[CPU_SUBMIT_MAX];
444
445                 cpu_count++;
446                 if (cpu_states_grow())
447                         return;
448
449                 memset(local_rates, 0, sizeof(local_rates));
450
451                 cdt = cdtime();
452                 for (i = 0; i < CPU_SUBMIT_ACTIVE; i++) {
453                         if (report_percent) {
454                                 value_t rate;
455                                 int index;
456
457                                 if (derives[i] == -1)
458                                         continue;
459
460                                 index = (cpu_num * CPU_SUBMIT_MAX) + i;
461                                 if (value_to_rate(&rate, derives[i], &values[index],
462                                                         DS_TYPE_DERIVE, cdt) != 0) {
463                                         local_rates[i] = -1;
464                                         continue;
465                                 }
466
467                                 local_rates[i] = rate.gauge;
468                                 cpu_total += rate.gauge;
469                                 if (i != CPU_SUBMIT_IDLE)
470                                         cpu_active += rate.gauge;
471                         }
472                         else {
473                                 cpu_total += derives[i];
474                                 if (i != CPU_SUBMIT_IDLE)
475                                         cpu_active += derives[i];
476                         }
477                 }
478                 if (cpu_total == 0.0)
479                         return;
480
481                 if (report_active)
482                         local_rates[CPU_SUBMIT_ACTIVE] = cpu_active;
483
484                 for (i = 0; i < cpu_submit_max; i++) {
485                         if (local_rates[i] == -1)
486                                 continue;
487
488                         if (report_percent)
489                                 value = (local_rates[i] / cpu_total) * 100;
490                         else
491                                 value = derives[i];
492                         if (report_by_cpu) {
493                                 if (report_percent) {
494                                         submit_percent (cpu_num, i, value);
495                                 } else {
496                                         submit_derive(cpu_num, i, value);
497                                 }
498                         }
499                         else {
500                                 if (agg_values[i] == -1)
501                                         agg_values[i] = value;
502                                 else
503                                         agg_values[i] += value;
504                         }
505                 }
506         }
507 }
508
509 static int cpu_read (void)
510 {
511 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
512         int cpu;
513
514         kern_return_t status;
515
516 #if PROCESSOR_CPU_LOAD_INFO
517         processor_cpu_load_info_data_t cpu_info;
518         mach_msg_type_number_t         cpu_info_len;
519 #endif
520 #if PROCESSOR_TEMPERATURE
521         processor_info_data_t          cpu_temp;
522         mach_msg_type_number_t         cpu_temp_len;
523 #endif
524
525         host_t cpu_host;
526
527         for (cpu = 0; cpu < cpu_list_len; cpu++)
528         {
529 #if PROCESSOR_CPU_LOAD_INFO
530                 derive_t derives[CPU_SUBMIT_MAX] = {
531                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
532                 };
533                 memset(derives, -1, sizeof(derives));
534                 cpu_host = 0;
535                 cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
536
537                 if ((status = processor_info (cpu_list[cpu],
538                                                 PROCESSOR_CPU_LOAD_INFO, &cpu_host,
539                                                 (processor_info_t) &cpu_info, &cpu_info_len)) != KERN_SUCCESS)
540                 {
541                         ERROR ("cpu plugin: processor_info failed with status %i", (int) status);
542                         continue;
543                 }
544
545                 if (cpu_info_len < CPU_STATE_MAX)
546                 {
547                         ERROR ("cpu plugin: processor_info returned only %i elements..", cpu_info_len);
548                         continue;
549                 }
550
551                 derives[CPU_SUBMIT_USER] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_USER];
552                 derives[CPU_SUBMIT_NICE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE];
553                 derives[CPU_SUBMIT_SYSTEM] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM];
554                 derives[CPU_SUBMIT_IDLE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE];
555                 submit (cpu, derives);
556
557 #endif /* PROCESSOR_CPU_LOAD_INFO */
558 #if PROCESSOR_TEMPERATURE
559                 /*
560                  * Not all Apple computers do have this ability. To minimize
561                  * the messages sent to the syslog we do an exponential
562                  * stepback if `processor_info' fails. We still try ~once a day
563                  * though..
564                  */
565                 if (cpu_temp_retry_counter > 0)
566                 {
567                         cpu_temp_retry_counter--;
568                         continue;
569                 }
570
571                 cpu_temp_len = PROCESSOR_INFO_MAX;
572
573                 status = processor_info (cpu_list[cpu],
574                                 PROCESSOR_TEMPERATURE,
575                                 &cpu_host,
576                                 cpu_temp, &cpu_temp_len);
577                 if (status != KERN_SUCCESS)
578                 {
579                         ERROR ("cpu plugin: processor_info failed: %s",
580                                         mach_error_string (status));
581
582                         cpu_temp_retry_counter = cpu_temp_retry_step;
583                         cpu_temp_retry_step *= 2;
584                         if (cpu_temp_retry_step > cpu_temp_retry_max)
585                                 cpu_temp_retry_step = cpu_temp_retry_max;
586
587                         continue;
588                 }
589
590                 if (cpu_temp_len != 1)
591                 {
592                         DEBUG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
593                                         (int) cpu_temp_len);
594                         continue;
595                 }
596
597                 cpu_temp_retry_counter = 0;
598                 cpu_temp_retry_step    = 1;
599 #endif /* PROCESSOR_TEMPERATURE */
600         }
601         submit_flush ();
602 /* #endif PROCESSOR_CPU_LOAD_INFO */
603
604 #elif defined(KERNEL_LINUX)
605         int cpu;
606         FILE *fh;
607         char buf[1024];
608
609         char *fields[9];
610         int numfields;
611
612         if ((fh = fopen ("/proc/stat", "r")) == NULL)
613         {
614                 char errbuf[1024];
615                 ERROR ("cpu plugin: fopen (/proc/stat) failed: %s",
616                                 sstrerror (errno, errbuf, sizeof (errbuf)));
617                 return (-1);
618         }
619
620         while (fgets (buf, 1024, fh) != NULL)
621         {
622                 derive_t derives[CPU_SUBMIT_MAX] = {
623                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
624                 };
625
626                 if (strncmp (buf, "cpu", 3))
627                         continue;
628                 if ((buf[3] < '0') || (buf[3] > '9'))
629                         continue;
630
631                 numfields = strsplit (buf, fields, 9);
632                 if (numfields < 5)
633                         continue;
634
635                 cpu = atoi (fields[0] + 3);
636                 derives[CPU_SUBMIT_USER] = atoll(fields[1]);
637                 derives[CPU_SUBMIT_NICE] = atoll(fields[2]);
638                 derives[CPU_SUBMIT_SYSTEM] = atoll(fields[3]);
639                 derives[CPU_SUBMIT_IDLE] = atoll(fields[4]);
640
641                 if (numfields >= 8)
642                 {
643                         derives[CPU_SUBMIT_WAIT] = atoll(fields[5]);
644                         derives[CPU_SUBMIT_INTERRUPT] = atoll(fields[6]);
645                         derives[CPU_SUBMIT_SOFTIRQ] = atoll(fields[6]);
646
647                         if (numfields >= 9)
648                                 derives[CPU_SUBMIT_STEAL] = atoll(fields[8]);
649                 }
650                 submit(cpu, derives);
651         }
652         submit_flush();
653
654         fclose (fh);
655 /* #endif defined(KERNEL_LINUX) */
656
657 #elif defined(HAVE_LIBKSTAT)
658         int cpu;
659         static cpu_stat_t cs;
660
661         if (kc == NULL)
662                 return (-1);
663
664         for (cpu = 0; cpu < numcpu; cpu++)
665         {
666                 derive_t derives[CPU_SUBMIT_MAX] = {
667                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
668                 };
669
670                 if (kstat_read (kc, ksp[cpu], &cs) == -1)
671                         continue; /* error message? */
672
673                 memset(derives, -1, sizeof(derives));
674                 derives[CPU_SUBMIT_IDLE] = cs.cpu_sysinfo.cpu[CPU_IDLE];
675                 derives[CPU_SUBMIT_USER] = cs.cpu_sysinfo.cpu[CPU_USER];
676                 derives[CPU_SUBMIT_SYSTEM] = cs.cpu_sysinfo.cpu[CPU_KERNEL];
677                 derives[CPU_SUBMIT_WAIT] = cs.cpu_sysinfo.cpu[CPU_WAIT];
678                 submit (ksp[cpu]->ks_instance, derives);
679         }
680         submit_flush ();
681 /* #endif defined(HAVE_LIBKSTAT) */
682
683 #elif CAN_USE_SYSCTL
684         uint64_t cpuinfo[numcpu][CPUSTATES];
685         size_t cpuinfo_size;
686         int status;
687         int i;
688
689         if (numcpu < 1)
690         {
691                 ERROR ("cpu plugin: Could not determine number of "
692                                 "installed CPUs using sysctl(3).");
693                 return (-1);
694         }
695
696         memset (cpuinfo, 0, sizeof (cpuinfo));
697
698 #if defined(KERN_CPTIME2)
699         if (numcpu > 1) {
700                 for (i = 0; i < numcpu; i++) {
701                         int mib[] = {CTL_KERN, KERN_CPTIME2, i};
702
703                         cpuinfo_size = sizeof (cpuinfo[0]);
704
705                         status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
706                                         cpuinfo[i], &cpuinfo_size, NULL, 0);
707                         if (status == -1) {
708                                 char errbuf[1024];
709                                 ERROR ("cpu plugin: sysctl failed: %s.",
710                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
711                                 return (-1);
712                         }
713                 }
714         }
715         else
716 #endif /* defined(KERN_CPTIME2) */
717         {
718                 int mib[] = {CTL_KERN, KERN_CPTIME};
719                 long cpuinfo_tmp[CPUSTATES];
720
721                 cpuinfo_size = sizeof(cpuinfo_tmp);
722
723                 status = sysctl (mib, STATIC_ARRAY_SIZE (mib),
724                                         &cpuinfo_tmp, &cpuinfo_size, NULL, 0);
725                 if (status == -1)
726                 {
727                         char errbuf[1024];
728                         ERROR ("cpu plugin: sysctl failed: %s.",
729                                         sstrerror (errno, errbuf, sizeof (errbuf)));
730                         return (-1);
731                 }
732
733                 for(i = 0; i < CPUSTATES; i++) {
734                         cpuinfo[0][i] = cpuinfo_tmp[i];
735                 }
736         }
737
738         for (i = 0; i < numcpu; i++) {
739                 derive_t derives[CPU_SUBMIT_MAX] = {
740                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
741                 };
742
743                 derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
744                 derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
745                 derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
746                 derives[CPU_SUBMIT_IDLE] = cpuinfo[i][CP_IDLE];
747                 derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
748                 submit(i, derives);
749         }
750         submit_flush();
751 /* #endif CAN_USE_SYSCTL */
752 #elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES)
753         long cpuinfo[maxcpu][CPUSTATES];
754         size_t cpuinfo_size;
755         int i;
756
757         memset (cpuinfo, 0, sizeof (cpuinfo));
758
759         cpuinfo_size = sizeof (cpuinfo);
760         if (sysctlbyname("kern.cp_times", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
761         {
762                 char errbuf[1024];
763                 ERROR ("cpu plugin: sysctlbyname failed: %s.",
764                                 sstrerror (errno, errbuf, sizeof (errbuf)));
765                 return (-1);
766         }
767
768         for (i = 0; i < numcpu; i++) {
769                 derive_t derives[CPU_SUBMIT_MAX] = {
770                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
771                 };
772
773                 derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
774                 derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
775                 derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
776                 derives[CPU_SUBMIT_IDLE] = cpuinfo[i][CP_IDLE];
777                 derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
778                 submit(i, derives);
779         }
780         submit_flush();
781
782 /* #endif HAVE_SYSCTL_KERN_CP_TIMES */
783 #elif defined(HAVE_SYSCTLBYNAME)
784         long cpuinfo[CPUSTATES];
785         size_t cpuinfo_size;
786         derive_t derives[CPU_SUBMIT_MAX] = {
787                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
788         };
789
790         cpuinfo_size = sizeof (cpuinfo);
791
792         if (sysctlbyname("kern.cp_time", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
793         {
794                 char errbuf[1024];
795                 ERROR ("cpu plugin: sysctlbyname failed: %s.",
796                                 sstrerror (errno, errbuf, sizeof (errbuf)));
797                 return (-1);
798         }
799
800         derives[CPU_SUBMIT_USER] = cpuinfo[CP_USER];
801         derives[CPU_SUBMIT_SYSTEM] = cpuinfo[CP_SYS];
802         derives[CPU_SUBMIT_NICE] = cpuinfo[CP_NICE];
803         derives[CPU_SUBMIT_IDLE] = cpuinfo[CP_IDLE];
804         derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[CP_INTR];
805         submit(0, derives);
806         submit_flush();
807
808 /* #endif HAVE_SYSCTLBYNAME */
809
810 #elif defined(HAVE_LIBSTATGRAB)
811         sg_cpu_stats *cs;
812         derive_t derives[CPU_SUBMIT_MAX] = {
813                 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
814         };
815         cs = sg_get_cpu_stats ();
816
817         if (cs == NULL)
818         {
819                 ERROR ("cpu plugin: sg_get_cpu_stats failed.");
820                 return (-1);
821         }
822
823         derives[CPU_SUBMIT_IDLE] = (derive_t) cs->idle;
824         derives[CPU_SUBMIT_NICE] = (derive_t) cs->nice;
825         derives[CPU_SUBMIT_SWAP] = (derive_t) cs->swap;
826         derives[CPU_SUBMIT_SYSTEM] = (derive_t) cs->kernel;
827         derives[CPU_SUBMIT_USER] = (derive_t) cs->user;
828         derives[CPU_SUBMIT_WAIT] = (derive_t) cs->iowait;
829         submit(0, derives);
830         submit_flush();
831 /* #endif HAVE_LIBSTATGRAB */
832
833 #elif defined(HAVE_PERFSTAT)
834         perfstat_id_t id;
835         int i, cpus;
836
837         numcpu =  perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
838         if(numcpu == -1)
839         {
840                 char errbuf[1024];
841                 WARNING ("cpu plugin: perfstat_cpu: %s",
842                         sstrerror (errno, errbuf, sizeof (errbuf)));
843                 return (-1);
844         }
845
846         if (pnumcpu != numcpu || perfcpu == NULL)
847         {
848                 if (perfcpu != NULL)
849                         free(perfcpu);
850                 perfcpu = malloc(numcpu * sizeof(perfstat_cpu_t));
851         }
852         pnumcpu = numcpu;
853
854         id.name[0] = '\0';
855         if ((cpus = perfstat_cpu(&id, perfcpu, sizeof(perfstat_cpu_t), numcpu)) < 0)
856         {
857                 char errbuf[1024];
858                 WARNING ("cpu plugin: perfstat_cpu: %s",
859                         sstrerror (errno, errbuf, sizeof (errbuf)));
860                 return (-1);
861         }
862
863         for (i = 0; i < cpus; i++)
864         {
865                 derive_t derives[CPU_SUBMIT_MAX] = {
866                         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
867                 };
868                 derives[CPU_SUBMIT_IDLE] = perfcpu[i].idle;
869                 derives[CPU_SUBMIT_SYSTEM] = perfcpu[i].sys;
870                 derives[CPU_SUBMIT_USER] = perfcpu[i].user;
871                 derives[CPU_SUBMIT_WAIT] = perfcpu[i].wait;
872                 submit(i, derives);
873         }
874         submit_flush();
875 #endif /* HAVE_PERFSTAT */
876
877         return (0);
878 }
879
880 void module_register (void)
881 {
882         plugin_register_init ("cpu", init);
883         plugin_register_config ("cpu", cpu_config, config_keys, config_keys_num);
884         plugin_register_read ("cpu", cpu_read);
885 } /* void module_register */