1 /*
2  * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #include "libperfstat_aix.hpp"
26 #include "misc_aix.hpp"
27 
28 #include <dlfcn.h>
29 
30 // Handle to the libperfstat.
31 static void* g_libhandle = NULL;
32 
33 typedef int (*fun_perfstat_cpu_total_t) (perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff,
34                                          int sizeof_userbuff, int desired_number);
35 
36 typedef int (*fun_perfstat_memory_total_t) (perfstat_id_t *name, perfstat_memory_total_t* userbuff,
37                                             int sizeof_userbuff, int desired_number);
38 
39 typedef int (*fun_perfstat_partition_total_t) (perfstat_id_t *name,
40     PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, int sizeof_userbuff,
41     int desired_number);
42 
43 typedef int (*fun_perfstat_wpar_total_t) (perfstat_id_wpar_t *name,
44     PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff, int sizeof_userbuff,
45     int desired_number);
46 
47 typedef void (*fun_perfstat_reset_t) ();
48 
49 typedef cid_t (*fun_wpar_getcid_t) ();
50 
51 static fun_perfstat_cpu_total_t     g_fun_perfstat_cpu_total = NULL;
52 static fun_perfstat_memory_total_t  g_fun_perfstat_memory_total = NULL;
53 static fun_perfstat_partition_total_t g_fun_perfstat_partition_total = NULL;
54 static fun_perfstat_wpar_total_t    g_fun_perfstat_wpar_total = NULL;
55 static fun_perfstat_reset_t         g_fun_perfstat_reset = NULL;
56 static fun_wpar_getcid_t            g_fun_wpar_getcid = NULL;
57 
init()58 bool libperfstat::init() {
59 
60   // Dynamically load the libperfstat porting library.
61   g_libhandle = dlopen("/usr/lib/libperfstat.a(shr_64.o)", RTLD_MEMBER | RTLD_NOW);
62   if (!g_libhandle) {
63     trcVerbose("Cannot load libperfstat.a (dlerror: %s)", dlerror());
64     return false;
65   }
66 
67   // Resolve function pointers
68 
69 #define RESOLVE_FUN_NO_ERROR(name) \
70   g_fun_##name = (fun_##name##_t) dlsym(g_libhandle, #name);
71 
72 #define RESOLVE_FUN(name) \
73   RESOLVE_FUN_NO_ERROR(name) \
74   if (!g_fun_##name) { \
75     trcVerbose("Cannot resolve " #name "() from libperfstat.a\n" \
76                       "   (dlerror: %s)", dlerror()); \
77     return false; \
78   }
79 
80   // These functions may or may not be there depending on the OS release.
81   RESOLVE_FUN_NO_ERROR(perfstat_partition_total);
82   RESOLVE_FUN_NO_ERROR(perfstat_wpar_total);
83   RESOLVE_FUN_NO_ERROR(wpar_getcid);
84 
85   // These functions are required for every release.
86   RESOLVE_FUN(perfstat_cpu_total);
87   RESOLVE_FUN(perfstat_memory_total);
88   RESOLVE_FUN(perfstat_reset);
89 
90   trcVerbose("libperfstat loaded.");
91 
92   return true;
93 }
94 
cleanup()95 void libperfstat::cleanup() {
96 
97   if (g_libhandle) {
98     dlclose(g_libhandle);
99     g_libhandle = NULL;
100   }
101 
102   g_fun_perfstat_cpu_total = NULL;
103   g_fun_perfstat_memory_total = NULL;
104   g_fun_perfstat_partition_total = NULL;
105   g_fun_perfstat_wpar_total = NULL;
106   g_fun_perfstat_reset = NULL;
107   g_fun_wpar_getcid = NULL;
108 
109 }
110 
perfstat_memory_total(perfstat_id_t * name,perfstat_memory_total_t * userbuff,int sizeof_userbuff,int desired_number)111 int libperfstat::perfstat_memory_total(perfstat_id_t *name,
112                                        perfstat_memory_total_t* userbuff,
113                                        int sizeof_userbuff, int desired_number) {
114   if (g_fun_perfstat_memory_total == NULL) {
115     return -1;
116   }
117   return g_fun_perfstat_memory_total(name, userbuff, sizeof_userbuff, desired_number);
118 }
119 
perfstat_cpu_total(perfstat_id_t * name,PERFSTAT_CPU_TOTAL_T_LATEST * userbuff,int sizeof_userbuff,int desired_number)120 int libperfstat::perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff,
121                                     int sizeof_userbuff, int desired_number) {
122   if (g_fun_perfstat_cpu_total == NULL) {
123     return -1;
124   }
125   return g_fun_perfstat_cpu_total(name, userbuff, sizeof_userbuff, desired_number);
126 }
127 
perfstat_partition_total(perfstat_id_t * name,PERFSTAT_PARTITON_TOTAL_T_LATEST * userbuff,int sizeof_userbuff,int desired_number)128 int libperfstat::perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff,
129                                           int sizeof_userbuff, int desired_number) {
130   if (g_fun_perfstat_partition_total == NULL) {
131     return -1;
132   }
133   return g_fun_perfstat_partition_total(name, userbuff, sizeof_userbuff, desired_number);
134 }
135 
perfstat_wpar_total(perfstat_id_wpar_t * name,PERFSTAT_WPAR_TOTAL_T_LATEST * userbuff,int sizeof_userbuff,int desired_number)136 int libperfstat::perfstat_wpar_total(perfstat_id_wpar_t *name, PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff,
137                                      int sizeof_userbuff, int desired_number) {
138   if (g_fun_perfstat_wpar_total == NULL) {
139     return -1;
140   }
141   return g_fun_perfstat_wpar_total(name, userbuff, sizeof_userbuff, desired_number);
142 }
143 
perfstat_reset()144 void libperfstat::perfstat_reset() {
145   if (g_fun_perfstat_reset != NULL) {
146     g_fun_perfstat_reset();
147   }
148 }
149 
wpar_getcid()150 cid_t libperfstat::wpar_getcid() {
151   if (g_fun_wpar_getcid == NULL) {
152     return (cid_t) -1;
153   }
154   return g_fun_wpar_getcid();
155 }
156 
157 
158 //////////////////// convenience functions, release-independent /////////////////////////////
159 
160 
161 // Retrieve global cpu information.
get_cpuinfo(cpuinfo_t * pci)162 bool libperfstat::get_cpuinfo(cpuinfo_t* pci) {
163 
164   assert(pci, "get_cpuinfo: invalid parameter");
165   memset(pci, 0, sizeof(cpuinfo_t));
166 
167   PERFSTAT_CPU_TOTAL_T_LATEST psct;
168   memset (&psct, '\0', sizeof(psct));
169 
170   if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(PERFSTAT_CPU_TOTAL_T_LATEST), 1)) {
171     if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t_71), 1)) {
172       if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t_61), 1)) {
173         if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t_53), 1)) {
174           trcVerbose("perfstat_cpu_total() failed (errno=%d)", errno);
175           return false;
176         }
177       }
178     }
179   }
180 
181   // Global cpu information.
182   strcpy(pci->description, psct.description);
183   pci->processorHZ = psct.processorHZ;
184   pci->ncpus = psct.ncpus;
185   for (int i = 0; i < 3; i++) {
186     pci->loadavg[i] = (double) psct.loadavg[i] / (1 << SBITS);
187   }
188 
189   pci->user_clock_ticks = psct.user;
190   pci->sys_clock_ticks  = psct.sys;
191   pci->idle_clock_ticks = psct.idle;
192   pci->wait_clock_ticks = psct.wait;
193 
194   return true;
195 }
196 
197 // Retrieve partition information.
get_partitioninfo(partitioninfo_t * ppi)198 bool libperfstat::get_partitioninfo(partitioninfo_t* ppi) {
199 
200   assert(ppi, "get_partitioninfo: invalid parameter");
201   memset(ppi, 0, sizeof(partitioninfo_t));
202 
203   PERFSTAT_PARTITON_TOTAL_T_LATEST pspt;
204   memset(&pspt, '\0', sizeof(pspt));
205 
206   bool ame_details = true;
207 
208   if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(PERFSTAT_PARTITON_TOTAL_T_LATEST), 1)) {
209     if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_71), 1)) {
210       ame_details = false;
211       if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_61), 1)) {
212         if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_53), 1)) {
213           if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_53_5), 1)) {
214             trcVerbose("perfstat_partition_total() failed (errno=%d)", errno);
215             return false;
216           }
217         }
218       }
219     }
220   }
221 
222   // partition type info
223   ppi->shared_enabled = pspt.type.b.shared_enabled;
224   ppi->smt_capable = pspt.type.b.smt_capable;
225   ppi->smt_enabled = pspt.type.b.smt_enabled;
226   ppi->lpar_capable = pspt.type.b.lpar_capable;
227   ppi->lpar_enabled = pspt.type.b.lpar_enabled;
228   ppi->dlpar_capable = pspt.type.b.dlpar_capable;
229   ppi->capped = pspt.type.b.capped;
230   ppi->kernel_is_64 = pspt.type.b.kernel_is_64;
231   ppi->pool_util_authority = pspt.type.b.pool_util_authority;
232   ppi->donate_capable = pspt.type.b.donate_capable;
233   ppi->donate_enabled = pspt.type.b.donate_enabled;
234   ppi->ams_capable = pspt.type.b.ams_capable;
235   ppi->ams_enabled = pspt.type.b.ams_enabled;
236   ppi->power_save = pspt.type.b.power_save;
237   ppi->ame_enabled = pspt.type.b.ame_enabled;
238 
239   // partition total info
240   ppi->online_cpus = pspt.online_cpus;
241   ppi->entitled_proc_capacity = pspt.entitled_proc_capacity;
242   ppi->var_proc_capacity_weight = pspt.var_proc_capacity_weight;
243   ppi->phys_cpus_pool = pspt.phys_cpus_pool;
244   ppi->pool_id = pspt.pool_id;
245   ppi->entitled_pool_capacity = pspt.entitled_pool_capacity;
246   strcpy(ppi->name, pspt.name);
247 
248   // Added values to ppi that we need for later computation of cpu utilization
249   // ( pool authorization needed for pool_idle_time ??? )
250   ppi->timebase_last   = pspt.timebase_last;
251   ppi->pool_idle_time  = pspt.pool_idle_time;
252   ppi->pcpu_tics_user  = pspt.puser;
253   ppi->pcpu_tics_sys   = pspt.psys;
254   ppi->pcpu_tics_idle  = pspt.pidle;
255   ppi->pcpu_tics_wait  = pspt.pwait;
256 
257   // Additional AME information.
258   if (ame_details) {
259     ppi->true_memory = pspt.true_memory * 4096;
260     ppi->expanded_memory = pspt.expanded_memory * 4096;
261     ppi->target_memexp_factr = pspt.target_memexp_factr;
262     ppi->current_memexp_factr = pspt.current_memexp_factr;
263     ppi->cmcs_total_time = pspt.cmcs_total_time;
264   }
265 
266   return true;
267 }
268 
269 // Retrieve wpar information.
get_wparinfo(wparinfo_t * pwi)270 bool libperfstat::get_wparinfo(wparinfo_t* pwi) {
271 
272   assert(pwi, "get_wparinfo: invalid parameter");
273   memset(pwi, 0, sizeof(wparinfo_t));
274 
275   if (libperfstat::wpar_getcid() <= 0) {
276     return false;
277   }
278 
279   PERFSTAT_WPAR_TOTAL_T_LATEST pswt;
280   memset (&pswt, '\0', sizeof(pswt));
281 
282   if (-1 == libperfstat::perfstat_wpar_total(NULL, &pswt, sizeof(PERFSTAT_WPAR_TOTAL_T_LATEST), 1)) {
283     if (-1 == libperfstat::perfstat_wpar_total(NULL, &pswt, sizeof(perfstat_wpar_total_t_61), 1)) {
284       trcVerbose("perfstat_wpar_total() failed (errno=%d)", errno);
285       return false;
286     }
287   }
288 
289   // WPAR type info.
290   pwi->app_wpar = pswt.type.b.app_wpar;
291   pwi->cpu_rset = pswt.type.b.cpu_rset;
292   pwi->cpu_xrset = pswt.type.b.cpu_xrset;
293   pwi->cpu_limits = pswt.type.b.cpu_limits;
294   pwi->mem_limits = pswt.type.b.mem_limits;
295   // WPAR total info.
296   strcpy(pwi->name, pswt.name);
297   pwi->wpar_id = pswt.wpar_id;
298   pwi->cpu_limit = pswt.cpu_limit;
299   pwi->mem_limit = pswt.mem_limit;
300 
301   return true;
302 }
303