1 /******************************************************************************* 2 * Copyright (c) 2003, 2016 IBM Corporation and others. 3 * 4 * This program and the accompanying materials are made 5 * available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at 6 * https://www.eclipse.org/legal/epl-2.0/ 7 * 8 * SPDX-License-Identifier: EPL-2.0 9 * 10 * Contributors: IBM Corporation - initial API and implementation 11 *******************************************************************************/ 12 13 package org.eclipse.test.internal.performance; 14 15 import java.io.BufferedReader; 16 import java.io.FileReader; 17 import java.io.IOException; 18 import java.io.InputStreamReader; 19 import java.util.Map; 20 import java.util.StringTokenizer; 21 22 class PerformanceMonitorLinux extends PerformanceMonitor { 23 24 private static long PAGESIZE = 4096; 25 private static long JIFFIES = 10L; 26 private static boolean fgHasElapsedTime = true; 27 private static long fgStartupTime; 28 29 /** 30 * Write out operating system counters for Linux. 31 * 32 * @param scalars 33 */ 34 @Override collectOperatingSystemCounters(Map scalars)35 protected void collectOperatingSystemCounters(Map scalars) { 36 synchronized (this) { 37 /** 38 * The status values for a Linux process, that is the values that come from /proc/self/stat. The names of the variables match 39 * the man proc page. 40 */ 41 StringTokenizer st = readTokens("/proc/self/stat", false); //$NON-NLS-1$ 42 if (st != null) { 43 st.nextToken(); // int pid; // Process id. 44 st.nextToken(); // String comm; // The command name. 45 st.nextToken(); // String state; 46 st.nextToken(); // int ppid; // Parent process id. */ 47 st.nextToken(); // int pgrp; // Process group. */ 48 st.nextToken(); // int session; 49 st.nextToken(); // int ttry_nr; 50 st.nextToken(); // int tpgid; 51 st.nextToken(); // long flags; 52 long minflt = Long.parseLong(st.nextToken()); // Minor page faults (didn't need to load a page from disk). */ 53 st.nextToken(); // long cminflt; // Minor page faults for the process and it's children. */ 54 long majflt = Long.parseLong(st.nextToken()); // Major page faults. */ 55 st.nextToken(); // long cmajflt; // Major page faults for the process and it's children. */ 56 long utime = Long.parseLong(st.nextToken()); // User time in jiffies. */ 57 long stime = Long.parseLong(st.nextToken()); // System time in jiffies. */ 58 st.nextToken(); // long cutime; // User time for the process and it's children. */ 59 st.nextToken(); // long cstime; // System time for the process and it's children. */ 60 61 // addScalar(scalars, InternalDimensions.USER_TIME, utime*JIFFIES); 62 addScalar(scalars, InternalDimensions.KERNEL_TIME, stime * JIFFIES); 63 addScalar(scalars, InternalDimensions.CPU_TIME, (utime + stime) * JIFFIES); 64 addScalar(scalars, InternalDimensions.SOFT_PAGE_FAULTS, minflt); 65 addScalar(scalars, InternalDimensions.HARD_PAGE_FAULTS, majflt); 66 } 67 68 /** 69 * The status memory values values for a Linux process, that is the values that come from /proc/self/statm. The names of the 70 * variables match the man proc page. 71 */ 72 st = readTokens("/proc/self/statm", false); //$NON-NLS-1$ 73 if (st != null) { 74 st.nextToken(); // int size; // Size of the process in pages 75 int resident = Integer.parseInt(st.nextToken()); // Resident size in pages. 76 st.nextToken(); // int shared; // Shared size in pages. 77 int trs = Integer.parseInt(st.nextToken()); // Text (code) size in pages. 78 int drs = Integer.parseInt(st.nextToken()); // Data/Stack size in pages. 79 int lrs = Integer.parseInt(st.nextToken()); // Library size in pages. 80 // st.nextToken(); // int dt; // Dirty pages. 81 82 addScalar(scalars, InternalDimensions.WORKING_SET, resident * PAGESIZE); 83 addScalar(scalars, InternalDimensions.TRS, trs * PAGESIZE); 84 addScalar(scalars, InternalDimensions.DRS, drs * PAGESIZE); 85 addScalar(scalars, InternalDimensions.LRS, lrs * PAGESIZE); 86 } 87 88 long currentTime = System.currentTimeMillis(); 89 90 addScalar(scalars, InternalDimensions.SYSTEM_TIME, currentTime); 91 92 if (fgHasElapsedTime) { 93 if (fgStartupTime == 0) { 94 String t = System.getProperty("eclipse.startTime"); //$NON-NLS-1$ 95 if (t != null) { 96 try { 97 fgStartupTime = Long.parseLong(t); 98 } catch (NumberFormatException e) { 99 fgHasElapsedTime = false; 100 } 101 } else 102 fgHasElapsedTime = false; 103 } 104 if (fgHasElapsedTime) 105 addScalar(scalars, InternalDimensions.ELAPSED_PROCESS, currentTime - fgStartupTime); 106 } 107 108 super.collectOperatingSystemCounters(scalars); 109 } 110 } 111 112 /** 113 * Write out the global machine counters for Linux. 114 * 115 * @param scalars 116 */ 117 @Override collectGlobalPerformanceInfo(Map scalars)118 protected void collectGlobalPerformanceInfo(Map scalars) { 119 synchronized (this) { 120 /** 121 * The meminfo values for a Linux machine, that is the values that come from /proc/meminfo. 122 */ 123 // /proc/meminfo is formatted on linux - use byte-counted output from free 124 StringTokenizer st = readOutput("free -b", true); //$NON-NLS-1$ 125 if (st != null) { 126 st.nextToken(); // throw away label 127 long total = Long.parseLong(st.nextToken()); 128 long used = Long.parseLong(st.nextToken()); 129 long free = Long.parseLong(st.nextToken()); 130 st.nextToken(); // long shared; 131 long buffers = Long.parseLong(st.nextToken()); 132 long cache = Long.parseLong(st.nextToken()); 133 134 addScalar(scalars, InternalDimensions.PHYSICAL_TOTAL, total); 135 addScalar(scalars, InternalDimensions.USED_LINUX_MEM, used); 136 addScalar(scalars, InternalDimensions.FREE_LINUX_MEM, free); 137 addScalar(scalars, InternalDimensions.BUFFERS_LINUX, buffers); 138 addScalar(scalars, InternalDimensions.SYSTEM_CACHE, cache); 139 } 140 super.collectGlobalPerformanceInfo(scalars); 141 } 142 } 143 readTokens(String procPath, boolean skipFirst)144 private StringTokenizer readTokens(String procPath, boolean skipFirst) { 145 try (BufferedReader rdr = new BufferedReader(new FileReader(procPath));){ 146 if (skipFirst) 147 rdr.readLine(); // throw away the heading line 148 return new StringTokenizer(rdr.readLine()); 149 } catch (IOException e) { 150 PerformanceTestPlugin.log(e); 151 } 152 return null; 153 } 154 readOutput(String cmd, boolean skipFirst)155 private StringTokenizer readOutput(String cmd, boolean skipFirst) { 156 BufferedReader rdr = null; 157 try { 158 Process process = Runtime.getRuntime().exec(cmd); 159 rdr = new BufferedReader(new InputStreamReader(process.getInputStream())); 160 if (skipFirst) 161 rdr.readLine(); // throw away the heading line 162 return new StringTokenizer(rdr.readLine()); 163 } catch (IOException e) { 164 PerformanceTestPlugin.log(e); 165 } 166 finally { 167 try { 168 if (rdr != null) 169 rdr.close(); 170 } catch (IOException e) { 171 // silently ignored 172 } 173 } 174 return null; 175 } 176 } 177