blob: 55807f2395f1d9f3b3be0dbbfc03e2d4e27e14bd [file] [log] [blame]
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.util;
16
17import static java.nio.charset.StandardCharsets.US_ASCII;
18
19import com.google.common.base.CharMatcher;
20import com.google.common.base.Splitter;
21import com.google.common.collect.Iterables;
22import com.google.common.io.Files;
23
24import com.sun.management.OperatingSystemMXBean;
25
26import java.io.File;
27import java.io.IOException;
28import java.lang.management.ManagementFactory;
29import java.lang.management.MemoryMXBean;
30import java.util.Iterator;
31
32/**
33 * Provides methods to measure the current resource usage of the current
34 * process. Also provides some convenience methods to obtain several system
35 * characteristics, like number of processors , total memory, etc.
36 */
37public final class ResourceUsage {
38
39 /*
40 * Use com.sun.management.OperatingSystemMXBean instead of
41 * java.lang.management.OperatingSystemMXBean because the latter does not
42 * support getTotalPhysicalMemorySize() and getFreePhysicalMemorySize().
43 */
44 private static final OperatingSystemMXBean OS_BEAN =
45 (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
46
47 private static final MemoryMXBean MEM_BEAN = ManagementFactory.getMemoryMXBean();
48 private static final Splitter WHITESPACE_SPLITTER = Splitter.on(CharMatcher.WHITESPACE);
49
50 /**
51 * Calculates an estimate of the current total CPU usage and the CPU usage of
52 * the process in percent measured from the two given measurements. The
53 * returned CPU usages rea average values for the time between the two
54 * measurements. The returned array contains the total CPU usage at index 0
55 * and the CPU usage of the measured process at index 1.
56 */
57 public static float[] calculateCurrentCpuUsage(Measurement oldMeasurement,
58 Measurement newMeasurement) {
59 if (oldMeasurement == null) {
60 return new float[2];
61 }
62 long idleJiffies =
63 newMeasurement.getTotalCpuIdleTimeInJiffies()
64 - oldMeasurement.getTotalCpuIdleTimeInJiffies();
65 long oldProcessJiffies =
66 oldMeasurement.getCpuUtilizationInJiffies()[0]
67 + oldMeasurement.getCpuUtilizationInJiffies()[1];
68 long newProcessJiffies =
69 newMeasurement.getCpuUtilizationInJiffies()[0]
70 + newMeasurement.getCpuUtilizationInJiffies()[1];
71 long processJiffies = newProcessJiffies - oldProcessJiffies;
72 long elapsedTimeJiffies =
73 newMeasurement.getTimeInJiffies() - oldMeasurement.getTimeInJiffies();
74 int processors = getAvailableProcessors();
75 // TODO(bazel-team): Sometimes smaller then zero. Not sure why.
76 double totalUsage = Math.max(0, 1.0D - (double) idleJiffies / elapsedTimeJiffies / processors);
77 double usage = Math.max(0, (double) processJiffies / elapsedTimeJiffies / processors);
78 return new float[] {(float) totalUsage * 100, (float) usage * 100};
79 }
80
81 private ResourceUsage() {
82 }
83
84 /**
85 * Returns the number of processors available to the Java virtual machine.
86 */
87 public static int getAvailableProcessors() {
88 return OS_BEAN.getAvailableProcessors();
89 }
90
91 /**
92 * Returns the total physical memory in bytes.
93 */
94 public static long getTotalPhysicalMemorySize() {
95 return OS_BEAN.getTotalPhysicalMemorySize();
96 }
97
98 /**
99 * Returns the operating system architecture.
100 */
101 public static String getOsArchitecture() {
102 return OS_BEAN.getArch();
103 }
104
105 /**
106 * Returns the operating system name.
107 */
108 public static String getOsName() {
109 return OS_BEAN.getName();
110 }
111
112 /**
113 * Returns the operating system version.
114 */
115 public static String getOsVersion() {
116 return OS_BEAN.getVersion();
117 }
118
119 /**
120 * Returns the initial size of heap memory in bytes.
121 *
122 * @see MemoryMXBean#getHeapMemoryUsage()
123 */
124 public static long getHeapMemoryInit() {
125 return MEM_BEAN.getHeapMemoryUsage().getInit();
126 }
127
128 /**
129 * Returns the initial size of non heap memory in bytes.
130 *
131 * @see MemoryMXBean#getNonHeapMemoryUsage()
132 */
133 public static long getNonHeapMemoryInit() {
134 return MEM_BEAN.getNonHeapMemoryUsage().getInit();
135 }
136
137 /**
138 * Returns the maximum size of heap memory in bytes.
139 *
140 * @see MemoryMXBean#getHeapMemoryUsage()
141 */
142 public static long getHeapMemoryMax() {
143 return MEM_BEAN.getHeapMemoryUsage().getMax();
144 }
145
146 /**
147 * Returns the maximum size of non heap memory in bytes.
148 *
149 * @see MemoryMXBean#getNonHeapMemoryUsage()
150 */
151 public static long getNonHeapMemoryMax() {
152 return MEM_BEAN.getNonHeapMemoryUsage().getMax();
153 }
154
155 /**
156 * Returns a measurement of the current resource usage of the current process.
157 */
158 public static Measurement measureCurrentResourceUsage() {
159 return measureCurrentResourceUsage("self");
160 }
161
162 /**
163 * Returns a measurement of the current resource usage of the process with the
164 * given process id.
165 *
166 * @param processId the process id or <code>self</code> for the current
167 * process.
168 */
169 public static Measurement measureCurrentResourceUsage(String processId) {
170 return new Measurement(MEM_BEAN.getHeapMemoryUsage().getUsed(), MEM_BEAN.getHeapMemoryUsage()
171 .getCommitted(), MEM_BEAN.getNonHeapMemoryUsage().getUsed(), MEM_BEAN
172 .getNonHeapMemoryUsage().getCommitted(), (float) OS_BEAN.getSystemLoadAverage(), OS_BEAN
173 .getFreePhysicalMemorySize(), getCurrentTotalIdleTimeInJiffies(),
174 getCurrentCpuUtilizationInJiffies(processId));
175 }
176
177 /**
178 * Returns the current total idle time of the processors since system boot.
179 * Reads /proc/stat to obtain this information.
180 */
181 private static long getCurrentTotalIdleTimeInJiffies() {
182 try {
183 File file = new File("/proc/stat");
184 String content = Files.toString(file, US_ASCII);
185 String value = Iterables.get(WHITESPACE_SPLITTER.split(content), 5);
186 return Long.parseLong(value);
187 } catch (NumberFormatException | IOException e) {
188 return 0L;
189 }
190 }
191
192 /**
193 * Returns the current cpu utilization of the current process with the given
194 * id in jiffies. The returned array contains the following information: The
195 * 1st entry is the number of jiffies that the process has executed in user
196 * mode, and the 2nd entry is the number of jiffies that the process has
197 * executed in kernel mode. Reads /proc/self/stat to obtain this information.
198 *
199 * @param processId the process id or <code>self</code> for the current
200 * process.
201 */
202 private static long[] getCurrentCpuUtilizationInJiffies(String processId) {
203 try {
204 File file = new File("/proc/" + processId + "/stat");
205 if (file.isDirectory()) {
206 return new long[2];
207 }
208 Iterator<String> stat = WHITESPACE_SPLITTER.split(
209 Files.toString(file, US_ASCII)).iterator();
210 for (int i = 0; i < 13; ++i) {
211 stat.next();
212 }
213 long token13 = Long.parseLong(stat.next());
214 long token14 = Long.parseLong(stat.next());
215 return new long[] { token13, token14 };
216 } catch (NumberFormatException e) {
217 return new long[2];
218 } catch (IOException e) {
219 return new long[2];
220 }
221 }
222
223 /**
224 * A snapshot of the resource usage of the current process at a point in time.
225 */
226 public static class Measurement {
227
228 private final long timeInNanos;
229 private final long heapMemoryUsed;
230 private final long heapMemoryCommitted;
231 private final long nonHeapMemoryUsed;
232 private final long nonHeapMemoryCommitted;
233 private final float loadAverageLastMinute;
234 private final long freePhysicalMemory;
235 private final long totalCpuIdleTimeInJiffies;
236 private final long[] cpuUtilizationInJiffies;
237
238 public Measurement(long heapMemoryUsed, long heapMemoryCommitted, long nonHeapMemoryUsed,
239 long nonHeapMemoryCommitted, float loadAverageLastMinute, long freePhysicalMemory,
240 long totalCpuIdleTimeInJiffies, long[] cpuUtilizationInJiffies) {
241 super();
242 timeInNanos = System.nanoTime();
243 this.heapMemoryUsed = heapMemoryUsed;
244 this.heapMemoryCommitted = heapMemoryCommitted;
245 this.nonHeapMemoryUsed = nonHeapMemoryUsed;
246 this.nonHeapMemoryCommitted = nonHeapMemoryCommitted;
247 this.loadAverageLastMinute = loadAverageLastMinute;
248 this.freePhysicalMemory = freePhysicalMemory;
249 this.totalCpuIdleTimeInJiffies = totalCpuIdleTimeInJiffies;
250 this.cpuUtilizationInJiffies = cpuUtilizationInJiffies;
251 }
252
253 /**
254 * Returns the time of the measurement in jiffies.
255 */
256 public long getTimeInJiffies() {
257 return timeInNanos / 10000000;
258 }
259
260 /**
261 * Returns the time of the measurement in ms.
262 */
263 public long getTimeInMs() {
264 return timeInNanos / 1000000;
265 }
266
267 /**
268 * Returns the amount of used heap memory in bytes at the time of
269 * measurement.
270 *
271 * @see MemoryMXBean#getHeapMemoryUsage()
272 */
273 public long getHeapMemoryUsed() {
274 return heapMemoryUsed;
275 }
276
277 /**
278 * Returns the amount of used non heap memory in bytes at the time of
279 * measurement.
280 *
281 * @see MemoryMXBean#getNonHeapMemoryUsage()
282 */
283 public long getHeapMemoryCommitted() {
284 return heapMemoryCommitted;
285 }
286
287 /**
288 * Returns the amount of memory in bytes that is committed for the Java
289 * virtual machine to use for the heap at the time of measurement.
290 *
291 * @see MemoryMXBean#getHeapMemoryUsage()
292 */
293 public long getNonHeapMemoryUsed() {
294 return nonHeapMemoryUsed;
295 }
296
297 /**
298 * Returns the amount of memory in bytes that is committed for the Java
299 * virtual machine to use for non heap memory at the time of measurement.
300 *
301 * @see MemoryMXBean#getNonHeapMemoryUsage()
302 */
303 public long getNonHeapMemoryCommitted() {
304 return nonHeapMemoryCommitted;
305 }
306
307 /**
308 * Returns the system load average for the last minute at the time of
309 * measurement.
310 *
311 * @see OperatingSystemMXBean#getSystemLoadAverage()
312 */
313 public float getLoadAverageLastMinute() {
314 return loadAverageLastMinute;
315 }
316
317 /**
318 * Returns the free physical memmory in bytes at the time of measurement.
319 */
320 public long getFreePhysicalMemory() {
321 return freePhysicalMemory;
322 }
323
324 /**
325 * Returns the current total cpu idle since system boot in jiffies.
326 */
327 public long getTotalCpuIdleTimeInJiffies() {
328 return totalCpuIdleTimeInJiffies;
329 }
330
331 /**
332 * Returns the current cpu utilization of the current process in jiffies.
333 * The returned array contains the following information: The 1st entry is
334 * the number of jiffies that the process has executed in user mode, and the
335 * 2nd entry is the number of jiffies that the process has executed in
336 * kernel mode. Reads /proc/self/stat to obtain this information.
337 */
338 public long[] getCpuUtilizationInJiffies() {
339 return cpuUtilizationInJiffies;
340 }
341
342 /**
343 * Returns the current cpu utilization of the current process in ms. The
344 * returned array contains the following information: The 1st entry is the
345 * number of ms that the process has executed in user mode, and the 2nd
346 * entry is the number of ms that the process has executed in kernel mode.
347 * Reads /proc/self/stat to obtain this information.
348 */
349 public long[] getCpuUtilizationInMs() {
350 return new long[] {cpuUtilizationInJiffies[0] * 10, cpuUtilizationInJiffies[1] * 10};
351 }
352 }
353}