8221535: add steal tick related information to hs_error file [linux]
authormbaesken
Mon, 08 Apr 2019 14:36:33 +0200
changeset 54470 14986fb09d9a
parent 54469 8592226f5cd3
child 54471 f22759e92191
8221535: add steal tick related information to hs_error file [linux] Reviewed-by: dholmes, goetz
src/hotspot/os/aix/os_perf_aix.cpp
src/hotspot/os/linux/os_linux.cpp
src/hotspot/os/linux/os_linux.hpp
src/hotspot/os/linux/os_perf_linux.cpp
--- a/src/hotspot/os/aix/os_perf_aix.cpp	Mon Apr 08 21:39:43 2019 +0000
+++ b/src/hotspot/os/aix/os_perf_aix.cpp	Mon Apr 08 14:36:33 2019 +0200
@@ -336,20 +336,8 @@
 
   fclose(fh);
   if (n < expected_assign_count || logical_cpu != which_logical_cpu) {
-#ifdef DEBUG_LINUX_PROC_STAT
-    vm_fprintf(stderr, "[stat] read failed");
-#endif
     return OS_ERR;
   }
-
-#ifdef DEBUG_LINUX_PROC_STAT
-  vm_fprintf(stderr, "[stat] read "
-          UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
-          UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n",
-          userTicks, niceTicks, systemTicks, idleTicks,
-          iowTicks, irqTicks, sirqTicks);
-#endif
-
   pticks->used       = userTicks + niceTicks;
   pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
   pticks->total      = userTicks + niceTicks + systemTicks + idleTicks +
--- a/src/hotspot/os/linux/os_linux.cpp	Mon Apr 08 21:39:43 2019 +0000
+++ b/src/hotspot/os/linux/os_linux.cpp	Mon Apr 08 14:36:33 2019 +0200
@@ -227,6 +227,82 @@
   return phys_mem;
 }
 
+static uint64_t initial_total_ticks = 0;
+static uint64_t initial_steal_ticks = 0;
+static bool     has_initial_tick_info = false;
+
+static void next_line(FILE *f) {
+  int c;
+  do {
+    c = fgetc(f);
+  } while (c != '\n' && c != EOF);
+}
+
+bool os::Linux::get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu) {
+  FILE*         fh;
+  uint64_t      userTicks, niceTicks, systemTicks, idleTicks;
+  // since at least kernel 2.6 : iowait: time waiting for I/O to complete
+  // irq: time  servicing interrupts; softirq: time servicing softirqs
+  uint64_t      iowTicks = 0, irqTicks = 0, sirqTicks= 0;
+  // steal (since kernel 2.6.11): time spent in other OS when running in a virtualized environment
+  uint64_t      stealTicks = 0;
+  // guest (since kernel 2.6.24): time spent running a virtual CPU for guest OS under the
+  // control of the Linux kernel
+  uint64_t      guestNiceTicks = 0;
+  int           logical_cpu = -1;
+  const int     required_tickinfo_count = (which_logical_cpu == -1) ? 4 : 5;
+  int           n;
+
+  memset(pticks, 0, sizeof(CPUPerfTicks));
+
+  if ((fh = fopen("/proc/stat", "r")) == NULL) {
+    return false;
+  }
+
+  if (which_logical_cpu == -1) {
+    n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
+            UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
+            UINT64_FORMAT " " UINT64_FORMAT " ",
+            &userTicks, &niceTicks, &systemTicks, &idleTicks,
+            &iowTicks, &irqTicks, &sirqTicks,
+            &stealTicks, &guestNiceTicks);
+  } else {
+    // Move to next line
+    next_line(fh);
+
+    // find the line for requested cpu faster to just iterate linefeeds?
+    for (int i = 0; i < which_logical_cpu; i++) {
+      next_line(fh);
+    }
+
+    n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
+               UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
+               UINT64_FORMAT " " UINT64_FORMAT " ",
+               &logical_cpu, &userTicks, &niceTicks,
+               &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks,
+               &stealTicks, &guestNiceTicks);
+  }
+
+  fclose(fh);
+  if (n < required_tickinfo_count || logical_cpu != which_logical_cpu) {
+    return false;
+  }
+  pticks->used       = userTicks + niceTicks;
+  pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
+  pticks->total      = userTicks + niceTicks + systemTicks + idleTicks +
+                       iowTicks + irqTicks + sirqTicks + stealTicks + guestNiceTicks;
+
+  if (n > required_tickinfo_count + 3) {
+    pticks->steal = stealTicks;
+    pticks->has_steal_ticks = true;
+  } else {
+    pticks->steal = 0;
+    pticks->has_steal_ticks = false;
+  }
+
+  return true;
+}
+
 // Return true if user is running as root.
 
 bool os::have_special_privileges() {
@@ -1977,6 +2053,8 @@
   os::Linux::print_container_info(st);
 
   os::Linux::print_virtualization_info(st);
+
+  os::Linux::print_steal_info(st);
 }
 
 // Try to identify popular distros.
