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);
45 static int pool_stats = 0,
48 static u_longlong_t last_time_base;
49 static u_longlong_t ent_counter;
50 static int donate_flag = 0;
53 static int lpar_config (const char *key, const char *value)
55 if (strcasecmp ("CpuPoolStats", key) == 0)
60 else if (strcasecmp ("ReportBySerial", key) == 0)
71 } /* int lpar_config */
73 static int lpar_init (void)
75 perfstat_partition_total_t lparstats;
77 /* Retrieve the initial metrics */
78 if (!perfstat_partition_total (NULL, &lparstats,
79 sizeof (perfstat_partition_total_t), 1))
81 ERROR ("lpar plugin: perfstat_partition_total failed.");
85 if (!lparstats.type.b.shared_enabled && lparstats.type.b.donate_enabled)
90 if (pool_stats && !lparstats.type.b.pool_util_authority)
92 WARNING ("lpar plugin: this system does not have pool authority. "
93 "Disabling CPU pool statistics collection.");
97 /* Initialize the fake counter for entitled capacity */
98 last_time_base = lparstats.timebase_last;
102 } /* int lpar_init */
104 static void lpar_submit (const char *type_instance, double value)
107 value_list_t vl = VALUE_LIST_INIT;
109 /* Although it appears as a double, value is really a (scaled) counter,
110 expressed in CPU x seconds. At high collection rates (< 1 min), its
111 integer part is very small and the resulting graphs get blocky. We regain
112 some precision by applying a x100 factor before casting it to a counter,
113 turning the final value into CPU units instead of CPUs. */
114 values[0].counter = (counter_t)(value * 100.0 + 0.5);
119 /* An LPAR has the same serial number as the physical system it is currently
120 running on. It is a convenient way of tracking LPARs as they are moved
121 from chassis to chassis through Live Partition Mobility (LPM). */
122 if (report_by_serial)
125 if (uname (&name) != 0)
127 ERROR ("lpar plugin: uname failed.");
130 sstrncpy (vl.host, name.machine, sizeof (vl.host));
131 sstrncpy (vl.plugin_instance, hostname_g, sizeof (vl.plugin));
135 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
137 sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
138 sstrncpy (vl.type, "cpu", sizeof (vl.type));
139 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
141 plugin_dispatch_values (&vl);
144 static int lpar_read (void)
146 u_longlong_t delta_time_base;
147 perfstat_partition_total_t lparstats;
149 /* Retrieve the current metrics */
150 if (!perfstat_partition_total (NULL, &lparstats,
151 sizeof (perfstat_partition_total_t), 1))
153 ERROR ("lpar plugin: perfstat_partition_total failed.");
157 delta_time_base = lparstats.timebase_last - last_time_base;
158 last_time_base = lparstats.timebase_last;
160 lpar_submit ("user", HTIC2SEC(lparstats.puser));
161 lpar_submit ("sys", HTIC2SEC(lparstats.psys));
162 lpar_submit ("wait", HTIC2SEC(lparstats.pwait));
163 lpar_submit ("idle", HTIC2SEC(lparstats.pidle));
164 /* Entitled capacity is reported as an absolute value instead of a counter,
165 so we fake one. It's also in CPU units, hence the division by 100 before
167 ent_counter += lparstats.entitled_proc_capacity * delta_time_base;
168 lpar_submit ("ent", HTIC2SEC(ent_counter) / 100.0);
172 lpar_submit ("idle_donated", HTIC2SEC(lparstats.idle_donated_purr));
173 lpar_submit ("busy_donated", HTIC2SEC(lparstats.busy_donated_purr));
174 lpar_submit ("idle_stolen", HTIC2SEC(lparstats.idle_stolen_purr));
175 lpar_submit ("busy_stolen", HTIC2SEC(lparstats.busy_stolen_purr));
180 char typinst[TYPE_INST_LEN];
182 /* Pool stats are in CPU x ns */
183 ssnprintf (typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id);
184 lpar_submit (typinst, (double)lparstats.pool_busy_time / 1000000000.0);
186 ssnprintf (typinst, sizeof(typinst), "pool-%X-total", lparstats.pool_id);
187 lpar_submit (typinst, (double)lparstats.pool_max_time / 1000000000.0);
191 } /* int lpar_read */
193 void module_register (void)
195 plugin_register_config ("lpar", lpar_config,
196 config_keys, config_keys_num);
197 plugin_register_init ("lpar", lpar_init);
198 plugin_register_read ("lpar", lpar_read);
199 } /* void module_register */
201 /* vim: set sw=2 sts=2 ts=8 : */