Path: blob/jdk8u272-b10-aarch32-20201026/hotspot/src/os/linux/vm/os_perf_linux.cpp
48785 views
/*1* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jvm.h"26#include "memory/allocation.inline.hpp"27#include "os_linux.inline.hpp"28#include "runtime/os.hpp"29#include "runtime/os_perf.hpp"3031#ifdef TARGET_ARCH_aarch3232# include "vm_version_ext_aarch32.hpp"33#endif34#ifdef TARGET_ARCH_aarch6435# include "vm_version_ext_aarch64.hpp"36#endif37#ifdef TARGET_ARCH_x8638# include "vm_version_ext_x86.hpp"39#endif40#ifdef TARGET_ARCH_sparc41# include "vm_version_ext_sparc.hpp"42#endif43#ifdef TARGET_ARCH_zero44# include "vm_version_ext_zero.hpp"45#endif46#ifdef TARGET_ARCH_arm47# include "vm_version_ext_arm.hpp"48#endif49#ifdef TARGET_ARCH_ppc50# include "vm_version_ext_ppc.hpp"51#endif5253#include <stdio.h>54#include <stdarg.h>55#include <unistd.h>56#include <errno.h>57#include <string.h>58#include <sys/resource.h>59#include <sys/types.h>60#include <sys/stat.h>61#include <dirent.h>62#include <stdlib.h>63#include <dlfcn.h>64#include <pthread.h>65#include <limits.h>66#ifdef __ANDROID__67# include "ifaddrs.h"68#else69# include <ifaddrs.h>70#endif71#include <fcntl.h>7273/**74/proc/[number]/stat75Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.7677The fields, in order, with their proper scanf(3) format specifiers, are:78791. pid %d The process id.80812. comm %s82The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.83843. state %c85One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk86sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.87884. ppid %d89The PID of the parent.90915. pgrp %d92The process group ID of the process.93946. session %d95The session ID of the process.96977. tty_nr %d98The tty the process uses.991008. tpgid %d101The process group ID of the process which currently owns the tty that the process is connected to.1021039. flags %lu104The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10.10510610. minflt %lu107The number of minor faults the process has made which have not required loading a memory page from disk.10810911. cminflt %lu110The number of minor faults that the process's waited-for children have made.11111212. majflt %lu113The number of major faults the process has made which have required loading a memory page from disk.11411513. cmajflt %lu116The number of major faults that the process's waited-for children have made.11711814. utime %lu119The number of jiffies that this process has been scheduled in user mode.12012115. stime %lu122The number of jiffies that this process has been scheduled in kernel mode.12312416. cutime %ld125The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)12612717. cstime %ld128The number of jiffies that this process' waited-for children have been scheduled in kernel mode.12913018. priority %ld131The standard nice value, plus fifteen. The value is never negative in the kernel.13213319. nice %ld134The nice value ranges from 19 (nicest) to -19 (not nice to others).13513620. 0 %ld This value is hard coded to 0 as a placeholder for a removed field.13713821. itrealvalue %ld139The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.14014122. starttime %lu142The time in jiffies the process started after system boot.14314423. vsize %lu145Virtual memory size in bytes.14614724. rss %ld148Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count149towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out.15015125. rlim %lu152Current limit in bytes on the rss of the process (usually 4294967295 on i386).15315426. startcode %lu155The address above which program text can run.15615727. endcode %lu158The address below which program text can run.15916028. startstack %lu161The address of the start of the stack.16216329. kstkesp %lu164The current value of esp (stack pointer), as found in the kernel stack page for the process.16516630. kstkeip %lu167The current EIP (instruction pointer).16816931. signal %lu170The bitmap of pending signals (usually 0).17117232. blocked %lu173The bitmap of blocked signals (usually 0, 2 for shells).17417533. sigignore %lu176The bitmap of ignored signals.17717834. sigcatch %lu179The bitmap of catched signals.18018135. wchan %lu182This 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 need183a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)18418536. nswap %lu186Number of pages swapped - not maintained.18718837. cnswap %lu189Cumulative nswap for child processes.19019138. exit_signal %d192Signal to be sent to parent when we die.19319439. processor %d195CPU number last executed on.196197198199///// SSCANF FORMAT STRING. Copy and use.200201field: 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 39202format: %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 %d203204205*/206207/**208* For platforms that have them, when declaring209* a printf-style function,210* formatSpec is the parameter number (starting at 1)211* that is the format argument ("%d pid %s")212* params is the parameter number where the actual args to213* the format starts. If the args are in a va_list, this214* should be 0.215*/216#ifndef PRINTF_ARGS217# define PRINTF_ARGS(formatSpec, params) ATTRIBUTE_PRINTF(formatSpec, params)218#endif219220#ifndef SCANF_ARGS221# define SCANF_ARGS(formatSpec, params) ATTRIBUTE_SCANF(formatSpec, params)222#endif223224#ifndef _PRINTFMT_225# define _PRINTFMT_226#endif227228#ifndef _SCANFMT_229# define _SCANFMT_230#endif231232233struct CPUPerfTicks {234uint64_t used;235uint64_t usedKernel;236uint64_t total;237};238239typedef enum {240CPU_LOAD_VM_ONLY,241CPU_LOAD_GLOBAL,242} CpuLoadTarget;243244enum {245UNDETECTED,246UNDETECTABLE,247LINUX26_NPTL,248BAREMETAL249};250251struct CPUPerfCounters {252int nProcs;253CPUPerfTicks jvmTicks;254CPUPerfTicks* cpus;255};256257static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);258259/** reads /proc/<pid>/stat data, with some checks and some skips.260* Ensure that 'fmt' does _NOT_ contain the first two "%d %s"261*/262static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) {263FILE*f;264int n;265char buf[2048];266267if ((f = fopen(procfile, "r")) == NULL) {268return -1;269}270271if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {272char *tmp;273274buf[n-1] = '\0';275/** skip through pid and exec name. */276if ((tmp = strrchr(buf, ')')) != NULL) {277// skip the ')' and the following space278// but check that buffer is long enough279tmp += 2;280if (tmp < buf + n) {281n = vsscanf(tmp, fmt, args);282}283}284}285286fclose(f);287288return n;289}290291static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) {292int n;293va_list args;294295va_start(args, fmt);296n = vread_statdata(procfile, fmt, args);297va_end(args);298return n;299}300301static FILE* open_statfile(void) {302FILE *f;303304if ((f = fopen("/proc/stat", "r")) == NULL) {305static int haveWarned = 0;306if (!haveWarned) {307haveWarned = 1;308}309}310return f;311}312313static void314next_line(FILE *f) {315int c;316do {317c = fgetc(f);318} while (c != '\n' && c != EOF);319}320321/**322* Return the total number of ticks since the system was booted.323* If the usedTicks parameter is not NULL, it will be filled with324* the number of ticks spent on actual processes (user, system or325* nice processes) since system boot. Note that this is the total number326* of "executed" ticks on _all_ CPU:s, that is on a n-way system it is327* n times the number of ticks that has passed in clock time.328*329* Returns a negative value if the reading of the ticks failed.330*/331static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {332FILE* fh;333uint64_t userTicks, niceTicks, systemTicks, idleTicks;334uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0;335int logical_cpu = -1;336const int expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5;337int n;338339if ((fh = open_statfile()) == NULL) {340return OS_ERR;341}342if (-1 == which_logical_cpu) {343n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "344UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,345&userTicks, &niceTicks, &systemTicks, &idleTicks,346&iowTicks, &irqTicks, &sirqTicks);347} else {348// Move to next line349next_line(fh);350351// find the line for requested cpu faster to just iterate linefeeds?352for (int i = 0; i < which_logical_cpu; i++) {353next_line(fh);354}355356n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "357UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,358&logical_cpu, &userTicks, &niceTicks,359&systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks);360}361362fclose(fh);363if (n < expected_assign_count || logical_cpu != which_logical_cpu) {364#ifdef DEBUG_LINUX_PROC_STAT365vm_fprintf(stderr, "[stat] read failed");366#endif367return OS_ERR;368}369370#ifdef DEBUG_LINUX_PROC_STAT371vm_fprintf(stderr, "[stat] read "372UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "373UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n",374userTicks, niceTicks, systemTicks, idleTicks,375iowTicks, irqTicks, sirqTicks);376#endif377378pticks->used = userTicks + niceTicks;379pticks->usedKernel = systemTicks + irqTicks + sirqTicks;380pticks->total = userTicks + niceTicks + systemTicks + idleTicks +381iowTicks + irqTicks + sirqTicks;382383return OS_OK;384}385386387static int get_systemtype(void) {388static int procEntriesType = UNDETECTED;389DIR *taskDir;390391if (procEntriesType != UNDETECTED) {392return procEntriesType;393}394395// Check whether we have a task subdirectory396if ((taskDir = opendir("/proc/self/task")) == NULL) {397procEntriesType = UNDETECTABLE;398} else {399// The task subdirectory exists; we're on a Linux >= 2.6 system400closedir(taskDir);401procEntriesType = LINUX26_NPTL;402}403404return procEntriesType;405}406407/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */408static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {409return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,410userTicks, systemTicks);411}412413/**414* Return the number of ticks spent in any of the processes belonging415* to the JVM on any CPU.416*/417static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {418uint64_t userTicks;419uint64_t systemTicks;420421if (get_systemtype() != LINUX26_NPTL) {422return OS_ERR;423}424425if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {426return OS_ERR;427}428429// get the total430if (get_total_ticks(-1, pticks) != OS_OK) {431return OS_ERR;432}433434pticks->used = userTicks;435pticks->usedKernel = systemTicks;436437return OS_OK;438}439440/**441* Return the load of the CPU as a double. 1.0 means the CPU process uses all442* available time for user or system processes, 0.0 means the CPU uses all time443* being idle.444*445* Returns a negative value if there is a problem in determining the CPU load.446*/447static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {448uint64_t udiff, kdiff, tdiff;449CPUPerfTicks* pticks;450CPUPerfTicks tmp;451double user_load;452453*pkernelLoad = 0.0;454455if (target == CPU_LOAD_VM_ONLY) {456pticks = &counters->jvmTicks;457} else if (-1 == which_logical_cpu) {458pticks = &counters->cpus[counters->nProcs];459} else {460pticks = &counters->cpus[which_logical_cpu];461}462463tmp = *pticks;464465if (target == CPU_LOAD_VM_ONLY) {466if (get_jvm_ticks(pticks) != OS_OK) {467return -1.0;468}469} else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) {470return -1.0;471}472473// seems like we sometimes end up with less kernel ticks when474// reading /proc/self/stat a second time, timing issue between cpus?475if (pticks->usedKernel < tmp.usedKernel) {476kdiff = 0;477} else {478kdiff = pticks->usedKernel - tmp.usedKernel;479}480tdiff = pticks->total - tmp.total;481udiff = pticks->used - tmp.used;482483if (tdiff == 0) {484return 0.0;485} else if (tdiff < (udiff + kdiff)) {486tdiff = udiff + kdiff;487}488*pkernelLoad = (kdiff / (double)tdiff);489// BUG9044876, normalize return values to sane values490*pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);491*pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);492493user_load = (udiff / (double)tdiff);494user_load = MAX2<double>(user_load, 0.0);495user_load = MIN2<double>(user_load, 1.0);496497return user_load;498}499500static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) {501FILE *f;502va_list args;503504va_start(args, fmt);505506if ((f = open_statfile()) == NULL) {507va_end(args);508return OS_ERR;509}510for (;;) {511char line[80];512if (fgets(line, sizeof(line), f) != NULL) {513if (vsscanf(line, fmt, args) == 1) {514fclose(f);515va_end(args);516return OS_OK;517}518} else {519fclose(f);520va_end(args);521return OS_ERR;522}523}524}525526static int get_noof_context_switches(uint64_t* switches) {527return parse_stat("ctxt " UINT64_FORMAT "\n", switches);528}529530/** returns boot time in _seconds_ since epoch */531static int get_boot_time(uint64_t* time) {532return parse_stat("btime " UINT64_FORMAT "\n", time);533}534535static int perf_context_switch_rate(double* rate) {536static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;537static uint64_t lastTime;538static uint64_t lastSwitches;539static double lastRate;540541uint64_t lt = 0;542int res = 0;543544if (lastTime == 0) {545uint64_t tmp;546if (get_boot_time(&tmp) < 0) {547return OS_ERR;548}549lt = tmp * 1000;550}551552res = OS_OK;553554pthread_mutex_lock(&contextSwitchLock);555{556557uint64_t sw;558s8 t, d;559560if (lastTime == 0) {561lastTime = lt;562}563564t = os::javaTimeMillis();565d = t - lastTime;566567if (d == 0) {568*rate = lastRate;569} else if (!get_noof_context_switches(&sw)) {570*rate = ( (double)(sw - lastSwitches) / d ) * 1000;571lastRate = *rate;572lastSwitches = sw;573lastTime = t;574} else {575*rate = 0;576res = OS_ERR;577}578if (*rate <= 0) {579*rate = 0;580lastRate = 0;581}582}583pthread_mutex_unlock(&contextSwitchLock);584585return res;586}587588class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {589friend class CPUPerformanceInterface;590private:591CPUPerfCounters _counters;592593int cpu_load(int which_logical_cpu, double* cpu_load);594int context_switch_rate(double* rate);595int cpu_load_total_process(double* cpu_load);596int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);597598public:599CPUPerformance();600bool initialize();601~CPUPerformance();602};603604CPUPerformanceInterface::CPUPerformance::CPUPerformance() {605_counters.nProcs = os::active_processor_count();606_counters.cpus = NULL;607}608609bool CPUPerformanceInterface::CPUPerformance::initialize() {610size_t tick_array_size = (_counters.nProcs +1) * sizeof(CPUPerfTicks);611_counters.cpus = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);612if (NULL == _counters.cpus) {613return false;614}615memset(_counters.cpus, 0, tick_array_size);616617// For the CPU load total618get_total_ticks(-1, &_counters.cpus[_counters.nProcs]);619620// For each CPU621for (int i = 0; i < _counters.nProcs; i++) {622get_total_ticks(i, &_counters.cpus[i]);623}624// For JVM load625get_jvm_ticks(&_counters.jvmTicks);626627// initialize context switch system628// the double is only for init629double init_ctx_switch_rate;630perf_context_switch_rate(&init_ctx_switch_rate);631632return true;633}634635CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {636if (_counters.cpus != NULL) {637FREE_C_HEAP_ARRAY(char, _counters.cpus, mtInternal);638}639}640641int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {642double u, s;643u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);644if (u < 0) {645*cpu_load = 0.0;646return OS_ERR;647}648// Cap total systemload to 1.0649*cpu_load = MIN2<double>((u + s), 1.0);650return OS_OK;651}652653int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {654double u, s;655u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);656if (u < 0) {657*cpu_load = 0.0;658return OS_ERR;659}660*cpu_load = u + s;661return OS_OK;662}663664int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {665double u, s, t;666667assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");668assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");669assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");670671u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);672if (u < 0) {673*pjvmUserLoad = 0.0;674*pjvmKernelLoad = 0.0;675*psystemTotalLoad = 0.0;676return OS_ERR;677}678679cpu_load(-1, &t);680// clamp at user+system and 1.0681if (u + s > t) {682t = MIN2<double>(u + s, 1.0);683}684685*pjvmUserLoad = u;686*pjvmKernelLoad = s;687*psystemTotalLoad = t;688689return OS_OK;690}691692int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {693return perf_context_switch_rate(rate);694}695696CPUPerformanceInterface::CPUPerformanceInterface() {697_impl = NULL;698}699700bool CPUPerformanceInterface::initialize() {701_impl = new CPUPerformanceInterface::CPUPerformance();702return NULL == _impl ? false : _impl->initialize();703}704705CPUPerformanceInterface::~CPUPerformanceInterface() {706if (_impl != NULL) {707delete _impl;708}709}710711int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {712return _impl->cpu_load(which_logical_cpu, cpu_load);713}714715int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {716return _impl->cpu_load_total_process(cpu_load);717}718719int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {720return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);721}722723int CPUPerformanceInterface::context_switch_rate(double* rate) const {724return _impl->context_switch_rate(rate);725}726727class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {728friend class SystemProcessInterface;729private:730class ProcessIterator : public CHeapObj<mtInternal> {731friend class SystemProcessInterface::SystemProcesses;732private:733DIR* _dir;734struct dirent* _entry;735bool _valid;736char _exeName[PATH_MAX];737char _exePath[PATH_MAX];738739ProcessIterator();740~ProcessIterator();741bool initialize();742743bool is_valid() const { return _valid; }744bool is_valid_entry(struct dirent* entry) const;745bool is_dir(const char* name) const;746int fsize(const char* name, uint64_t& size) const;747748char* allocate_string(const char* str) const;749void get_exe_name();750char* get_exe_path();751char* get_cmdline();752753int current(SystemProcess* process_info);754int next_process();755};756757ProcessIterator* _iterator;758SystemProcesses();759bool initialize();760~SystemProcesses();761762//information about system processes763int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;764};765766bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {767struct stat mystat;768int ret_val = 0;769770ret_val = stat(name, &mystat);771if (ret_val < 0) {772return false;773}774ret_val = S_ISDIR(mystat.st_mode);775return ret_val > 0;776}777778int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {779assert(name != NULL, "name pointer is NULL!");780size = 0;781struct stat fbuf;782783if (stat(name, &fbuf) < 0) {784return OS_ERR;785}786size = fbuf.st_size;787return OS_OK;788}789790// if it has a numeric name, is a directory and has a 'stat' file in it791bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {792char buffer[PATH_MAX];793uint64_t size = 0;794795if (atoi(entry->d_name) != 0) {796jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);797buffer[PATH_MAX - 1] = '\0';798799if (is_dir(buffer)) {800jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);801buffer[PATH_MAX - 1] = '\0';802if (fsize(buffer, size) != OS_ERR) {803return true;804}805}806}807return false;808}809810// get exe-name from /proc/<pid>/stat811void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {812FILE* fp;813char buffer[PATH_MAX];814815jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);816buffer[PATH_MAX - 1] = '\0';817if ((fp = fopen(buffer, "r")) != NULL) {818if (fgets(buffer, PATH_MAX, fp) != NULL) {819char* start, *end;820// exe-name is between the first pair of ( and )821start = strchr(buffer, '(');822if (start != NULL && start[1] != '\0') {823start++;824end = strrchr(start, ')');825if (end != NULL) {826size_t len;827len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);828memcpy(_exeName, start, len);829_exeName[len] = '\0';830}831}832}833fclose(fp);834}835}836837// get command line from /proc/<pid>/cmdline838char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {839FILE* fp;840char buffer[PATH_MAX];841char* cmdline = NULL;842843jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);844buffer[PATH_MAX - 1] = '\0';845if ((fp = fopen(buffer, "r")) != NULL) {846size_t size = 0;847char dummy;848849// find out how long the file is (stat always returns 0)850while (fread(&dummy, 1, 1, fp) == 1) {851size++;852}853if (size > 0) {854cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);855if (cmdline != NULL) {856cmdline[0] = '\0';857if (fseek(fp, 0, SEEK_SET) == 0) {858if (fread(cmdline, 1, size, fp) == size) {859// the file has the arguments separated by '\0',860// so we translate '\0' to ' '861for (size_t i = 0; i < size; i++) {862if (cmdline[i] == '\0') {863cmdline[i] = ' ';864}865}866cmdline[size] = '\0';867}868}869}870}871fclose(fp);872}873return cmdline;874}875876// get full path to exe from /proc/<pid>/exe symlink877char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {878char buffer[PATH_MAX];879880jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);881buffer[PATH_MAX - 1] = '\0';882return realpath(buffer, _exePath);883}884885char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {886if (str != NULL) {887size_t len = strlen(str);888char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);889strncpy(tmp, str, len);890tmp[len] = '\0';891return tmp;892}893return NULL;894}895896int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {897if (!is_valid()) {898return OS_ERR;899}900901process_info->set_pid(atoi(_entry->d_name));902903get_exe_name();904process_info->set_name(allocate_string(_exeName));905906if (get_exe_path() != NULL) {907process_info->set_path(allocate_string(_exePath));908}909910char* cmdline = NULL;911cmdline = get_cmdline();912if (cmdline != NULL) {913process_info->set_command_line(allocate_string(cmdline));914FREE_C_HEAP_ARRAY(char, cmdline, mtInternal);915}916917return OS_OK;918}919920int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {921if (!is_valid()) {922return OS_ERR;923}924925do {926_entry = os::readdir(_dir);927if (_entry == NULL) {928// Error or reached end. Could use errno to distinguish those cases.929_valid = false;930return OS_ERR;931}932} while(!is_valid_entry(_entry));933934_valid = true;935return OS_OK;936}937938SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {939_dir = NULL;940_entry = NULL;941_valid = false;942}943944bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {945_dir = os::opendir("/proc");946_entry = NULL;947_valid = true;948next_process();949950return true;951}952953SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {954if (_dir != NULL) {955os::closedir(_dir);956}957}958959SystemProcessInterface::SystemProcesses::SystemProcesses() {960_iterator = NULL;961}962963bool SystemProcessInterface::SystemProcesses::initialize() {964_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();965return NULL == _iterator ? false : _iterator->initialize();966}967968SystemProcessInterface::SystemProcesses::~SystemProcesses() {969if (_iterator != NULL) {970delete _iterator;971}972}973974int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {975assert(system_processes != NULL, "system_processes pointer is NULL!");976assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");977assert(_iterator != NULL, "iterator is NULL!");978979// initialize pointers980*no_of_sys_processes = 0;981*system_processes = NULL;982983while (_iterator->is_valid()) {984SystemProcess* tmp = new SystemProcess();985_iterator->current(tmp);986987//if already existing head988if (*system_processes != NULL) {989//move "first to second"990tmp->set_next(*system_processes);991}992// new head993*system_processes = tmp;994// increment995(*no_of_sys_processes)++;996// step forward997_iterator->next_process();998}999return OS_OK;1000}10011002int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {1003return _impl->system_processes(system_procs, no_of_sys_processes);1004}10051006SystemProcessInterface::SystemProcessInterface() {1007_impl = NULL;1008}10091010bool SystemProcessInterface::initialize() {1011_impl = new SystemProcessInterface::SystemProcesses();1012return NULL == _impl ? false : _impl->initialize();1013}10141015SystemProcessInterface::~SystemProcessInterface() {1016if (_impl != NULL) {1017delete _impl;1018}1019}10201021CPUInformationInterface::CPUInformationInterface() {1022_cpu_info = NULL;1023}10241025bool CPUInformationInterface::initialize() {1026_cpu_info = new CPUInformation();1027if (NULL == _cpu_info) {1028return false;1029}1030_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());1031_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());1032_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());1033_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());1034_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());10351036return true;1037}10381039CPUInformationInterface::~CPUInformationInterface() {1040if (_cpu_info != NULL) {1041if (_cpu_info->cpu_name() != NULL) {1042const char* cpu_name = _cpu_info->cpu_name();1043FREE_C_HEAP_ARRAY(char, cpu_name, mtInternal);1044_cpu_info->set_cpu_name(NULL);1045}1046if (_cpu_info->cpu_description() != NULL) {1047const char* cpu_desc = _cpu_info->cpu_description();1048FREE_C_HEAP_ARRAY(char, cpu_desc, mtInternal);1049_cpu_info->set_cpu_description(NULL);1050}1051delete _cpu_info;1052}1053}10541055int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {1056if (_cpu_info == NULL) {1057return OS_ERR;1058}10591060cpu_info = *_cpu_info; // shallow copy assignment1061return OS_OK;1062}10631064class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {1065friend class NetworkPerformanceInterface;1066private:1067NetworkPerformance();1068NetworkPerformance(const NetworkPerformance& rhs); // no impl1069NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl1070bool initialize();1071~NetworkPerformance();1072int64_t read_counter(const char* iface, const char* counter) const;1073int network_utilization(NetworkInterface** network_interfaces) const;1074};10751076NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {10771078}10791080bool NetworkPerformanceInterface::NetworkPerformance::initialize() {1081return true;1082}10831084NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {1085}10861087int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char* iface, const char* counter) const {1088char buf[128];10891090snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter);10911092int fd = open(buf, O_RDONLY);1093if (fd == -1) {1094return -1;1095}10961097ssize_t num_bytes = read(fd, buf, sizeof(buf));1098close(fd);1099if ((num_bytes == -1) || (num_bytes >= static_cast<ssize_t>(sizeof(buf))) || (num_bytes < 1)) {1100return -1;1101}11021103buf[num_bytes] = '\0';1104int64_t value = strtoll(buf, NULL, 10);11051106return value;1107}11081109int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const1110{1111ifaddrs* addresses;1112ifaddrs* cur_address;11131114if (getifaddrs(&addresses) != 0) {1115return OS_ERR;1116}11171118NetworkInterface* ret = NULL;1119for (cur_address = addresses; cur_address != NULL; cur_address = cur_address->ifa_next) {1120if ((cur_address->ifa_addr == NULL) || (cur_address->ifa_addr->sa_family != AF_PACKET)) {1121continue;1122}11231124int64_t bytes_in = read_counter(cur_address->ifa_name, "rx_bytes");1125int64_t bytes_out = read_counter(cur_address->ifa_name, "tx_bytes");11261127NetworkInterface* cur = new NetworkInterface(cur_address->ifa_name, bytes_in, bytes_out, ret);1128ret = cur;1129}11301131freeifaddrs(addresses);1132*network_interfaces = ret;11331134return OS_OK;1135}11361137NetworkPerformanceInterface::NetworkPerformanceInterface() {1138_impl = NULL;1139}11401141NetworkPerformanceInterface::~NetworkPerformanceInterface() {1142if (_impl != NULL) {1143delete _impl;1144}1145}11461147bool NetworkPerformanceInterface::initialize() {1148_impl = new NetworkPerformanceInterface::NetworkPerformance();1149return _impl != NULL && _impl->initialize();1150}11511152int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {1153return _impl->network_utilization(network_interfaces);1154}115511561157