lpar plugin: Use booleans for the config options.
[collectd.git] / src / lpar.c
1 /**
2  * collectd - src/lpar.c
3  * Copyright (C) 2010  AurĂ©lien Reynaud
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  *   Aurelien Reynaud <collectd at wattapower.net>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include <sys/protosw.h>
26 #include <libperfstat.h>
27 #include <sys/utsname.h>
28
29 #ifndef XINTFRAC
30 # include <sys/systemcfg.h>
31 # define XINTFRAC ((double)(_system_configuration.Xint) / \
32                    (double)(_system_configuration.Xfrac))
33 #endif
34 #define HTIC2SEC(x)     ((double)x * XINTFRAC / 1000000000.0)
35
36 /* Max length of the type instance string */
37 #define TYPE_INST_LEN (sizeof("pool--total") + 2*sizeof(int) + 1)
38
39 static const char *config_keys[] =
40 {
41   "CpuPoolStats",
42   "ReportBySerial"
43 };
44 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
45
46 static _Bool pool_stats = 0;
47 static _Bool report_by_serial = 0;
48
49 static u_longlong_t last_time_base;
50 static u_longlong_t ent_counter;
51 static _Bool donate_flag = 0;
52
53
54 static int lpar_config (const char *key, const char *value)
55 {
56         if (strcasecmp ("CpuPoolStats", key) == 0)
57         {
58                 if (IS_TRUE (value))
59                         pool_stats = 1;
60                 else
61                         pool_stats = 0;
62         }
63         else if (strcasecmp ("ReportBySerial", key) == 0)
64         {
65                 if (IS_TRUE (value))
66                         report_by_serial = 1;
67                 else
68                         report_by_serial = 0;
69         }
70         else
71         {
72                 return (-1);
73         }
74
75         return (0);
76 } /* int lpar_config */
77
78 static int lpar_init (void)
79 {
80         perfstat_partition_total_t lparstats;
81
82         /* Retrieve the initial metrics */
83         if (!perfstat_partition_total (NULL, &lparstats,
84                                        sizeof (perfstat_partition_total_t), 1))
85         {
86                 ERROR ("lpar plugin: perfstat_partition_total failed.");
87                 return (-1);
88         }
89
90         if (!lparstats.type.b.shared_enabled && lparstats.type.b.donate_enabled)
91         {
92                 donate_flag = 1;
93         }
94
95         if (pool_stats && !lparstats.type.b.pool_util_authority)
96         {
97                 WARNING ("lpar plugin: this system does not have pool authority. "
98                         "Disabling CPU pool statistics collection.");
99                 pool_stats = 0;
100         }
101
102         /* Initialize the fake counter for entitled capacity */
103         last_time_base = lparstats.timebase_last;
104         ent_counter = 0;
105
106         return (0);
107 } /* int lpar_init */
108
109 static void lpar_submit (const char *type_instance, double value)
110 {
111         value_t values[1];
112         value_list_t vl = VALUE_LIST_INIT;
113
114         /* Although it appears as a double, value is really a (scaled) counter,
115            expressed in CPU x seconds. At high collection rates (< 1 min), its
116            integer part is very small and the resulting graphs get blocky. We regain
117            some precision by applying a x100 factor before casting it to a counter,
118            turning the final value into CPU units instead of CPUs. */
119         values[0].counter = (counter_t)(value * 100.0 + 0.5);
120
121         vl.values = values;
122         vl.values_len = 1;
123
124         /* An LPAR has the same serial number as the physical system it is currently
125            running on. It is a convenient way of tracking LPARs as they are moved
126            from chassis to chassis through Live Partition Mobility (LPM). */
127         if (report_by_serial)
128         {
129                 struct utsname name;
130                 if (uname (&name) != 0)
131                 {
132                         ERROR ("lpar plugin: uname failed.");
133                         return;
134                 }
135                 sstrncpy (vl.host, name.machine, sizeof (vl.host));
136                 sstrncpy (vl.plugin_instance, hostname_g, sizeof (vl.plugin));
137         }
138         else
139         {
140                 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
141         }
142         sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
143         sstrncpy (vl.type, "cpu", sizeof (vl.type));
144         sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
145
146         plugin_dispatch_values (&vl);
147 }
148
149 static int lpar_read (void)
150 {
151         u_longlong_t delta_time_base;
152         perfstat_partition_total_t lparstats;
153
154         /* Retrieve the current metrics */
155         if (!perfstat_partition_total (NULL, &lparstats,
156                                        sizeof (perfstat_partition_total_t), 1))
157         {
158                 ERROR ("lpar plugin: perfstat_partition_total failed.");
159                 return (-1);
160         }
161
162         delta_time_base = lparstats.timebase_last - last_time_base;
163         last_time_base  = lparstats.timebase_last;
164
165         lpar_submit ("user", HTIC2SEC(lparstats.puser));
166         lpar_submit ("sys",  HTIC2SEC(lparstats.psys));
167         lpar_submit ("wait", HTIC2SEC(lparstats.pwait));
168         lpar_submit ("idle", HTIC2SEC(lparstats.pidle));
169         /* Entitled capacity is reported as an absolute value instead of a counter,
170            so we fake one. It's also in CPU units, hence the division by 100 before
171            submission. */
172         ent_counter += lparstats.entitled_proc_capacity * delta_time_base;
173         lpar_submit ("ent",  HTIC2SEC(ent_counter) / 100.0);
174
175         if (donate_flag)
176         {
177                 lpar_submit ("idle_donated", HTIC2SEC(lparstats.idle_donated_purr));
178                 lpar_submit ("busy_donated", HTIC2SEC(lparstats.busy_donated_purr));
179                 lpar_submit ("idle_stolen",  HTIC2SEC(lparstats.idle_stolen_purr));
180                 lpar_submit ("busy_stolen",  HTIC2SEC(lparstats.busy_stolen_purr));
181         }
182
183         if (pool_stats)
184         {
185                 char typinst[TYPE_INST_LEN];
186
187                 /* Pool stats are in CPU x ns */
188                 ssnprintf (typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id);
189                 lpar_submit (typinst, (double)lparstats.pool_busy_time / 1000000000.0);
190
191                 ssnprintf (typinst, sizeof(typinst), "pool-%X-total", lparstats.pool_id);
192                 lpar_submit (typinst, (double)lparstats.pool_max_time / 1000000000.0);
193         }
194
195         return (0);
196 } /* int lpar_read */
197
198 void module_register (void)
199 {
200         plugin_register_config ("lpar", lpar_config,
201                                 config_keys, config_keys_num);
202         plugin_register_init ("lpar", lpar_init);
203         plugin_register_read ("lpar", lpar_read);
204 } /* void module_register */
205
206 /* vim: set sw=8 noet : */
207