@@ -2265,6 +2343,24 @@
 #endif
 }
 
+void os::Linux::print_steal_info(outputStream* st) {
+  if (has_initial_tick_info) {
+    CPUPerfTicks pticks;
+    bool res = os::Linux::get_tick_information(&pticks, -1);
+
+    if (res && pticks.has_steal_ticks) {
+      uint64_t steal_ticks_difference = pticks.steal - initial_steal_ticks;
+      uint64_t total_ticks_difference = pticks.total - initial_total_ticks;
+      double steal_ticks_perc = 0.0;
+      if (total_ticks_difference != 0) {
+        steal_ticks_perc = (double) steal_ticks_difference / total_ticks_difference;
+      }
+      st->print_cr("Steal ticks since vm start: " UINT64_FORMAT, steal_ticks_difference);
+      st->print_cr("Steal ticks percentage since vm start:%7.3f", steal_ticks_perc);
+    }
+  }
+}
+
 void os::print_memory_info(outputStream* st) {
 
   st->print("Memory:");
@@ -4989,6 +5085,15 @@
 
   Linux::initialize_os_info();
 
+  os::Linux::CPUPerfTicks pticks;
+  bool res = os::Linux::get_tick_information(&pticks, -1);
+
+  if (res && pticks.has_steal_ticks) {
+    has_initial_tick_info = true;
+    initial_total_ticks = pticks.total;
+    initial_steal_ticks = pticks.steal;
+  }
+
   // _main_thread points to the thread that created/loaded the JVM.
   Linux::_main_thread = pthread_self();
 
--- a/src/hotspot/os/linux/os_linux.hpp	Mon Apr 08 21:39:43 2019 +0000
+++ b/src/hotspot/os/linux/os_linux.hpp	Mon Apr 08 14:36:33 2019 +0200
@@ -109,12 +109,23 @@
   static void print_full_memory_info(outputStream* st);
   static void print_container_info(outputStream* st);
   static void print_virtualization_info(outputStream* st);
+  static void print_steal_info(outputStream* st);
   static void print_distro_info(outputStream* st);
   static void print_libversion_info(outputStream* st);
   static void print_proc_sys_info(outputStream* st);
   static void print_ld_preload_file(outputStream* st);
 
  public:
+  struct CPUPerfTicks {
+    uint64_t used;
+    uint64_t usedKernel;
+    uint64_t total;
+    uint64_t steal;
+    bool     has_steal_ticks;
+  };
+
+  // which_logical_cpu=-1 returns accumulated ticks for all cpus.
+  static bool get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu);
   static bool _stack_is_executable;
   static void *dlopen_helper(const char *name, char *ebuf, int ebuflen);
   static void *dll_load_in_vmthread(const char *name, char *ebuf, int ebuflen);
--- a/src/hotspot/os/linux/os_perf_linux.cpp	Mon Apr 08 21:39:43 2019 +0000
+++ b/src/hotspot/os/linux/os_perf_linux.cpp	Mon Apr 08 14:36:33 2019 +0200
@@ -206,13 +206,6 @@
 #  define _SCANFMT_
 #endif
 
-
-struct CPUPerfTicks {
-  uint64_t  used;
-  uint64_t  usedKernel;
-  uint64_t  total;
-};
-
 typedef enum {
   CPU_LOAD_VM_ONLY,
   CPU_LOAD_GLOBAL,
@@ -227,8 +220,8 @@
 
 struct CPUPerfCounters {
   int   nProcs;
-  CPUPerfTicks jvmTicks;
-  CPUPerfTicks* cpus;
+  os::Linux::CPUPerfTicks jvmTicks;
+  os::Linux::CPUPerfTicks* cpus;
 };
 
 static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target);
@@ -287,80 +280,6 @@
   return f;
 }
 
