Merge remote-tracking branch 'github/pr/1749'
[collectd.git] / src / xencpu.c
1 /**
2  * collectd - src/xencpu.c
3  * Copyright (C) 2016       Pavel Rochnyak
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Pavel Rochnyak <pavel2000 ngs.ru>
20  **/
21
22 #include "collectd.h"
23
24 #include "common.h"
25 #include "plugin.h"
26
27 #include <xenctrl.h>
28
29 #ifdef XENCTRL_HAS_XC_INTERFACE
30
31 //Xen-4.1+
32 #define XC_INTERFACE_INIT_ARGS NULL,NULL,0
33 xc_interface *xc_handle;
34
35 #else /* XENCTRL_HAS_XC_INTERFACE */
36
37 //For xen-3.4/xen-4.0
38 #include <string.h>
39 #define xc_strerror(xc_interface, errcode) strerror(errcode)
40 #define XC_INTERFACE_INIT_ARGS
41 typedef int xc_interface;
42 xc_interface xc_handle = 0;
43
44 #endif /* XENCTRL_HAS_XC_INTERFACE */
45
46 uint32_t num_cpus = 0;
47 xc_cpuinfo_t *cpu_info;
48 static value_to_rate_state_t *cpu_states;
49
50 static int xencpu_init (void)
51 {
52     xc_handle = xc_interface_open(XC_INTERFACE_INIT_ARGS);
53     if (!xc_handle)
54     {
55         ERROR ("xencpu: xc_interface_open() failed");
56         return (-1);
57     }
58
59     xc_physinfo_t *physinfo;
60
61     physinfo = calloc(1, sizeof(xc_physinfo_t));
62     if (physinfo == NULL)
63     {
64         ERROR ("xencpu plugin: calloc() for physinfo failed.");
65         xc_interface_close(xc_handle);
66         return (ENOMEM);
67     }
68
69     if (xc_physinfo(xc_handle, physinfo) < 0)
70     {
71         ERROR ("xencpu plugin: xc_physinfo() failed");
72         xc_interface_close(xc_handle);
73         free(physinfo);
74         return (-1);
75     }
76
77     num_cpus = physinfo->nr_cpus;
78     free(physinfo);
79
80     INFO ("xencpu plugin: Found %"PRIu32" processors.", num_cpus);
81
82     cpu_info = calloc(num_cpus, sizeof(xc_cpuinfo_t));
83     if (cpu_info == NULL)
84     {
85         ERROR ("xencpu plugin: calloc() for num_cpus failed.");
86         xc_interface_close(xc_handle);
87         return (ENOMEM);
88     }
89
90     cpu_states = calloc (num_cpus, sizeof (value_to_rate_state_t));
91     if (cpu_states == NULL)
92     {
93         ERROR ("xencpu plugin: calloc() for cpu_states failed.");
94         xc_interface_close(xc_handle);
95         free(cpu_info);
96         return (ENOMEM);
97     }
98
99     return (0);
100 } /* static int xencpu_init */
101
102 static int xencpu_shutdown (void)
103 {
104     free(cpu_states);
105     free(cpu_info);
106     xc_interface_close(xc_handle);
107
108     return 0;
109 } /* static int xencpu_shutdown */
110
111 static void submit_value (int cpu_num, gauge_t value)
112 {
113     value_list_t vl = VALUE_LIST_INIT;
114
115     vl.values = &(value_t) { .gauge = value };
116     vl.values_len = 1;
117
118     sstrncpy (vl.plugin, "xencpu", sizeof (vl.plugin));
119     sstrncpy (vl.type, "percent", sizeof (vl.type));
120     sstrncpy (vl.type_instance, "load", sizeof (vl.type_instance));
121
122     if (cpu_num >= 0) {
123         ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
124                 "%i", cpu_num);
125     }
126     plugin_dispatch_values (&vl);
127 } /* static void submit_value */
128
129 static int xencpu_read (void)
130 {
131     cdtime_t now = cdtime ();
132
133     int rc, nr_cpus;
134
135     rc = xc_getcpuinfo(xc_handle, num_cpus, cpu_info, &nr_cpus);
136     if (rc < 0) {
137         ERROR ("xencpu: xc_getcpuinfo() Failed: %d %s\n", rc, xc_strerror(xc_handle,errno));
138         return (-1);
139     }
140
141     int status;
142     for (int cpu = 0; cpu < nr_cpus; cpu++) {
143         gauge_t rate = NAN;
144
145         status = value_to_rate (&rate,
146                                 (value_t) { .derive = cpu_info[cpu].idletime }, DS_TYPE_DERIVE,
147                                 now, &cpu_states[cpu]);
148         if (status == 0) {
149             submit_value(cpu, 100 - rate/10000000);
150         }
151     }
152
153     return (0);
154 } /* static int xencpu_read */
155
156 void module_register (void)
157 {
158     plugin_register_init ("xencpu", xencpu_init);
159     plugin_register_read ("xencpu", xencpu_read);
160     plugin_register_shutdown ("xencpu", xencpu_shutdown);
161 } /* void module_register */