Code

adafbeac44ca488187c075d854361cf530a5e7ca
[collectd.git] / src / cpu.c
1 #include "cpu.h"
3 #if COLLECT_CPU
4 #define MODULE_NAME "cpu"
6 #ifdef HAVE_LIBKSTAT
7 #include <sys/sysinfo.h>
8 #endif /* HAVE_LIBKSTAT */
10 #ifdef HAVE_SYSCTLBYNAME
11 #ifdef HAVE_SYS_SYSCTL_H
12 #include <sys/sysctl.h>
13 #endif
15 #ifdef HAVE_SYS_DKSTAT_H
16 #include <sys/dkstat.h>
17 #endif
19 #if !defined(CP_USER) || !defined(CP_NICE) || !defined(CP_SYS) || !defined(CP_INTR) || !defined(CP_IDLE) || !defined(CPUSTATES)
20 #define CP_USER   0
21 #define CP_NICE   1
22 #define CP_SYS    2
23 #define CP_INTR   3
24 #define CP_IDLE   4
25 #define CPUSTATES 5
26 #endif
27 #endif /* HAVE_SYSCTLBYNAME */
29 #include "plugin.h"
30 #include "common.h"
32 #ifdef HAVE_LIBKSTAT
33 /* colleague tells me that Sun doesn't sell systems with more than 100 or so CPUs.. */
34 #define MAX_NUMCPU 256
35 extern kstat_ctl_t *kc;
36 static kstat_t *ksp[MAX_NUMCPU];
37 static int numcpu;
38 #endif /* HAVE_LIBKSTAT */
40 #ifdef HAVE_SYSCTLBYNAME
41 static int numcpu;
42 #endif /* HAVE_SYSCTLBYNAME */
44 static char *cpu_filename = "cpu-%s.rrd";
46 static char *ds_def[] =
47 {
48         "DS:user:COUNTER:25:0:100",
49         "DS:nice:COUNTER:25:0:100",
50         "DS:syst:COUNTER:25:0:100",
51         "DS:idle:COUNTER:25:0:100",
52         "DS:wait:COUNTER:25:0:100",
53         NULL
54 };
55 static int ds_num = 5;
57 extern time_t curtime;
59 void cpu_init (void)
60 {
61 #ifdef HAVE_LIBKSTAT
62         kstat_t *ksp_chain;
64         numcpu = 0;
66         if (kc == NULL)
67                 return;
69         /* Solaris doesn't count linear.. *sigh* */
70         for (numcpu = 0, ksp_chain = kc->kc_chain;
71                         (numcpu < MAX_NUMCPU) && (ksp_chain != NULL);
72                         ksp_chain = ksp_chain->ks_next)
73                 if (strncmp (ksp_chain->ks_module, "cpu_stat", 8) == 0)
74                         ksp[numcpu++] = ksp_chain;
75 /* #endif HAVE_LIBKSTAT */
77 #elif defined (HAVE_SYSCTLBYNAME)
78         size_t numcpu_size;
80         numcpu_size = sizeof (numcpu);
82         if (sysctlbyname ("hw.ncpu", &numcpu, &numcpu_size, NULL, 0) < 0)
83         {
84                 syslog (LOG_WARNING, "cpu: sysctlbyname: %s", strerror (errno));
85                 return;
86         }
88         if (numcpu != 1)
89                 syslog (LOG_NOTICE, "cpu: Only one processor supported when using `sysctlbyname' (found %i)", numcpu);
90 #endif
92         return;
93 }
95 void cpu_write (char *host, char *inst, char *val)
96 {
97         char file[512];
98         int status;
100         status = snprintf (file, 512, cpu_filename, inst);
101         if (status < 1)
102                 return;
103         else if (status >= 512)
104                 return;
106         rrd_update_file (host, file, val, ds_def, ds_num);
109 #define BUFSIZE 512
110 void cpu_submit (int cpu_num, unsigned long long user, unsigned long long nice, unsigned long long syst,
111                 unsigned long long idle, unsigned long long wait)
113         char buf[BUFSIZE];
114         char cpu[16];
116         if (snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu", (unsigned int) curtime,
117                                 user, nice, syst, idle, wait) >= BUFSIZE)
118                 return;
119         snprintf (cpu, 16, "%i", cpu_num);
121         plugin_submit (MODULE_NAME, cpu, buf);
123 #undef BUFSIZE
125 void cpu_read (void)
127 #ifdef KERNEL_LINUX
128 #define BUFSIZE 1024
129         int cpu;
130         unsigned long long user, nice, syst, idle;
131         unsigned long long wait, intr, sitr; /* sitr == soft interrupt */
132         FILE *fh;
133         char buf[BUFSIZE];
135         char *fields[9];
136         int numfields;
138         if ((fh = fopen ("/proc/stat", "r")) == NULL)
139         {
140                 syslog (LOG_WARNING, "cpu: fopen: %s", strerror (errno));
141                 return;
142         }
144         while (fgets (buf, BUFSIZE, fh) != NULL)
145         {
146                 if (strncmp (buf, "cpu", 3))
147                         continue;
148                 if ((buf[3] < '0') || (buf[3] > '9'))
149                         continue;
151                 numfields = strsplit (buf, fields, 9);
152                 if (numfields < 5)
153                         continue;
155                 cpu = atoi (fields[0] + 3);
156                 user = atoll (fields[1]);
157                 nice = atoll (fields[2]);
158                 syst = atoll (fields[3]);
159                 idle = atoll (fields[4]);
161                 if (numfields >= 8)
162                 {
163                         wait = atoll (fields[5]);
164                         intr = atoll (fields[6]);
165                         sitr = atoll (fields[7]);
167                         /* I doubt anyone cares about the time spent in
168                          * interrupt handlers.. */
169                         syst += intr + sitr;
170                 }
171                 else
172                 {
173                         wait = 0LL;
174                 }
176                 cpu_submit (cpu, user, nice, syst, idle, wait);
177         }
179         fclose (fh);
180 #undef BUFSIZE
181 /* #endif defined(KERNEL_LINUX) */
183 #elif defined(HAVE_LIBKSTAT)
184         int cpu;
185         unsigned long long user, syst, idle, wait;
186         static cpu_stat_t cs;
188         if (kc == NULL)
189                 return;
191         for (cpu = 0; cpu < numcpu; cpu++)
192         {
193                 if (kstat_read (kc, ksp[cpu], &cs) == -1)
194                         continue; /* error message? */
196                 idle = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_IDLE];
197                 user = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_USER];
198                 syst = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_KERNEL];
199                 wait = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_WAIT];
201                 cpu_submit (ksp[cpu]->ks_instance,
202                                 user, 0LL, syst, idle, wait);
203         }
204 /* #endif defined(HAVE_LIBKSTAT) */
206 #elif defined (HAVE_SYSCTLBYNAME)
207         long cpuinfo[CPUSTATES];
208         size_t cpuinfo_size;
210         cpuinfo_size = sizeof (cpuinfo);
212         if (sysctlbyname("kern.cp_time", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
213         {
214                 syslog (LOG_WARNING, "cpu: sysctlbyname: %s", strerror (errno));
215                 return;
216         }
218         cpuinfo[CP_SYS] += cpuinfo[CP_INTR];
220         /* FIXME: Instance is always `0' */
221         cpu_submit (0, cpuinfo[CP_USER], cpuinfo[CP_NICE], cpuinfo[CP_SYS], cpuinfo[CP_IDLE], 0LL);
222 #endif
225 void module_register (void)
227         plugin_register (MODULE_NAME, cpu_init, cpu_read, cpu_write);
230 #undef MODULE_NAME
231 #endif /* COLLECT_CPU */