-static void
-next_line(FILE *f) {
-  int c;
-  do {
-    c = fgetc(f);
-  } while (c != '\n' && c != EOF);
-}
-
-/**
- * Return the total number of ticks since the system was booted.
- * If the usedTicks parameter is not NULL, it will be filled with
- * the number of ticks spent on actual processes (user, system or
- * nice processes) since system boot. Note that this is the total number
- * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is
- * n times the number of ticks that has passed in clock time.
- *
- * Returns a negative value if the reading of the ticks failed.
- */
-static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) {
-  FILE*         fh;
-  uint64_t      userTicks, niceTicks, systemTicks, idleTicks;
-  uint64_t      iowTicks = 0, irqTicks = 0, sirqTicks= 0;
-  int           logical_cpu = -1;
-  const int     expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5;
-  int           n;
-
-  if ((fh = open_statfile()) == NULL) {
-    return OS_ERR;
-  }
-  if (-1 == which_logical_cpu) {
-    n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
-            UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
-            &userTicks, &niceTicks, &systemTicks, &idleTicks,
-            &iowTicks, &irqTicks, &sirqTicks);
-  } else {
-    // Move to next line
-    next_line(fh);
-
-    // find the line for requested cpu faster to just iterate linefeeds?
-    for (int i = 0; i < which_logical_cpu; i++) {
-      next_line(fh);
-    }
-
-    n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
-               UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT,
-               &logical_cpu, &userTicks, &niceTicks,
-               &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks);
-  }
-
-  fclose(fh);
-  if (n < expected_assign_count || logical_cpu != which_logical_cpu) {
-#ifdef DEBUG_LINUX_PROC_STAT
-    vm_fprintf(stderr, "[stat] read failed");
-#endif
-    return OS_ERR;
-  }
-
-#ifdef DEBUG_LINUX_PROC_STAT
-  vm_fprintf(stderr, "[stat] read "
-          UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " "
-          UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n",
-          userTicks, niceTicks, systemTicks, idleTicks,
-          iowTicks, irqTicks, sirqTicks);
-#endif
-
-  pticks->used       = userTicks + niceTicks;
-  pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
-  pticks->total      = userTicks + niceTicks + systemTicks + idleTicks +
-                       iowTicks + irqTicks + sirqTicks;
-
-  return OS_OK;
-}
-
-
 static int get_systemtype(void) {
   static int procEntriesType = UNDETECTED;
   DIR *taskDir;
@@ -391,7 +310,7 @@
  * Return the number of ticks spent in any of the processes belonging
  * to the JVM on any CPU.
  */
-static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) {
+static OSReturn get_jvm_ticks(os::Linux::CPUPerfTicks* pticks) {
   uint64_t userTicks;
   uint64_t systemTicks;
 
@@ -404,7 +323,7 @@
   }
 
   // get the total
-  if (get_total_ticks(-1, pticks) != OS_OK) {
+  if (! os::Linux::get_tick_information(pticks, -1)) {
     return OS_ERR;
   }
 
@@ -423,8 +342,8 @@
  */
 static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) {
   uint64_t udiff, kdiff, tdiff;
-  CPUPerfTicks* pticks;
-  CPUPerfTicks  tmp;
+  os::Linux::CPUPerfTicks* pticks;
+  os::Linux::CPUPerfTicks  tmp;
   double user_load;
 
   *pkernelLoad = 0.0;
@@ -443,7 +362,7 @@
     if (get_jvm_ticks(pticks) != OS_OK) {
       return -1.0;
     }
-  } else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) {
+  } else if (! os::Linux::get_tick_information(pticks, which_logical_cpu)) {
     return -1.0;
   }
 
@@ -584,19 +503,19 @@
 }
 
 bool CPUPerformanceInterface::CPUPerformance::initialize() {
-  size_t tick_array_size = (_counters.nProcs +1) * sizeof(CPUPerfTicks);
-  _counters.cpus = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
+  size_t tick_array_size = (_counters.nProcs +1) * sizeof(os::Linux::CPUPerfTicks);
+  _counters.cpus = (os::Linux::CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
   if (NULL == _counters.cpus) {
     return false;
   }
   memset(_counters.cpus, 0, tick_array_size);
 
   // For the CPU load total
-  get_total_ticks(-1, &_counters.cpus[_counters.nProcs]);
+  os::Linux::get_tick_information(&_counters.cpus[_counters.nProcs], -1);
 
   // For each CPU
   for (int i = 0; i < _counters.nProcs; i++) {
-    get_total_ticks(i, &_counters.cpus[i]);
+    os::Linux::get_tick_information(&_counters.cpus[i], i);
   }
   // For JVM load
   get_jvm_ticks(&_counters.jvmTicks);