Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/aix/vm/os_perf_aix.cpp
32284 views
/*1* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "jvm.h"27#include "memory/allocation.inline.hpp"28#include "os_aix.inline.hpp"29#include "runtime/os.hpp"30#include "runtime/os_perf.hpp"31#include "vm_version_ext_ppc.hpp"3233#include <stdio.h>34#include <stdarg.h>35#include <unistd.h>36#include <errno.h>37#include <string.h>38#include <sys/resource.h>39#include <sys/types.h>40#include <sys/stat.h>41#include <dirent.h>42#include <stdlib.h>43#include <dlfcn.h>44#include <pthread.h>45#include <limits.h>4647/**48/proc/[number]/stat49Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.5051The fields, in order, with their proper scanf(3) format specifiers, are:52531. pid %d The process id.54552. comm %s56The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.57583. state %c59One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk60sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.61624. ppid %d63The PID of the parent.64655. pgrp %d66The process group ID of the process.67686. session %d69The session ID of the process.70717. tty_nr %d72The tty the process uses.73748. tpgid %d75The process group ID of the process which currently owns the tty that the process is connected to.76779. flags %lu78The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10.798010. minflt %lu81The number of minor faults the process has made which have not required loading a memory page from disk.828311. cminflt %lu84The number of minor faults that the process's waited-for children have made.858612. majflt %lu87The number of major faults the process has made which have required loading a memory page from disk.888913. cmajflt %lu90The number of major faults that the process's waited-for children have made.919214. utime %lu93The number of jiffies that this process has been scheduled in user mode.949515. stime %lu96The number of jiffies that this process has been scheduled in kernel mode.979816. cutime %ld99The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)10010117. cstime %ld102The number of jiffies that this process' waited-for children have been scheduled in kernel mode.10310418. priority %ld105The standard nice value, plus fifteen. The value is never negative in the kernel.10610719. nice %ld108The nice value ranges from 19 (nicest) to -19 (not nice to others).10911020. 0 %ld This value is hard coded to 0 as a placeholder for a removed field.11111221. itrealvalue %ld113The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.11411522. starttime %lu116The time in jiffies the process started after system boot.11711823. vsize %lu119Virtual memory size in bytes.12012124. rss %ld122Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count123towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out.12412525. rlim %lu126Current limit in bytes on the rss of the process (usually 4294967295 on i386).12712826. startcode %lu129The address above which program text can run.13013127. endcode %lu132The address below which program text can run.13313428. startstack %lu135The address of the start of the stack.13613729. kstkesp %lu138The current value of esp (stack pointer), as found in the kernel stack page for the process.13914030. kstkeip %lu141The current EIP (instruction pointer).14214331. signal %lu144The bitmap of pending signals (usually 0).14514632. blocked %lu147The bitmap of blocked signals (usually 0, 2 for shells).14814933. sigignore %lu150The bitmap of ignored signals.15115234. sigcatch %lu153The bitmap of catched signals.15415535. wchan %lu156This is the "channel" in which the process is waiting. It is the address of a system call, and can be looked up in a namelist if you need157a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)15815936. nswap %lu160Number of pages swapped - not maintained.16116237. cnswap %lu163Cumulative nswap for child processes.16416538. exit_signal %d166Signal to be sent to parent when we die.16716839. processor %d169CPU number last executed on.170171172173///// SSCANF FORMAT STRING. Copy and use.174175field: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39176format: %d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d177178179*/180181struct CPUPerfTicks {182uint64_t used;183uint64_t usedKernel;184uint64_t total;185};186187typedef enum {188CPU_LOAD_VM_ONLY,189CPU_LOAD_GLOBAL,190} CpuLoadTarget;191192enum {193UNDETECTED,194UNDETECTABLE,195LINUX26_NPTL,196BAREMETAL197};198199struct CPUPerfCounters {200int nProcs;201CPUPerfTicks jvmTicks;202CPUPerfTicks* cpus;203};204205static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);206207/** reads /proc/<pid>/stat data, with some checks and some skips.208* Ensure that 'fmt' does _NOT_ contain the first two "%d %s"209*/210static int vread_statdata(const char* procfile, const char* fmt, va_list args) {211FILE*f;212int n;213char buf[2048];214215if ((f = fopen(procfile, "r")) == NULL) {216return -1;217}218219if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {220char *tmp;221222buf[n-1] = '\0';223/** skip through pid and exec name. */224if ((tmp = strrchr(buf, ')')) != NULL) {225// skip the ')' and the following space226// but check that buffer is long enough227tmp += 2;228if (tmp < buf + n) {229n = vsscanf(tmp, fmt, args);230}231}232}233234fclose(f);235236return n;237}238239static int read_statdata(const char* procfile, const char* fmt, ...) {240int n;241va_list args;242243va_start(args, fmt);244n = vread_statdata(procfile, fmt, args);245va_end(args);246return n;247}248249static FILE* open_statfile(void) {250FILE *f;251252if ((f = fopen("/proc/stat", "r")) == NULL) {253static int haveWarned = 0;254if (!haveWarned) {255haveWarned = 1;256}257}258return f;259}260261static void262next_line(FILE *f) {263int c;264do {265c = fgetc(f);266} while (c != '\n' && c != EOF);267}268269/**270* Return the total number of ticks since the system was booted.271* If the usedTicks parameter is not NULL, it will be filled with272* the number of ticks spent on actual processes (user, system or273* nice processes) since system boot. Note that this is the total number274* of "executed" ticks on _all_ CPU:s, that is on a n-way system it is275* n times the number of ticks that has passed in clock time.276*277* Returns a negative value if the reading of the ticks failed.278*/279static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {280FILE* fh;281uint64_t userTicks, niceTicks, systemTicks, idleTicks;282uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0;283int logical_cpu = -1;284const int expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5;285int n;286287if ((fh = open_statfile()) == NULL) {288return OS_ERR;289}290if (-1 == which_logical_cpu) {291n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "292UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,293&userTicks, &niceTicks, &systemTicks, &idleTicks,294&iowTicks, &irqTicks, &sirqTicks);295} else {296// Move to next line297next_line(fh);298299// find the line for requested cpu faster to just iterate linefeeds?300for (int i = 0; i < which_logical_cpu; i++) {301next_line(fh);302}303304n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "305UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,306&logical_cpu, &userTicks, &niceTicks,307&systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks);308}309310fclose(fh);311if (n < expected_assign_count || logical_cpu != which_logical_cpu) {312#ifdef DEBUG_LINUX_PROC_STAT313vm_fprintf(stderr, "[stat] read failed");314#endif315return OS_ERR;316}317318#ifdef DEBUG_LINUX_PROC_STAT319vm_fprintf(stderr, "[stat] read "320UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "321UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n",322userTicks, niceTicks, systemTicks, idleTicks,323iowTicks, irqTicks, sirqTicks);324#endif325326pticks->used = userTicks + niceTicks;327pticks->usedKernel = systemTicks + irqTicks + sirqTicks;328pticks->total = userTicks + niceTicks + systemTicks + idleTicks +329iowTicks + irqTicks + sirqTicks;330331return OS_OK;332}333334335static int get_systemtype(void) {336static int procEntriesType = UNDETECTED;337DIR *taskDir;338339if (procEntriesType != UNDETECTED) {340return procEntriesType;341}342343// Check whether we have a task subdirectory344if ((taskDir = opendir("/proc/self/task")) == NULL) {345procEntriesType = UNDETECTABLE;346} else {347// The task subdirectory exists; we're on a Linux >= 2.6 system348closedir(taskDir);349procEntriesType = LINUX26_NPTL;350}351352return procEntriesType;353}354355/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */356static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {357return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,358userTicks, systemTicks);359}360361/**362* Return the number of ticks spent in any of the processes belonging363* to the JVM on any CPU.364*/365static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {366uint64_t userTicks;367uint64_t systemTicks;368369if (get_systemtype() != LINUX26_NPTL) {370return OS_ERR;371}372373if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {374return OS_ERR;375}376377// get the total378if (get_total_ticks(-1, pticks) != OS_OK) {379return OS_ERR;380}381382pticks->used = userTicks;383pticks->usedKernel = systemTicks;384385return OS_OK;386}387388/**389* Return the load of the CPU as a double. 1.0 means the CPU process uses all390* available time for user or system processes, 0.0 means the CPU uses all time391* being idle.392*393* Returns a negative value if there is a problem in determining the CPU load.394*/395static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {396uint64_t udiff, kdiff, tdiff;397CPUPerfTicks* pticks;398CPUPerfTicks tmp;399double user_load;400401*pkernelLoad = 0.0;402403if (target == CPU_LOAD_VM_ONLY) {404pticks = &counters->jvmTicks;405} else if (-1 == which_logical_cpu) {406pticks = &counters->cpus[counters->nProcs];407} else {408pticks = &counters->cpus[which_logical_cpu];409}410411tmp = *pticks;412413if (target == CPU_LOAD_VM_ONLY) {414if (get_jvm_ticks(pticks) != OS_OK) {415return -1.0;416}417} else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) {418return -1.0;419}420421// seems like we sometimes end up with less kernel ticks when422// reading /proc/self/stat a second time, timing issue between cpus?423if (pticks->usedKernel < tmp.usedKernel) {424kdiff = 0;425} else {426kdiff = pticks->usedKernel - tmp.usedKernel;427}428tdiff = pticks->total - tmp.total;429udiff = pticks->used - tmp.used;430431if (tdiff == 0) {432return 0.0;433} else if (tdiff < (udiff + kdiff)) {434tdiff = udiff + kdiff;435}436*pkernelLoad = (kdiff / (double)tdiff);437// BUG9044876, normalize return values to sane values438*pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);439*pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);440441user_load = (udiff / (double)tdiff);442user_load = MAX2<double>(user_load, 0.0);443user_load = MIN2<double>(user_load, 1.0);444445return user_load;446}447448static int parse_stat(const char* fmt, ...) {449FILE *f;450va_list args;451452va_start(args, fmt);453454if ((f = open_statfile()) == NULL) {455va_end(args);456return OS_ERR;457}458for (;;) {459char line[80];460if (fgets(line, sizeof(line), f) != NULL) {461if (vsscanf(line, fmt, args) == 1) {462fclose(f);463va_end(args);464return OS_OK;465}466} else {467fclose(f);468va_end(args);469return OS_ERR;470}471}472}473474static int get_noof_context_switches(uint64_t* switches) {475return parse_stat("ctxt " UINT64_FORMAT "\n", switches);476}477478/** returns boot time in _seconds_ since epoch */479static int get_boot_time(uint64_t* time) {480return parse_stat("btime " UINT64_FORMAT "\n", time);481}482483static int perf_context_switch_rate(double* rate) {484static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;485static uint64_t lastTime;486static uint64_t lastSwitches;487static double lastRate;488489uint64_t lt = 0;490int res = 0;491492if (lastTime == 0) {493uint64_t tmp;494if (get_boot_time(&tmp) < 0) {495return OS_ERR;496}497lt = tmp * 1000;498}499500res = OS_OK;501502pthread_mutex_lock(&contextSwitchLock);503{504505uint64_t sw;506s8 t, d;507508if (lastTime == 0) {509lastTime = lt;510}511512t = os::javaTimeMillis();513d = t - lastTime;514515if (d == 0) {516*rate = lastRate;517} else if (!get_noof_context_switches(&sw)) {518*rate = ( (double)(sw - lastSwitches) / d ) * 1000;519lastRate = *rate;520lastSwitches = sw;521lastTime = t;522} else {523*rate = 0;524res = OS_ERR;525}526if (*rate <= 0) {527*rate = 0;528lastRate = 0;529}530}531pthread_mutex_unlock(&contextSwitchLock);532533return res;534}535536class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {537friend class CPUPerformanceInterface;538private:539CPUPerfCounters _counters;540541int cpu_load(int which_logical_cpu, double* cpu_load);542int context_switch_rate(double* rate);543int cpu_load_total_process(double* cpu_load);544int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);545546public:547CPUPerformance();548bool initialize();549~CPUPerformance();550};551552CPUPerformanceInterface::CPUPerformance::CPUPerformance() {553_counters.nProcs = os::active_processor_count();554_counters.cpus = NULL;555}556557bool CPUPerformanceInterface::CPUPerformance::initialize() {558size_t tick_array_size = (_counters.nProcs +1) * sizeof(CPUPerfTicks);559_counters.cpus = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);560if (NULL == _counters.cpus) {561return false;562}563memset(_counters.cpus, 0, tick_array_size);564565// For the CPU load total566get_total_ticks(-1, &_counters.cpus[_counters.nProcs]);567568// For each CPU569for (int i = 0; i < _counters.nProcs; i++) {570get_total_ticks(i, &_counters.cpus[i]);571}572// For JVM load573get_jvm_ticks(&_counters.jvmTicks);574575// initialize context switch system576// the double is only for init577double init_ctx_switch_rate;578perf_context_switch_rate(&init_ctx_switch_rate);579580return true;581}582583CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {584if (_counters.cpus != NULL) {585FREE_C_HEAP_ARRAY(char, _counters.cpus, mtInternal);586}587}588589int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {590double u, s;591u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);592if (u < 0) {593*cpu_load = 0.0;594return OS_ERR;595}596// Cap total systemload to 1.0597*cpu_load = MIN2<double>((u + s), 1.0);598return OS_OK;599}600601int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {602double u, s;603u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);604if (u < 0) {605*cpu_load = 0.0;606return OS_ERR;607}608*cpu_load = u + s;609return OS_OK;610}611612int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {613double u, s, t;614615assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");616assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");617assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");618619u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);620if (u < 0) {621*pjvmUserLoad = 0.0;622*pjvmKernelLoad = 0.0;623*psystemTotalLoad = 0.0;624return OS_ERR;625}626627cpu_load(-1, &t);628// clamp at user+system and 1.0629if (u + s > t) {630t = MIN2<double>(u + s, 1.0);631}632633*pjvmUserLoad = u;634*pjvmKernelLoad = s;635*psystemTotalLoad = t;636637return OS_OK;638}639640int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {641return perf_context_switch_rate(rate);642}643644CPUPerformanceInterface::CPUPerformanceInterface() {645_impl = NULL;646}647648bool CPUPerformanceInterface::initialize() {649_impl = new CPUPerformanceInterface::CPUPerformance();650return NULL == _impl ? false : _impl->initialize();651}652653CPUPerformanceInterface::~CPUPerformanceInterface() {654if (_impl != NULL) {655delete _impl;656}657}658659int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {660return _impl->cpu_load(which_logical_cpu, cpu_load);661}662663int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {664return _impl->cpu_load_total_process(cpu_load);665}666667int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {668return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);669}670671int CPUPerformanceInterface::context_switch_rate(double* rate) const {672return _impl->context_switch_rate(rate);673}674675class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {676friend class SystemProcessInterface;677private:678class ProcessIterator : public CHeapObj<mtInternal> {679friend class SystemProcessInterface::SystemProcesses;680private:681DIR* _dir;682struct dirent* _entry;683bool _valid;684char _exeName[PATH_MAX];685char _exePath[PATH_MAX];686687ProcessIterator();688~ProcessIterator();689bool initialize();690691bool is_valid() const { return _valid; }692bool is_valid_entry(struct dirent* entry) const;693bool is_dir(const char* name) const;694int fsize(const char* name, uint64_t& size) const;695696char* allocate_string(const char* str) const;697void get_exe_name();698char* get_exe_path();699char* get_cmdline();700701int current(SystemProcess* process_info);702int next_process();703};704705ProcessIterator* _iterator;706SystemProcesses();707bool initialize();708~SystemProcesses();709710//information about system processes711int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;712};713714bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {715struct stat mystat;716int ret_val = 0;717718ret_val = stat(name, &mystat);719if (ret_val < 0) {720return false;721}722ret_val = S_ISDIR(mystat.st_mode);723return ret_val > 0;724}725726int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {727assert(name != NULL, "name pointer is NULL!");728size = 0;729struct stat fbuf;730731if (stat(name, &fbuf) < 0) {732return OS_ERR;733}734size = fbuf.st_size;735return OS_OK;736}737738// if it has a numeric name, is a directory and has a 'stat' file in it739bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {740char buffer[PATH_MAX];741uint64_t size = 0;742743if (atoi(entry->d_name) != 0) {744jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);745buffer[PATH_MAX - 1] = '\0';746747if (is_dir(buffer)) {748jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);749buffer[PATH_MAX - 1] = '\0';750if (fsize(buffer, size) != OS_ERR) {751return true;752}753}754}755return false;756}757758// get exe-name from /proc/<pid>/stat759void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {760FILE* fp;761char buffer[PATH_MAX];762763jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);764buffer[PATH_MAX - 1] = '\0';765if ((fp = fopen(buffer, "r")) != NULL) {766if (fgets(buffer, PATH_MAX, fp) != NULL) {767char* start, *end;768// exe-name is between the first pair of ( and )769start = strchr(buffer, '(');770if (start != NULL && start[1] != '\0') {771start++;772end = strrchr(start, ')');773if (end != NULL) {774size_t len;775len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);776memcpy(_exeName, start, len);777_exeName[len] = '\0';778}779}780}781fclose(fp);782}783}784785// get command line from /proc/<pid>/cmdline786char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {787FILE* fp;788char buffer[PATH_MAX];789char* cmdline = NULL;790791jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);792buffer[PATH_MAX - 1] = '\0';793if ((fp = fopen(buffer, "r")) != NULL) {794size_t size = 0;795char dummy;796797// find out how long the file is (stat always returns 0)798while (fread(&dummy, 1, 1, fp) == 1) {799size++;800}801if (size > 0) {802cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);803if (cmdline != NULL) {804cmdline[0] = '\0';805if (fseek(fp, 0, SEEK_SET) == 0) {806if (fread(cmdline, 1, size, fp) == size) {807// the file has the arguments separated by '\0',808// so we translate '\0' to ' '809for (size_t i = 0; i < size; i++) {810if (cmdline[i] == '\0') {811cmdline[i] = ' ';812}813}814cmdline[size] = '\0';815}816}817}818}819fclose(fp);820}821return cmdline;822}823824// get full path to exe from /proc/<pid>/exe symlink825char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {826char buffer[PATH_MAX];827828jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);829buffer[PATH_MAX - 1] = '\0';830return realpath(buffer, _exePath);831}832833char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {834if (str != NULL) {835size_t len = strlen(str);836char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);837strncpy(tmp, str, len);838tmp[len] = '\0';839return tmp;840}841return NULL;842}843844int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {845if (!is_valid()) {846return OS_ERR;847}848849process_info->set_pid(atoi(_entry->d_name));850851get_exe_name();852process_info->set_name(allocate_string(_exeName));853854if (get_exe_path() != NULL) {855process_info->set_path(allocate_string(_exePath));856}857858char* cmdline = NULL;859cmdline = get_cmdline();860if (cmdline != NULL) {861process_info->set_command_line(allocate_string(cmdline));862FREE_C_HEAP_ARRAY(char, cmdline, mtInternal);863}864865return OS_OK;866}867868int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {869if (!is_valid()) {870return OS_ERR;871}872873do {874_entry = os::readdir(_dir);875if (_entry == NULL) {876// Error or reached end. Could use errno to distinguish those cases.877_valid = false;878return OS_ERR;879}880} while(!is_valid_entry(_entry));881882_valid = true;883return OS_OK;884}885886SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {887_dir = NULL;888_entry = NULL;889_valid = false;890}891892bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {893// Not yet implemented.894return false;895}896897SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {898if (_dir != NULL) {899os::closedir(_dir);900}901}902903SystemProcessInterface::SystemProcesses::SystemProcesses() {904_iterator = NULL;905}906907bool SystemProcessInterface::SystemProcesses::initialize() {908_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();909return NULL == _iterator ? false : _iterator->initialize();910}911912SystemProcessInterface::SystemProcesses::~SystemProcesses() {913if (_iterator != NULL) {914delete _iterator;915}916}917918int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {919assert(system_processes != NULL, "system_processes pointer is NULL!");920assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");921assert(_iterator != NULL, "iterator is NULL!");922923// initialize pointers924*no_of_sys_processes = 0;925*system_processes = NULL;926927while (_iterator->is_valid()) {928SystemProcess* tmp = new SystemProcess();929_iterator->current(tmp);930931//if already existing head932if (*system_processes != NULL) {933//move "first to second"934tmp->set_next(*system_processes);935}936// new head937*system_processes = tmp;938// increment939(*no_of_sys_processes)++;940// step forward941_iterator->next_process();942}943return OS_OK;944}945946int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {947return _impl->system_processes(system_procs, no_of_sys_processes);948}949950SystemProcessInterface::SystemProcessInterface() {951_impl = NULL;952}953954bool SystemProcessInterface::initialize() {955_impl = new SystemProcessInterface::SystemProcesses();956return NULL == _impl ? false : _impl->initialize();957}958959SystemProcessInterface::~SystemProcessInterface() {960if (_impl != NULL) {961delete _impl;962}963}964965CPUInformationInterface::CPUInformationInterface() {966_cpu_info = NULL;967}968969bool CPUInformationInterface::initialize() {970_cpu_info = new CPUInformation();971if (NULL == _cpu_info) {972return false;973}974_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());975_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());976_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());977_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());978_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());979980return true;981}982983CPUInformationInterface::~CPUInformationInterface() {984if (_cpu_info != NULL) {985if (_cpu_info->cpu_name() != NULL) {986const char* cpu_name = _cpu_info->cpu_name();987FREE_C_HEAP_ARRAY(char, cpu_name, mtInternal);988_cpu_info->set_cpu_name(NULL);989}990if (_cpu_info->cpu_description() != NULL) {991const char* cpu_desc = _cpu_info->cpu_description();992FREE_C_HEAP_ARRAY(char, cpu_desc, mtInternal);993_cpu_info->set_cpu_description(NULL);994}995delete _cpu_info;996}997}998999int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {1000if (_cpu_info == NULL) {1001return OS_ERR;1002}10031004cpu_info = *_cpu_info; // shallow copy assignment1005return OS_OK;1006}10071008class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {1009friend class NetworkPerformanceInterface;1010private:1011NetworkPerformance();1012NetworkPerformance(const NetworkPerformance& rhs); // no impl1013NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl1014bool initialize();1015~NetworkPerformance();1016int network_utilization(NetworkInterface** network_interfaces) const;1017};10181019NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {10201021}10221023bool NetworkPerformanceInterface::NetworkPerformance::initialize() {1024return true;1025}10261027NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {1028}10291030int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const1031{1032return FUNCTIONALITY_NOT_IMPLEMENTED;1033}10341035NetworkPerformanceInterface::NetworkPerformanceInterface() {1036_impl = NULL;1037}10381039NetworkPerformanceInterface::~NetworkPerformanceInterface() {1040if (_impl != NULL) {1041delete _impl;1042}1043}10441045bool NetworkPerformanceInterface::initialize() {1046_impl = new NetworkPerformanceInterface::NetworkPerformance();1047return _impl != NULL && _impl->initialize();1048}10491050int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {1051return _impl->network_utilization(network_interfaces);1052}105310541055