WPAR plugin: Refactored read and init callbacks.
[collectd.git] / src / wpar.c
1 /**
2  * collectd - src/wpar.c
3  * Copyright (C) 2010  Manuel Sanmartin
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  *   Manuel Sanmartin <manuel.luis at gmail.com>
20  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25
26 #if !HAVE_PERFSTAT
27 # error "No applicable input method."
28 #endif
29
30 #include <sys/proc.h> /* AIX 5 */
31 #include <sys/protosw.h>
32 #include <libperfstat.h>
33
34 static int pagesize;
35 static int wpar_total_num;
36 static perfstat_wpar_total_t *wpar_total = NULL;
37
38 static int wpar_init(void) /* {{{ */
39 {
40   pagesize = getpagesize ();
41   return (0);
42 } /* }}} int wpar_init */
43
44 static void memory_submit (const char *plugin_instance, const char *type_instance, gauge_t value) /* {{{ */
45 {
46   value_t values[1];
47   value_list_t vl = VALUE_LIST_INIT;
48
49   values[0].gauge = value;
50
51   vl.values = values;
52   vl.values_len = 1;
53   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
54   sstrncpy (vl.plugin, "wpar", sizeof (vl.plugin));
55   sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
56   sstrncpy (vl.type, "memory", sizeof (vl.type));
57   sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
58
59   plugin_dispatch_values (&vl);
60 } /* }}} void memory_submit */
61
62 static void cpu_submit (const char *plugin_instance, const char *type_instance, derive_t value) /* {{{ */
63 {
64   value_t values[1];
65   value_list_t vl = VALUE_LIST_INIT;
66
67   values[0].counter = value;
68
69   vl.values = values;
70   vl.values_len = 1;
71   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
72   sstrncpy (vl.plugin, "wpar", sizeof (vl.plugin));
73   sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
74   sstrncpy (vl.type, "cpu", sizeof (vl.type));
75   sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
76
77   plugin_dispatch_values (&vl);
78 } /* }}} void cpu_submit */
79
80 static void load_submit (const char *plugin_instance, gauge_t snum, gauge_t mnum, gauge_t lnum) /* {{{ */
81 {
82   value_t values[3];
83   value_list_t vl = VALUE_LIST_INIT;
84
85   values[0].gauge = snum;
86   values[1].gauge = mnum;
87   values[2].gauge = lnum;
88
89   vl.values = values;
90   vl.values_len = STATIC_ARRAY_SIZE (values);
91   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
92   sstrncpy (vl.plugin, "wpar", sizeof (vl.plugin));
93   sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
94   sstrncpy (vl.type, "load", sizeof (vl.type));
95
96   plugin_dispatch_values (&vl);
97 } /* }}} void load_submit */
98
99 static int wpar_read_memory (const perfstat_id_wpar_t *id_wpar, /* {{{ */
100     const char *wname)
101 {
102   perfstat_memory_total_wpar_t wmemory;
103   int status;
104
105   status = perfstat_memory_total_wpar(/* id = */ id_wpar,
106       /* (out) */ &wmemory,
107       /* size = */ sizeof(wmemory), /* nmemb = */ 1);
108   if (status < 0)
109   {
110     char errbuf[1024];
111     WARNING ("wpar plugin: perfstat_memory_total_wpar(%s) failed: %s",
112         wname, sstrerror (errno, errbuf, sizeof (errbuf)));
113     return (status);
114   }
115
116   memory_submit (wname, "used",   wmemory.real_inuse * pagesize);
117   memory_submit (wname, "free",   wmemory.real_free  * pagesize);
118   memory_submit (wname, "cached", wmemory.numperm    * pagesize);
119   /* XXX: In which case would total != used + free + cached? */
120   memory_submit (wname, "total",  wmemory.real_total * pagesize);
121
122   return (0);
123 } /* }}} int wpar_read_memory */
124
125 /* Read CPU and load information of one workload partition. */
126 static int wpar_read_cpu_load (const perfstat_id_wpar_t *id_wpar, /* {{{ */
127     const char *wname)
128 {
129   perfstat_cpu_total_wpar_t wcpu;
130   double factor, snum, mnum, lnum;
131   int status;
132
133   status = perfstat_cpu_total_wpar(/* id = */ id_wpar,
134       /* (out) */ &wcpu,
135       /* size = */ sizeof(wcpu), /* nmemb = */ 1);
136   if (status < 0)
137   {
138     char errbuf[1024];
139     WARNING ("wpar plugin: perfstat_cpu_total_wpar(%s) failed: %s",
140         wname, sstrerror (errno, errbuf, sizeof (errbuf)));
141     continue;
142   }
143
144   factor = 1.0 / ((gauge_t) (1 << SBITS));
145   snum = ((gauge_t) wcpu.loadavg[0]) * factor;
146   mnum = ((gauge_t) wcpu.loadavg[1]) * factor;
147   lnum = ((gauge_t) wcpu.loadavg[2]) * factor;
148
149   load_submit (wname, snum, mnum, lnum);
150
151   cpu_submit (wname, "idle",   (derive_t) wcpu.pidle);
152   cpu_submit (wname, "system", (derive_t) wcpu.psys);
153   cpu_submit (wname, "user",   (derive_t) wcpu.puser);
154   cpu_submit (wname, "wait",   (derive_t) wcpu.pwait);
155
156   return (0);
157 } /* }}} int wpar_read_cpu_load */
158
159 static int wpar_read (void) /* {{{ */
160 {
161   _Bool have_data = 0;
162   int i;
163
164   do /* while (!have_data) */
165   {
166     perfstat_id_wpar_t id_wpar;
167     int status;
168
169     if (wpar_total != NULL)
170       memset (wpar_total, 0, wpar_total_num * sizeof (*wpar_total));
171
172     /* Assume the number of partitions has not been changed since the last run.
173      * On the first run, wpar_total will be NULL and only the number of elements
174      * is returned. */
175     status = perfstat_wpar_total (/* id = */ &id_wpar,
176         /* (out) wpar_total */ wpar_total,
177         /* size = */ sizeof (*wpar_total),
178         /* nmemb = */ wpar_total_num);
179     if (status < 0)
180     {
181       char errbuf[1024];
182       WARNING ("wpar plugin: perfstat_wpar_total failed: %s",
183           sstrerror (errno, errbuf, sizeof (errbuf)));
184       return (-1);
185     }
186     else if (status == 0)
187     {
188       /* Avoid "realloc returned NULL" messages */
189       INFO ("wpar plugin: perfstat_wpar_total returned zero.");
190       return (0);
191     }
192
193     /* If the number of values returned fitted into our buffer, we're done. If
194      * the number of partitions increased, we will have to try again. */
195     assert (status > 0);
196     if (status <= wpar_total_num)
197       have_data = 1;
198
199     /* If the call returned a different number than before, call realloc(3) to
200      * adjust the buffer size. */
201     if (status != wpar_total_num) /* {{{ */
202     {
203       perfstat_wpar_total_t *tmp;
204
205       tmp = realloc (wpar_total, status * sizeof (*wpar_total));
206       if (tmp == NULL)
207       {
208         /* We tried to allocate more memory. */
209         if (status > wpar_total_num)
210         {
211           ERROR ("wpar plugin: realloc(3) failed.");
212           return (ENOMEM);
213         }
214         else
215         {
216           /* decreasing the buffer size failed: Big whoop! We must adjust
217            * "wpar_total_num" though otherwise the loop below will do too much
218            * work. */
219           wpar_total_num = status;
220         }
221       }
222       else /* if (tmp != NULL) */
223       {
224         wpar_total = tmp;
225         wpar_total_num = status;
226       }
227     } /* }}} if (status != wpar_total_num) */
228   } while (!have_data)
229
230   /* Iterate over all WPARs and dispatch information */
231   for (i = 0; i < wpar_total_num; i++)
232   {
233     perfstat_id_wpar_t id_wpar;
234     const char *wname = wpar_total[i].name;
235     int status;
236
237     /* Update the ID structure */
238     memset (&id_wpar, 0, sizeof (id_wpar));
239     id_wpar.spec = WPARID;
240     id_wpar.u.wpar_id = wpar_total[i].wpar_id;
241
242     wpar_read_memory (&id_wpar, wname);
243     wpar_read_cpu_load (&id_wpar, wname);
244   }
245
246   return (0);
247 } /* }}} int wpar_read */
248
249 static int wpar_shutdown (void) /* {{{ */
250 {
251   sfree (wpar_total);
252   wpar_total_num = 0;
253
254   return (0);
255 } /* }}} int wpar_shutdown */
256
257 void module_register (void)
258 {
259   plugin_register_init ("wpar", wpar_init);
260   plugin_register_read ("wpar", wpar_read);
261   plugin_register_shutdown ("wpar", wpar_shutdown);
262 }
263
264 /* vim: set sw=2 sts=2 et fdm=marker : */