Merge pull request #3329 from efuss/fix-3311
[collectd.git] / src / contextswitch.c
1 /**
2  * collectd - src/contextswitch.c
3  * Copyright (C) 2009  Patrik Weiskircher
4  * Copyright (C) 2010  Kimo Rosenbaum
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; only version 2 of the License is applicable.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Patrik Weiskircher <weiskircher at inqnet.at>
21  *   Kimo Rosenbaum <http://github.com/kimor79>
22  **/
23
24 #include "collectd.h"
25
26 #include "plugin.h"
27 #include "utils/common/common.h"
28
29 #if defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYS_SYSCTL_H)
30 #include <sys/sysctl.h>
31 /* no global variables */
32 /* #endif HAVE_SYSCTLBYNAME */
33
34 #elif KERNEL_LINUX
35 /* no global variables */
36 /* #endif KERNEL_LINUX */
37
38 #elif HAVE_PERFSTAT
39 #include <libperfstat.h>
40 #include <sys/protosw.h>
41 /* #endif HAVE_PERFSTAT */
42
43 #else
44 #error "No applicable input method."
45 #endif
46
47 static void cs_submit(derive_t context_switches) {
48   value_list_t vl = VALUE_LIST_INIT;
49
50   vl.values = &(value_t){.derive = context_switches};
51   vl.values_len = 1;
52   sstrncpy(vl.plugin, "contextswitch", sizeof(vl.plugin));
53   sstrncpy(vl.type, "contextswitch", sizeof(vl.type));
54
55   plugin_dispatch_values(&vl);
56 }
57
58 static int cs_read(void) {
59 #if HAVE_SYSCTLBYNAME
60   int value = 0;
61   size_t value_len = sizeof(value);
62   int status;
63
64   status = sysctlbyname("vm.stats.sys.v_swtch", &value, &value_len,
65                         /* new pointer = */ NULL, /* new length = */ 0);
66   if (status != 0) {
67     ERROR("contextswitch plugin: sysctlbyname "
68           "(vm.stats.sys.v_swtch) failed");
69     return -1;
70   }
71
72   cs_submit(value);
73   /* #endif HAVE_SYSCTLBYNAME */
74
75 #elif KERNEL_LINUX
76   FILE *fh;
77   char buffer[64];
78   int numfields;
79   char *fields[3];
80   derive_t result = 0;
81   int status = -2;
82
83   fh = fopen("/proc/stat", "r");
84   if (fh == NULL) {
85     ERROR("contextswitch plugin: unable to open /proc/stat: %s", STRERRNO);
86     return -1;
87   }
88
89   while (fgets(buffer, sizeof(buffer), fh) != NULL) {
90     char *endptr;
91
92     numfields = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
93     if (numfields != 2)
94       continue;
95
96     if (strcmp("ctxt", fields[0]) != 0)
97       continue;
98
99     errno = 0;
100     endptr = NULL;
101     result = (derive_t)strtoll(fields[1], &endptr, /* base = */ 10);
102     if ((endptr == fields[1]) || (errno != 0)) {
103       ERROR("contextswitch plugin: Cannot parse ctxt value: %s", fields[1]);
104       status = -1;
105       break;
106     }
107
108     cs_submit(result);
109     status = 0;
110     break;
111   }
112   fclose(fh);
113
114   if (status == -2)
115     ERROR("contextswitch plugin: Unable to find context switch value.");
116     /* #endif  KERNEL_LINUX */
117
118 #elif HAVE_PERFSTAT
119   int status = 0;
120   perfstat_cpu_total_t perfcputotal;
121
122   status =
123       perfstat_cpu_total(NULL, &perfcputotal, sizeof(perfstat_cpu_total_t), 1);
124   if (status < 0) {
125     ERROR("contextswitch plugin: perfstat_cpu_total: %s", STRERRNO);
126     return -1;
127   }
128
129   cs_submit(perfcputotal.pswitch);
130   status = 0;
131 #endif /* defined(HAVE_PERFSTAT) */
132
133   return status;
134 }
135
136 void module_register(void) {
137   plugin_register_read("contextswitch", cs_read);
138 } /* void module_register */