2 * collectd - src/lpar.c
3 * Copyright (C) 2010 Aurélien Reynaud
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.
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.
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
19 * Aurelien Reynaud <collectd at wattapower.net>
25 #include <sys/protosw.h>
26 #include <libperfstat.h>
27 #include <sys/utsname.h>
30 # include <sys/systemcfg.h>
31 # define XINTFRAC ((double)(_system_configuration.Xint) / \
32 (double)(_system_configuration.Xfrac))
34 #define HTIC2SEC(x) ((double)x * XINTFRAC / 1000000000.0)
36 /* Max length of the type instance string */
37 #define TYPE_INST_LEN (sizeof("pool--total") + 2*sizeof(int) + 1)
39 static const char *config_keys[] =
44 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
46 static _Bool pool_stats = 0;
47 static _Bool report_by_serial = 0;
49 static u_longlong_t last_time_base;
50 static u_longlong_t ent_counter;
51 static _Bool donate_flag = 0;
54 static int lpar_config (const char *key, const char *value)
56 if (strcasecmp ("CpuPoolStats", key) == 0)
63 else if (strcasecmp ("ReportBySerial", key) == 0)
76 } /* int lpar_config */
78 static int lpar_init (void)
80 perfstat_partition_total_t lparstats;
82 /* Retrieve the initial metrics */
83 if (!perfstat_partition_total (NULL, &lparstats,
84 sizeof (perfstat_partition_total_t), 1))
86 ERROR ("lpar plugin: perfstat_partition_total failed.");
90 if (!lparstats.type.b.shared_enabled && lparstats.type.b.donate_enabled)
95 if (pool_stats && !lparstats.type.b.pool_util_authority)
97 WARNING ("lpar plugin: this system does not have pool authority. "
98 "Disabling CPU pool statistics collection.");
102 /* Initialize the fake counter for entitled capacity */
103 last_time_base = lparstats.timebase_last;
107 } /* int lpar_init */
109 static void lpar_submit (const char *type_instance, double value)
112 value_list_t vl = VALUE_LIST_INIT;
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);
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)
130 if (uname (&name) != 0)
132 ERROR ("lpar plugin: uname failed.");
135 sstrncpy (vl.host, name.machine, sizeof (vl.host));
136 sstrncpy (vl.plugin_instance, hostname_g, sizeof (vl.plugin));
140 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
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));
146 plugin_dispatch_values (&vl);
149 static int lpar_read (void)
151 u_longlong_t delta_time_base;
152 perfstat_partition_total_t lparstats;
154 /* Retrieve the current metrics */
155 if (!perfstat_partition_total (NULL, &lparstats,
156 sizeof (perfstat_partition_total_t), 1))
158 ERROR ("lpar plugin: perfstat_partition_total failed.");
162 delta_time_base = lparstats.timebase_last - last_time_base;
163 last_time_base = lparstats.timebase_last;
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
172 ent_counter += lparstats.entitled_proc_capacity * delta_time_base;
173 lpar_submit ("ent", HTIC2SEC(ent_counter) / 100.0);
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));
185 char typinst[TYPE_INST_LEN];
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);
191 ssnprintf (typinst, sizeof(typinst), "pool-%X-total", lparstats.pool_id);
192 lpar_submit (typinst, (double)lparstats.pool_max_time / 1000000000.0);
196 } /* int lpar_read */
198 void module_register (void)
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 */
206 /* vim: set sw=8 noet : */