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