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