src/os/aix/vm/os_perf_aix.cpp

Tue, 21 Apr 2020 12:03:29 +0200

author
clanger
date
Tue, 21 Apr 2020 12:03:29 +0200
changeset 9907
35063c223567
parent 9858
b985cbb00e68
permissions
-rw-r--r--

8241902: AIX Build broken after integration of JDK-8223147 (JFR Backport)
Reviewed-by: mdoerr, apetushkov

     1 /*
     2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * Copyright (c) 2020 SAP SE. All rights reserved.
     4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5  *
     6  * This code is free software; you can redistribute it and/or modify it
     7  * under the terms of the GNU General Public License version 2 only, as
     8  * published by the Free Software Foundation.
     9  *
    10  * This code is distributed in the hope that it will be useful, but WITHOUT
    11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    13  * version 2 for more details (a copy is included in the LICENSE file that
    14  * accompanied this code).
    15  *
    16  * You should have received a copy of the GNU General Public License version
    17  * 2 along with this work; if not, write to the Free Software Foundation,
    18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    19  *
    20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    21  * or visit www.oracle.com if you need additional information or have any
    22  * questions.
    23  *
    24  */
    26 #include "precompiled.hpp"
    27 #include "jvm.h"
    28 #include "memory/allocation.inline.hpp"
    29 #include "os_aix.inline.hpp"
    30 #include "runtime/os.hpp"
    31 #include "runtime/os_perf.hpp"
    32 #include "vm_version_ext_ppc.hpp"
    34 #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>
    48 /**
    49    /proc/[number]/stat
    50               Status information about the process.  This is used by ps(1).  It is defined in /usr/src/linux/fs/proc/array.c.
    52               The fields, in order, with their proper scanf(3) format specifiers, are:
    54               1. pid %d The process id.
    56               2. comm %s
    57                      The filename of the executable, in parentheses.  This is visible whether or not the executable is swapped out.
    59               3. state %c
    60                      One  character  from  the  string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk
    61                      sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
    63               4. ppid %d
    64                      The PID of the parent.
    66               5. pgrp %d
    67                      The process group ID of the process.
    69               6. session %d
    70                      The session ID of the process.
    72               7. tty_nr %d
    73                      The tty the process uses.
    75               8. tpgid %d
    76                      The process group ID of the process which currently owns the tty that the process is connected to.
    78               9. flags %lu
    79                      The flags of the process.  The math bit is decimal 4, and the traced bit is decimal 10.
    81               10. minflt %lu
    82                      The number of minor faults the process has made which have not required loading a memory page from disk.
    84               11. cminflt %lu
    85                      The number of minor faults that the process's waited-for children have made.
    87               12. majflt %lu
    88                      The number of major faults the process has made which have required loading a memory page from disk.
    90               13. cmajflt %lu
    91                      The number of major faults that the process's waited-for children have made.
    93               14. utime %lu
    94                      The number of jiffies that this process has been scheduled in user mode.
    96               15. stime %lu
    97                      The number of jiffies that this process has been scheduled in kernel mode.
    99               16. cutime %ld
   100                      The number of jiffies that this process's waited-for children have been scheduled in user mode. (See also times(2).)
   102               17. cstime %ld
   103                      The number of jiffies that this process' waited-for children have been scheduled in kernel mode.
   105               18. priority %ld
   106                      The standard nice value, plus fifteen.  The value is never negative in the kernel.
   108               19. nice %ld
   109                      The nice value ranges from 19 (nicest) to -19 (not nice to others).
   111               20. 0 %ld  This value is hard coded to 0 as a placeholder for a removed field.
   113               21. itrealvalue %ld
   114                      The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.
   116               22. starttime %lu
   117                      The time in jiffies the process started after system boot.
   119               23. vsize %lu
   120                      Virtual memory size in bytes.
   122               24. rss %ld
   123                      Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes. This is just the pages which  count
   124                      towards text, data, or stack space.  This does not include pages which have not been demand-loaded in, or which are swapped out.
   126               25. rlim %lu
   127                      Current limit in bytes on the rss of the process (usually 4294967295 on i386).
   129               26. startcode %lu
   130                      The address above which program text can run.
   132               27. endcode %lu
   133                      The address below which program text can run.
   135               28. startstack %lu
   136                      The address of the start of the stack.
   138               29. kstkesp %lu
   139                      The current value of esp (stack pointer), as found in the kernel stack page for the process.
   141               30. kstkeip %lu
   142                      The current EIP (instruction pointer).
   144               31. signal %lu
   145                      The bitmap of pending signals (usually 0).
   147               32. blocked %lu
   148                      The bitmap of blocked signals (usually 0, 2 for shells).
   150               33. sigignore %lu
   151                      The bitmap of ignored signals.
   153               34. sigcatch %lu
   154                      The bitmap of catched signals.
   156               35. wchan %lu
   157                      This  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 need
   158                      a textual name.  (If you have an up-to-date /etc/psdatabase, then try ps -l to see the WCHAN field in action.)
   160               36. nswap %lu
   161                      Number of pages swapped - not maintained.
   163               37. cnswap %lu
   164                      Cumulative nswap for child processes.
   166               38. exit_signal %d
   167                      Signal to be sent to parent when we die.
   169               39. processor %d
   170                      CPU number last executed on.
   174  ///// SSCANF FORMAT STRING. Copy and use.
   176 field:        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 39
   177 format:       %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 %d
   180 */
   182 struct CPUPerfTicks {
   183   uint64_t  used;
   184   uint64_t  usedKernel;
   185   uint64_t  total;
   186 };
   188 typedef enum {
   189   CPU_LOAD_VM_ONLY,
   190   CPU_LOAD_GLOBAL,
   191 } CpuLoadTarget;
   193 enum {
   194   UNDETECTED,
   195   UNDETECTABLE,
   196   LINUX26_NPTL,
   197   BAREMETAL
   198 };
   200 struct CPUPerfCounters {
   201   int   nProcs;
   202   CPUPerfTicks jvmTicks;
   203   CPUPerfTicks* cpus;
   204 };
   206 static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);
   208 /** reads /proc/<pid>/stat data, with some checks and some skips.
   209  *  Ensure that 'fmt' does _NOT_ contain the first two "%d %s"
   210  */
   211 static int vread_statdata(const char* procfile, const char* fmt, va_list args) {
   212   FILE*f;
   213   int n;
   214   char buf[2048];
   216   if ((f = fopen(procfile, "r")) == NULL) {
   217     return -1;
   218   }
   220   if ((n = fread(buf, 1, sizeof(buf), f)) != -1) {
   221     char *tmp;
   223     buf[n-1] = '\0';
   224     /** skip through pid and exec name. */
   225     if ((tmp = strrchr(buf, ')')) != NULL) {
   226       // skip the ')' and the following space
   227       // but check that buffer is long enough
   228       tmp += 2;
   229       if (tmp < buf + n) {
   230         n = vsscanf(tmp, fmt, args);
   231       }
   232     }
   233   }
   235   fclose(f);
   237   return n;
   238 }
   240 static int read_statdata(const char* procfile, const char* fmt, ...) {
   241   int   n;
   242   va_list args;
   244   va_start(args, fmt);
   245   n = vread_statdata(procfile, fmt, args);
   246   va_end(args);
   247   return n;
   248 }
   250 static FILE* open_statfile(void) {
   251   FILE *f;
   253   if ((f = fopen("/proc/stat", "r")) == NULL) {
   254     static int haveWarned = 0;
   255     if (!haveWarned) {
   256       haveWarned = 1;
   257     }
   258   }
   259   return f;
   260 }
   262 static void
   263 next_line(FILE *f) {
   264   int c;
   265   do {
   266     c = fgetc(f);
   267   } while (c != '\n' && c != EOF);
   268 }
   270 /**
   271  * Return the total number of ticks since the system was booted.
   272  * If the usedTicks parameter is not NULL, it will be filled with
   273  * the number of ticks spent on actual processes (user, system or
   274  * nice processes) since system boot. Note that this is the total number
   275  * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is
   276  * n times the number of ticks that has passed in clock time.
   277  *
   278  * Returns a negative value if the reading of the ticks failed.
   279  */
   280 static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {
   281   FILE*         fh;
   282   uint64_t      userTicks, niceTicks, systemTicks, idleTicks;
   283   uint64_t      iowTicks = 0, irqTicks = 0, sirqTicks= 0;
   284   int           logical_cpu = -1;
   285   const int     expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5;
   286   int           n;
   288   if ((fh = open_statfile()) == NULL) {
   289     return OS_ERR;
   290   }
   291   if (-1 == which_logical_cpu) {
   292     n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
   293             UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
   294             &userTicks, &niceTicks, &systemTicks, &idleTicks,
   295             &iowTicks, &irqTicks, &sirqTicks);
   296   } else {
   297     // Move to next line
   298     next_line(fh);
   300     // find the line for requested cpu faster to just iterate linefeeds?
   301     for (int i = 0; i < which_logical_cpu; i++) {
   302       next_line(fh);
   303     }
   305     n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
   306                UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
   307                &logical_cpu, &userTicks, &niceTicks,
   308                &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks);
   309   }
   311   fclose(fh);
   312   if (n < expected_assign_count || logical_cpu != which_logical_cpu) {
   313 #ifdef DEBUG_LINUX_PROC_STAT
   314     vm_fprintf(stderr, "[stat] read failed");
   315 #endif
   316     return OS_ERR;
   317   }
   319 #ifdef DEBUG_LINUX_PROC_STAT
   320   vm_fprintf(stderr, "[stat] read "
   321           UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
   322           UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n",
   323           userTicks, niceTicks, systemTicks, idleTicks,
   324           iowTicks, irqTicks, sirqTicks);
   325 #endif
   327   pticks->used       = userTicks + niceTicks;
   328   pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
   329   pticks->total      = userTicks + niceTicks + systemTicks + idleTicks +
   330                        iowTicks + irqTicks + sirqTicks;
   332   return OS_OK;
   333 }
   336 static int get_systemtype(void) {
   337   static int procEntriesType = UNDETECTED;
   338   DIR *taskDir;
   340   if (procEntriesType != UNDETECTED) {
   341     return procEntriesType;
   342   }
   344   // Check whether we have a task subdirectory
   345   if ((taskDir = opendir("/proc/self/task")) == NULL) {
   346     procEntriesType = UNDETECTABLE;
   347   } else {
   348     // The task subdirectory exists; we're on a Linux >= 2.6 system
   349     closedir(taskDir);
   350     procEntriesType = LINUX26_NPTL;
   351   }
   353   return procEntriesType;
   354 }
   356 /** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */
   357 static int read_ticks(const char* procfile, uint64_t* userTicks, uint64_t* systemTicks) {
   358   return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u " UINT64_FORMAT " " UINT64_FORMAT,
   359     userTicks, systemTicks);
   360 }
   362 /**
   363  * Return the number of ticks spent in any of the processes belonging
   364  * to the JVM on any CPU.
   365  */
   366 static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {
   367   uint64_t userTicks;
   368   uint64_t systemTicks;
   370   if (get_systemtype() != LINUX26_NPTL) {
   371     return OS_ERR;
   372   }
   374   if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) {
   375     return OS_ERR;
   376   }
   378   // get the total
   379   if (get_total_ticks(-1, pticks) != OS_OK) {
   380     return OS_ERR;
   381   }
   383   pticks->used       = userTicks;
   384   pticks->usedKernel = systemTicks;
   386   return OS_OK;
   387 }
   389 /**
   390  * Return the load of the CPU as a double. 1.0 means the CPU process uses all
   391  * available time for user or system processes, 0.0 means the CPU uses all time
   392  * being idle.
   393  *
   394  * Returns a negative value if there is a problem in determining the CPU load.
   395  */
   396 static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {
   397   uint64_t udiff, kdiff, tdiff;
   398   CPUPerfTicks* pticks;
   399   CPUPerfTicks  tmp;
   400   double user_load;
   402   *pkernelLoad = 0.0;
   404   if (target == CPU_LOAD_VM_ONLY) {
   405     pticks = &counters->jvmTicks;
   406   } else if (-1 == which_logical_cpu) {
   407     pticks = &counters->cpus[counters->nProcs];
   408   } else {
   409     pticks = &counters->cpus[which_logical_cpu];
   410   }
   412   tmp = *pticks;
   414   if (target == CPU_LOAD_VM_ONLY) {
   415     if (get_jvm_ticks(pticks) != OS_OK) {
   416       return -1.0;
   417     }
   418   } else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) {
   419     return -1.0;
   420   }
   422   // seems like we sometimes end up with less kernel ticks when
   423   // reading /proc/self/stat a second time, timing issue between cpus?
   424   if (pticks->usedKernel < tmp.usedKernel) {
   425     kdiff = 0;
   426   } else {
   427     kdiff = pticks->usedKernel - tmp.usedKernel;
   428   }
   429   tdiff = pticks->total - tmp.total;
   430   udiff = pticks->used - tmp.used;
   432   if (tdiff == 0) {
   433     return 0.0;
   434   } else if (tdiff < (udiff + kdiff)) {
   435     tdiff = udiff + kdiff;
   436   }
   437   *pkernelLoad = (kdiff / (double)tdiff);
   438   // BUG9044876, normalize return values to sane values
   439   *pkernelLoad = MAX2<double>(*pkernelLoad, 0.0);
   440   *pkernelLoad = MIN2<double>(*pkernelLoad, 1.0);
   442   user_load = (udiff / (double)tdiff);
   443   user_load = MAX2<double>(user_load, 0.0);
   444   user_load = MIN2<double>(user_load, 1.0);
   446   return user_load;
   447 }
   449 static int parse_stat(const char* fmt, ...) {
   450   FILE *f;
   451   va_list args;
   453   va_start(args, fmt);
   455   if ((f = open_statfile()) == NULL) {
   456     va_end(args);
   457     return OS_ERR;
   458   }
   459   for (;;) {
   460     char line[80];
   461     if (fgets(line, sizeof(line), f) != NULL) {
   462       if (vsscanf(line, fmt, args) == 1) {
   463         fclose(f);
   464         va_end(args);
   465         return OS_OK;
   466       }
   467     } else {
   468         fclose(f);
   469         va_end(args);
   470         return OS_ERR;
   471     }
   472   }
   473 }
   475 static int get_noof_context_switches(uint64_t* switches) {
   476   return parse_stat("ctxt " UINT64_FORMAT "\n", switches);
   477 }
   479 /** returns boot time in _seconds_ since epoch */
   480 static int get_boot_time(uint64_t* time) {
   481   return parse_stat("btime " UINT64_FORMAT "\n", time);
   482 }
   484 static int perf_context_switch_rate(double* rate) {
   485   static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
   486   static uint64_t      lastTime;
   487   static uint64_t      lastSwitches;
   488   static double        lastRate;
   490   uint64_t lt = 0;
   491   int res = 0;
   493   if (lastTime == 0) {
   494     uint64_t tmp;
   495     if (get_boot_time(&tmp) < 0) {
   496       return OS_ERR;
   497     }
   498     lt = tmp * 1000;
   499   }
   501   res = OS_OK;
   503   pthread_mutex_lock(&contextSwitchLock);
   504   {
   506     uint64_t sw;
   507     s8 t, d;
   509     if (lastTime == 0) {
   510       lastTime = lt;
   511     }
   513     t = os::javaTimeMillis();
   514     d = t - lastTime;
   516     if (d == 0) {
   517       *rate = lastRate;
   518     } else if (!get_noof_context_switches(&sw)) {
   519       *rate      = ( (double)(sw - lastSwitches) / d ) * 1000;
   520       lastRate     = *rate;
   521       lastSwitches = sw;
   522       lastTime     = t;
   523     } else {
   524       *rate = 0;
   525       res   = OS_ERR;
   526     }
   527     if (*rate <= 0) {
   528       *rate = 0;
   529       lastRate = 0;
   530     }
   531   }
   532   pthread_mutex_unlock(&contextSwitchLock);
   534   return res;
   535 }
   537 class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
   538   friend class CPUPerformanceInterface;
   539  private:
   540   CPUPerfCounters _counters;
   542   int cpu_load(int which_logical_cpu, double* cpu_load);
   543   int context_switch_rate(double* rate);
   544   int cpu_load_total_process(double* cpu_load);
   545   int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
   547  public:
   548   CPUPerformance();
   549   bool initialize();
   550   ~CPUPerformance();
   551 };
   553 CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
   554   _counters.nProcs = os::active_processor_count();
   555   _counters.cpus = NULL;
   556 }
   558 bool CPUPerformanceInterface::CPUPerformance::initialize() {
   559   size_t tick_array_size = (_counters.nProcs +1) * sizeof(CPUPerfTicks);
   560   _counters.cpus = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
   561   if (NULL == _counters.cpus) {
   562     return false;
   563   }
   564   memset(_counters.cpus, 0, tick_array_size);
   566   // For the CPU load total
   567   get_total_ticks(-1, &_counters.cpus[_counters.nProcs]);
   569   // For each CPU
   570   for (int i = 0; i < _counters.nProcs; i++) {
   571     get_total_ticks(i, &_counters.cpus[i]);
   572   }
   573   // For JVM load
   574   get_jvm_ticks(&_counters.jvmTicks);
   576   // initialize context switch system
   577   // the double is only for init
   578   double init_ctx_switch_rate;
   579   perf_context_switch_rate(&init_ctx_switch_rate);
   581   return true;
   582 }
   584 CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
   585   if (_counters.cpus != NULL) {
   586     FREE_C_HEAP_ARRAY(char, _counters.cpus, mtInternal);
   587   }
   588 }
   590 int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
   591   double u, s;
   592   u = get_cpu_load(which_logical_cpu, &_counters, &s, CPU_LOAD_GLOBAL);
   593   if (u < 0) {
   594     *cpu_load = 0.0;
   595     return OS_ERR;
   596   }
   597   // Cap total systemload to 1.0
   598   *cpu_load = MIN2<double>((u + s), 1.0);
   599   return OS_OK;
   600 }
   602 int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
   603   double u, s;
   604   u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
   605   if (u < 0) {
   606     *cpu_load = 0.0;
   607     return OS_ERR;
   608   }
   609   *cpu_load = u + s;
   610   return OS_OK;
   611 }
   613 int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
   614   double u, s, t;
   616   assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
   617   assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
   618   assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
   620   u = get_cpu_load(-1, &_counters, &s, CPU_LOAD_VM_ONLY);
   621   if (u < 0) {
   622     *pjvmUserLoad = 0.0;
   623     *pjvmKernelLoad = 0.0;
   624     *psystemTotalLoad = 0.0;
   625     return OS_ERR;
   626   }
   628   cpu_load(-1, &t);
   629   // clamp at user+system and 1.0
   630   if (u + s > t) {
   631     t = MIN2<double>(u + s, 1.0);
   632   }
   634   *pjvmUserLoad = u;
   635   *pjvmKernelLoad = s;
   636   *psystemTotalLoad = t;
   638   return OS_OK;
   639 }
   641 int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
   642   return perf_context_switch_rate(rate);
   643 }
   645 CPUPerformanceInterface::CPUPerformanceInterface() {
   646   _impl = NULL;
   647 }
   649 bool CPUPerformanceInterface::initialize() {
   650   _impl = new CPUPerformanceInterface::CPUPerformance();
   651   return NULL == _impl ? false : _impl->initialize();
   652 }
   654 CPUPerformanceInterface::~CPUPerformanceInterface() {
   655   if (_impl != NULL) {
   656     delete _impl;
   657   }
   658 }
   660 int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
   661   return _impl->cpu_load(which_logical_cpu, cpu_load);
   662 }
   664 int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
   665   return _impl->cpu_load_total_process(cpu_load);
   666 }
   668 int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
   669   return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
   670 }
   672 int CPUPerformanceInterface::context_switch_rate(double* rate) const {
   673   return _impl->context_switch_rate(rate);
   674 }
   676 class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
   677   friend class SystemProcessInterface;
   678  private:
   679   class ProcessIterator : public CHeapObj<mtInternal> {
   680     friend class SystemProcessInterface::SystemProcesses;
   681    private:
   682     DIR*           _dir;
   683     struct dirent* _entry;
   684     bool           _valid;
   685     char           _exeName[PATH_MAX];
   686     char           _exePath[PATH_MAX];
   688     ProcessIterator();
   689     ~ProcessIterator();
   690     bool initialize();
   692     bool is_valid() const { return _valid; }
   693     bool is_valid_entry(struct dirent* entry) const;
   694     bool is_dir(const char* name) const;
   695     int  fsize(const char* name, uint64_t& size) const;
   697     char* allocate_string(const char* str) const;
   698     void  get_exe_name();
   699     char* get_exe_path();
   700     char* get_cmdline();
   702     int current(SystemProcess* process_info);
   703     int next_process();
   704   };
   706   ProcessIterator* _iterator;
   707   SystemProcesses();
   708   bool initialize();
   709   ~SystemProcesses();
   711   //information about system processes
   712   int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
   713 };
   715 bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
   716   struct stat mystat;
   717   int ret_val = 0;
   719   ret_val = stat(name, &mystat);
   720   if (ret_val < 0) {
   721     return false;
   722   }
   723   ret_val = S_ISDIR(mystat.st_mode);
   724   return ret_val > 0;
   725 }
   727 int SystemProcessInterface::SystemProcesses::ProcessIterator::fsize(const char* name, uint64_t& size) const {
   728   assert(name != NULL, "name pointer is NULL!");
   729   size = 0;
   730   struct stat fbuf;
   732   if (stat(name, &fbuf) < 0) {
   733     return OS_ERR;
   734   }
   735   size = fbuf.st_size;
   736   return OS_OK;
   737 }
   739 // if it has a numeric name, is a directory and has a 'stat' file in it
   740 bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
   741   char buffer[PATH_MAX];
   742   uint64_t size = 0;
   744   if (atoi(entry->d_name) != 0) {
   745     jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
   746     buffer[PATH_MAX - 1] = '\0';
   748     if (is_dir(buffer)) {
   749       jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", entry->d_name);
   750       buffer[PATH_MAX - 1] = '\0';
   751       if (fsize(buffer, size) != OS_ERR) {
   752         return true;
   753       }
   754     }
   755   }
   756   return false;
   757 }
   759 // get exe-name from /proc/<pid>/stat
   760 void SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_name() {
   761   FILE* fp;
   762   char  buffer[PATH_MAX];
   764   jio_snprintf(buffer, PATH_MAX, "/proc/%s/stat", _entry->d_name);
   765   buffer[PATH_MAX - 1] = '\0';
   766   if ((fp = fopen(buffer, "r")) != NULL) {
   767     if (fgets(buffer, PATH_MAX, fp) != NULL) {
   768       char* start, *end;
   769       // exe-name is between the first pair of ( and )
   770       start = strchr(buffer, '(');
   771       if (start != NULL && start[1] != '\0') {
   772         start++;
   773         end = strrchr(start, ')');
   774         if (end != NULL) {
   775           size_t len;
   776           len = MIN2<size_t>(end - start, sizeof(_exeName) - 1);
   777           memcpy(_exeName, start, len);
   778           _exeName[len] = '\0';
   779         }
   780       }
   781     }
   782     fclose(fp);
   783   }
   784 }
   786 // get command line from /proc/<pid>/cmdline
   787 char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_cmdline() {
   788   FILE* fp;
   789   char  buffer[PATH_MAX];
   790   char* cmdline = NULL;
   792   jio_snprintf(buffer, PATH_MAX, "/proc/%s/cmdline", _entry->d_name);
   793   buffer[PATH_MAX - 1] = '\0';
   794   if ((fp = fopen(buffer, "r")) != NULL) {
   795     size_t size = 0;
   796     char   dummy;
   798     // find out how long the file is (stat always returns 0)
   799     while (fread(&dummy, 1, 1, fp) == 1) {
   800       size++;
   801     }
   802     if (size > 0) {
   803       cmdline = NEW_C_HEAP_ARRAY(char, size + 1, mtInternal);
   804       if (cmdline != NULL) {
   805         cmdline[0] = '\0';
   806         if (fseek(fp, 0, SEEK_SET) == 0) {
   807           if (fread(cmdline, 1, size, fp) == size) {
   808             // the file has the arguments separated by '\0',
   809             // so we translate '\0' to ' '
   810             for (size_t i = 0; i < size; i++) {
   811               if (cmdline[i] == '\0') {
   812                 cmdline[i] = ' ';
   813               }
   814             }
   815             cmdline[size] = '\0';
   816           }
   817         }
   818       }
   819     }
   820     fclose(fp);
   821   }
   822   return cmdline;
   823 }
   825 // get full path to exe from /proc/<pid>/exe symlink
   826 char* SystemProcessInterface::SystemProcesses::ProcessIterator::get_exe_path() {
   827   char buffer[PATH_MAX];
   829   jio_snprintf(buffer, PATH_MAX, "/proc/%s/exe", _entry->d_name);
   830   buffer[PATH_MAX - 1] = '\0';
   831   return realpath(buffer, _exePath);
   832 }
   834 char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
   835   if (str != NULL) {
   836     size_t len = strlen(str);
   837     char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
   838     strncpy(tmp, str, len);
   839     tmp[len] = '\0';
   840     return tmp;
   841   }
   842   return NULL;
   843 }
   845 int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
   846   if (!is_valid()) {
   847     return OS_ERR;
   848   }
   850   process_info->set_pid(atoi(_entry->d_name));
   852   get_exe_name();
   853   process_info->set_name(allocate_string(_exeName));
   855   if (get_exe_path() != NULL) {
   856      process_info->set_path(allocate_string(_exePath));
   857   }
   859   char* cmdline = NULL;
   860   cmdline = get_cmdline();
   861   if (cmdline != NULL) {
   862     process_info->set_command_line(allocate_string(cmdline));
   863     FREE_C_HEAP_ARRAY(char, cmdline, mtInternal);
   864   }
   866   return OS_OK;
   867 }
   869 int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
   870   if (!is_valid()) {
   871     return OS_ERR;
   872   }
   874   do {
   875     _entry = os::readdir(_dir);
   876     if (_entry == NULL) {
   877       // Error or reached end.  Could use errno to distinguish those cases.
   878       _valid = false;
   879       return OS_ERR;
   880     }
   881   } while(!is_valid_entry(_entry));
   883   _valid = true;
   884   return OS_OK;
   885 }
   887 SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
   888   _dir = NULL;
   889   _entry = NULL;
   890   _valid = false;
   891 }
   893 bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
   894   // Not yet implemented.
   895   return false;
   896 }
   898 SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
   899   if (_dir != NULL) {
   900     os::closedir(_dir);
   901   }
   902 }
   904 SystemProcessInterface::SystemProcesses::SystemProcesses() {
   905   _iterator = NULL;
   906 }
   908 bool SystemProcessInterface::SystemProcesses::initialize() {
   909   _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
   910   return NULL == _iterator ? false : _iterator->initialize();
   911 }
   913 SystemProcessInterface::SystemProcesses::~SystemProcesses() {
   914   if (_iterator != NULL) {
   915     delete _iterator;
   916   }
   917 }
   919 int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
   920   assert(system_processes != NULL, "system_processes pointer is NULL!");
   921   assert(no_of_sys_processes != NULL, "system_processes counter pointers is NULL!");
   922   assert(_iterator != NULL, "iterator is NULL!");
   924   // initialize pointers
   925   *no_of_sys_processes = 0;
   926   *system_processes = NULL;
   928   while (_iterator->is_valid()) {
   929     SystemProcess* tmp = new SystemProcess();
   930     _iterator->current(tmp);
   932     //if already existing head
   933     if (*system_processes != NULL) {
   934       //move "first to second"
   935       tmp->set_next(*system_processes);
   936     }
   937     // new head
   938     *system_processes = tmp;
   939     // increment
   940     (*no_of_sys_processes)++;
   941     // step forward
   942     _iterator->next_process();
   943   }
   944   return OS_OK;
   945 }
   947 int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
   948   return _impl->system_processes(system_procs, no_of_sys_processes);
   949 }
   951 SystemProcessInterface::SystemProcessInterface() {
   952   _impl = NULL;
   953 }
   955 bool SystemProcessInterface::initialize() {
   956   _impl = new SystemProcessInterface::SystemProcesses();
   957   return NULL == _impl ? false : _impl->initialize();
   958 }
   960 SystemProcessInterface::~SystemProcessInterface() {
   961   if (_impl != NULL) {
   962     delete _impl;
   963   }
   964 }
   966 CPUInformationInterface::CPUInformationInterface() {
   967   _cpu_info = NULL;
   968 }
   970 bool CPUInformationInterface::initialize() {
   971   _cpu_info = new CPUInformation();
   972   if (NULL == _cpu_info) {
   973     return false;
   974   }
   975   _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
   976   _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
   977   _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
   978   _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
   979   _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
   981   return true;
   982 }
   984 CPUInformationInterface::~CPUInformationInterface() {
   985   if (_cpu_info != NULL) {
   986     if (_cpu_info->cpu_name() != NULL) {
   987       const char* cpu_name = _cpu_info->cpu_name();
   988       FREE_C_HEAP_ARRAY(char, cpu_name, mtInternal);
   989       _cpu_info->set_cpu_name(NULL);
   990     }
   991     if (_cpu_info->cpu_description() != NULL) {
   992        const char* cpu_desc = _cpu_info->cpu_description();
   993        FREE_C_HEAP_ARRAY(char, cpu_desc, mtInternal);
   994       _cpu_info->set_cpu_description(NULL);
   995     }
   996     delete _cpu_info;
   997   }
   998 }
  1000 int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
  1001   if (_cpu_info == NULL) {
  1002     return OS_ERR;
  1005   cpu_info = *_cpu_info; // shallow copy assignment
  1006   return OS_OK;
  1009 class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
  1010   friend class NetworkPerformanceInterface;
  1011  private:
  1012   NetworkPerformance();
  1013   NetworkPerformance(const NetworkPerformance& rhs); // no impl
  1014   NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
  1015   bool initialize();
  1016   ~NetworkPerformance();
  1017   int network_utilization(NetworkInterface** network_interfaces) const;
  1018 };
  1020 NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
  1024 bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
  1025   return true;
  1028 NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
  1031 int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
  1033   return FUNCTIONALITY_NOT_IMPLEMENTED;
  1036 NetworkPerformanceInterface::NetworkPerformanceInterface() {
  1037   _impl = NULL;
  1040 NetworkPerformanceInterface::~NetworkPerformanceInterface() {
  1041   if (_impl != NULL) {
  1042     delete _impl;
  1046 bool NetworkPerformanceInterface::initialize() {
  1047   _impl = new NetworkPerformanceInterface::NetworkPerformance();
  1048   return _impl != NULL && _impl->initialize();
  1051 int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
  1052   return _impl->network_utilization(network_interfaces);

mercurial