Path: blob/master/src/hotspot/os/linux/os_perf_linux.cpp
64440 views
/*1* Copyright (c) 2012, 2020, 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"30#include "utilities/globalDefinitions.hpp"3132#include CPU_HEADER(vm_version_ext)3334#include <stdio.h>35#include <stdarg.h>36#include <unistd.h>37#include <errno.h>38#include <string.h>39#include <sys/resource.h>40#include <sys/types.h>41#include <sys/stat.h>42#include <dirent.h>43#include <stdlib.h>44#include <dlfcn.h>45#include <pthread.h>46#include <limits.h>47#include <ifaddrs.h>48#include <fcntl.h>4950/**51/proc/[number]/stat52Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.5354The fields, in order, with their proper scanf(3) format specifiers, are:55561. pid %d The process id.57582. comm %s59The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.60613. state %c62One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk63sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.64654. ppid %d66The PID of the parent.67685. pgrp %d69The process group ID of the process.70716. session %d72The session ID of the process.73747. tty_nr %d75The tty the process uses.76778. tpgid %d78The process group ID of the process which currently owns the tty that the process is connected to.79809. flags %lu81The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10.828310. minflt %lu84The number of minor faults the process has made which have not required loading a memory page from disk.858611. cminflt %lu87The number of minor faults that the process's waited-for children have made.888912. majflt %lu90The number of major faults the process has made which have required loading a memory page from disk.919213. cmajflt %lu93The number of major faults that the process's waited-for children have made.949514. utime %lu96The number of jiffies that this process has been scheduled in user mode.979815. stime %lu99The number of jiffies that this process has been scheduled in kernel mode.10010116. cutime %ld102The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)10310417. cstime %ld105The number of jiffies that this process' waited-for children have been scheduled in kernel mode.10610718. priority %ld108The standard nice value, plus fifteen. The value is never negative in the kernel.10911019. nice %ld111The nice value ranges from 19 (nicest) to -19 (not nice to others).11211320. 0 %ld This value is hard coded to 0 as a placeholder for a removed field.11411521. itrealvalue %ld116The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.11711822. starttime %lu119The time in jiffies the process started after system boot.12012123. vsize %lu122Virtual memory size in bytes.12312424. rss %ld125Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count126towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out.12712825. rlim %lu129Current limit in bytes on the rss of the process (usually 4294967295 on i386).13013126. startcode %lu132The address above which program text can run.13313427. endcode %lu135The address below which program text can run.13613728. startstack %lu138The address of the start of the stack.13914029. kstkesp %lu141The current value of esp (stack pointer), as found in the kernel stack page for the process.14214330. kstkeip %lu144The current EIP (instruction pointer).14514631. signal %lu147The bitmap of pending signals (usually 0).14814932. blocked %lu150The bitmap of blocked signals (usually 0, 2 for shells).15115233. sigignore %lu153The bitmap of ignored signals.15415534. sigcatch %lu156The bitmap of catched signals.15715835. wchan %lu159This 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 need160a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)16116236. nswap %lu163Number of pages swapped - not maintained.16416537. cnswap %lu166Cumulative nswap for child processes.16716838. exit_signal %d169Signal to be sent to parent when we die.17017139. processor %d172CPU number last executed on.173174175176///// SSCANF FORMAT STRING. Copy and use.177178field: 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 39179format: %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 %d180181182*/183184/**185* For platforms that have them, when declaring186* a printf-style function,187* formatSpec is the parameter number (starting at 1)188* that is the format argument ("%d pid %s")189* params is the parameter number where the actual args to190* the format starts. If the args are in a va_list, this191* should be 0.192*/193#ifndef PRINTF_ARGS194# define PRINTF_ARGS(formatSpec, params) ATTRIBUTE_PRINTF(formatSpec, params)195#endif196197#ifndef SCANF_ARGS198# define SCANF_ARGS(formatSpec, params) ATTRIBUTE_SCANF(formatSpec, params)199#endif200201#ifndef _PRINTFMT_202# define _PRINTFMT_203#endif204205#ifndef _SCANFMT_206# define _SCANFMT_207#endif208209typedef enum {210CPU_LOAD_VM_ONLY,211CPU_LOAD_GLOBAL,212} CpuLoadTarget;213214enum {215UNDETECTED,216UNDETECTABLE,217LINUX26_NPTL,218BAREMETAL219};220221struct CPUPerfCounters {222int nProcs;223os::Linux::CPUPerfTicks jvmTicks;224os::Linux::CPUPerfTicks* cpus;225};226227static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);228229/** reads /proc/<pid>/stat data, with some checks and some skips.230* Ensure that 'fmt' does _NOT_ contain the first two "%d %s"231*/232static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) {233FILE*f;234int n;235char buf[2048];236237if ((f = fopen(procfile, "r")) == NULL) {238return -1;239}240241if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {242char *tmp;243244buf[n-1] = '\0';245/** skip through pid and exec name. */246if ((tmp = strrchr(buf, ')')) != NULL) {247// skip the ')' and the following space248// but check that buffer is long enough249tmp += 2;250if (tmp < buf + n) {251n = vsscanf(tmp, fmt, args);252}253}254}255256fclose(f);257258return n;259}260261static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) {262int n;263va_list args;264265va_start(args, fmt);266n = vread_statdata(procfile, fmt, args);267va_end(args);268return n;269}270271static FILE* open_statfile(void) {272FILE *f;273274if ((f = fopen("/proc/stat", "r")) == NULL) {275static int haveWarned = 0;276if (!haveWarned) {277haveWarned = 1;278}279}280return f;281}282283static int get_systemtype(void) {284static int procEntriesType = UNDETECTED;285DIR *taskDir;286287if (procEntriesType != UNDETECTED) {288return procEntriesType;289}290291// Check whether we have a task subdirectory292if ((taskDir = opendir("/proc/self/task")) == NULL) {293procEntriesType = UNDETECTABLE;294} else {295// The task subdirectory exists; we're on a Linux >= 2.6 system296closedir(taskDir);297procEntriesType = LINUX26_NPTL;298}299300return procEntriesType;301}302303/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */304static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {305return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,306userTicks, systemTicks);307}308309/**310* Return the number of ticks spent in any of the processes belonging311* to the JVM on any CPU.312*/313static OSReturn get_jvm_ticks(os::Linux::CPUPerfTicks* pticks) {314uint64_t userTicks;315uint64_t systemTicks;316317if (get_systemtype() != LINUX26_NPTL) {318return OS_ERR;319}320321if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {322return OS_ERR;323}324325// get the total326if (! os::Linux::get_tick_information(pticks, -1)) {327return OS_ERR;328}329330pticks->used = userTicks;331pticks->usedKernel = systemTicks;332333return OS_OK;334}335336/**337* Return the load of the CPU as a double. 1.0 means the CPU process uses all338* available time for user or system processes, 0.0 means the CPU uses all time339* being idle.340*341* Returns a negative value if there is a problem in determining the CPU load.342*/343static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {344uint64_t udiff, kdiff, tdiff;345os::Linux::CPUPerfTicks* pticks;346os::Linux::CPUPerfTicks tmp;347double user_load;348349*pkernelLoad = 0.0;350351if (target == CPU_LOAD_VM_ONLY) {352pticks = &counters->jvmTicks;353} else if (-1 == which_logical_cpu) {354pticks = &counters->cpus[counters->nProcs];355} else {356pticks = &counters->cpus[which_logical_cpu];357}358359tmp = *pticks;360361if (target == CPU_LOAD_VM_ONLY) {362if (get_jvm_ticks(pticks) != OS_OK) {363return -1.0;364}365} else if (! os::Linux::get_tick_information(pticks, which_logical_cpu)) {366return -1.0;367}368369// seems like we sometimes end up with less kernel ticks when370// reading /proc/self/stat a second time, timing issue between cpus?371if (pticks->usedKernel < tmp.usedKernel) {372kdiff = 0;373} else {374kdiff = pticks->usedKernel - tmp.usedKernel;375}376tdiff = pticks->total - tmp.total;377udiff = pticks->used - tmp.used;378379if (tdiff == 0) {380return 0.0;381} else if (tdiff < (udiff + kdiff)) {382tdiff = udiff + kdiff;383}384*pkernelLoad = (kdiff / (double)tdiff);385// BUG9044876, normalize return values to sane values386*pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);387*pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);388389user_load = (udiff / (double)tdiff);390user_load = MAX2<double>(user_load, 0.0);391user_load = MIN2<double>(user_load, 1.0);392393return user_load;394}395396static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) {397FILE *f;398va_list args;399400va_start(args, fmt);401402if ((f = open_statfile()) == NULL) {403va_end(args);404return OS_ERR;405}406for (;;) {407char line[80];408if (fgets(line, sizeof(line), f) != NULL) {409if (vsscanf(line, fmt, args) == 1) {410fclose(f);411va_end(args);412return OS_OK;413}414} else {415fclose(f);416va_end(args);417return OS_ERR;418}419}420}421422static int get_noof_context_switches(uint64_t* switches) {423return parse_stat("ctxt " UINT64_FORMAT "\n", switches);424}425426/** returns boot time in _seconds_ since epoch */427static int get_boot_time(uint64_t* time) {428return parse_stat("btime " UINT64_FORMAT "\n", time);429}430431static int perf_context_switch_rate(double* rate) {432static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;433static uint64_t bootTime;434static uint64_t lastTimeNanos;435static uint64_t lastSwitches;436static double lastRate;437438uint64_t bt = 0;439int res = 0;440441// First time through bootTime will be zero.442if (bootTime == 0) {443uint64_t tmp;444if (get_boot_time(&tmp) < 0) {445return OS_ERR;446}447bt = tmp * 1000;448}449450res = OS_OK;451452pthread_mutex_lock(&contextSwitchLock);453{454455uint64_t sw;456s8 t, d;457458if (bootTime == 0) {459// First interval is measured from boot time which is460// seconds since the epoch. Thereafter we measure the461// elapsed time using javaTimeNanos as it is monotonic-462// non-decreasing.463lastTimeNanos = os::javaTimeNanos();464t = os::javaTimeMillis();465d = t - bt;466// keep bootTime zero for now to use as a first-time-through flag467} else {468t = os::javaTimeNanos();469d = nanos_to_millis(t - lastTimeNanos);470}471472if (d == 0) {473*rate = lastRate;474} else if (get_noof_context_switches(&sw) == 0) {475*rate = ( (double)(sw - lastSwitches) / d ) * 1000;476lastRate = *rate;477lastSwitches = sw;478if (bootTime != 0) {479lastTimeNanos = t;480}481} else {482*rate = 0;483res = OS_ERR;484}485if (*rate <= 0) {486*rate = 0;487lastRate = 0;488}489490if (bootTime == 0) {491bootTime = bt;492}493}494pthread_mutex_unlock(&contextSwitchLock);495496return res;497}498499class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {500friend class CPUPerformanceInterface;501private:502CPUPerfCounters _counters;503504int cpu_load(int which_logical_cpu, double* cpu_load);505int context_switch_rate(double* rate);506int cpu_load_total_process(double* cpu_load);507int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);508509public:510CPUPerformance();511bool initialize();512~CPUPerformance();513};514515CPUPerformanceInterface::CPUPerformance::CPUPerformance() {516_counters.nProcs = os::active_processor_count();517_counters.cpus = NULL;518}519520bool CPUPerformanceInterface::CPUPerformance::initialize() {521size_t array_entry_count = _counters.nProcs + 1;522_counters.cpus = NEW_C_HEAP_ARRAY(os::Linux::CPUPerfTicks, array_entry_count, mtInternal);523memset(_counters.cpus, 0, array_entry_count * sizeof(*_counters.cpus));524525// For the CPU load total526os::Linux::get_tick_information(&_counters.cpus[_counters.nProcs], -1);527528// For each CPU529for (int i = 0; i < _counters.nProcs; i++) {530os::Linux::get_tick_information(&_counters.cpus[i], i);531}532// For JVM load533get_jvm_ticks(&_counters.jvmTicks);534535// initialize context switch system536// the double is only for init537double init_ctx_switch_rate;538perf_context_switch_rate(&init_ctx_switch_rate);539540return true;541}542543CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {544if (_counters.cpus != NULL) {545FREE_C_HEAP_ARRAY(char, _counters.cpus);546}547}548549int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {550double u, s;551u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);552if (u < 0) {553*cpu_load = 0.0;554return OS_ERR;555}556// Cap total systemload to 1.0557*cpu_load = MIN2<double>((u + s), 1.0);558return OS_OK;559}560561int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {562double u, s;563u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);564if (u < 0) {565*cpu_load = 0.0;566return OS_ERR;567}568*cpu_load = u + s;569return OS_OK;570}571572int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {573double u, s, t;574575assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");576assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");577assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");578579u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);580if (u < 0) {581*pjvmUserLoad = 0.0;582*pjvmKernelLoad = 0.0;583*psystemTotalLoad = 0.0;584return OS_ERR;585}586587cpu_load(-1, &t);588// clamp at user+system and 1.0589if (u + s > t) {590t = MIN2<double>(u + s, 1.0);591}592593*pjvmUserLoad = u;594*pjvmKernelLoad = s;595*psystemTotalLoad = t;596597return OS_OK;598}599600int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {601return perf_context_switch_rate(rate);602}603604CPUPerformanceInterface::CPUPerformanceInterface() {605_impl = NULL;606}607608bool CPUPerformanceInterface::initialize() {609_impl = new CPUPerformanceInterface::CPUPerformance();610return _impl->initialize();611}612613CPUPerformanceInterface::~CPUPerformanceInterface() {614if (_impl != NULL) {615delete _impl;616}617}618619int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {620return _impl->cpu_load(which_logical_cpu, cpu_load);621}622623int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {624return _impl->cpu_load_total_process(cpu_load);625}626627int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {628return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);629}630631int CPUPerformanceInterface::context_switch_rate(double* rate) const {632return _impl->context_switch_rate(rate);633}634635class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {636friend class SystemProcessInterface;637private:638class ProcessIterator : public CHeapObj<mtInternal> {639friend class SystemProcessInterface::SystemProcesses;640private:641DIR* _dir;642struct dirent* _entry;643bool _valid;644char _exeName[PATH_MAX];645char _exePath[PATH_MAX];646647ProcessIterator();648~ProcessIterator();649bool initialize();650651bool is_valid() const { return _valid; }652bool is_valid_entry(struct dirent* entry) const;653bool is_dir(const char* name) const;654int fsize(const char* name, uint64_t& size) const;655656char* allocate_string(const char* str) const;657void get_exe_name();658char* get_exe_path();659char* get_cmdline();660661int current(SystemProcess* process_info);662int next_process();663};664665ProcessIterator* _iterator;666SystemProcesses();667bool initialize();668~SystemProcesses();669670//information about system processes671int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;672};673674bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {675struct stat mystat;676int ret_val = 0;677678ret_val = stat(name, &mystat);679if (ret_val < 0) {680return false;681}682ret_val = S_ISDIR(mystat.st_mode);683return ret_val > 0;684}685686int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {687assert(name != NULL, "name pointer is NULL!");688size = 0;689struct stat fbuf;690691if (stat(name, &fbuf) < 0) {692return OS_ERR;693}694size = fbuf.st_size;695return OS_OK;696}697698// if it has a numeric name, is a directory and has a 'stat' file in it699bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {700char buffer[PATH_MAX];701uint64_t size = 0;702703if (atoi(entry->d_name) != 0) {704jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);705buffer[PATH_MAX - 1] = '\0';706707if (is_dir(buffer)) {708jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);709buffer[PATH_MAX - 1] = '\0';710if (fsize(buffer, size) != OS_ERR) {711return true;712}713}714}715return false;716}717718// get exe-name from /proc/<pid>/stat719void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {720FILE* fp;721char buffer[PATH_MAX];722723jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);724buffer[PATH_MAX - 1] = '\0';725if ((fp = fopen(buffer, "r")) != NULL) {726if (fgets(buffer, PATH_MAX, fp) != NULL) {727char* start, *end;728// exe-name is between the first pair of ( and )729start = strchr(buffer, '(');730if (start != NULL && start[1] != '\0') {731start++;732end = strrchr(start, ')');733if (end != NULL) {734size_t len;735len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);736memcpy(_exeName, start, len);737_exeName[len] = '\0';738}739}740}741fclose(fp);742}743}744745// get command line from /proc/<pid>/cmdline746char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {747FILE* fp;748char buffer[PATH_MAX];749char* cmdline = NULL;750751jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);752buffer[PATH_MAX - 1] = '\0';753if ((fp = fopen(buffer, "r")) != NULL) {754size_t size = 0;755char dummy;756757// find out how long the file is (stat always returns 0)758while (fread(&dummy, 1, 1, fp) == 1) {759size++;760}761if (size > 0) {762cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);763cmdline[0] = '\0';764if (fseek(fp, 0, SEEK_SET) == 0) {765if (fread(cmdline, 1, size, fp) == size) {766// the file has the arguments separated by '\0',767// so we translate '\0' to ' '768for (size_t i = 0; i < size; i++) {769if (cmdline[i] == '\0') {770cmdline[i] = ' ';771}772}773cmdline[size] = '\0';774}775}776}777fclose(fp);778}779return cmdline;780}781782// get full path to exe from /proc/<pid>/exe symlink783char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {784char buffer[PATH_MAX];785786jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);787buffer[PATH_MAX - 1] = '\0';788return realpath(buffer, _exePath);789}790791char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {792if (str != NULL) {793return os::strdup_check_oom(str, mtInternal);794}795return NULL;796}797798int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {799if (!is_valid()) {800return OS_ERR;801}802803process_info->set_pid(atoi(_entry->d_name));804805get_exe_name();806process_info->set_name(allocate_string(_exeName));807808if (get_exe_path() != NULL) {809process_info->set_path(allocate_string(_exePath));810}811812char* cmdline = NULL;813cmdline = get_cmdline();814if (cmdline != NULL) {815process_info->set_command_line(allocate_string(cmdline));816FREE_C_HEAP_ARRAY(char, cmdline);817}818819return OS_OK;820}821822int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {823if (!is_valid()) {824return OS_ERR;825}826827do {828_entry = os::readdir(_dir);829if (_entry == NULL) {830// Error or reached end. Could use errno to distinguish those cases.831_valid = false;832return OS_ERR;833}834} while(!is_valid_entry(_entry));835836_valid = true;837return OS_OK;838}839840SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {841_dir = NULL;842_entry = NULL;843_valid = false;844}845846bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {847_dir = os::opendir("/proc");848_entry = NULL;849_valid = true;850next_process();851852return true;853}854855SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {856if (_dir != NULL) {857os::closedir(_dir);858}859}860861SystemProcessInterface::SystemProcesses::SystemProcesses() {862_iterator = NULL;863}864865bool SystemProcessInterface::SystemProcesses::initialize() {866_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();867return _iterator->initialize();868}869870SystemProcessInterface::SystemProcesses::~SystemProcesses() {871if (_iterator != NULL) {872delete _iterator;873}874}875876int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {877assert(system_processes != NULL, "system_processes pointer is NULL!");878assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");879assert(_iterator != NULL, "iterator is NULL!");880881// initialize pointers882*no_of_sys_processes = 0;883*system_processes = NULL;884885while (_iterator->is_valid()) {886SystemProcess* tmp = new SystemProcess();887_iterator->current(tmp);888889//if already existing head890if (*system_processes != NULL) {891//move "first to second"892tmp->set_next(*system_processes);893}894// new head895*system_processes = tmp;896// increment897(*no_of_sys_processes)++;898// step forward899_iterator->next_process();900}901return OS_OK;902}903904int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {905return _impl->system_processes(system_procs, no_of_sys_processes);906}907908SystemProcessInterface::SystemProcessInterface() {909_impl = NULL;910}911912bool SystemProcessInterface::initialize() {913_impl = new SystemProcessInterface::SystemProcesses();914return _impl->initialize();915}916917SystemProcessInterface::~SystemProcessInterface() {918if (_impl != NULL) {919delete _impl;920}921}922923CPUInformationInterface::CPUInformationInterface() {924_cpu_info = NULL;925}926927bool CPUInformationInterface::initialize() {928_cpu_info = new CPUInformation();929_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());930_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());931_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());932_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());933_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());934return true;935}936937CPUInformationInterface::~CPUInformationInterface() {938if (_cpu_info != NULL) {939if (_cpu_info->cpu_name() != NULL) {940const char* cpu_name = _cpu_info->cpu_name();941FREE_C_HEAP_ARRAY(char, cpu_name);942_cpu_info->set_cpu_name(NULL);943}944if (_cpu_info->cpu_description() != NULL) {945const char* cpu_desc = _cpu_info->cpu_description();946FREE_C_HEAP_ARRAY(char, cpu_desc);947_cpu_info->set_cpu_description(NULL);948}949delete _cpu_info;950}951}952953int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {954if (_cpu_info == NULL) {955return OS_ERR;956}957958cpu_info = *_cpu_info; // shallow copy assignment959return OS_OK;960}961962class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {963friend class NetworkPerformanceInterface;964private:965NetworkPerformance();966NONCOPYABLE(NetworkPerformance);967bool initialize();968~NetworkPerformance();969int64_t read_counter(const char* iface, const char* counter) const;970int network_utilization(NetworkInterface** network_interfaces) const;971};972973NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {974975}976977bool NetworkPerformanceInterface::NetworkPerformance::initialize() {978return true;979}980981NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {982}983984int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char* iface, const char* counter) const {985char buf[128];986987snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter);988989int fd = os::open(buf, O_RDONLY, 0);990if (fd == -1) {991return -1;992}993994ssize_t num_bytes = read(fd, buf, sizeof(buf));995close(fd);996if ((num_bytes == -1) || (num_bytes >= static_cast<ssize_t>(sizeof(buf))) || (num_bytes < 1)) {997return -1;998}9991000buf[num_bytes] = '\0';1001int64_t value = strtoll(buf, NULL, 10);10021003return value;1004}10051006int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const1007{1008ifaddrs* addresses;1009ifaddrs* cur_address;10101011if (getifaddrs(&addresses) != 0) {1012return OS_ERR;1013}10141015NetworkInterface* ret = NULL;1016for (cur_address = addresses; cur_address != NULL; cur_address = cur_address->ifa_next) {1017if ((cur_address->ifa_addr == NULL) || (cur_address->ifa_addr->sa_family != AF_PACKET)) {1018continue;1019}10201021int64_t bytes_in = read_counter(cur_address->ifa_name, "rx_bytes");1022int64_t bytes_out = read_counter(cur_address->ifa_name, "tx_bytes");10231024NetworkInterface* cur = new NetworkInterface(cur_address->ifa_name, bytes_in, bytes_out, ret);1025ret = cur;1026}10271028freeifaddrs(addresses);1029*network_interfaces = ret;10301031return OS_OK;1032}10331034NetworkPerformanceInterface::NetworkPerformanceInterface() {1035_impl = NULL;1036}10371038NetworkPerformanceInterface::~NetworkPerformanceInterface() {1039if (_impl != NULL) {1040delete _impl;1041}1042}10431044bool NetworkPerformanceInterface::initialize() {1045_impl = new NetworkPerformanceInterface::NetworkPerformance();1046return _impl->initialize();1047}10481049int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {1050return _impl->network_utilization(network_interfaces);1051}105210531054