author | stuefe |
Mon, 16 Nov 2015 10:58:14 +0100 | |
changeset 34647 | fafb32d71489 |
parent 34646 | e2442a5c90e4 |
child 34648 | b7ea5d095ef5 |
--- a/hotspot/src/os/aix/vm/globals_aix.hpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/globals_aix.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -29,37 +29,61 @@ // // Defines Aix specific flags. They are not available on other platforms. // +// (Please keep the switches sorted alphabetically.) #define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \ \ + /* Whether to allow the VM to run if EXTSHM=ON. EXTSHM is an environment */ \ + /* variable used on AIX to activate certain hacks which allow more shm segments */\ + /* for 32bit processes. For 64bit processes, it is pointless and may have */ \ + /* harmful side effects (e.g. for some reasonn prevents allocation of 64k pages */\ + /* via shmctl). */ \ + /* Per default we quit with an error if that variable is found; for certain */ \ + /* customer scenarios, we may want to be able to run despite that variable. */ \ + product(bool, AllowExtshm, false, \ + "Allow VM to run with EXTSHM=ON.") \ + \ + product(intx, AttachListenerTimeout, 1000, \ + "Timeout in ms the attach listener waits for a request") \ + range(0, 2147483) \ + \ + /* Maximum expected size of the data segment. That correlates with the */ \ + /* to the maximum C Heap consumption we expect. */ \ + /* We need to know this because we need to leave "breathing space" for the */ \ + /* data segment when placing the java heap. If that space is too small, we */ \ + /* reduce our chance of getting a low heap address (needed for compressed */ \ + /* Oops). */ \ + product(uintx, MaxExpectedDataSegmentSize, (SIZE_4G * 2), \ + "Maximum expected Data Segment Size.") \ + \ + /* Use optimized addresses for the polling page. */ \ + product(bool, OptimizePollingPageLocation, true, \ + "Optimize the location of the polling page used for Safepoints") \ + \ /* Use 64K pages for virtual memory (shmat). */ \ product(bool, Use64KPages, true, \ "Use 64K pages if available.") \ \ - /* If UseLargePages == true allow or deny usage of 16M pages. 16M pages are */ \ - /* a scarce resource and there may be situations where we do not want the VM */ \ - /* to run with 16M pages. (Will fall back to 64K pages). */ \ - product_pd(bool, Use16MPages, \ - "Use 16M pages if available.") \ + /* If VM uses 64K paged memory (shmat) for virtual memory: threshold below */ \ + /* which virtual memory allocations are done with 4K memory (mmap). This is */ \ + /* mainly for test purposes. */ \ + develop(uintx, Use64KPagesThreshold, 0, \ + "4K/64K page allocation threshold.") \ \ - /* use optimized addresses for the polling page, */ \ - /* e.g. map it to a special 32-bit address. */ \ - product_pd(bool, OptimizePollingPageLocation, \ - "Optimize the location of the polling page used for Safepoints") \ - \ - product_pd(intx, AttachListenerTimeout, \ - "Timeout in ms the attach listener waits for a request") \ - range(0, 2147483) \ + /* Normally AIX commits memory on touch, but sometimes it is helpful to have */ \ + /* explicit commit behaviour. This flag, if true, causes the VM to touch */ \ + /* memory on os::commit_memory() (which normally is a noop). */ \ + product(bool, UseExplicitCommit, false, \ + "Explicit commit for virtual memory.") \ \ -// Per default, do not allow 16M pages. 16M pages have to be switched on specifically. -define_pd_global(bool, Use16MPages, false); -define_pd_global(bool, OptimizePollingPageLocation, true); -define_pd_global(intx, AttachListenerTimeout, 1000); // // Defines Aix-specific default values. The flags are available on all // platforms, but they may have different default values on other platforms. // + +// UseLargePages means nothing, for now, on AIX. +// Use Use64KPages or Use16MPages instead. define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, false); define_pd_global(bool, UseOSErrorReporting, false);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/aix/vm/libo4.cpp Mon Nov 16 10:58:14 2015 +0100 @@ -0,0 +1,38 @@ +/* + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// This is only a stub. Will flesh out later when/if we add further support +// for PASE. + +#include "libo4.hpp" + +bool libo4::init() { return false; } +void libo4::cleanup() {} +bool libo4::get_memory_info (unsigned long long* p_virt_total, unsigned long long* p_real_total, + unsigned long long* p_real_free, unsigned long long* p_pgsp_total, unsigned long long* p_pgsp_free) { + return false; +} +bool libo4::get_load_avg (double* p_avg1, double* p_avg5, double* p_avg15) { return false; } +bool libo4::realpath (const char* file_name, char* resolved_name, int resolved_name_len) { return false; } +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/aix/vm/libo4.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright 2012, 2015 SAP AG. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// A C++ wrapper around the libo4 porting library. The libo4 porting library +// is a set of bridge functions into native AS/400 functionality. + +#ifndef OS_AIX_VM_LIBO4_HPP +#define OS_AIX_VM_LIBO4_HPP + + +class libo4 { +public: + + // Initialize the libo4 porting library. + // Returns true if succeeded, false if error. + static bool init(); + + // cleanup of the libo4 porting library. + static void cleanup(); + + // returns a number of memory statistics from the + // AS/400. + // + // Specify NULL for numbers you are not interested in. + // + // returns false if an error happened. Activate OsMisc trace for + // trace output. + // + static bool get_memory_info (unsigned long long* p_virt_total, unsigned long long* p_real_total, + unsigned long long* p_real_free, unsigned long long* p_pgsp_total, unsigned long long* p_pgsp_free); + + // returns information about system load + // (similar to "loadavg()" under other Unices) + // + // Specify NULL for numbers you are not interested in. + // + // returns false if an error happened. Activate OsMisc trace for + // trace output. + // + static bool get_load_avg (double* p_avg1, double* p_avg5, double* p_avg15); + + // this is a replacement for the "realpath()" API which does not really work + // on PASE + // + // Specify NULL for numbers you are not interested in. + // + // returns false if an error happened. Activate OsMisc trace for + // trace output. + // + static bool realpath (const char* file_name, + char* resolved_name, int resolved_name_len); + +}; + +#endif // OS_AIX_VM_LIBO4_HPP +
--- a/hotspot/src/os/aix/vm/libperfstat_aix.cpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/libperfstat_aix.cpp Mon Nov 16 10:58:14 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,49 +22,50 @@ * */ -#include "runtime/arguments.hpp" #include "libperfstat_aix.hpp" +#include "misc_aix.hpp" -// For dlopen and friends -#include <fcntl.h> +#include <dlfcn.h> +#include <sys/systemcfg.h> -// handle to the libperfstat +// Handle to the libperfstat. static void* g_libhandle = NULL; -// whether initialization worked -static bool g_initialized = false; - - -typedef int (*fun_perfstat_cpu_total_t) (perfstat_id_t *name, perfstat_cpu_total_t* userbuff, +typedef int (*fun_perfstat_cpu_total_t) (perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number); typedef int (*fun_perfstat_memory_total_t) (perfstat_id_t *name, perfstat_memory_total_t* userbuff, int sizeof_userbuff, int desired_number); +typedef int (*fun_perfstat_partition_total_t) (perfstat_id_t *name, + PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, + int desired_number); + +typedef int (*fun_perfstat_wpar_total_t) (perfstat_id_wpar_t *name, + PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, + int desired_number); + typedef void (*fun_perfstat_reset_t) (); +typedef cid_t (*fun_wpar_getcid_t) (); + static fun_perfstat_cpu_total_t g_fun_perfstat_cpu_total = NULL; static fun_perfstat_memory_total_t g_fun_perfstat_memory_total = NULL; +static fun_perfstat_partition_total_t g_fun_perfstat_partition_total = NULL; +static fun_perfstat_wpar_total_t g_fun_perfstat_wpar_total = NULL; static fun_perfstat_reset_t g_fun_perfstat_reset = NULL; +static fun_wpar_getcid_t g_fun_wpar_getcid = NULL; bool libperfstat::init() { - if (g_initialized) { - return true; - } - - g_initialized = false; - - // dynamically load the libperfstat porting library. + // Dynamically load the libperfstat porting library. g_libhandle = dlopen("/usr/lib/libperfstat.a(shr_64.o)", RTLD_MEMBER | RTLD_NOW); if (!g_libhandle) { - if (Verbose) { - fprintf(stderr, "Cannot load libperfstat.a (dlerror: %s)", dlerror()); - } + trcVerbose("Cannot load libperfstat.a (dlerror: %s)", dlerror()); return false; } - // resolve function pointers + // Resolve function pointers #define RESOLVE_FUN_NO_ERROR(name) \ g_fun_##name = (fun_##name##_t) dlsym(g_libhandle, #name); @@ -72,26 +73,28 @@ #define RESOLVE_FUN(name) \ RESOLVE_FUN_NO_ERROR(name) \ if (!g_fun_##name) { \ - if (Verbose) { \ - fprintf(stderr, "Cannot resolve " #name "() from libperfstat.a\n" \ + trcVerbose("Cannot resolve " #name "() from libperfstat.a\n" \ " (dlerror: %s)", dlerror()); \ - } \ return false; \ } + // These functions may or may not be there depending on the OS release. + RESOLVE_FUN_NO_ERROR(perfstat_partition_total); + RESOLVE_FUN_NO_ERROR(perfstat_wpar_total); + RESOLVE_FUN_NO_ERROR(wpar_getcid); + + // These functions are required for every release. RESOLVE_FUN(perfstat_cpu_total); RESOLVE_FUN(perfstat_memory_total); RESOLVE_FUN(perfstat_reset); - g_initialized = true; + trcVerbose("libperfstat loaded."); return true; } void libperfstat::cleanup() { - g_initialized = false; - if (g_libhandle) { dlclose(g_libhandle); g_libhandle = NULL; @@ -99,26 +102,250 @@ g_fun_perfstat_cpu_total = NULL; g_fun_perfstat_memory_total = NULL; + g_fun_perfstat_partition_total = NULL; + g_fun_perfstat_wpar_total = NULL; g_fun_perfstat_reset = NULL; + g_fun_wpar_getcid = NULL; + } int libperfstat::perfstat_memory_total(perfstat_id_t *name, perfstat_memory_total_t* userbuff, int sizeof_userbuff, int desired_number) { - assert(g_initialized, "libperfstat not initialized"); - assert(g_fun_perfstat_memory_total, ""); + if (g_fun_perfstat_memory_total == NULL) { + return -1; + } return g_fun_perfstat_memory_total(name, userbuff, sizeof_userbuff, desired_number); } -int libperfstat::perfstat_cpu_total(perfstat_id_t *name, perfstat_cpu_total_t* userbuff, +int libperfstat::perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number) { - assert(g_initialized, "libperfstat not initialized"); - assert(g_fun_perfstat_cpu_total, ""); + if (g_fun_perfstat_cpu_total == NULL) { + return -1; + } return g_fun_perfstat_cpu_total(name, userbuff, sizeof_userbuff, desired_number); } +int libperfstat::perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_partition_total == NULL) { + return -1; + } + return g_fun_perfstat_partition_total(name, userbuff, sizeof_userbuff, desired_number); +} + +int libperfstat::perfstat_wpar_total(perfstat_id_wpar_t *name, PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number) { + if (g_fun_perfstat_wpar_total == NULL) { + return -1; + } + return g_fun_perfstat_wpar_total(name, userbuff, sizeof_userbuff, desired_number); +} + void libperfstat::perfstat_reset() { - assert(g_initialized, "libperfstat not initialized"); - assert(g_fun_perfstat_reset, ""); - g_fun_perfstat_reset(); + if (g_fun_perfstat_reset != NULL) { + g_fun_perfstat_reset(); + } +} + +cid_t libperfstat::wpar_getcid() { + if (g_fun_wpar_getcid == NULL) { + return (cid_t) -1; + } + return g_fun_wpar_getcid(); +} + + +//////////////////// convenience functions, release-independent ///////////////////////////// + +// Excerpts from systemcfg.h definitions newer than AIX 5.3 (our oldest build platform) + +#define PV_6 0x100000 /* Power PC 6 */ +#define PV_6_1 0x100001 /* Power PC 6 DD1.x */ +#define PV_7 0x200000 /* Power PC 7 */ +#define PV_5_Compat 0x0F8000 /* Power PC 5 */ +#define PV_6_Compat 0x108000 /* Power PC 6 */ +#define PV_7_Compat 0x208000 /* Power PC 7 */ +#define PV_8 0x300000 /* Power PC 8 */ +#define PV_8_Compat 0x308000 /* Power PC 8 */ + + +// Retrieve global cpu information. +bool libperfstat::get_cpuinfo(cpuinfo_t* pci) { + + assert(pci, "get_cpuinfo: invalid parameter"); + memset(pci, 0, sizeof(cpuinfo_t)); + + PERFSTAT_CPU_TOTAL_T_LATEST psct; + memset (&psct, '\0', sizeof(psct)); + + if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(PERFSTAT_CPU_TOTAL_T_LATEST), 1)) { + if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t_61), 1)) { + if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t_53), 1)) { + trcVerbose("perfstat_cpu_total() failed (errno=%d)", errno); + return false; + } + } + } + + // Global cpu information. + strcpy (pci->description, psct.description); + pci->processorHZ = psct.processorHZ; + pci->ncpus = psct.ncpus; + for (int i = 0; i < 3; i++) { + pci->loadavg[i] = (double) psct.loadavg[i] / (1 << SBITS); + } + + pci->user_clock_ticks = psct.user; + pci->sys_clock_ticks = psct.sys; + pci->idle_clock_ticks = psct.idle; + pci->wait_clock_ticks = psct.wait; + + // Get the processor version from _system_configuration. + switch (_system_configuration.version) { + case PV_8: + strcpy(pci->version, "Power PC 8"); + break; + case PV_7: + strcpy(pci->version, "Power PC 7"); + break; + case PV_6_1: + strcpy(pci->version, "Power PC 6 DD1.x"); + break; + case PV_6: + strcpy(pci->version, "Power PC 6"); + break; + case PV_5: + strcpy(pci->version, "Power PC 5"); + break; + case PV_5_2: + strcpy(pci->version, "Power PC 5_2"); + break; + case PV_5_3: + strcpy(pci->version, "Power PC 5_3"); + break; + case PV_5_Compat: + strcpy(pci->version, "PV_5_Compat"); + break; + case PV_6_Compat: + strcpy(pci->version, "PV_6_Compat"); + break; + case PV_7_Compat: + strcpy(pci->version, "PV_7_Compat"); + break; + case PV_8_Compat: + strcpy(pci->version, "PV_8_Compat"); + break; + default: + strcpy(pci->version, "unknown"); + } + + return true; } + +// Retrieve partition information. +bool libperfstat::get_partitioninfo(partitioninfo_t* ppi) { + + assert(ppi, "get_partitioninfo: invalid parameter"); + memset(ppi, 0, sizeof(partitioninfo_t)); + + PERFSTAT_PARTITON_TOTAL_T_LATEST pspt; + memset(&pspt, '\0', sizeof(pspt)); + + bool ame_details = true; + + if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(PERFSTAT_PARTITON_TOTAL_T_LATEST), 1)) { + if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_71), 1)) { + ame_details = false; + if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_61), 1)) { + if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_53), 1)) { + if (-1 == libperfstat::perfstat_partition_total(NULL, &pspt, sizeof(perfstat_partition_total_t_53_5), 1)) { + trcVerbose("perfstat_partition_total() failed (errno=%d)", errno); + return false; + } + } + } + } + } + + // partition type info + ppi->shared_enabled = pspt.type.b.shared_enabled; + ppi->smt_capable = pspt.type.b.smt_capable; + ppi->smt_enabled = pspt.type.b.smt_enabled; + ppi->lpar_capable = pspt.type.b.lpar_capable; + ppi->lpar_enabled = pspt.type.b.lpar_enabled; + ppi->dlpar_capable = pspt.type.b.dlpar_capable; + ppi->capped = pspt.type.b.capped; + ppi->kernel_is_64 = pspt.type.b.kernel_is_64; + ppi->pool_util_authority = pspt.type.b.pool_util_authority; + ppi->donate_capable = pspt.type.b.donate_capable; + ppi->donate_enabled = pspt.type.b.donate_enabled; + ppi->ams_capable = pspt.type.b.ams_capable; + ppi->ams_enabled = pspt.type.b.ams_enabled; + ppi->power_save = pspt.type.b.power_save; + ppi->ame_enabled = pspt.type.b.ame_enabled; + + // partition total info + ppi->online_cpus = pspt.online_cpus; + ppi->entitled_proc_capacity = pspt.entitled_proc_capacity; + ppi->var_proc_capacity_weight = pspt.var_proc_capacity_weight; + ppi->phys_cpus_pool = pspt.phys_cpus_pool; + ppi->pool_id = pspt.pool_id; + ppi->entitled_pool_capacity = pspt.entitled_pool_capacity; + strcpy(ppi->name, pspt.name); + + // Added values to ppi that we need for later computation of cpu utilization + // ( pool authorization needed for pool_idle_time ??? ) + ppi->timebase_last = pspt.timebase_last; + ppi->pool_idle_time = pspt.pool_idle_time; + ppi->pcpu_tics_user = pspt.puser; + ppi->pcpu_tics_sys = pspt.psys; + ppi->pcpu_tics_idle = pspt.pidle; + ppi->pcpu_tics_wait = pspt.pwait; + + // Additional AME information. + if (ame_details) { + ppi->true_memory = pspt.true_memory * 4096; + ppi->expanded_memory = pspt.expanded_memory * 4096; + ppi->target_memexp_factr = pspt.target_memexp_factr; + ppi->current_memexp_factr = pspt.current_memexp_factr; + ppi->cmcs_total_time = pspt.cmcs_total_time; + } + + return true; +} + +// Retrieve wpar information. +bool libperfstat::get_wparinfo(wparinfo_t* pwi) { + + assert(pwi, "get_wparinfo: invalid parameter"); + memset(pwi, 0, sizeof(wparinfo_t)); + + if (libperfstat::wpar_getcid() <= 0) { + return false; + } + + PERFSTAT_WPAR_TOTAL_T_LATEST pswt; + memset (&pswt, '\0', sizeof(pswt)); + + if (-1 == libperfstat::perfstat_wpar_total(NULL, &pswt, sizeof(PERFSTAT_WPAR_TOTAL_T_LATEST), 1)) { + if (-1 == libperfstat::perfstat_wpar_total(NULL, &pswt, sizeof(perfstat_wpar_total_t_61), 1)) { + trcVerbose("perfstat_wpar_total() failed (errno=%d)", errno); + return false; + } + } + + // WPAR type info. + pwi->app_wpar = pswt.type.b.app_wpar; + pwi->cpu_rset = pswt.type.b.cpu_rset; + pwi->cpu_xrset = pswt.type.b.cpu_xrset; + pwi->cpu_limits = pswt.type.b.cpu_limits; + pwi->mem_limits = pswt.type.b.mem_limits; + // WPAR total info. + strcpy(pwi->name, pswt.name); + pwi->wpar_id = pswt.wpar_id; + pwi->cpu_limit = pswt.cpu_limit; + pwi->mem_limit = pswt.mem_limit; + + return true; +}
--- a/hotspot/src/os/aix/vm/libperfstat_aix.hpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/libperfstat_aix.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -22,7 +22,7 @@ * */ -// encapsulates the libperfstat library. +// Encapsulates the libperfstat library. // // The purpose of this code is to dynamically load the libperfstat library // instead of statically linking against it. The libperfstat library is an @@ -32,7 +32,732 @@ #ifndef OS_AIX_VM_LIBPERFSTAT_AIX_HPP #define OS_AIX_VM_LIBPERFSTAT_AIX_HPP -#include <libperfstat.h> +#include <sys/types.h> +#include <stdlib.h> + +/////////////////////////////////////////////////////////////////////////////////////////////// +// These are excerpts from the AIX 5.3, 6.1, 7.1 libperfstat.h - +// this is all we need from libperfstat.h and I want to avoid having to include <libperfstat.h> +// +// Note: I define all structures as if I were to include libperfstat.h on an AIX 5.2 +// build machine. +// +// The ratio behind that is that if I would build on an AIX 5.2 build machine, +// include libperfstat.h and hard-link against libperfstat.a, the program should +// work without recompilation on all newer AIX versions. +// + +#define IDENTIFIER_LENGTH 64 /* length of strings included in the structures */ + + +typedef struct { /* structure element identifier */ + char name[IDENTIFIER_LENGTH]; /* name of the identifier */ +} perfstat_id_t; + +#define CEC_ID_LEN 40 /* CEC identifier length */ +#define MAXCORRALNAMELEN 25 /* length of the wpar name */ +#define FIRST_WPARNAME "" /* pseudo-name for the first WPAR */ +#define FIRST_WPARID -1 /* pseudo-id for the first WPAR */ + +typedef unsigned short cid_t; /* workload partition identifier */ + +typedef struct { /* Virtual memory utilization */ + u_longlong_t virt_total; /* total virtual memory (in 4KB pages) */ + u_longlong_t real_total; /* total real memory (in 4KB pages) */ + u_longlong_t real_free; /* free real memory (in 4KB pages) */ + u_longlong_t real_pinned; /* real memory which is pinned (in 4KB pages) */ + u_longlong_t real_inuse; /* real memory which is in use (in 4KB pages) */ + u_longlong_t pgbad; /* number of bad pages */ + u_longlong_t pgexct; /* number of page faults */ + u_longlong_t pgins; /* number of pages paged in */ + u_longlong_t pgouts; /* number of pages paged out */ + u_longlong_t pgspins; /* number of page ins from paging space */ + u_longlong_t pgspouts; /* number of page outs from paging space */ + u_longlong_t scans; /* number of page scans by clock */ + u_longlong_t cycles; /* number of page replacement cycles */ + u_longlong_t pgsteals; /* number of page steals */ + u_longlong_t numperm; /* number of frames used for files (in 4KB pages) */ + u_longlong_t pgsp_total; /* total paging space (in 4KB pages) */ + u_longlong_t pgsp_free; /* free paging space (in 4KB pages) */ + u_longlong_t pgsp_rsvd; /* reserved paging space (in 4KB pages) */ + u_longlong_t real_system; /* real memory used by system segments (in 4KB pages). This is the sum of all the used pages in segment marked for system usage. + * Since segment classifications are not always guaranteed to be accurate, this number is only an approximation. */ + u_longlong_t real_user; /* real memory used by non-system segments (in 4KB pages). This is the sum of all pages used in segments not marked for system usage. + * Since segment classifications are not always guaranteed to be accurate, this number is only an approximation. */ + u_longlong_t real_process; /* real memory used by process segments (in 4KB pages). This is real_total-real_free-numperm-real_system. Since real_system is an + * approximation, this number is too. */ + u_longlong_t virt_active; /* Active virtual pages. Virtual pages are considered active if they have been accessed */ + +} perfstat_memory_total_t; + +typedef struct { /* global cpu information AIX 5.3 < TL10 */ + int ncpus; /* number of active logical processors */ + int ncpus_cfg; /* number of configured processors */ + char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */ + u_longlong_t processorHZ; /* processor speed in Hz */ + u_longlong_t user; /* raw total number of clock ticks spent in user mode */ + u_longlong_t sys; /* raw total number of clock ticks spent in system mode */ + u_longlong_t idle; /* raw total number of clock ticks spent idle */ + u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */ + u_longlong_t pswitch; /* number of process switches (change in currently running process) */ + u_longlong_t syscall; /* number of system calls executed */ + u_longlong_t sysread; /* number of read system calls executed */ + u_longlong_t syswrite; /* number of write system calls executed */ + u_longlong_t sysfork; /* number of forks system calls executed */ + u_longlong_t sysexec; /* number of execs system calls executed */ + u_longlong_t readch; /* number of characters tranferred with read system call */ + u_longlong_t writech; /* number of characters tranferred with write system call */ + u_longlong_t devintrs; /* number of device interrupts */ + u_longlong_t softintrs; /* number of software interrupts */ + time_t lbolt; /* number of ticks since last reboot */ + u_longlong_t loadavg[3]; /* (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes. + * To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. */ + u_longlong_t runque; /* length of the run queue (processes ready) */ + u_longlong_t swpque; /* ength of the swap queue (processes waiting to be paged in) */ + u_longlong_t bread; /* number of blocks read */ + u_longlong_t bwrite; /* number of blocks written */ + u_longlong_t lread; /* number of logical read requests */ + u_longlong_t lwrite; /* number of logical write requests */ + u_longlong_t phread; /* number of physical reads (reads on raw devices) */ + u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */ + u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied. + * This can be used to compute the simple average of ready processes */ + u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied. + * This can be used to compute the simple average processes waiting to be paged in */ + u_longlong_t iget; /* number of inode lookups */ + u_longlong_t namei; /* number of vnode lookup from a path name */ + u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */ + u_longlong_t msg; /* number of IPC message operations */ + u_longlong_t sema; /* number of IPC semaphore operations */ + u_longlong_t rcvint; /* number of tty receive interrupts */ + u_longlong_t xmtint; /* number of tyy transmit interrupts */ + u_longlong_t mdmint; /* number of modem interrupts */ + u_longlong_t tty_rawinch; /* number of raw input characters */ + u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */ + u_longlong_t tty_rawoutch; /* number of raw output characters */ + u_longlong_t ksched; /* number of kernel processes created */ + u_longlong_t koverf; /* kernel process creation attempts where: + * -the user has forked to their maximum limit + * -the configuration limit of processes has been reached */ + u_longlong_t kexit; /* number of kernel processes that became zombies */ + u_longlong_t rbread; /* number of remote read requests */ + u_longlong_t rcread; /* number of cached remote reads */ + u_longlong_t rbwrt; /* number of remote writes */ + u_longlong_t rcwrt; /* number of cached remote writes */ + u_longlong_t traps; /* number of traps */ + int ncpus_high; /* index of highest processor online */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t decrintrs; /* number of decrementer tics interrupts */ + u_longlong_t mpcrintrs; /* number of mpc's received interrupts */ + u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */ + u_longlong_t phantintrs; /* number of phantom interrupts */ + u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ + short iowait; /* number of processes that are asleep waiting for buffered I/O */ + short physio; /* number of processes waiting for raw I/O */ + longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */ + u_longlong_t hpi; /* number of hypervisor page-ins */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */ +} perfstat_cpu_total_t_53; + +typedef struct { /* global cpu information AIX 6.1|5.3 > TL09 */ + int ncpus; /* number of active logical processors */ + int ncpus_cfg; /* number of configured processors */ + char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */ + u_longlong_t processorHZ; /* processor speed in Hz */ + u_longlong_t user; /* raw total number of clock ticks spent in user mode */ + u_longlong_t sys; /* raw total number of clock ticks spent in system mode */ + u_longlong_t idle; /* raw total number of clock ticks spent idle */ + u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */ + u_longlong_t pswitch; /* number of process switches (change in currently running process) */ + u_longlong_t syscall; /* number of system calls executed */ + u_longlong_t sysread; /* number of read system calls executed */ + u_longlong_t syswrite; /* number of write system calls executed */ + u_longlong_t sysfork; /* number of forks system calls executed */ + u_longlong_t sysexec; /* number of execs system calls executed */ + u_longlong_t readch; /* number of characters tranferred with read system call */ + u_longlong_t writech; /* number of characters tranferred with write system call */ + u_longlong_t devintrs; /* number of device interrupts */ + u_longlong_t softintrs; /* number of software interrupts */ + time_t lbolt; /* number of ticks since last reboot */ + u_longlong_t loadavg[3]; /* (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes. + * To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. */ + u_longlong_t runque; /* length of the run queue (processes ready) */ + u_longlong_t swpque; /* length of the swap queue (processes waiting to be paged in) */ + u_longlong_t bread; /* number of blocks read */ + u_longlong_t bwrite; /* number of blocks written */ + u_longlong_t lread; /* number of logical read requests */ + u_longlong_t lwrite; /* number of logical write requests */ + u_longlong_t phread; /* number of physical reads (reads on raw devices) */ + u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */ + u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied. + * This can be used to compute the simple average of ready processes */ + u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied. + * This can be used to compute the simple average processes waiting to be paged in */ + u_longlong_t iget; /* number of inode lookups */ + u_longlong_t namei; /* number of vnode lookup from a path name */ + u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */ + u_longlong_t msg; /* number of IPC message operations */ + u_longlong_t sema; /* number of IPC semaphore operations */ + u_longlong_t rcvint; /* number of tty receive interrupts */ + u_longlong_t xmtint; /* number of tyy transmit interrupts */ + u_longlong_t mdmint; /* number of modem interrupts */ + u_longlong_t tty_rawinch; /* number of raw input characters */ + u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */ + u_longlong_t tty_rawoutch; /* number of raw output characters */ + u_longlong_t ksched; /* number of kernel processes created */ + u_longlong_t koverf; /* kernel process creation attempts where: + * -the user has forked to their maximum limit + * -the configuration limit of processes has been reached */ + u_longlong_t kexit; /* number of kernel processes that became zombies */ + u_longlong_t rbread; /* number of remote read requests */ + u_longlong_t rcread; /* number of cached remote reads */ + u_longlong_t rbwrt; /* number of remote writes */ + u_longlong_t rcwrt; /* number of cached remote writes */ + u_longlong_t traps; /* number of traps */ + int ncpus_high; /* index of highest processor online */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t decrintrs; /* number of decrementer tics interrupts */ + u_longlong_t mpcrintrs; /* number of mpc's received interrupts */ + u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */ + u_longlong_t phantintrs; /* number of phantom interrupts */ + u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ + short iowait; /* number of processes that are asleep waiting for buffered I/O */ + short physio; /* number of processes waiting for raw I/O */ + longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */ + u_longlong_t hpi; /* number of hypervisor page-ins */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */ + u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */ + u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */ + u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */ + u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */ + int spurrflag; /* set if running in spurr mode */ +} perfstat_cpu_total_t_61; + +typedef struct { /* global cpu information AIX 7.1 */ + int ncpus; /* number of active logical processors */ + int ncpus_cfg; /* number of configured processors */ + char description[IDENTIFIER_LENGTH]; /* processor description (type/official name) */ + u_longlong_t processorHZ; /* processor speed in Hz */ + u_longlong_t user; /* raw total number of clock ticks spent in user mode */ + u_longlong_t sys; /* raw total number of clock ticks spent in system mode */ + u_longlong_t idle; /* raw total number of clock ticks spent idle */ + u_longlong_t wait; /* raw total number of clock ticks spent waiting for I/O */ + u_longlong_t pswitch; /* number of process switches (change in currently running process) */ + u_longlong_t syscall; /* number of system calls executed */ + u_longlong_t sysread; /* number of read system calls executed */ + u_longlong_t syswrite; /* number of write system calls executed */ + u_longlong_t sysfork; /* number of forks system calls executed */ + u_longlong_t sysexec; /* number of execs system calls executed */ + u_longlong_t readch; /* number of characters tranferred with read system call */ + u_longlong_t writech; /* number of characters tranferred with write system call */ + u_longlong_t devintrs; /* number of device interrupts */ + u_longlong_t softintrs; /* number of software interrupts */ + time_t lbolt; /* number of ticks since last reboot */ + u_longlong_t loadavg[3]; /* (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes. + * To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. */ + u_longlong_t runque; /* length of the run queue (processes ready) */ + u_longlong_t swpque; /* ength of the swap queue (processes waiting to be paged in) */ + u_longlong_t bread; /* number of blocks read */ + u_longlong_t bwrite; /* number of blocks written */ + u_longlong_t lread; /* number of logical read requests */ + u_longlong_t lwrite; /* number of logical write requests */ + u_longlong_t phread; /* number of physical reads (reads on raw devices) */ + u_longlong_t phwrite; /* number of physical writes (writes on raw devices) */ + u_longlong_t runocc; /* updated whenever runque is updated, i.e. the runqueue is occupied. + * This can be used to compute the simple average of ready processes */ + u_longlong_t swpocc; /* updated whenever swpque is updated. i.e. the swpqueue is occupied. + * This can be used to compute the simple average processes waiting to be paged in */ + u_longlong_t iget; /* number of inode lookups */ + u_longlong_t namei; /* number of vnode lookup from a path name */ + u_longlong_t dirblk; /* number of 512-byte block reads by the directory search routine to locate an entry for a file */ + u_longlong_t msg; /* number of IPC message operations */ + u_longlong_t sema; /* number of IPC semaphore operations */ + u_longlong_t rcvint; /* number of tty receive interrupts */ + u_longlong_t xmtint; /* number of tyy transmit interrupts */ + u_longlong_t mdmint; /* number of modem interrupts */ + u_longlong_t tty_rawinch; /* number of raw input characters */ + u_longlong_t tty_caninch; /* number of canonical input characters (always zero) */ + u_longlong_t tty_rawoutch; /* number of raw output characters */ + u_longlong_t ksched; /* number of kernel processes created */ + u_longlong_t koverf; /* kernel process creation attempts where: + * -the user has forked to their maximum limit + * -the configuration limit of processes has been reached */ + u_longlong_t kexit; /* number of kernel processes that became zombies */ + u_longlong_t rbread; /* number of remote read requests */ + u_longlong_t rcread; /* number of cached remote reads */ + u_longlong_t rbwrt; /* number of remote writes */ + u_longlong_t rcwrt; /* number of cached remote writes */ + u_longlong_t traps; /* number of traps */ + int ncpus_high; /* index of highest processor online */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t decrintrs; /* number of decrementer tics interrupts */ + u_longlong_t mpcrintrs; /* number of mpc's received interrupts */ + u_longlong_t mpcsintrs; /* number of mpc's sent interrupts */ + u_longlong_t phantintrs; /* number of phantom interrupts */ + u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ + short iowait; /* number of processes that are asleep waiting for buffered I/O */ + short physio; /* number of processes waiting for raw I/O */ + longlong_t twait; /* number of threads that are waiting for filesystem direct(cio) */ + u_longlong_t hpi; /* number of hypervisor page-ins */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds) */ + u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */ + u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */ + u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */ + u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */ + int spurrflag; /* set if running in spurr mode */ + u_longlong_t version; /* version number (1, 2, etc.,) */ +/* >>>>> END OF STRUCTURE DEFINITION <<<<< */ +#define CURR_VERSION_CPU_TOTAL 1 /* Incremented by one for every new release * + * of perfstat_cpu_total_t data structure */ +} perfstat_cpu_total_t_71; + +typedef union { + uint w; + struct { + unsigned smt_capable :1; /* OS supports SMT mode */ + unsigned smt_enabled :1; /* SMT mode is on */ + unsigned lpar_capable :1; /* OS supports logical partitioning */ + unsigned lpar_enabled :1; /* logical partitioning is on */ + unsigned shared_capable :1; /* OS supports shared processor LPAR */ + unsigned shared_enabled :1; /* partition runs in shared mode */ + unsigned dlpar_capable :1; /* OS supports dynamic LPAR */ + unsigned capped :1; /* partition is capped */ + unsigned kernel_is_64 :1; /* kernel is 64 bit */ + unsigned pool_util_authority :1; /* pool utilization available */ + unsigned donate_capable :1; /* capable of donating cycles */ + unsigned donate_enabled :1; /* enabled for donating cycles */ + unsigned ams_capable:1; /* 1 = AMS(Active Memory Sharing) capable, 0 = Not AMS capable */ + unsigned ams_enabled:1; /* 1 = AMS(Active Memory Sharing) enabled, 0 = Not AMS enabled */ + unsigned power_save:1; /* 1 = Power saving mode is enabled */ + unsigned ame_enabled:1; /* Active Memory Expansion is enabled */ + unsigned shared_extended :1; + unsigned spare :15; /* reserved for future usage */ + } b; +} perfstat_partition_type_t; + +typedef struct { /* partition total information AIX 5.3 < TL6 */ + char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ + perfstat_partition_type_t type; /* set of bits describing the partition */ + int lpar_id; /* logical partition identifier */ + int group_id; /* identifier of the LPAR group this partition is a member of */ + int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ + int online_cpus; /* number of virtual CPUs currently online on the partition */ + int max_cpus; /* maximum number of virtual CPUs this parition can ever have */ + int min_cpus; /* minimum number of virtual CPUs this partition must have */ + u_longlong_t online_memory; /* amount of memory currently online */ + u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ + u_longlong_t min_memory; /* minimum amount of memory this partition must have */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ + int max_proc_capacity; /* maximum number of processor units this partition can ever have */ + int min_proc_capacity; /* minimum number of processor units this partition must have */ + int proc_capacity_increment; /* increment value to the entitled capacity */ + int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ + int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ + int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ + int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ + int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ + int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ + u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ + u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ + u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ + u_longlong_t timebase_last; /* most recently cpu time base */ + u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */ + u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ +} perfstat_partition_total_t_53_5; + +typedef struct { /* partition total information AIX 5.3 < TL10 */ + char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ + perfstat_partition_type_t type; /* set of bits describing the partition */ + int lpar_id; /* logical partition identifier */ + int group_id; /* identifier of the LPAR group this partition is a member of */ + int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ + int online_cpus; /* number of virtual CPUs currently online on the partition */ + int max_cpus; /* maximum number of virtual CPUs this parition can ever have */ + int min_cpus; /* minimum number of virtual CPUs this partition must have */ + u_longlong_t online_memory; /* amount of memory currently online */ + u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ + u_longlong_t min_memory; /* minimum amount of memory this partition must have */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ + int max_proc_capacity; /* maximum number of processor units this partition can ever have */ + int min_proc_capacity; /* minimum number of processor units this partition must have */ + int proc_capacity_increment; /* increment value to the entitled capacity */ + int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ + int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ + int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ + int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ + int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ + int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ + u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ + u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ + u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ + u_longlong_t timebase_last; /* most recently cpu time base */ + u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */ + u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ + u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */ + u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */ + u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */ + u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */ + u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */ + u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */ + int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */ + int var_mem_weight; /* variable memory capacity weight */ + u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/ + u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/ + u_longlong_t hpi; /* number of hypervisor page-ins */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/ + u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/ +} perfstat_partition_total_t_53; + +typedef struct { /* partition total information AIX 6.1|5.3 > TL09 */ + char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ + perfstat_partition_type_t type; /* set of bits describing the partition */ + int lpar_id; /* logical partition identifier */ + int group_id; /* identifier of the LPAR group this partition is a member of */ + int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ + int online_cpus; /* number of virtual CPUs currently online on the partition */ + int max_cpus; /* maximum number of virtual CPUs this parition can ever have */ + int min_cpus; /* minimum number of virtual CPUs this partition must have */ + u_longlong_t online_memory; /* amount of memory currently online */ + u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ + u_longlong_t min_memory; /* minimum amount of memory this partition must have */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ + int max_proc_capacity; /* maximum number of processor units this partition can ever have */ + int min_proc_capacity; /* minimum number of processor units this partition must have */ + int proc_capacity_increment; /* increment value to the entitled capacity */ + int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ + int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ + int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ + int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ + int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ + int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ + u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ + u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ + u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ + u_longlong_t timebase_last; /* most recently cpu time base */ + u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */ + u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ + u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */ + u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */ + u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */ + u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */ + u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */ + u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */ + int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */ + int var_mem_weight; /* variable memory capacity weight */ + u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/ + u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/ + u_longlong_t hpi; /* number of hypervisor page-ins */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/ + u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/ + uint online_lcpus; /* number of online logical cpus */ + uint smt_thrds; /* number of hardware threads that are running */ + u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */ + u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */ + u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */ + u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */ + int spurrflag; /* set if running in spurr mode */ +} perfstat_partition_total_t_61; + +typedef struct { /* partition total information AIX 7.1 */ + char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ + perfstat_partition_type_t type; /* set of bits describing the partition */ + int lpar_id; /* logical partition identifier */ + int group_id; /* identifier of the LPAR group this partition is a member of */ + int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ + int online_cpus; /* number of virtual CPUs currently online on the partition */ + int max_cpus; /* maximum number of virtual CPUs this parition can ever have */ + int min_cpus; /* minimum number of virtual CPUs this partition must have */ + u_longlong_t online_memory; /* amount of memory currently online */ + u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ + u_longlong_t min_memory; /* minimum amount of memory this partition must have */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ + int max_proc_capacity; /* maximum number of processor units this partition can ever have */ + int min_proc_capacity; /* minimum number of processor units this partition must have */ + int proc_capacity_increment; /* increment value to the entitled capacity */ + int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ + int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ + int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ + int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ + int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ + int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ + u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ + u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ + u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ + u_longlong_t timebase_last; /* most recently cpu time base */ + u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */ + u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ + u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */ + u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */ + u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */ + u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */ + u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */ + u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */ + int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */ + int var_mem_weight; /* variable memory capacity weight */ + u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/ + u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/ + u_longlong_t hpi; /* number of hypervisor page-ins */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/ + u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/ + uint online_lcpus; /* number of online logical cpus */ + uint smt_thrds; /* number of hardware threads that are running */ + u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */ + u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */ + u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */ + u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */ + int spurrflag; /* set if running in spurr mode */ + char hardwareid[CEC_ID_LEN]; /* CEC Identifier */ + uint power_save_mode; /* Power save mode for the LPAR. Introduced through LI 53K PRF : Feature 728 292*/ + ushort ame_version; /* AME Version */ + u_longlong_t true_memory; /* True Memory Size in 4KB pages */ + u_longlong_t expanded_memory; /* Expanded Memory Size in 4KB pages */ + u_longlong_t target_memexp_factr; /* Target Memory Expansion Factor scaled by 100 */ + u_longlong_t current_memexp_factr; /* Current Memory Expansion Factor scaled by 100 */ + u_longlong_t target_cpool_size; /* Target Compressed Pool Size in bytes */ + u_longlong_t max_cpool_size; /* Max Size of Compressed Pool in bytes */ + u_longlong_t min_ucpool_size; /* Min Size of Uncompressed Pool in bytes */ + u_longlong_t ame_deficit_size; /*Deficit memory size in bytes */ + u_longlong_t version; /* version number (1, 2, etc.,) */ + u_longlong_t cmcs_total_time; /* Total CPU time spent due to active memory expansion */ +} perfstat_partition_total_t_71; + +typedef struct { /* partition total information AIX 7.1 >= TL1*/ + char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ + perfstat_partition_type_t type; /* set of bits describing the partition */ + int lpar_id; /* logical partition identifier */ + int group_id; /* identifier of the LPAR group this partition is a member of */ + int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ + int online_cpus; /* number of virtual CPUs currently online on the partition */ + int max_cpus; /* maximum number of virtual CPUs this parition can ever have */ + int min_cpus; /* minimum number of virtual CPUs this partition must have */ + u_longlong_t online_memory; /* amount of memory currently online */ + u_longlong_t max_memory; /* maximum amount of memory this partition can ever have */ + u_longlong_t min_memory; /* minimum amount of memory this partition must have */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ + int max_proc_capacity; /* maximum number of processor units this partition can ever have */ + int min_proc_capacity; /* minimum number of processor units this partition must have */ + int proc_capacity_increment; /* increment value to the entitled capacity */ + int unalloc_proc_capacity; /* number of processor units currently unallocated in the shared processor pool this partition belongs to */ + int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ + int unalloc_var_proc_capacity_weight; /* number of variable processor capacity weight units currently unallocated in the shared processor pool this partition belongs to */ + int online_phys_cpus_sys; /* number of physical CPUs currently active in the system containing this partition */ + int max_phys_cpus_sys; /* maximum possible number of physical CPUs in the system containing this partition */ + int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ + u_longlong_t puser; /* raw number of physical processor tics in user mode */ + u_longlong_t psys; /* raw number of physical processor tics in system mode */ + u_longlong_t pidle; /* raw number of physical processor tics idle */ + u_longlong_t pwait; /* raw number of physical processor tics waiting for I/O */ + u_longlong_t pool_idle_time; /* number of clock tics a processor in the shared pool was idle */ + u_longlong_t phantintrs; /* number of phantom interrupts received by the partition */ + u_longlong_t invol_virt_cswitch; /* number involuntary virtual CPU context switches */ + u_longlong_t vol_virt_cswitch; /* number voluntary virtual CPU context switches */ + u_longlong_t timebase_last; /* most recently cpu time base */ + u_longlong_t reserved_pages; /* Currenlty number of 16GB pages. Cannot participate in DR operations */ + u_longlong_t reserved_pagesize; /* Currently 16GB pagesize Cannot participate in DR operations */ + u_longlong_t idle_donated_purr; /* number of idle cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_donated_spurr; /* number of idle spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_purr; /* number of busy cycles donated by a dedicated partition enabled for donation */ + u_longlong_t busy_donated_spurr; /* number of busy spurr cycles donated by a dedicated partition enabled for donation */ + u_longlong_t idle_stolen_purr; /* number of idle cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t idle_stolen_spurr; /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_purr; /* number of busy cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t busy_stolen_spurr; /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */ + u_longlong_t shcpus_in_sys; /* Number of physical processors allocated for shared processor use */ + u_longlong_t max_pool_capacity; /* Maximum processor capacity of partitions pool */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */ + u_longlong_t pool_max_time; /* Summation of maximum time that could be consumed by the pool (nano seconds) */ + u_longlong_t pool_busy_time; /* Summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t pool_scaled_busy_time; /* Scaled summation of busy (non-idle) time accumulated across all partitions in the pool (nano seconds) */ + u_longlong_t shcpu_tot_time; /* Summation of total time across all physical processors allocated for shared processor use (nano seconds) */ + u_longlong_t shcpu_busy_time; /* Summation of busy (non-idle) time accumulated across all shared processor partitions (nano seconds) */ + u_longlong_t shcpu_scaled_busy_time; /* Scaled summation of busy time accumulated across all shared processor partitions (nano seconds) */ + int ams_pool_id; /* AMS pool id of the pool the LPAR belongs to */ + int var_mem_weight; /* variable memory capacity weight */ + u_longlong_t iome; /* I/O memory entitlement of the partition in bytes*/ + u_longlong_t pmem; /* Physical memory currently backing the partition's logical memory in bytes*/ + u_longlong_t hpi; /* number of hypervisor page-ins */ + u_longlong_t hpit; /* Time spent in hypervisor page-ins (in nanoseconds)*/ + u_longlong_t hypv_pagesize; /* Hypervisor page size in KB*/ + uint online_lcpus; /* number of online logical cpus */ + uint smt_thrds; /* number of hardware threads that are running */ + u_longlong_t puser_spurr; /* number of spurr cycles spent in user mode */ + u_longlong_t psys_spurr; /* number of spurr cycles spent in kernel mode */ + u_longlong_t pidle_spurr; /* number of spurr cycles spent in idle mode */ + u_longlong_t pwait_spurr; /* number of spurr cycles spent in wait mode */ + int spurrflag; /* set if running in spurr mode */ + char hardwareid[CEC_ID_LEN]; /* CEC Identifier */ + uint power_save_mode; /* Power save mode for the LPAR. Introduced through LI 53K PRF : Feature 728 292*/ + ushort ame_version; /* AME Version */ + u_longlong_t true_memory; /* True Memory Size in 4KB pages */ + u_longlong_t expanded_memory; /* Expanded Memory Size in 4KB pages */ + u_longlong_t target_memexp_factr; /* Target Memory Expansion Factor scaled by 100 */ + u_longlong_t current_memexp_factr; /* Current Memory Expansion Factor scaled by 100 */ + u_longlong_t target_cpool_size; /* Target Compressed Pool Size in bytes */ + u_longlong_t max_cpool_size; /* Max Size of Compressed Pool in bytes */ + u_longlong_t min_ucpool_size; /* Min Size of Uncompressed Pool in bytes */ + u_longlong_t ame_deficit_size; /*Deficit memory size in bytes */ + u_longlong_t version; /* version number (1, 2, etc.,) */ + u_longlong_t cmcs_total_time; /* Total CPU time spent due to active memory expansion */ + u_longlong_t purr_coalescing; /* If the calling partition is authorized to see pool wide statistics then PURR cycles consumed to coalesce data else set to zero.*/ + u_longlong_t spurr_coalescing; /* If the calling partition is authorized to see pool wide statistics then SPURR cycles consumed to coalesce data else set to zero.*/ + u_longlong_t MemPoolSize; /* Indicates the memory pool size of the pool that the partition belongs to (in bytes)., mpsz */ + u_longlong_t IOMemEntInUse; /* I/O memory entitlement of the LPAR in use in bytes. iomu */ + u_longlong_t IOMemEntFree; /* free I/O memory entitlement in bytes. iomf */ + u_longlong_t IOHighWaterMark; /* high water mark of I/O memory entitlement usage in bytes. iohwn */ + u_longlong_t purr_counter; /* number of purr cycles spent in user + kernel mode */ + u_longlong_t spurr_counter; /* number of spurr cycles spent in user + kernel mode */ + + /* Marketing Requirement(MR): MR1124083744 */ + u_longlong_t real_free; /* free real memory (in 4KB pages) */ + u_longlong_t real_avail; /* number of pages available for user application (memfree + numperm - minperm - minfree) */ + /* >>>>> END OF STRUCTURE DEFINITION <<<<< */ +#define CURR_VERSION_PARTITION_TOTAL 5 /* Incremented by one for every new release * + * of perfstat_partition_total_t data structure */ +} perfstat_partition_total_t_71_1; + +typedef union { /* WPAR Type & Flags */ + uint w; + struct { + unsigned app_wpar :1; /* Application WPAR */ + unsigned cpu_rset :1; /* WPAR restricted to CPU resource set */ + unsigned cpu_xrset:1; /* WPAR restricted to CPU Exclusive resource set */ + unsigned cpu_limits :1; /* CPU resource limits enforced */ + unsigned mem_limits :1; /* Memory resource limits enforced */ + unsigned spare :27; /* reserved for future usage */ + } b; +} perfstat_wpar_type_t; + +typedef struct { /* Workload partition Information AIX 5.3 & 6.1*/ + char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */ + perfstat_wpar_type_t type; /* set of bits describing the wpar */ + cid_t wpar_id; /* workload partition identifier */ + uint online_cpus; /* Number of Virtual CPUs in partition rset or number of virtual CPUs currently online on the Global partition*/ + int cpu_limit; /* CPU limit in 100ths of % - 1..10000 */ + int mem_limit; /* Memory limit in 100ths of % - 1..10000 */ + u_longlong_t online_memory; /* amount of memory currently online in Global Partition */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ +} perfstat_wpar_total_t_61; + +typedef struct { /* Workload partition Information AIX 7.1*/ + char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */ + perfstat_wpar_type_t type; /* set of bits describing the wpar */ + cid_t wpar_id; /* workload partition identifier */ + uint online_cpus; /* Number of Virtual CPUs in partition rset or number of virtual CPUs currently online on the Global partition*/ + int cpu_limit; /* CPU limit in 100ths of % - 1..10000 */ + int mem_limit; /* Memory limit in 100ths of % - 1..10000 */ + u_longlong_t online_memory; /* amount of memory currently online in Global Partition */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ + u_longlong_t version; /* version number (1, 2, etc.,) */ +/* >>>>> END OF STRUCTURE DEFINITION <<<<< */ +#define CURR_VERSION_WPAR_TOTAL 1 /* Incremented by one for every new release * + * of perfstat_wpar_total_t data structure */ +} perfstat_wpar_total_t_71; + +typedef void * rsethandle_t; /* Type to identify a resource set handle: rsethandle_t */ + +typedef enum { WPARNAME, WPARID, RSETHANDLE } wparid_specifier; /* Type of wparid_specifier */ + +typedef struct { /* WPAR identifier */ + wparid_specifier spec; /* Specifier to choose wpar id or name */ + union { + cid_t wpar_id; /* WPAR ID */ + rsethandle_t rset; /* Rset Handle */ + char wparname[MAXCORRALNAMELEN+1]; /* WPAR NAME */ + } u; + char name[IDENTIFIER_LENGTH]; /* name of the structure element identifier */ +} perfstat_id_wpar_t; + + + +// end: libperfstat.h (AIX 5.2, 5.3, 6.1, 7.1) +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define PERFSTAT_PARTITON_TOTAL_T_LATEST perfstat_partition_total_t_71_1/* latest perfstat_partition_total_t structure */ +#define PERFSTAT_CPU_TOTAL_T_LATEST perfstat_cpu_total_t_71 /* latest perfstat_cpu_total_t structure */ +#define PERFSTAT_WPAR_TOTAL_T_LATEST perfstat_wpar_total_t_71 /* latest perfstat_wpar_total_t structure */ class libperfstat { @@ -41,19 +766,107 @@ // Load the libperfstat library (must be in LIBPATH). // Returns true if succeeded, false if error. static bool init(); - - // cleanup of the libo4 porting library. static void cleanup(); - // direct wrappers for the libperfstat functionality. All they do is + // Direct wrappers for the libperfstat functionality. All they do is // to call the functions with the same name via function pointers. - static int perfstat_cpu_total(perfstat_id_t *name, perfstat_cpu_total_t* userbuff, + // Get all available data also on newer AIX versions (PERFSTAT_CPU_TOTAL_T_LATEST). + static int perfstat_cpu_total(perfstat_id_t *name, PERFSTAT_CPU_TOTAL_T_LATEST* userbuff, int sizeof_userbuff, int desired_number); static int perfstat_memory_total(perfstat_id_t *name, perfstat_memory_total_t* userbuff, int sizeof_userbuff, int desired_number); + static int perfstat_partition_total(perfstat_id_t *name, PERFSTAT_PARTITON_TOTAL_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + static void perfstat_reset(); + + static int perfstat_wpar_total(perfstat_id_wpar_t *name, PERFSTAT_WPAR_TOTAL_T_LATEST* userbuff, + int sizeof_userbuff, int desired_number); + + static cid_t wpar_getcid(); + + + //////////////////////////////////////////////////////////////// + // The convenience functions get_partitioninfo(), get_cpuinfo(), get_wparinfo() return + // information about partition, cpu and wpars, respectivly. They can be used without + // regard for which OS release we are on. On older AIX release, some output structure + // members will be 0. + + // Result struct for get_partitioninfo(). + struct partitioninfo_t { + // partition type info + unsigned smt_capable :1; /* OS supports SMT mode */ + unsigned smt_enabled :1; /* SMT mode is on */ + unsigned lpar_capable :1; /* OS supports logical partitioning */ + unsigned lpar_enabled :1; /* logical partitioning is on */ + unsigned shared_capable :1; /* OS supports shared processor LPAR */ + unsigned shared_enabled :1; /* partition runs in shared mode */ + unsigned dlpar_capable :1; /* OS supports dynamic LPAR */ + unsigned capped :1; /* partition is capped */ + unsigned kernel_is_64 :1; /* kernel is 64 bit */ + unsigned pool_util_authority :1; /* pool utilization available */ + unsigned donate_capable :1; /* capable of donating cycles */ + unsigned donate_enabled :1; /* enabled for donating cycles */ + unsigned ams_capable:1; /* 1 = AMS(Active Memory Sharing) capable, 0 = Not AMS capable */ + unsigned ams_enabled:1; /* 1 = AMS(Active Memory Sharing) enabled, 0 = Not AMS enabled */ + unsigned power_save:1; /* 1 = Power saving mode is enabled */ + unsigned ame_enabled:1; /* Active Memory Expansion is enabled */ + // partition total info + int online_cpus; /* number of virtual CPUs currently online on the partition */ + int entitled_proc_capacity; /* number of processor units this partition is entitled to receive */ + int var_proc_capacity_weight; /* partition priority weight to receive extra capacity */ + int phys_cpus_pool; /* number of the physical CPUs currently in the shared processor pool this partition belong to */ + int pool_id; /* identifier of the shared pool of physical processors this partition is a member of */ + u_longlong_t entitled_pool_capacity; /* Entitled processor capacity of partitions pool */ + char name[IDENTIFIER_LENGTH]; /* name of the logical partition */ + + u_longlong_t timebase_last; /* most recently cpu time base (an incremented long int on PowerPC) */ + u_longlong_t pool_idle_time; /* pool idle time = number of clock tics a processor in the shared pool was idle */ + u_longlong_t pcpu_tics_user; /* raw number of physical processor tics in user mode */ + u_longlong_t pcpu_tics_sys; /* raw number of physical processor tics in system mode */ + u_longlong_t pcpu_tics_idle; /* raw number of physical processor tics idle */ + u_longlong_t pcpu_tics_wait; /* raw number of physical processor tics waiting for I/O */ + + u_longlong_t true_memory; /* True Memory Size in 4KB pages */ + u_longlong_t expanded_memory; /* Expanded Memory Size in 4KB pages */ + u_longlong_t target_memexp_factr; /* Target Memory Expansion Factor scaled by 100 */ + u_longlong_t current_memexp_factr; /* Current Memory Expansion Factor scaled by 100 */ + u_longlong_t cmcs_total_time; /* Total CPU time spent due to active memory expansion */ + }; + + // Result struct for get_cpuinfo(). + struct cpuinfo_t { + char description[IDENTIFIER_LENGTH]; // processor description (type/official name) + u_longlong_t processorHZ; // processor speed in Hz + int ncpus; // number of active logical processors + double loadavg[3]; // (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes. + // To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. + char version[20]; // processor version from _system_configuration (sys/systemcfg.h) + unsigned long long user_clock_ticks; // raw total number of clock ticks spent in user mode + unsigned long long sys_clock_ticks; // raw total number of clock ticks spent in system mode + unsigned long long idle_clock_ticks; // raw total number of clock ticks spent idle + unsigned long long wait_clock_ticks; // raw total number of clock ticks spent waiting for I/O + }; + + // Result struct for get_wparinfo(). + struct wparinfo_t { + char name[MAXCORRALNAMELEN+1]; /* name of the Workload Partition */ + unsigned short wpar_id; /* workload partition identifier */ + unsigned app_wpar :1; /* Application WPAR */ + unsigned cpu_rset :1; /* WPAR restricted to CPU resource set */ + unsigned cpu_xrset:1; /* WPAR restricted to CPU Exclusive resource set */ + unsigned cpu_limits :1; /* CPU resource limits enforced */ + unsigned mem_limits :1; /* Memory resource limits enforced */ + int cpu_limit; /* CPU limit in 100ths of % - 1..10000 */ + int mem_limit; /* Memory limit in 100ths of % - 1..10000 */ + }; + + static bool get_partitioninfo(partitioninfo_t* ppi); + static bool get_cpuinfo(cpuinfo_t* pci); + static bool get_wparinfo(wparinfo_t* pwi); + }; #endif // OS_AIX_VM_LIBPERFSTAT_AIX_HPP
--- a/hotspot/src/os/aix/vm/loadlib_aix.cpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/loadlib_aix.cpp Mon Nov 16 10:58:14 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ #endif #include "loadlib_aix.hpp" -// for CritSect #include "misc_aix.hpp" #include "porting_aix.hpp" #include "utilities/debug.hpp"
--- a/hotspot/src/os/aix/vm/misc_aix.cpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/misc_aix.cpp Mon Nov 16 10:58:14 2015 +0100 @@ -26,6 +26,8 @@ #include "runtime/stubRoutines.hpp" #include <pthread.h> +#include <unistd.h> +#include <errno.h> void MiscUtils::init_critsect(MiscUtils::critsect_t* cs) { const int rc = pthread_mutex_init(cs, NULL);
--- a/hotspot/src/os/aix/vm/misc_aix.hpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/misc_aix.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -29,6 +29,8 @@ // misc_aix.hpp, misc_aix.cpp: convenience functions needed for the OpenJDK AIX // port. #include "utilities/globalDefinitions.hpp" +#include "runtime/globals.hpp" +#include "utilities/debug.hpp" #include <pthread.h> @@ -40,7 +42,6 @@ } \ } #define ERRBYE(s) { trcVerbose(s); return -1; } -#define trc(fmt, ...) #define assert0(b) assert((b), "") #define guarantee0(b) guarantee((b), "")
--- a/hotspot/src/os/aix/vm/osThread_aix.cpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/osThread_aix.cpp Mon Nov 16 10:58:14 2015 +0100 @@ -35,7 +35,7 @@ void OSThread::pd_initialize() { assert(this != NULL, "check"); _thread_id = 0; - _pthread_id = 0; + _kernel_thread_id = 0; _siginfo = NULL; _ucontext = NULL; _expanding_stack = 0;
--- a/hotspot/src/os/aix/vm/osThread_aix.hpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/osThread_aix.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -27,7 +27,7 @@ #define OS_AIX_VM_OSTHREAD_AIX_HPP public: - typedef pid_t thread_id_t; + typedef pthread_t thread_id_t; private: int _thread_type; @@ -43,9 +43,13 @@ private: - // _pthread_id is the pthread id, which is used by library calls - // (e.g. pthread_kill). - pthread_t _pthread_id; + // On AIX, we use the pthread id as OSThread::thread_id and keep the kernel thread id + // separately for diagnostic purposes. + // + // Note: this kernel thread id is saved at thread start. Depending on the + // AIX scheduling mode, this may not be the current thread id (usually not + // a problem though as we run with AIXTHREAD_SCOPE=S). + tid_t _kernel_thread_id; sigset_t _caller_sigmask; // Caller's signal mask @@ -66,11 +70,16 @@ return false; } #endif // ASSERT - pthread_t pthread_id() const { - return _pthread_id; + tid_t kernel_thread_id() const { + return _kernel_thread_id; } - void set_pthread_id(pthread_t tid) { - _pthread_id = tid; + void set_kernel_thread_id(tid_t tid) { + _kernel_thread_id = tid; + } + + pthread_t pthread_id() const { + // Here: same as OSThread::thread_id() + return _thread_id; } // ***************************************************************
--- a/hotspot/src/os/aix/vm/os_aix.cpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/os_aix.cpp Mon Nov 16 10:58:14 2015 +0100 @@ -36,6 +36,7 @@ #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" #include "jvm_aix.h" +#include "libo4.hpp" #include "libperfstat_aix.hpp" #include "loadlib_aix.hpp" #include "memory/allocation.inline.hpp" @@ -108,25 +109,14 @@ #include <sys/vminfo.h> #include <sys/wait.h> -// If RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling -// getrusage() is prepared to handle the associated failure. -#ifndef RUSAGE_THREAD -#define RUSAGE_THREAD (1) /* only the calling thread */ -#endif - -// PPC port -static const uintx Use64KPagesThreshold = 1*M; -static const uintx MaxExpectedDataSegmentSize = SIZE_4G*2; - -// Add missing declarations (should be in procinfo.h but isn't until AIX 6.1). +// Missing prototypes for various system APIs. +extern "C" +int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t); + #if !defined(_AIXVERSION_610) -extern "C" { - int getthrds64(pid_t ProcessIdentifier, - struct thrdentry64* ThreadBuffer, - int ThreadSize, - tid64_t* IndexPointer, - int Count); -} +extern "C" int getthrds64(pid_t, struct thrdentry64*, int, tid64_t*, int); +extern "C" int getprocs64(procentry64*, int, fdsinfo*, int, pid_t*, int); +extern "C" int getargs (procsinfo*, int, char*, int); #endif #define MAX_PATH (2 * K) @@ -150,18 +140,9 @@ typedef unsigned long stackslot_t; typedef stackslot_t* stackptr_t; -// Excerpts from systemcfg.h definitions newer than AIX 5.3. -#ifndef PV_7 -#define PV_7 0x200000 /* Power PC 7 */ -#define PV_7_Compat 0x208000 /* Power PC 7 */ -#endif -#ifndef PV_8 -#define PV_8 0x300000 /* Power PC 8 */ -#define PV_8_Compat 0x308000 /* Power PC 8 */ -#endif - // Query dimensions of the stack of the calling thread. static bool query_stack_dimensions(address* p_stack_base, size_t* p_stack_size); +static address resolve_function_descriptor_to_code_pointer(address p); // Function to check a given stack pointer against given stack limits. inline bool is_valid_stackpointer(stackptr_t sp, stackptr_t stack_base, size_t stack_size) { @@ -185,7 +166,7 @@ if (((uintptr_t)p) & 0x3) { return false; } - if (!LoadedLibraries::find_for_text_address(p, NULL)) { + if (LoadedLibraries::find_for_text_address(p, NULL) == NULL) { return false; } return true; @@ -203,31 +184,44 @@ CHECK_STACK_PTR(sp, stack_base, stack_size); \ } +static void vmembk_print_on(outputStream* os); + //////////////////////////////////////////////////////////////////////////////// // global variables (for a description see os_aix.hpp) julong os::Aix::_physical_memory = 0; + pthread_t os::Aix::_main_thread = ((pthread_t)0); int os::Aix::_page_size = -1; + +// -1 = uninitialized, 0 if AIX, 1 if OS/400 pase int os::Aix::_on_pase = -1; + +// -1 = uninitialized, otherwise os version in the form 0xMMmm - MM:major, mm:minor +// E.g. 0x0601 for AIX 6.1 or 0x0504 for OS/400 V5R4 int os::Aix::_os_version = -1; + int os::Aix::_stack_page_size = -1; + +// -1 = uninitialized, 0 - no, 1 - yes int os::Aix::_xpg_sus_mode = -1; + +// -1 = uninitialized, 0 - no, 1 - yes int os::Aix::_extshm = -1; -int os::Aix::_logical_cpus = -1; //////////////////////////////////////////////////////////////////////////////// // local variables -static int g_multipage_error = -1; // error analysis for multipage initialization static jlong initial_time_count = 0; static int clock_tics_per_sec = 100; static sigset_t check_signal_done; // For diagnostics to print a message once (see run_periodic_checks) static bool check_signals = true; -static pid_t _initial_pid = 0; static int SR_signum = SIGUSR2; // Signal used to suspend/resume a thread (must be > SIGSEGV, see 4355769) static sigset_t SR_sigset; +// Process break recorded at startup. +static address g_brk_at_startup = NULL; + // This describes the state of multipage support of the underlying // OS. Note that this is of no interest to the outsize world and // therefore should not be defined in AIX class. @@ -278,8 +272,9 @@ // a specific wish address, e.g. to place the heap in a // compressed-oops-friendly way. static bool is_close_to_brk(address a) { - address a1 = (address) sbrk(0); - if (a >= a1 && a < (a1 + MaxExpectedDataSegmentSize)) { + assert0(g_brk_at_startup != NULL); + if (a >= g_brk_at_startup && + a < (g_brk_at_startup + MaxExpectedDataSegmentSize)) { return true; } return false; @@ -290,11 +285,15 @@ } julong os::Aix::available_memory() { + // Avoid expensive API call here, as returned value will always be null. + if (os::Aix::on_pase()) { + return 0x0LL; + } os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { return mi.real_free; } else { - return 0xFFFFFFFFFFFFFFFFLL; + return ULONG_MAX; } } @@ -332,7 +331,7 @@ for (int i = 0; i < numFullDisclaimsNeeded; i ++) { if (::disclaim(p, maxDisclaimSize, DISCLAIM_ZEROMEM) != 0) { - trc("Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno); + trcVerbose("Cannot disclaim %p - %p (errno %d)\n", p, p + maxDisclaimSize, errno); return false; } p += maxDisclaimSize; @@ -340,7 +339,7 @@ if (lastDisclaimSize > 0) { if (::disclaim(p, lastDisclaimSize, DISCLAIM_ZEROMEM) != 0) { - trc("Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno); + trcVerbose("Cannot disclaim %p - %p (errno %d)\n", p, p + lastDisclaimSize, errno); return false; } } @@ -357,25 +356,30 @@ #error Add appropriate cpu_arch setting #endif +// Wrap the function "vmgetinfo" which is not available on older OS releases. +static int checked_vmgetinfo(void *out, int command, int arg) { + if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) { + guarantee(false, "cannot call vmgetinfo on AS/400 older than V6R1"); + } + return ::vmgetinfo(out, command, arg); +} // Given an address, returns the size of the page backing that address. size_t os::Aix::query_pagesize(void* addr) { + if (os::Aix::on_pase() && os::Aix::os_version() < 0x0601) { + // AS/400 older than V6R1: no vmgetinfo here, default to 4K + return SIZE_4K; + } + vm_page_info pi; pi.addr = (uint64_t)addr; - if (::vmgetinfo(&pi, VM_PAGE_INFO, sizeof(pi)) == 0) { + if (checked_vmgetinfo(&pi, VM_PAGE_INFO, sizeof(pi)) == 0) { return pi.pagesize; } else { - fprintf(stderr, "vmgetinfo failed to retrieve page size for address %p (errno %d).\n", addr, errno); assert(false, "vmgetinfo failed to retrieve page size"); return SIZE_4K; } - -} - -// Returns the kernel thread id of the currently running thread. -pid_t os::Aix::gettid() { - return (pid_t) thread_self(); } void os::Aix::initialize_system_info() { @@ -387,7 +391,6 @@ // Retrieve total physical storage. os::Aix::meminfo_t mi; if (!os::Aix::get_meminfo(&mi)) { - fprintf(stderr, "os::Aix::get_meminfo failed.\n"); fflush(stderr); assert(false, "os::Aix::get_meminfo failed."); } _physical_memory = (julong) mi.real_total; @@ -400,7 +403,6 @@ case SIZE_64K: return "64K"; case SIZE_16M: return "16M"; case SIZE_16G: return "16G"; - case -1: return "not set"; default: assert(false, "surprise"); return "??"; @@ -431,6 +433,8 @@ } // Query default shm page size (LDR_CNTRL SHMPSIZE). + // Note that this is pure curiosity. We do not rely on default page size but set + // our own page size after allocated. { const int shmid = ::shmget(IPC_PRIVATE, 1, IPC_CREAT | S_IRUSR | S_IWUSR); guarantee(shmid != -1, "shmget failed"); @@ -447,26 +451,26 @@ // number of reasons so we may just as well guarantee it here. guarantee0(!os::Aix::is_primordial_thread()); - // Query pthread stack page size. + // Query pthread stack page size. Should be the same as data page size because + // pthread stacks are allocated from C-Heap. { int dummy = 0; g_multipage_support.pthr_stack_pagesize = os::Aix::query_pagesize(&dummy); } // Query default text page size (LDR_CNTRL TEXTPSIZE). - /* PPC port: so far unused. { address any_function = - (address) resolve_function_descriptor_to_code_pointer((address)describe_pagesize); + resolve_function_descriptor_to_code_pointer((address)describe_pagesize); g_multipage_support.textpsize = os::Aix::query_pagesize(any_function); } - */ // Now probe for support of 64K pages and 16M pages. // Before OS/400 V6R1, there is no support for pages other than 4K. if (os::Aix::on_pase_V5R4_or_older()) { - Unimplemented(); + trcVerbose("OS/400 < V6R1 - no large page support."); + g_multipage_support.error = ERROR_MP_OS_TOO_OLD; goto query_multipage_support_end; } @@ -474,10 +478,10 @@ { const int MAX_PAGE_SIZES = 4; psize_t sizes[MAX_PAGE_SIZES]; - const int num_psizes = ::vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES); + const int num_psizes = checked_vmgetinfo(sizes, VMINFO_GETPSIZES, MAX_PAGE_SIZES); if (num_psizes == -1) { - trc("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)\n", errno); - trc("disabling multipage support.\n"); + trcVerbose("vmgetinfo(VMINFO_GETPSIZES) failed (errno: %d)", errno); + trcVerbose("disabling multipage support."); g_multipage_support.error = ERROR_MP_VMGETINFO_FAILED; goto query_multipage_support_end; } @@ -505,8 +509,8 @@ if (::shmctl(shmid, SHM_PAGESIZE, &shm_buf) != 0) { const int en = errno; ::shmctl(shmid, IPC_RMID, NULL); // As early as possible! - // PPC port trcVerbose("shmctl(SHM_PAGESIZE) failed with %s", - // PPC port MiscUtils::describe_errno(en)); + trcVerbose("shmctl(SHM_PAGESIZE) failed with errno=%n", + errno); } else { // Attach and double check pageisze. void* p = ::shmat(shmid, NULL, 0); @@ -532,35 +536,35 @@ query_multipage_support_end: - trcVerbose("base page size (sysconf _SC_PAGESIZE): %s\n", + trcVerbose("base page size (sysconf _SC_PAGESIZE): %s", describe_pagesize(g_multipage_support.pagesize)); - trcVerbose("Data page size (C-Heap, bss, etc): %s\n", + trcVerbose("Data page size (C-Heap, bss, etc): %s", describe_pagesize(g_multipage_support.datapsize)); - trcVerbose("Text page size: %s\n", + trcVerbose("Text page size: %s", describe_pagesize(g_multipage_support.textpsize)); - trcVerbose("Thread stack page size (pthread): %s\n", + trcVerbose("Thread stack page size (pthread): %s", describe_pagesize(g_multipage_support.pthr_stack_pagesize)); - trcVerbose("Default shared memory page size: %s\n", + trcVerbose("Default shared memory page size: %s", describe_pagesize(g_multipage_support.shmpsize)); - trcVerbose("Can use 64K pages dynamically with shared meory: %s\n", + trcVerbose("Can use 64K pages dynamically with shared meory: %s", (g_multipage_support.can_use_64K_pages ? "yes" :"no")); - trcVerbose("Can use 16M pages dynamically with shared memory: %s\n", + trcVerbose("Can use 16M pages dynamically with shared memory: %s", (g_multipage_support.can_use_16M_pages ? "yes" :"no")); - trcVerbose("Multipage error details: %d\n", + trcVerbose("Multipage error details: %d", g_multipage_support.error); // sanity checks assert0(g_multipage_support.pagesize == SIZE_4K); assert0(g_multipage_support.datapsize == SIZE_4K || g_multipage_support.datapsize == SIZE_64K); - // PPC port: so far unused.assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K); + assert0(g_multipage_support.textpsize == SIZE_4K || g_multipage_support.textpsize == SIZE_64K); assert0(g_multipage_support.pthr_stack_pagesize == g_multipage_support.datapsize); assert0(g_multipage_support.shmpsize == SIZE_4K || g_multipage_support.shmpsize == SIZE_64K); -} // end os::Aix::query_multipage_support() +} void os::init_system_properties_values() { -#define DEFAULT_LIBPATH "/usr/lib:/lib" +#define DEFAULT_LIBPATH "/lib:/usr/lib" #define EXTENSIONS_DIR "/lib/ext" // Buffer that fits several sprintfs. @@ -578,7 +582,10 @@ // Found the full path to libjvm.so. // Now cut the path to <java_home>/jre if we can. - *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /libjvm.so. + } pslash = strrchr(buf, '/'); if (pslash != NULL) { *pslash = '\0'; // Get rid of /{client|server|hotspot}. @@ -753,8 +760,21 @@ memset(pmi, 0, sizeof(meminfo_t)); if (os::Aix::on_pase()) { - - Unimplemented(); + // On PASE, use the libo4 porting library. + + unsigned long long virt_total = 0; + unsigned long long real_total = 0; + unsigned long long real_free = 0; + unsigned long long pgsp_total = 0; + unsigned long long pgsp_free = 0; + if (libo4::get_memory_info(&virt_total, &real_total, &real_free, &pgsp_total, &pgsp_free)) { + pmi->virt_total = virt_total; + pmi->real_total = real_total; + pmi->real_free = real_free; + pmi->pgsp_total = pgsp_total; + pmi->pgsp_free = pgsp_free; + return true; + } return false; } else { @@ -770,7 +790,7 @@ memset (&psmt, '\0', sizeof(psmt)); const int rc = libperfstat::perfstat_memory_total(NULL, &psmt, sizeof(psmt), 1); if (rc == -1) { - fprintf(stderr, "perfstat_memory_total() failed (errno=%d)\n", errno); + trcVerbose("perfstat_memory_total() failed (errno=%d)", errno); assert(0, "perfstat_memory_total() failed"); return false; } @@ -798,81 +818,6 @@ } } // end os::Aix::get_meminfo -// Retrieve global cpu information. -// Returns false if something went wrong; -// the content of pci is undefined in this case. -bool os::Aix::get_cpuinfo(cpuinfo_t* pci) { - assert(pci, "get_cpuinfo: invalid parameter"); - memset(pci, 0, sizeof(cpuinfo_t)); - - perfstat_cpu_total_t psct; - memset (&psct, '\0', sizeof(psct)); - - if (-1 == libperfstat::perfstat_cpu_total(NULL, &psct, sizeof(perfstat_cpu_total_t), 1)) { - fprintf(stderr, "perfstat_cpu_total() failed (errno=%d)\n", errno); - assert(0, "perfstat_cpu_total() failed"); - return false; - } - - // global cpu information - strcpy (pci->description, psct.description); - pci->processorHZ = psct.processorHZ; - pci->ncpus = psct.ncpus; - os::Aix::_logical_cpus = psct.ncpus; - for (int i = 0; i < 3; i++) { - pci->loadavg[i] = (double) psct.loadavg[i] / (1 << SBITS); - } - - // get the processor version from _system_configuration - switch (_system_configuration.version) { - case PV_8: - strcpy(pci->version, "Power PC 8"); - break; - case PV_7: - strcpy(pci->version, "Power PC 7"); - break; - case PV_6_1: - strcpy(pci->version, "Power PC 6 DD1.x"); - break; - case PV_6: - strcpy(pci->version, "Power PC 6"); - break; - case PV_5: - strcpy(pci->version, "Power PC 5"); - break; - case PV_5_2: - strcpy(pci->version, "Power PC 5_2"); - break; - case PV_5_3: - strcpy(pci->version, "Power PC 5_3"); - break; - case PV_5_Compat: - strcpy(pci->version, "PV_5_Compat"); - break; - case PV_6_Compat: - strcpy(pci->version, "PV_6_Compat"); - break; - case PV_7_Compat: - strcpy(pci->version, "PV_7_Compat"); - break; - case PV_8_Compat: - strcpy(pci->version, "PV_8_Compat"); - break; - default: - strcpy(pci->version, "unknown"); - } - - return true; - -} //end os::Aix::get_cpuinfo - -////////////////////////////////////////////////////////////////////////////// -// detecting pthread library - -void os::Aix::libpthread_init() { - return; -} - ////////////////////////////////////////////////////////////////////////////// // create new thread @@ -889,6 +834,26 @@ thread->set_stack_size(size); } + const pthread_t pthread_id = ::pthread_self(); + const tid_t kernel_thread_id = ::thread_self(); + + trcVerbose("newborn Thread : pthread-id %u, ktid " UINT64_FORMAT + ", stack %p ... %p, stacksize 0x%IX (%IB)", + pthread_id, kernel_thread_id, + thread->stack_base() - thread->stack_size(), + thread->stack_base(), + thread->stack_size(), + thread->stack_size()); + + // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc() + // by the pthread library). In rare cases, this may not be the case, e.g. when third-party + // tools hook pthread_create(). In this case, we may run into problems establishing + // guard pages on those stacks, because the stacks may reside in memory which is not + // protectable (shmated). + if (thread->stack_base() > ::sbrk(0)) { + trcVerbose("Thread " UINT64_FORMAT ": stack not in data segment.", (uint64_t) pthread_id); + } + // Do some sanity checks. CHECK_CURRENT_STACK_PTR(thread->stack_base(), thread->stack_size()); @@ -906,28 +871,31 @@ OSThread* osthread = thread->osthread(); - // thread_id is kernel thread id (similar to Solaris LWP id) - osthread->set_thread_id(os::Aix::gettid()); - - // initialize signal mask for this thread + // Thread_id is pthread id. + osthread->set_thread_id(pthread_id); + + // .. but keep kernel thread id too for diagnostics + osthread->set_kernel_thread_id(kernel_thread_id); + + // Initialize signal mask for this thread. os::Aix::hotspot_sigmask(thread); - // initialize floating point control register + // Initialize floating point control register. os::Aix::init_thread_fpu_state(); assert(osthread->get_state() == RUNNABLE, "invalid os thread state"); - // call one more level start routine + // Call one more level start routine. thread->run(); + trcVerbose("Thread finished : pthread-id %u, ktid " UINT64_FORMAT ".", + pthread_id, kernel_thread_id); + return 0; } bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { - // We want the whole function to be synchronized. - ThreadCritical cs; - assert(thread->osthread() == NULL, "caller responsible"); // Allocate the OSThread object @@ -992,8 +960,14 @@ pthread_attr_destroy(&attr); if (ret == 0) { - // PPC port traceOsMisc(("Created New Thread : pthread-id %u", tid)); + trcVerbose("Created New Thread : pthread-id %u", tid); } else { + if (os::Aix::on_pase()) { + // QIBM_MULTI_THREADED=Y is needed when the launcher is started on iSeries + // using QSH. Otherwise pthread_create fails with errno=11. + trcVerbose("(Please make sure you set the environment variable " + "QIBM_MULTI_THREADED=Y before running this program.)"); + } if (PrintMiscellaneous && (Verbose || WizardMode)) { perror("pthread_create()"); } @@ -1003,8 +977,8 @@ return false; } - // Store pthread info into the OSThread - osthread->set_pthread_id(tid); + // OSThread::thread_id is the pthread id. + osthread->set_thread_id(tid); return true; } @@ -1030,9 +1004,21 @@ return false; } - // Store pthread info into the OSThread - osthread->set_thread_id(os::Aix::gettid()); - osthread->set_pthread_id(::pthread_self()); + const pthread_t pthread_id = ::pthread_self(); + const tid_t kernel_thread_id = ::thread_self(); + + trcVerbose("attaching Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)", + pthread_id, kernel_thread_id, + thread->stack_base() - thread->stack_size(), + thread->stack_base(), + thread->stack_size(), + thread->stack_size()); + + // OSThread::thread_id is the pthread id. + osthread->set_thread_id(pthread_id); + + // .. but keep kernel thread id too for diagnostics + osthread->set_kernel_thread_id(kernel_thread_id); // initialize floating point control register os::Aix::init_thread_fpu_state(); @@ -1126,17 +1112,15 @@ nanos = jlong(time.tv_usec) * 1000; } - -// We need to manually declare mread_real_time, -// because IBM didn't provide a prototype in time.h. -// (they probably only ever tested in C, not C++) -extern "C" -int mread_real_time(timebasestruct_t *t, size_t size_of_timebasestruct_t); - jlong os::javaTimeNanos() { if (os::Aix::on_pase()) { - Unimplemented(); - return 0; + + timeval time; + int status = gettimeofday(&time, NULL); + assert(status != -1, "PASE error at gettimeofday()"); + jlong usecs = jlong((unsigned long long) time.tv_sec * (1000 * 1000) + time.tv_usec); + return 1000 * usecs; + } else { // On AIX use the precision of processors real time clock // or time base registers. @@ -1265,22 +1249,12 @@ return n; } -intx os::current_thread_id() { return (intx)pthread_self(); } +intx os::current_thread_id() { + return (intx)pthread_self(); +} int os::current_process_id() { - - // This implementation returns a unique pid, the pid of the - // launcher thread that starts the vm 'process'. - - // Under POSIX, getpid() returns the same pid as the - // launcher thread rather than a unique pid per thread. - // Use gettid() if you want the old pre NPTL behaviour. - - // if you are looking for the result of a call to getpid() that - // returns a unique pid for the calling thread, then look at the - // OSThread::thread_id() method in osThread_linux.hpp file - - return (int)(_initial_pid ? _initial_pid : getpid()); + return getpid(); } // DLL functions @@ -1317,6 +1291,9 @@ } else if (strchr(pname, *os::path_separator()) != NULL) { int n; char** pelements = split_path(pname, &n); + if (pelements == NULL) { + return false; + } for (int i = 0; i < n; i++) { // Really shouldn't be NULL, but check can't hurt if (pelements[i] == NULL || strlen(pelements[i]) == 0) { @@ -1554,62 +1531,98 @@ os::loadavg(loadavg, 3); st->print("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]); st->cr(); + + // print wpar info + libperfstat::wparinfo_t wi; + if (libperfstat::get_wparinfo(&wi)) { + st->print_cr("wpar info"); + st->print_cr("name: %s", wi.name); + st->print_cr("id: %d", wi.wpar_id); + st->print_cr("type: %s", (wi.app_wpar ? "application" : "system")); + } + + // print partition info + libperfstat::partitioninfo_t pi; + if (libperfstat::get_partitioninfo(&pi)) { + st->print_cr("partition info"); + st->print_cr(" name: %s", pi.name); + } + } void os::print_memory_info(outputStream* st) { st->print_cr("Memory:"); - st->print_cr(" default page size: %s", describe_pagesize(os::vm_page_size())); - st->print_cr(" default stack page size: %s", describe_pagesize(os::vm_page_size())); + st->print_cr(" Base page size (sysconf _SC_PAGESIZE): %s", + describe_pagesize(g_multipage_support.pagesize)); + st->print_cr(" Data page size (C-Heap, bss, etc): %s", + describe_pagesize(g_multipage_support.datapsize)); + st->print_cr(" Text page size: %s", + describe_pagesize(g_multipage_support.textpsize)); + st->print_cr(" Thread stack page size (pthread): %s", + describe_pagesize(g_multipage_support.pthr_stack_pagesize)); st->print_cr(" Default shared memory page size: %s", describe_pagesize(g_multipage_support.shmpsize)); st->print_cr(" Can use 64K pages dynamically with shared meory: %s", (g_multipage_support.can_use_64K_pages ? "yes" :"no")); st->print_cr(" Can use 16M pages dynamically with shared memory: %s", (g_multipage_support.can_use_16M_pages ? "yes" :"no")); - if (g_multipage_error != 0) { - st->print_cr(" multipage error: %d", g_multipage_error); - } + st->print_cr(" Multipage error: %d", + g_multipage_support.error); + st->cr(); + st->print_cr(" os::vm_page_size: %s", describe_pagesize(os::vm_page_size())); + // not used in OpenJDK st->print_cr(" os::stack_page_size: %s", describe_pagesize(os::stack_page_size())); // print out LDR_CNTRL because it affects the default page sizes const char* const ldr_cntrl = ::getenv("LDR_CNTRL"); st->print_cr(" LDR_CNTRL=%s.", ldr_cntrl ? ldr_cntrl : "<unset>"); + // Print out EXTSHM because it is an unsupported setting. const char* const extshm = ::getenv("EXTSHM"); st->print_cr(" EXTSHM=%s.", extshm ? extshm : "<unset>"); if ( (strcmp(extshm, "on") == 0) || (strcmp(extshm, "ON") == 0) ) { st->print_cr(" *** Unsupported! Please remove EXTSHM from your environment! ***"); } - // Call os::Aix::get_meminfo() to retrieve memory statistics. + // Print out AIXTHREAD_GUARDPAGES because it affects the size of pthread stacks. + const char* const aixthread_guardpages = ::getenv("AIXTHREAD_GUARDPAGES"); + st->print_cr(" AIXTHREAD_GUARDPAGES=%s.", + aixthread_guardpages ? aixthread_guardpages : "<unset>"); + os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { char buffer[256]; if (os::Aix::on_aix()) { - jio_snprintf(buffer, sizeof(buffer), - " physical total : %llu\n" - " physical free : %llu\n" - " swap total : %llu\n" - " swap free : %llu\n", - mi.real_total, - mi.real_free, - mi.pgsp_total, - mi.pgsp_free); + st->print_cr("physical total : " SIZE_FORMAT, mi.real_total); + st->print_cr("physical free : " SIZE_FORMAT, mi.real_free); + st->print_cr("swap total : " SIZE_FORMAT, mi.pgsp_total); + st->print_cr("swap free : " SIZE_FORMAT, mi.pgsp_free); } else { - Unimplemented(); + // PASE - Numbers are result of QWCRSSTS; they mean: + // real_total: Sum of all system pools + // real_free: always 0 + // pgsp_total: we take the size of the system ASP + // pgsp_free: size of system ASP times percentage of system ASP unused + st->print_cr("physical total : " SIZE_FORMAT, mi.real_total); + st->print_cr("system asp total : " SIZE_FORMAT, mi.pgsp_total); + st->print_cr("%% system asp used : " SIZE_FORMAT, + mi.pgsp_total ? (100.0f * (mi.pgsp_total - mi.pgsp_free) / mi.pgsp_total) : -1.0f); } st->print_raw(buffer); - } else { - st->print_cr(" (no more information available)"); - } + } + st->cr(); + + // Print segments allocated with os::reserve_memory. + st->print_cr("internal virtual memory regions used by vm:"); + vmembk_print_on(st); } // Get a string for the cpuinfo that is a summary of the cpu type void os::get_summary_cpu_info(char* buf, size_t buflen) { // This looks good - os::Aix::cpuinfo_t ci; - if (os::Aix::get_cpuinfo(&ci)) { + libperfstat::cpuinfo_t ci; + if (libperfstat::get_cpuinfo(&ci)) { strncpy(buf, ci.version, buflen); } else { strncpy(buf, "AIX", buflen); @@ -1617,10 +1630,15 @@ } void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { + st->print("CPU:"); + st->print("total %d", os::processor_count()); + // It's not safe to query number of active processors after crash. + // st->print("(active %d)", os::active_processor_count()); + st->print(" %s", VM_Version::cpu_features()); + st->cr(); } void os::print_siginfo(outputStream* st, void* siginfo) { - // Use common posix version. os::Posix::print_siginfo_brief(st, (const siginfo_t*) siginfo); st->cr(); } @@ -1759,21 +1777,75 @@ // a counter for each possible signal value static volatile jint pending_signals[NSIG+1] = { 0 }; -// Linux(POSIX) specific hand shaking semaphore. +// Wrapper functions for: sem_init(), sem_post(), sem_wait() +// On AIX, we use sem_init(), sem_post(), sem_wait() +// On Pase, we need to use msem_lock() and msem_unlock(), because Posix Semaphores +// do not seem to work at all on PASE (unimplemented, will cause SIGILL). +// Note that just using msem_.. APIs for both PASE and AIX is not an option either, as +// on AIX, msem_..() calls are suspected of causing problems. static sem_t sig_sem; +static msemaphore* p_sig_msem = 0; + +static void local_sem_init() { + if (os::Aix::on_aix()) { + int rc = ::sem_init(&sig_sem, 0, 0); + guarantee(rc != -1, "sem_init failed"); + } else { + // Memory semaphores must live in shared mem. + guarantee0(p_sig_msem == NULL); + p_sig_msem = (msemaphore*)os::reserve_memory(sizeof(msemaphore), NULL); + guarantee(p_sig_msem, "Cannot allocate memory for memory semaphore"); + guarantee(::msem_init(p_sig_msem, 0) == p_sig_msem, "msem_init failed"); + } +} + +static void local_sem_post() { + static bool warn_only_once = false; + if (os::Aix::on_aix()) { + int rc = ::sem_post(&sig_sem); + if (rc == -1 && !warn_only_once) { + trcVerbose("sem_post failed (errno = %d, %s)", errno, strerror(errno)); + warn_only_once = true; + } + } else { + guarantee0(p_sig_msem != NULL); + int rc = ::msem_unlock(p_sig_msem, 0); + if (rc == -1 && !warn_only_once) { + trcVerbose("msem_unlock failed (errno = %d, %s)", errno, strerror(errno)); + warn_only_once = true; + } + } +} + +static void local_sem_wait() { + static bool warn_only_once = false; + if (os::Aix::on_aix()) { + int rc = ::sem_wait(&sig_sem); + if (rc == -1 && !warn_only_once) { + trcVerbose("sem_wait failed (errno = %d, %s)", errno, strerror(errno)); + warn_only_once = true; + } + } else { + guarantee0(p_sig_msem != NULL); // must init before use + int rc = ::msem_lock(p_sig_msem, 0); + if (rc == -1 && !warn_only_once) { + trcVerbose("msem_lock failed (errno = %d, %s)", errno, strerror(errno)); + warn_only_once = true; + } + } +} void os::signal_init_pd() { // Initialize signal structures ::memset((void*)pending_signals, 0, sizeof(pending_signals)); // Initialize signal semaphore - int rc = ::sem_init(&sig_sem, 0, 0); - guarantee(rc != -1, "sem_init failed"); + local_sem_init(); } void os::signal_notify(int sig) { Atomic::inc(&pending_signals[sig]); - ::sem_post(&sig_sem); + local_sem_post(); } static int check_pending_signals(bool wait) { @@ -1796,7 +1868,7 @@ thread->set_suspend_equivalent(); // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self() - ::sem_wait(&sig_sem); + local_sem_wait(); // were we externally suspended while we were waiting? threadIsSuspended = thread->handle_special_suspend_equivalent_condition(); @@ -1807,7 +1879,8 @@ // while suspended because that would surprise the thread that // suspended us. // - ::sem_post(&sig_sem); + + local_sem_post(); thread->java_suspend_self(); } @@ -1858,14 +1931,14 @@ // also check that range is fully page aligned to the page size if the block. void assert_is_valid_subrange(char* p, size_t s) const { if (!contains_range(p, s)) { - fprintf(stderr, "[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub " - "range of [" PTR_FORMAT " - " PTR_FORMAT "].\n", - p, p + s - 1, addr, addr + size - 1); + trcVerbose("[" PTR_FORMAT " - " PTR_FORMAT "] is not a sub " + "range of [" PTR_FORMAT " - " PTR_FORMAT "].", + p, p + s, addr, addr + size); guarantee0(false); } if (!is_aligned_to(p, pagesize) || !is_aligned_to(p + s, pagesize)) { - fprintf(stderr, "range [" PTR_FORMAT " - " PTR_FORMAT "] is not" - " aligned to pagesize (%s)\n", p, p + s); + trcVerbose("range [" PTR_FORMAT " - " PTR_FORMAT "] is not" + " aligned to pagesize (%lu)", p, p + s, (unsigned long) pagesize); guarantee0(false); } } @@ -1962,7 +2035,7 @@ // Reserve the shared segment. int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | S_IRUSR | S_IWUSR); if (shmid == -1) { - trc("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno); + trcVerbose("shmget(.., " UINTX_FORMAT ", ..) failed (errno: %d).", size, errno); return NULL; } @@ -1991,7 +2064,7 @@ // (A) Right after shmat and before handing shmat errors delete the shm segment. if (::shmctl(shmid, IPC_RMID, NULL) == -1) { - trc("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); + trcVerbose("shmctl(%u, IPC_RMID) failed (%d)\n", shmid, errno); assert(false, "failed to remove shared memory segment!"); } @@ -2056,6 +2129,8 @@ return true; } +//////////////////////////////// mmap-based routines ///////////////////////////////// + // Reserve memory via mmap. // If <requested_addr> is given, an attempt is made to attach at the given address. // Failing that, memory is allocated at any address. @@ -2201,9 +2276,6 @@ return rc; } -// End: shared memory bookkeeping -//////////////////////////////////////////////////////////////////////////////////////////////////// - int os::vm_page_size() { // Seems redundant as all get out. assert(os::Aix::page_size() != -1, "must call os::init"); @@ -2245,11 +2317,18 @@ size, os::vm_page_size()); vmembk_t* const vmi = vmembk_find(addr); - assert0(vmi); + guarantee0(vmi); vmi->assert_is_valid_subrange(addr, size); trcVerbose("commit_memory [" PTR_FORMAT " - " PTR_FORMAT "].", addr, addr + size - 1); + if (UseExplicitCommit) { + // AIX commits memory on touch. So, touch all pages to be committed. + for (char* p = addr; p < (addr + size); p += SIZE_4K) { + *p = '\0'; + } + } + return true; } @@ -2274,7 +2353,7 @@ // Dynamically do different things for mmap/shmat. const vmembk_t* const vmi = vmembk_find(addr); - assert0(vmi); + guarantee0(vmi); vmi->assert_is_valid_subrange(addr, size); if (vmi->type == VMEM_SHMATED) { @@ -2372,7 +2451,7 @@ // Dynamically do different things for mmap/shmat. vmembk_t* const vmi = vmembk_find(addr); - assert0(vmi); + guarantee0(vmi); // Always round to os::vm_page_size(), which may be larger than 4K. size = align_size_up(size, os::vm_page_size()); @@ -2448,11 +2527,31 @@ } else { rc = read_protected; } + + if (!rc) { + if (os::Aix::on_pase()) { + // There is an issue on older PASE systems where mprotect() will return success but the + // memory will not be protected. + // This has nothing to do with the problem of using mproect() on SPEC1170 incompatible + // machines; we only see it rarely, when using mprotect() to protect the guard page of + // a stack. It is an OS error. + // + // A valid strategy is just to try again. This usually works. :-/ + + ::usleep(1000); + if (::mprotect(addr, size, prot) == 0) { + const bool read_protected_2 = + (SafeFetch32((int*)addr, 0x12345678) == 0x12345678 && + SafeFetch32((int*)addr, 0x76543210) == 0x76543210) ? true : false; + rc = true; + } + } + } } } - if (!rc) { - assert(false, "mprotect failed."); - } + + assert(rc == true, "mprotect failed."); + return rc; } @@ -2489,10 +2588,11 @@ } char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { - // "exec" is passed in but not used. Creating the shared image for - // the code cache doesn't have an SHM_X executable permission to check. - Unimplemented(); - return 0; + // reserve_memory_special() is used to allocate large paged memory. On AIX, we implement + // 64k paged memory reservation using the normal memory allocation paths (os::reserve_memory()), + // so this is not needed. + assert(false, "should not be called on AIX"); + return NULL; } bool os::release_memory_special(char* base, size_t bytes) { @@ -2944,7 +3044,9 @@ // getting raised while being blocked. unblock_program_error_signals(); + int orig_errno = errno; // Preserve errno value over signal handler. JVM_handle_aix_signal(sig, info, uc, true); + errno = orig_errno; } // This boolean allows users to forward their own non-matching signals @@ -3066,7 +3168,6 @@ void* oldhand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction) : CAST_FROM_FN_PTR(void*, oldAct.sa_handler); - // Renamed 'signalHandler' to avoid collision with other shared libs. if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) && oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) && oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)javaSignalHandler)) { @@ -3090,7 +3191,6 @@ sigAct.sa_handler = SIG_DFL; sigAct.sa_flags = SA_RESTART; } else { - // Renamed 'signalHandler' to avoid collision with other shared libs. sigAct.sa_sigaction = javaSignalHandler; sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } @@ -3282,7 +3382,7 @@ struct sigaction act; if (os_sigaction == NULL) { // only trust the default sigaction, in case it has been interposed - os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction"); + os_sigaction = CAST_TO_FN_PTR(os_sigaction_t, dlsym(RTLD_DEFAULT, "sigaction")); if (os_sigaction == NULL) return; } @@ -3299,7 +3399,6 @@ case SIGPIPE: case SIGILL: case SIGXFSZ: - // Renamed 'signalHandler' to avoid collision with other shared libs. jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)javaSignalHandler); break; @@ -3357,6 +3456,10 @@ // (Shared memory boundary is supposed to be a 256M aligned.) assert(SHMLBA == ((uint64_t)0x10000000ULL)/*256M*/, "unexpected"); + // Record process break at startup. + g_brk_at_startup = (address) ::sbrk(0); + assert(g_brk_at_startup != (address) -1, "sbrk failed"); + // First off, we need to know whether we run on AIX or PASE, and // the OS level we run on. os::Aix::initialize_os_info(); @@ -3364,7 +3467,7 @@ // Scan environment (SPEC1170 behaviour, etc). os::Aix::scan_environment(); - // Check which pages are supported by AIX. + // Probe multipage support. query_multipage_support(); // Act like we only have one page size by eliminating corner cases which @@ -3417,9 +3520,9 @@ } } else { // datapsize = 64k. Data segment, thread stacks are 64k paged. - // This normally means that we can allocate 64k pages dynamically. - // (There is one special case where this may be false: EXTSHM=on. - // but we decided to not support that mode). + // This normally means that we can allocate 64k pages dynamically. + // (There is one special case where this may be false: EXTSHM=on. + // but we decided to not support that mode). assert0(g_multipage_support.can_use_64K_pages); Aix::_page_size = SIZE_64K; trcVerbose("64K page mode"); @@ -3435,7 +3538,7 @@ _page_sizes[0] = 0; // debug trace - trcVerbose("os::vm_page_size %s\n", describe_pagesize(os::vm_page_size())); + trcVerbose("os::vm_page_size %s", describe_pagesize(os::vm_page_size())); // Next, we need to initialize libo4 and libperfstat libraries. if (os::Aix::on_pase()) { @@ -3453,8 +3556,6 @@ // need libperfstat etc. os::Aix::initialize_system_info(); - _initial_pid = getpid(); - clock_tics_per_sec = sysconf(_SC_CLK_TCK); init_random(1234567); @@ -3479,11 +3580,21 @@ // This is called _after_ the global arguments have been parsed. jint os::init_2(void) { + if (os::Aix::on_pase()) { + trcVerbose("Running on PASE."); + } else { + trcVerbose("Running on AIX (not PASE)."); + } + trcVerbose("processor count: %d", os::_processor_count); trcVerbose("physical memory: %lu", Aix::_physical_memory); // Initially build up the loaded dll map. LoadedLibraries::reload(); + if (Verbose) { + trcVerbose("Loaded Libraries: "); + LoadedLibraries::print(tty); + } const int page_size = Aix::page_size(); const int map_size = page_size; @@ -3521,10 +3632,8 @@ map_size, prot, flags | MAP_FIXED, -1, 0); - if (Verbose) { - fprintf(stderr, "SafePoint Polling Page address: %p (wish) => %p\n", - address_wishes[i], map_address + (ssize_t)page_size); - } + trcVerbose("SafePoint Polling Page address: %p (wish) => %p", + address_wishes[i], map_address + (ssize_t)page_size); if (map_address + (ssize_t)page_size == address_wishes[i]) { // Map succeeded and map_address is at wished address, exit loop. @@ -3551,11 +3660,9 @@ guarantee(mem_serialize_page != NULL, "mmap Failed for memory serialize page"); os::set_memory_serialize_page(mem_serialize_page); -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page); - } -#endif + trcVerbose("Memory Serialize Page address: %p - %p, size %IX (%IB)", + mem_serialize_page, mem_serialize_page + Aix::page_size(), + Aix::page_size(), Aix::page_size()); } // initialize suspend/resume support - must do this before signal_sets_init() @@ -3592,7 +3699,10 @@ // Note that this can be 0, if no default stacksize was set. JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes, vm_page_size())); - Aix::libpthread_init(); + if (UseNUMA) { + UseNUMA = false; + warning("NUMA optimizations are not available on this OS."); + } if (MaxFDLimit) { // Set the number of file descriptors to max. print out error @@ -3614,7 +3724,7 @@ if (PerfAllowAtExitRegistration) { // Only register atexit functions if PerfAllowAtExitRegistration is set. - // Atexit functions can be delayed until process exit time, which + // At exit functions can be delayed until process exit time, which // can be problematic for embedded VM situations. Embedded VMs should // call DestroyJavaVM() to assure that VM resources are released. @@ -3714,16 +3824,6 @@ //////////////////////////////////////////////////////////////////////////////// // debug support -static address same_page(address x, address y) { - intptr_t page_bits = -os::vm_page_size(); - if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) - return x; - else if (x > y) - return (address)(intptr_t(y) | ~page_bits) + 1; - else - return (address)(intptr_t(y) & page_bits); -} - bool os::find(address addr, outputStream* st) { st->print(PTR_FORMAT ": ", addr); @@ -4087,24 +4187,28 @@ // For now just return the system wide load average (no processor sets). int os::loadavg(double values[], int nelem) { - // Implemented using libperfstat on AIX. - guarantee(nelem >= 0 && nelem <= 3, "argument error"); guarantee(values, "argument error"); if (os::Aix::on_pase()) { - Unimplemented(); - return -1; + + // AS/400 PASE: use libo4 porting library + double v[3] = { 0.0, 0.0, 0.0 }; + + if (libo4::get_load_avg(v, v + 1, v + 2)) { + for (int i = 0; i < nelem; i ++) { + values[i] = v[i]; + } + return nelem; + } else { + return -1; + } + } else { + // AIX: use libperfstat - // - // See also: - // http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/perfstat_cputot.htm - // /usr/include/libperfstat.h: - - // Use the already AIX version independent get_cpuinfo. - os::Aix::cpuinfo_t ci; - if (os::Aix::get_cpuinfo(&ci)) { + libperfstat::cpuinfo_t ci; + if (libperfstat::get_cpuinfo(&ci)) { for (int i = 0; i < nelem; i++) { values[i] = ci.loadavg[i]; } @@ -4131,8 +4235,7 @@ (void)::poll(NULL, 0, 100); } } else { - jio_fprintf(stderr, - "Could not open pause file '%s', continuing immediately.\n", filename); + trcVerbose("Could not open pause file '%s', continuing immediately.", filename); } } @@ -4154,7 +4257,7 @@ memset(&uts, 0, sizeof(uts)); strcpy(uts.sysname, "?"); if (::uname(&uts) == -1) { - trc("uname failed (%d)", errno); + trcVerbose("uname failed (%d)", errno); guarantee(0, "Could not determine whether we run on AIX or PASE"); } else { trcVerbose("uname says: sysname \"%s\" version \"%s\" release \"%s\" " @@ -4166,15 +4269,22 @@ assert(minor > 0, "invalid OS release"); _os_version = (major << 8) | minor; if (strcmp(uts.sysname, "OS400") == 0) { - Unimplemented(); + // We run on AS/400 PASE. We do not support versions older than V5R4M0. + _on_pase = 1; + if (_os_version < 0x0504) { + trcVerbose("OS/400 releases older than V5R4M0 not supported."); + assert(false, "OS/400 release too old."); + } else { + trcVerbose("We run on OS/400 (pase) V%dR%d", major, minor); + } } else if (strcmp(uts.sysname, "AIX") == 0) { // We run on AIX. We do not support versions older than AIX 5.3. _on_pase = 0; if (_os_version < 0x0503) { - trc("AIX release older than AIX 5.3 not supported."); + trcVerbose("AIX release older than AIX 5.3 not supported."); assert(false, "AIX release too old."); } else { - trcVerbose("We run on AIX %d.%d\n", major, minor); + trcVerbose("We run on AIX %d.%d", major, minor); } } else { assert(false, "unknown OS"); @@ -4200,12 +4310,17 @@ // This switch was needed on AIX 32bit, but on AIX 64bit the general // recommendation is (in OSS notes) to switch it off. p = ::getenv("EXTSHM"); - if (Verbose) { - fprintf(stderr, "EXTSHM=%s.\n", p ? p : "<unset>"); - } + trcVerbose("EXTSHM=%s.", p ? p : "<unset>"); if (p && strcasecmp(p, "ON") == 0) { - fprintf(stderr, "Unsupported setting: EXTSHM=ON. Large Page support will be disabled.\n"); _extshm = 1; + trcVerbose("*** Unsupported mode! Please remove EXTSHM from your environment! ***"); + if (!AllowExtshm) { + // We allow under certain conditions the user to continue. However, we want this + // to be a fatal error by default. On certain AIX systems, leaving EXTSHM=ON means + // that the VM is not able to allocate 64k pages for the heap. + // We do not want to run with reduced performance. + vm_exit_during_initialization("EXTSHM is ON. Please remove EXTSHM from your environment."); + } } else { _extshm = 0; } @@ -4222,7 +4337,7 @@ trcVerbose("XPG_SUS_ENV=%s.", p ? p : "<unset>"); if (p && strcmp(p, "ON") == 0) { _xpg_sus_mode = 1; - trc("Unsupported setting: XPG_SUS_ENV=ON"); + trcVerbose("Unsupported setting: XPG_SUS_ENV=ON"); // This is not supported. Worst of all, it changes behaviour of mmap MAP_FIXED to // clobber address ranges. If we ever want to support that, we have to do some // testing first. @@ -4231,35 +4346,46 @@ _xpg_sus_mode = 0; } - // Switch off AIX internal (pthread) guard pages. This has - // immediate effect for any pthread_create calls which follow. + if (os::Aix::on_pase()) { + p = ::getenv("QIBM_MULTI_THREADED"); + trcVerbose("QIBM_MULTI_THREADED=%s.", p ? p : "<unset>"); + } + + p = ::getenv("LDR_CNTRL"); + trcVerbose("LDR_CNTRL=%s.", p ? p : "<unset>"); + if (os::Aix::on_pase() && os::Aix::os_version() == 0x0701) { + if (p && ::strstr(p, "TEXTPSIZE")) { + trcVerbose("*** WARNING - LDR_CNTRL contains TEXTPSIZE. " + "you may experience hangs or crashes on OS/400 V7R1."); + } + } + p = ::getenv("AIXTHREAD_GUARDPAGES"); trcVerbose("AIXTHREAD_GUARDPAGES=%s.", p ? p : "<unset>"); - rc = ::putenv("AIXTHREAD_GUARDPAGES=0"); - guarantee(rc == 0, ""); } // end: os::Aix::scan_environment() -// PASE: initialize the libo4 library (AS400 PASE porting library). +// PASE: initialize the libo4 library (PASE porting library). void os::Aix::initialize_libo4() { - Unimplemented(); -} - -// AIX: initialize the libperfstat library (we load this dynamically -// because it is only available on AIX. + guarantee(os::Aix::on_pase(), "OS/400 only."); + if (!libo4::init()) { + trcVerbose("libo4 initialization failed."); + assert(false, "libo4 initialization failed"); + } else { + trcVerbose("libo4 initialized."); + } +} + +// AIX: initialize the libperfstat library. void os::Aix::initialize_libperfstat() { - assert(os::Aix::on_aix(), "AIX only"); - if (!libperfstat::init()) { - trc("libperfstat initialization failed."); + trcVerbose("libperfstat initialization failed."); assert(false, "libperfstat initialization failed"); } else { - if (Verbose) { - fprintf(stderr, "libperfstat initialized.\n"); - } - } -} // end: os::Aix::initialize_libperfstat + trcVerbose("libperfstat initialized."); + } +} ///////////////////////////////////////////////////////////////////////////// // thread stack @@ -4296,10 +4422,11 @@ } guarantee0(pinfo.__pi_stackend); - // The following can happen when invoking pthread_getthrds_np on a pthread running - // on a user provided stack (when handing down a stack to pthread create, see - // pthread_attr_setstackaddr). - // Not sure what to do here - I feel inclined to forbid this use case completely. + // The following may happen when invoking pthread_getthrds_np on a pthread + // running on a user provided stack (when handing down a stack to pthread + // create, see pthread_attr_setstackaddr). + // Not sure what to do then. + guarantee0(pinfo.__pi_stacksize); // Note: we get three values from pthread_getthrds_np: @@ -4326,7 +4453,8 @@ // address stack_base = (address)(pinfo.__pi_stackend); - address stack_low_addr = (address)align_ptr_up(pinfo.__pi_stackaddr, os::vm_page_size()); + address stack_low_addr = (address)align_ptr_up(pinfo.__pi_stackaddr, + os::vm_page_size()); size_t stack_size = stack_base - stack_low_addr; if (p_stack_base) {
--- a/hotspot/src/os/aix/vm/os_aix.hpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/os_aix.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -34,9 +34,6 @@ class Aix { friend class os; - // Length of strings included in the libperfstat structures. -#define IDENTIFIER_LENGTH 64 - static bool libjsig_is_loaded; // libjsig that interposes sigaction(), // __sigaction(), signal() is loaded static struct sigaction *(*get_signal_action)(int); @@ -45,13 +42,15 @@ static void check_signal_handler(int sig); - protected: + private: static julong _physical_memory; static pthread_t _main_thread; static Mutex* _createThread_lock; static int _page_size; - static int _logical_cpus; + + // Page size of newly created pthreads. + static int _stack_page_size; // -1 = uninitialized, 0 = AIX, 1 = OS/400 (PASE) static int _on_pase; @@ -63,6 +62,9 @@ // for OS/400 e.g. 0x0504 for OS/400 V5R4 static int _os_version; + // 4 Byte kernel version: Version, Release, Tech Level, Service Pack. + static unsigned int _os_kernel_version; + // -1 = uninitialized, // 0 - SPEC1170 not requested (XPG_SUS_ENV is OFF or not set) // 1 - SPEC1170 requested (XPG_SUS_ENV is ON) @@ -73,35 +75,6 @@ // 1 - EXTSHM=ON static int _extshm; - // page sizes on AIX. - // - // AIX supports four different page sizes - 4K, 64K, 16MB, 16GB. The latter two - // (16M "large" resp. 16G "huge" pages) require special setup and are normally - // not available. - // - // AIX supports multiple page sizes per process, for: - // - Stack (of the primordial thread, so not relevant for us) - // - Data - data, bss, heap, for us also pthread stacks - // - Text - text code - // - shared memory - // - // Default page sizes can be set via linker options (-bdatapsize, -bstacksize, ...) - // and via environment variable LDR_CNTRL (DATAPSIZE, STACKPSIZE, ...) - // - // For shared memory, page size can be set dynamically via shmctl(). Different shared memory - // regions can have different page sizes. - // - // More information can be found at AIBM info center: - // http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.prftungd/doc/prftungd/multiple_page_size_app_support.htm - // - // ----- - // We want to support 4K and 64K and, if the machine is set up correctly, 16MB pages. - // - - // page size of the stack of newly created pthreads - // (should be LDR_CNTRL DATAPSIZE because stack is allocated on heap by pthread lib) - static int _stack_page_size; - static julong available_memory(); static julong physical_memory() { return _physical_memory; } static void initialize_system_info(); @@ -125,9 +98,6 @@ public: static void init_thread_fpu_state(); static pthread_t main_thread(void) { return _main_thread; } - // returns kernel thread id (similar to LWP id on Solaris), which can be - // used to access /proc - static pid_t gettid(); static void set_createThread_lock(Mutex* lk) { _createThread_lock = lk; } static Mutex* createThread_lock(void) { return _createThread_lock; } static void hotspot_sigmask(Thread* thread); @@ -215,6 +185,14 @@ return _os_version; } + // Get 4 byte AIX kernel version number: + // highest 2 bytes: Version, Release + // if available: lowest 2 bytes: Tech Level, Service Pack. + static unsigned int os_kernel_version() { + if (_os_kernel_version) return _os_kernel_version; + return os_version() << 16; + } + // Convenience method: returns true if running on PASE V5R4 or older. static bool on_pase_V5R4_or_older() { return on_pase() && os_version() <= 0x0504; @@ -257,27 +235,12 @@ }; - // Result struct for get_cpuinfo(). - struct cpuinfo_t { - char description[IDENTIFIER_LENGTH]; // processor description (type/official name) - u_longlong_t processorHZ; // processor speed in Hz - int ncpus; // number of active logical processors - double loadavg[3]; // (1<<SBITS) times the average number of runnables processes during the last 1, 5 and 15 minutes. - // To calculate the load average, divide the numbers by (1<<SBITS). SBITS is defined in <sys/proc.h>. - char version[20]; // processor version from _system_configuration (sys/systemcfg.h) - }; - // Functions to retrieve memory information on AIX, PASE. // (on AIX, using libperfstat, on PASE with libo4.so). // Returns true if ok, false if error. static bool get_meminfo(meminfo_t* pmi); - // Function to retrieve cpu information on AIX - // (on AIX, using libperfstat) - // Returns true if ok, false if error. - static bool get_cpuinfo(cpuinfo_t* pci); - -}; // os::Aix class +}; class PlatformEvent : public CHeapObj<mtInternal> {
--- a/hotspot/src/os/aix/vm/os_aix.inline.hpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -60,6 +60,8 @@ // On Aix, reservations are made on a page by page basis, nothing to do. inline void os::pd_split_reserved_memory(char *base, size_t size, size_t split, bool realloc) { + // TODO: Determine whether Sys V memory is split. If yes, we need to treat + // this the same way Windows treats its VirtualAlloc allocations. } // Bang the shadow pages if they need to be touched to be mapped.
--- a/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp Sat Dec 05 07:16:52 2015 +0100 +++ b/hotspot/src/os_cpu/aix_ppc/vm/vmStructs_aix_ppc.hpp Mon Nov 16 10:58:14 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, 2013 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -35,8 +35,7 @@ /******************************/ \ /* Threads (NOTE: incomplete) */ \ /******************************/ \ - nonstatic_field(OSThread, _thread_id, pid_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) + nonstatic_field(OSThread, _thread_id, pthread_t) \ #define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ @@ -45,7 +44,6 @@ /* Posix Thread IDs */ \ /**********************/ \ \ - declare_integer_type(pid_t) \ declare_unsigned_integer_type(pthread_t) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)