lpar plugin: Use the "cpu" type for the general CPU statistics.
[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
26 #include <sys/protosw.h>
27 #include <libperfstat.h>
28 #include <sys/systemcfg.h>
29 #include <sys/utsname.h>
30
31 #ifndef XINTFRAC
32 # define XINTFRAC ((double)(_system_configuration.Xint) / \
33                    (double)(_system_configuration.Xfrac))
34 #endif
35
36 static const char *config_keys[] =
37 {
38   "CpuPoolStats"
39 };
40 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
41 static int pool_stats = 0;
42
43 /* As an LPAR can be moved transparently across physical systems
44  * through Live Partition Mobility (LPM), and the resources we are
45  * monitoring are tied to the underlying hardware, we need to keep
46  * track on which physical server we are currently on. This is done
47  * through the plugin instance which holds the chassis' serial.
48  */
49 static u_longlong_t last_time_base;
50 static u_longlong_t last_pcpu_user,
51                     last_pcpu_sys,
52                     last_pcpu_idle,
53                     last_pcpu_wait;
54 static u_longlong_t last_pool_idle_time = 0;
55 static u_longlong_t last_idle_donated_purr = 0,
56                     last_busy_donated_purr = 0,
57                     last_busy_stolen_purr = 0,
58                     last_idle_stolen_purr = 0;
59 static int donate_flag = 0;
60
61
62 /* Save the current values for the next iteration */
63 static void save_last_values (perfstat_partition_total_t *lparstats)
64 {
65         last_time_base = lparstats->timebase_last;
66
67         last_pcpu_user = lparstats->puser;
68         last_pcpu_sys  = lparstats->psys;
69         last_pcpu_idle = lparstats->pidle;
70         last_pcpu_wait = lparstats->pwait;
71
72         if (donate_flag)
73         {
74                 last_idle_donated_purr = lparstats->idle_donated_purr;
75                 last_busy_donated_purr = lparstats->busy_donated_purr;
76                 last_busy_stolen_purr  = lparstats->busy_stolen_purr;
77                 last_idle_stolen_purr  = lparstats->idle_stolen_purr;
78         }
79
80         last_pool_idle_time = lparstats->pool_idle_time;
81 }
82
83 static int lpar_config (const char *key, const char *value)
84 {
85         if (strcasecmp ("CpuPoolStats", key) == 0)
86         {
87                 if (IS_TRUE (value))
88                         pool_stats = 1;
89                 else
90                         pool_stats = 0;
91         }
92         else
93         {
94                 return (-1);
95         }
96
97         return (0);
98 } /* int lpar_config */
99
100 static int lpar_init (void)
101 {
102         perfstat_partition_total_t lparstats;
103
104         /* retrieve the initial metrics */
105         if (!perfstat_partition_total (NULL, &lparstats,
106                                        sizeof (perfstat_partition_total_t), 1))
107         {
108                 ERROR ("lpar plugin: perfstat_partition_total failed.");
109                 return (-1);
110         }
111
112         if (!lparstats.type.b.shared_enabled && lparstats.type.b.donate_enabled)
113         {
114                 donate_flag = 1;
115         }
116
117         /* save the initial data */
118         save_last_values (&lparstats);
119
120         return (0);
121 } /* int lpar_init */
122
123 static void lpar_submit (const char *plugin_inst, const char *type_instance, double value)
124 {
125         value_t values[1];
126         value_list_t vl = VALUE_LIST_INIT;
127
128         values[0].gauge = (gauge_t)value;
129
130         vl.values = values;
131         vl.values_len = 1;
132         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
133         sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
134         sstrncpy (vl.plugin_instance, plugin_inst, sizeof (vl.plugin));
135         sstrncpy (vl.type, "lpar_pcpu", sizeof (vl.type));
136         sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
137
138         plugin_dispatch_values (&vl);
139 }
140
141 static int submit_counter (const char *plugin_instance, /* {{{ */
142                 const char *type, const char *type_instance, counter_t value)
143 {
144         value_t values[1];
145         value_list_t vl = VALUE_LIST_INIT;
146
147         values[0].counter = value;
148
149         vl.values = values;
150         vl.values_len = 1;
151         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
152         sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
153         sstrncpy (vl.plugin_instance, plugin_inst, sizeof (vl.plugin));
154         sstrncpy (vl.type, type, sizeof (vl.type));
155         sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
156
157         return (plugin_dispatch_values (&vl));
158 } /* }}} int submit_counter */
159
160 static int lpar_read (void)
161 {
162         u_longlong_t delta_time_base;
163         perfstat_partition_total_t lparstats;
164         struct utsname name;
165         char plugin_inst[DATA_MAX_NAME_LEN];
166         _Bool have_donate = 0;
167
168         /* retrieve the current physical server's id and build the plugin
169            instance's name */
170         if (uname (&name) != 0)
171         {
172                 ERROR ("lpar plugin: uname failed.");
173                 return (-1);
174         }
175         sstrncpy (plugin_inst, name.machine, sizeof (plugin_inst));
176
177         /* retrieve the current metrics */
178         if (!perfstat_partition_total (/* name = */ NULL, /* "must be set to NULL" */
179                                 &lparstats, sizeof (lparstats),
180                                 /* desired_number = */ 1 /* "must be set to 1" */))
181         {
182                 ERROR ("lpar plugin: perfstat_partition_total failed.");
183                 return (-1);
184         }
185
186         if (!lparstats.type.b.shared_enabled
187                         && lparstats.type.b.donate_enabled)
188                 have_donate = 1;
189
190         delta_time_base = lparstats.timebase_last - last_time_base;
191         if (delta_time_base == 0)
192         {
193                 /* The system stats have not been updated since last time */
194                 return (0);
195         }
196
197         submit_counter (plugin_inst, "cpu", "user",   (counter_t) lparstats.puser);
198         submit_counter (plugin_inst, "cpu", "system", (counter_t) lparstats.psys);
199         submit_counter (plugin_inst, "cpu", "idle",   (counter_t) lparstats.pidle);
200         submit_counter (plugin_inst, "cpu", "wait",   (counter_t) lparstats.pwait);
201
202         /* FIXME: Use an appropriate GAUGE type here. */
203         lpar_submit (plugin_inst, "ent",  (double)lparstats.entitled_proc_capacity / 100.0);
204         lpar_submit (plugin_inst, "max",  (double)lparstats.max_proc_capacity / 100.0);
205         lpar_submit (plugin_inst, "min",  (double)lparstats.min_proc_capacity / 100.0);
206
207         if (have_donate)
208         {
209                 dlt_idle_donated = lparstats.idle_donated_purr - last_idle_donated_purr;
210                 dlt_busy_donated = lparstats.busy_donated_purr - last_busy_donated_purr;
211                 dlt_idle_stolen  = lparstats.idle_stolen_purr  - last_idle_stolen_purr;
212                 dlt_busy_stolen  = lparstats.busy_stolen_purr  - last_busy_stolen_purr;
213
214                 submit_counter (plugin_inst, "cpu", "donated-idle", (counter_t) lparstats.idle_donated_purr);
215                 submit_counter (plugin_inst, "cpu", "donated-busy", (counter_t) lparstats.busy_donated_purr);
216                 submit_counter (plugin_inst, "cpu", "stolen-idle",  (counter_t) lparstats.idle_stolen_purr);
217                 submit_counter (plugin_inst, "cpu", "stolen-busy",  (counter_t) lparstats.busy_stolen_purr);
218         }
219
220         if (pool_stats)
221         {
222                 if (!lparstats.type.b.pool_util_authority)
223                 {
224                         WARNING ("lpar plugin: Pool utilization data is not available.");
225                 }
226                 else
227                 {
228                         u_longlong_t dlt_pit;
229                         double total, idle;
230                         char type[DATA_MAX_NAME_LEN];
231
232                         /* FIXME: The pool id should probably be used as plugin instance. */
233                         dlt_pit = lparstats.pool_idle_time - last_pool_idle_time;
234                         total = (double)lparstats.phys_cpus_pool;
235                         idle  = (double)dlt_pit / XINTFRAC / (double)delta_time_base;
236                         ssnprintf (type, sizeof(type), "pool-%X-total", lparstats.pool_id);
237                         lpar_submit (plugin_inst, type, total);
238                         ssnprintf (type, sizeof(type), "pool-%X-used", lparstats.pool_id);
239                         lpar_submit (plugin_inst, type, total - idle);
240                 }
241         }
242
243         save_last_values (&lparstats);
244
245         return (0);
246 } /* int lpar_read */
247
248 void module_register (void)
249 {
250         plugin_register_config ("lpar", lpar_config,
251                                 config_keys, config_keys_num);
252         plugin_register_init ("lpar", lpar_init);
253         plugin_register_read ("lpar", lpar_read);
254 } /* void module_register */
255
256 /* vim: set sw=8 sts=8 ts=8 noet : */
257