Path: blob/master/src/hotspot/os/aix/os_perf_aix.cpp
40930 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_aix.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>4748/**49/proc/[number]/stat50Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.5152The fields, in order, with their proper scanf(3) format specifiers, are:53541. pid %d The process id.55562. comm %s57The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.58593. state %c60One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk61sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.62634. ppid %d64The PID of the parent.65665. pgrp %d67The process group ID of the process.68696. session %d70The session ID of the process.71727. tty_nr %d73The tty the process uses.74758. tpgid %d76The process group ID of the process which currently owns the tty that the process is connected to.77789. flags %lu79The flags of the process. The math bit is decimal 4, and the traced bit is decimal 10.808110. minflt %lu82The number of minor faults the process has made which have not required loading a memory page from disk.838411. cminflt %lu85The number of minor faults that the process's waited-for children have made.868712. majflt %lu88The number of major faults the process has made which have required loading a memory page from disk.899013. cmajflt %lu91The number of major faults that the process's waited-for children have made.929314. utime %lu94The number of jiffies that this process has been scheduled in user mode.959615. stime %lu97The number of jiffies that this process has been scheduled in kernel mode.989916. cutime %ld100The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)10110217. cstime %ld103The number of jiffies that this process' waited-for children have been scheduled in kernel mode.10410518. priority %ld106The standard nice value, plus fifteen. The value is never negative in the kernel.10710819. nice %ld109The nice value ranges from 19 (nicest) to -19 (not nice to others).11011120. 0 %ld This value is hard coded to 0 as a placeholder for a removed field.11211321. itrealvalue %ld114The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.11511622. starttime %lu117The time in jiffies the process started after system boot.11811923. vsize %lu120Virtual memory size in bytes.12112224. rss %ld123Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which count124towards text, data, or stack space. This does not include pages which have not been demand-loaded in, or which are swapped out.12512625. rlim %lu127Current limit in bytes on the rss of the process (usually 4294967295 on i386).12812926. startcode %lu130The address above which program text can run.13113227. endcode %lu133The address below which program text can run.13413528. startstack %lu136The address of the start of the stack.13713829. kstkesp %lu139The current value of esp (stack pointer), as found in the kernel stack page for the process.14014130. kstkeip %lu142The current EIP (instruction pointer).14314431. signal %lu145The bitmap of pending signals (usually 0).14614732. blocked %lu148The bitmap of blocked signals (usually 0, 2 for shells).14915033. sigignore %lu151The bitmap of ignored signals.15215334. sigcatch %lu154The bitmap of catched signals.15515635. wchan %lu157This 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 need158a textual name. (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)15916036. nswap %lu161Number of pages swapped - not maintained.16216337. cnswap %lu164Cumulative nswap for child processes.16516638. exit_signal %d167Signal to be sent to parent when we die.16816939. processor %d170CPU number last executed on.171172173174///// SSCANF FORMAT STRING. Copy and use.175176field: 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 39177format: %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 %d178179180*/181182/**183* For platforms that have them, when declaring184* a printf-style function,185* formatSpec is the parameter number (starting at 1)186* that is the format argument ("%d pid %s")187* params is the parameter number where the actual args to188* the format starts. If the args are in a va_list, this189* should be 0.190*/191#ifndef PRINTF_ARGS192# define PRINTF_ARGS(formatSpec, params) ATTRIBUTE_PRINTF(formatSpec, params)193#endif194195#ifndef SCANF_ARGS196# define SCANF_ARGS(formatSpec, params) ATTRIBUTE_SCANF(formatSpec, params)197#endif198199#ifndef _PRINTFMT_200# define _PRINTFMT_201#endif202203#ifndef _SCANFMT_204# define _SCANFMT_205#endif206207208struct CPUPerfTicks {209uint64_t used;210uint64_t usedKernel;211uint64_t total;212};213214typedef enum {215CPU_LOAD_VM_ONLY,216CPU_LOAD_GLOBAL,217} CpuLoadTarget;218219enum {220UNDETECTED,221UNDETECTABLE,222LINUX26_NPTL,223BAREMETAL224};225226struct CPUPerfCounters {227int nProcs;228CPUPerfTicks jvmTicks;229CPUPerfTicks* cpus;230};231232static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);233234/** reads /proc/<pid>/stat data, with some checks and some skips.235* Ensure that 'fmt' does _NOT_ contain the first two "%d %s"236*/237static int SCANF_ARGS(2, 0) vread_statdata(const char* procfile, _SCANFMT_ const char* fmt, va_list args) {238FILE*f;239int n;240char buf[2048];241242if ((f = fopen(procfile, "r")) == NULL) {243return -1;244}245246if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {247char *tmp;248249buf[n-1] = '\0';250/** skip through pid and exec name. */251if ((tmp = strrchr(buf, ')')) != NULL) {252// skip the ')' and the following space253// but check that buffer is long enough254tmp += 2;255if (tmp < buf + n) {256n = vsscanf(tmp, fmt, args);257}258}259}260261fclose(f);262263return n;264}265266static int SCANF_ARGS(2, 3) read_statdata(const char* procfile, _SCANFMT_ const char* fmt, ...) {267int n;268va_list args;269270va_start(args, fmt);271n = vread_statdata(procfile, fmt, args);272va_end(args);273return n;274}275276/**277* on Linux we got the ticks related information from /proc/stat278* this does not work on AIX, libperfstat might be an alternative279*/280static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {281return OS_ERR;282}283284/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */285static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {286return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,287userTicks, systemTicks);288}289290/**291* Return the number of ticks spent in any of the processes belonging292* to the JVM on any CPU.293*/294static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {295return OS_ERR;296}297298/**299* Return the load of the CPU as a double. 1.0 means the CPU process uses all300* available time for user or system processes, 0.0 means the CPU uses all time301* being idle.302*303* Returns a negative value if there is a problem in determining the CPU load.304*/305static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {306uint64_t udiff, kdiff, tdiff;307CPUPerfTicks* pticks;308CPUPerfTicks tmp;309double user_load;310311*pkernelLoad = 0.0;312313if (target == CPU_LOAD_VM_ONLY) {314pticks = &counters->jvmTicks;315} else if (-1 == which_logical_cpu) {316pticks = &counters->cpus[counters->nProcs];317} else {318pticks = &counters->cpus[which_logical_cpu];319}320321tmp = *pticks;322323if (target == CPU_LOAD_VM_ONLY) {324if (get_jvm_ticks(pticks) != OS_OK) {325return -1.0;326}327} else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) {328return -1.0;329}330331// seems like we sometimes end up with less kernel ticks when332// reading /proc/self/stat a second time, timing issue between cpus?333if (pticks->usedKernel < tmp.usedKernel) {334kdiff = 0;335} else {336kdiff = pticks->usedKernel - tmp.usedKernel;337}338tdiff = pticks->total - tmp.total;339udiff = pticks->used - tmp.used;340341if (tdiff == 0) {342return 0.0;343} else if (tdiff < (udiff + kdiff)) {344tdiff = udiff + kdiff;345}346*pkernelLoad = (kdiff / (double)tdiff);347// BUG9044876, normalize return values to sane values348*pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);349*pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);350351user_load = (udiff / (double)tdiff);352user_load = MAX2<double>(user_load, 0.0);353user_load = MIN2<double>(user_load, 1.0);354355return user_load;356}357358static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) {359return OS_ERR;360}361362static int get_noof_context_switches(uint64_t* switches) {363return parse_stat("ctxt " UINT64_FORMAT "\n", switches);364}365366/** returns boot time in _seconds_ since epoch */367static int get_boot_time(uint64_t* time) {368return parse_stat("btime " UINT64_FORMAT "\n", time);369}370371static int perf_context_switch_rate(double* rate) {372static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;373static uint64_t bootTime;374static uint64_t lastTimeNanos;375static uint64_t lastSwitches;376static double lastRate;377378uint64_t bt = 0;379int res = 0;380381// First time through bootTime will be zero.382if (bootTime == 0) {383uint64_t tmp;384if (get_boot_time(&tmp) < 0) {385return OS_ERR;386}387bt = tmp * 1000;388}389390res = OS_OK;391392pthread_mutex_lock(&contextSwitchLock);393{394395uint64_t sw;396s8 t, d;397398if (bootTime == 0) {399// First interval is measured from boot time which is400// seconds since the epoch. Thereafter we measure the401// elapsed time using javaTimeNanos as it is monotonic-402// non-decreasing.403lastTimeNanos = os::javaTimeNanos();404t = os::javaTimeMillis();405d = t - bt;406// keep bootTime zero for now to use as a first-time-through flag407} else {408t = os::javaTimeNanos();409d = nanos_to_millis(t - lastTimeNanos);410}411412if (d == 0) {413*rate = lastRate;414} else if (get_noof_context_switches(&sw) == 0) {415*rate = ( (double)(sw - lastSwitches) / d ) * 1000;416lastRate = *rate;417lastSwitches = sw;418if (bootTime != 0) {419lastTimeNanos = t;420}421} else {422*rate = 0;423res = OS_ERR;424}425if (*rate <= 0) {426*rate = 0;427lastRate = 0;428}429430if (bootTime == 0) {431bootTime = bt;432}433}434pthread_mutex_unlock(&contextSwitchLock);435436return res;437}438439class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {440friend class CPUPerformanceInterface;441private:442CPUPerfCounters _counters;443444int cpu_load(int which_logical_cpu, double* cpu_load);445int context_switch_rate(double* rate);446int cpu_load_total_process(double* cpu_load);447int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);448449public:450CPUPerformance();451bool initialize();452~CPUPerformance();453};454455CPUPerformanceInterface::CPUPerformance::CPUPerformance() {456_counters.nProcs = os::active_processor_count();457_counters.cpus = NULL;458}459460bool CPUPerformanceInterface::CPUPerformance::initialize() {461size_t array_entry_count = _counters.nProcs + 1;462_counters.cpus = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal);463memset(_counters.cpus, 0, array_entry_count * sizeof(*_counters.cpus));464465// For the CPU load total466get_total_ticks(-1, &_counters.cpus[_counters.nProcs]);467468// For each CPU469for (int i = 0; i < _counters.nProcs; i++) {470get_total_ticks(i, &_counters.cpus[i]);471}472// For JVM load473get_jvm_ticks(&_counters.jvmTicks);474475// initialize context switch system476// the double is only for init477double init_ctx_switch_rate;478perf_context_switch_rate(&init_ctx_switch_rate);479480return true;481}482483CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {484if (_counters.cpus != NULL) {485FREE_C_HEAP_ARRAY(char, _counters.cpus);486}487}488489int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {490double u, s;491u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);492if (u < 0) {493*cpu_load = 0.0;494return OS_ERR;495}496// Cap total systemload to 1.0497*cpu_load = MIN2<double>((u + s), 1.0);498return OS_OK;499}500501int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {502double u, s;503u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);504if (u < 0) {505*cpu_load = 0.0;506return OS_ERR;507}508*cpu_load = u + s;509return OS_OK;510}511512int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {513double u, s, t;514515assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");516assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");517assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");518519u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);520if (u < 0) {521*pjvmUserLoad = 0.0;522*pjvmKernelLoad = 0.0;523*psystemTotalLoad = 0.0;524return OS_ERR;525}526527cpu_load(-1, &t);528// clamp at user+system and 1.0529if (u + s > t) {530t = MIN2<double>(u + s, 1.0);531}532533*pjvmUserLoad = u;534*pjvmKernelLoad = s;535*psystemTotalLoad = t;536537return OS_OK;538}539540int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {541return perf_context_switch_rate(rate);542}543544CPUPerformanceInterface::CPUPerformanceInterface() {545_impl = NULL;546}547548bool CPUPerformanceInterface::initialize() {549_impl = new CPUPerformanceInterface::CPUPerformance();550return _impl->initialize();551}552553CPUPerformanceInterface::~CPUPerformanceInterface() {554if (_impl != NULL) {555delete _impl;556}557}558559int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {560return _impl->cpu_load(which_logical_cpu, cpu_load);561}562563int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {564return _impl->cpu_load_total_process(cpu_load);565}566567int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {568return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);569}570571int CPUPerformanceInterface::context_switch_rate(double* rate) const {572return _impl->context_switch_rate(rate);573}574575class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {576friend class SystemProcessInterface;577private:578class ProcessIterator : public CHeapObj<mtInternal> {579friend class SystemProcessInterface::SystemProcesses;580private:581DIR* _dir;582struct dirent* _entry;583bool _valid;584char _exeName[PATH_MAX];585char _exePath[PATH_MAX];586587ProcessIterator();588~ProcessIterator();589bool initialize();590591bool is_valid() const { return _valid; }592bool is_valid_entry(struct dirent* entry) const;593bool is_dir(const char* name) const;594int fsize(const char* name, uint64_t& size) const;595596char* allocate_string(const char* str) const;597void get_exe_name();598char* get_exe_path();599char* get_cmdline();600601int current(SystemProcess* process_info);602int next_process();603};604605ProcessIterator* _iterator;606SystemProcesses();607bool initialize();608~SystemProcesses();609610//information about system processes611int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;612};613614bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {615struct stat mystat;616int ret_val = 0;617618ret_val = stat(name, &mystat);619if (ret_val < 0) {620return false;621}622ret_val = S_ISDIR(mystat.st_mode);623return ret_val > 0;624}625626int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {627assert(name != NULL, "name pointer is NULL!");628size = 0;629struct stat fbuf;630631if (stat(name, &fbuf) < 0) {632return OS_ERR;633}634size = fbuf.st_size;635return OS_OK;636}637638// if it has a numeric name, is a directory and has a 'stat' file in it639bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {640char buffer[PATH_MAX];641uint64_t size = 0;642643if (atoi(entry->d_name) != 0) {644jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);645buffer[PATH_MAX - 1] = '\0';646647if (is_dir(buffer)) {648jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);649buffer[PATH_MAX - 1] = '\0';650if (fsize(buffer, size) != OS_ERR) {651return true;652}653}654}655return false;656}657658// get exe-name from /proc/<pid>/stat659void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {660FILE* fp;661char buffer[PATH_MAX];662663jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);664buffer[PATH_MAX - 1] = '\0';665if ((fp = fopen(buffer, "r")) != NULL) {666if (fgets(buffer, PATH_MAX, fp) != NULL) {667char* start, *end;668// exe-name is between the first pair of ( and )669start = strchr(buffer, '(');670if (start != NULL && start[1] != '\0') {671start++;672end = strrchr(start, ')');673if (end != NULL) {674size_t len;675len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);676memcpy(_exeName, start, len);677_exeName[len] = '\0';678}679}680}681fclose(fp);682}683}684685// get command line from /proc/<pid>/cmdline686char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {687FILE* fp;688char buffer[PATH_MAX];689char* cmdline = NULL;690691jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);692buffer[PATH_MAX - 1] = '\0';693if ((fp = fopen(buffer, "r")) != NULL) {694size_t size = 0;695char dummy;696697// find out how long the file is (stat always returns 0)698while (fread(&dummy, 1, 1, fp) == 1) {699size++;700}701if (size > 0) {702cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);703cmdline[0] = '\0';704if (fseek(fp, 0, SEEK_SET) == 0) {705if (fread(cmdline, 1, size, fp) == size) {706// the file has the arguments separated by '\0',707// so we translate '\0' to ' '708for (size_t i = 0; i < size; i++) {709if (cmdline[i] == '\0') {710cmdline[i] = ' ';711}712}713cmdline[size] = '\0';714}715}716}717fclose(fp);718}719return cmdline;720}721722// get full path to exe from /proc/<pid>/exe symlink723char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {724char buffer[PATH_MAX];725726jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);727buffer[PATH_MAX - 1] = '\0';728return realpath(buffer, _exePath);729}730731char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {732if (str != NULL) {733return os::strdup_check_oom(str, mtInternal);734}735return NULL;736}737738int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {739if (!is_valid()) {740return OS_ERR;741}742743process_info->set_pid(atoi(_entry->d_name));744745get_exe_name();746process_info->set_name(allocate_string(_exeName));747748if (get_exe_path() != NULL) {749process_info->set_path(allocate_string(_exePath));750}751752char* cmdline = NULL;753cmdline = get_cmdline();754if (cmdline != NULL) {755process_info->set_command_line(allocate_string(cmdline));756FREE_C_HEAP_ARRAY(char, cmdline);757}758759return OS_OK;760}761762int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {763if (!is_valid()) {764return OS_ERR;765}766767do {768_entry = os::readdir(_dir);769if (_entry == NULL) {770// Error or reached end. Could use errno to distinguish those cases.771_valid = false;772return OS_ERR;773}774} while(!is_valid_entry(_entry));775776_valid = true;777return OS_OK;778}779780SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {781_dir = NULL;782_entry = NULL;783_valid = false;784}785786bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {787// Not yet implemented.788return false;789}790791SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {792if (_dir != NULL) {793os::closedir(_dir);794}795}796797SystemProcessInterface::SystemProcesses::SystemProcesses() {798_iterator = NULL;799}800801bool SystemProcessInterface::SystemProcesses::initialize() {802_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();803return _iterator->initialize();804}805806SystemProcessInterface::SystemProcesses::~SystemProcesses() {807if (_iterator != NULL) {808delete _iterator;809}810}811812int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {813assert(system_processes != NULL, "system_processes pointer is NULL!");814assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");815assert(_iterator != NULL, "iterator is NULL!");816817// initialize pointers818*no_of_sys_processes = 0;819*system_processes = NULL;820821while (_iterator->is_valid()) {822SystemProcess* tmp = new SystemProcess();823_iterator->current(tmp);824825//if already existing head826if (*system_processes != NULL) {827//move "first to second"828tmp->set_next(*system_processes);829}830// new head831*system_processes = tmp;832// increment833(*no_of_sys_processes)++;834// step forward835_iterator->next_process();836}837return OS_OK;838}839840int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {841return _impl->system_processes(system_procs, no_of_sys_processes);842}843844SystemProcessInterface::SystemProcessInterface() {845_impl = NULL;846}847848bool SystemProcessInterface::initialize() {849_impl = new SystemProcessInterface::SystemProcesses();850return _impl->initialize();851}852853SystemProcessInterface::~SystemProcessInterface() {854if (_impl != NULL) {855delete _impl;856}857}858859CPUInformationInterface::CPUInformationInterface() {860_cpu_info = NULL;861}862863bool CPUInformationInterface::initialize() {864_cpu_info = new CPUInformation();865_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());866_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());867_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());868_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());869_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());870return true;871}872873CPUInformationInterface::~CPUInformationInterface() {874if (_cpu_info != NULL) {875if (_cpu_info->cpu_name() != NULL) {876const char* cpu_name = _cpu_info->cpu_name();877FREE_C_HEAP_ARRAY(char, cpu_name);878_cpu_info->set_cpu_name(NULL);879}880if (_cpu_info->cpu_description() != NULL) {881const char* cpu_desc = _cpu_info->cpu_description();882FREE_C_HEAP_ARRAY(char, cpu_desc);883_cpu_info->set_cpu_description(NULL);884}885delete _cpu_info;886}887}888889int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {890if (_cpu_info == NULL) {891return OS_ERR;892}893894cpu_info = *_cpu_info; // shallow copy assignment895return OS_OK;896}897898class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {899friend class NetworkPerformanceInterface;900private:901NetworkPerformance();902NONCOPYABLE(NetworkPerformance);903bool initialize();904~NetworkPerformance();905int network_utilization(NetworkInterface** network_interfaces) const;906};907908NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {909910}911912bool NetworkPerformanceInterface::NetworkPerformance::initialize() {913return true;914}915916NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {917}918919int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const920{921return FUNCTIONALITY_NOT_IMPLEMENTED;922}923924NetworkPerformanceInterface::NetworkPerformanceInterface() {925_impl = NULL;926}927928NetworkPerformanceInterface::~NetworkPerformanceInterface() {929if (_impl != NULL) {930delete _impl;931}932}933934bool NetworkPerformanceInterface::initialize() {935_impl = new NetworkPerformanceInterface::NetworkPerformance();936return _impl->initialize();937}938939int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {940return _impl->network_utilization(network_interfaces);941}942943944