diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/util/ResourceUsage.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/util/ResourceUsage.java | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/util/ResourceUsage.java b/src/main/java/com/google/devtools/build/lib/util/ResourceUsage.java new file mode 100644 index 0000000000..55807f2395 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/util/ResourceUsage.java @@ -0,0 +1,353 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.devtools.build.lib.util; + +import static java.nio.charset.StandardCharsets.US_ASCII; + +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import com.google.common.io.Files; + +import com.sun.management.OperatingSystemMXBean; + +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.util.Iterator; + +/** + * Provides methods to measure the current resource usage of the current + * process. Also provides some convenience methods to obtain several system + * characteristics, like number of processors , total memory, etc. + */ +public final class ResourceUsage { + + /* + * Use com.sun.management.OperatingSystemMXBean instead of + * java.lang.management.OperatingSystemMXBean because the latter does not + * support getTotalPhysicalMemorySize() and getFreePhysicalMemorySize(). + */ + private static final OperatingSystemMXBean OS_BEAN = + (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + + private static final MemoryMXBean MEM_BEAN = ManagementFactory.getMemoryMXBean(); + private static final Splitter WHITESPACE_SPLITTER = Splitter.on(CharMatcher.WHITESPACE); + + /** + * Calculates an estimate of the current total CPU usage and the CPU usage of + * the process in percent measured from the two given measurements. The + * returned CPU usages rea average values for the time between the two + * measurements. The returned array contains the total CPU usage at index 0 + * and the CPU usage of the measured process at index 1. + */ + public static float[] calculateCurrentCpuUsage(Measurement oldMeasurement, + Measurement newMeasurement) { + if (oldMeasurement == null) { + return new float[2]; + } + long idleJiffies = + newMeasurement.getTotalCpuIdleTimeInJiffies() + - oldMeasurement.getTotalCpuIdleTimeInJiffies(); + long oldProcessJiffies = + oldMeasurement.getCpuUtilizationInJiffies()[0] + + oldMeasurement.getCpuUtilizationInJiffies()[1]; + long newProcessJiffies = + newMeasurement.getCpuUtilizationInJiffies()[0] + + newMeasurement.getCpuUtilizationInJiffies()[1]; + long processJiffies = newProcessJiffies - oldProcessJiffies; + long elapsedTimeJiffies = + newMeasurement.getTimeInJiffies() - oldMeasurement.getTimeInJiffies(); + int processors = getAvailableProcessors(); + // TODO(bazel-team): Sometimes smaller then zero. Not sure why. + double totalUsage = Math.max(0, 1.0D - (double) idleJiffies / elapsedTimeJiffies / processors); + double usage = Math.max(0, (double) processJiffies / elapsedTimeJiffies / processors); + return new float[] {(float) totalUsage * 100, (float) usage * 100}; + } + + private ResourceUsage() { + } + + /** + * Returns the number of processors available to the Java virtual machine. + */ + public static int getAvailableProcessors() { + return OS_BEAN.getAvailableProcessors(); + } + + /** + * Returns the total physical memory in bytes. + */ + public static long getTotalPhysicalMemorySize() { + return OS_BEAN.getTotalPhysicalMemorySize(); + } + + /** + * Returns the operating system architecture. + */ + public static String getOsArchitecture() { + return OS_BEAN.getArch(); + } + + /** + * Returns the operating system name. + */ + public static String getOsName() { + return OS_BEAN.getName(); + } + + /** + * Returns the operating system version. + */ + public static String getOsVersion() { + return OS_BEAN.getVersion(); + } + + /** + * Returns the initial size of heap memory in bytes. + * + * @see MemoryMXBean#getHeapMemoryUsage() + */ + public static long getHeapMemoryInit() { + return MEM_BEAN.getHeapMemoryUsage().getInit(); + } + + /** + * Returns the initial size of non heap memory in bytes. + * + * @see MemoryMXBean#getNonHeapMemoryUsage() + */ + public static long getNonHeapMemoryInit() { + return MEM_BEAN.getNonHeapMemoryUsage().getInit(); + } + + /** + * Returns the maximum size of heap memory in bytes. + * + * @see MemoryMXBean#getHeapMemoryUsage() + */ + public static long getHeapMemoryMax() { + return MEM_BEAN.getHeapMemoryUsage().getMax(); + } + + /** + * Returns the maximum size of non heap memory in bytes. + * + * @see MemoryMXBean#getNonHeapMemoryUsage() + */ + public static long getNonHeapMemoryMax() { + return MEM_BEAN.getNonHeapMemoryUsage().getMax(); + } + + /** + * Returns a measurement of the current resource usage of the current process. + */ + public static Measurement measureCurrentResourceUsage() { + return measureCurrentResourceUsage("self"); + } + + /** + * Returns a measurement of the current resource usage of the process with the + * given process id. + * + * @param processId the process id or <code>self</code> for the current + * process. + */ + public static Measurement measureCurrentResourceUsage(String processId) { + return new Measurement(MEM_BEAN.getHeapMemoryUsage().getUsed(), MEM_BEAN.getHeapMemoryUsage() + .getCommitted(), MEM_BEAN.getNonHeapMemoryUsage().getUsed(), MEM_BEAN + .getNonHeapMemoryUsage().getCommitted(), (float) OS_BEAN.getSystemLoadAverage(), OS_BEAN + .getFreePhysicalMemorySize(), getCurrentTotalIdleTimeInJiffies(), + getCurrentCpuUtilizationInJiffies(processId)); + } + + /** + * Returns the current total idle time of the processors since system boot. + * Reads /proc/stat to obtain this information. + */ + private static long getCurrentTotalIdleTimeInJiffies() { + try { + File file = new File("/proc/stat"); + String content = Files.toString(file, US_ASCII); + String value = Iterables.get(WHITESPACE_SPLITTER.split(content), 5); + return Long.parseLong(value); + } catch (NumberFormatException | IOException e) { + return 0L; + } + } + + /** + * Returns the current cpu utilization of the current process with the given + * id in jiffies. The returned array contains the following information: The + * 1st entry is the number of jiffies that the process has executed in user + * mode, and the 2nd entry is the number of jiffies that the process has + * executed in kernel mode. Reads /proc/self/stat to obtain this information. + * + * @param processId the process id or <code>self</code> for the current + * process. + */ + private static long[] getCurrentCpuUtilizationInJiffies(String processId) { + try { + File file = new File("/proc/" + processId + "/stat"); + if (file.isDirectory()) { + return new long[2]; + } + Iterator<String> stat = WHITESPACE_SPLITTER.split( + Files.toString(file, US_ASCII)).iterator(); + for (int i = 0; i < 13; ++i) { + stat.next(); + } + long token13 = Long.parseLong(stat.next()); + long token14 = Long.parseLong(stat.next()); + return new long[] { token13, token14 }; + } catch (NumberFormatException e) { + return new long[2]; + } catch (IOException e) { + return new long[2]; + } + } + + /** + * A snapshot of the resource usage of the current process at a point in time. + */ + public static class Measurement { + + private final long timeInNanos; + private final long heapMemoryUsed; + private final long heapMemoryCommitted; + private final long nonHeapMemoryUsed; + private final long nonHeapMemoryCommitted; + private final float loadAverageLastMinute; + private final long freePhysicalMemory; + private final long totalCpuIdleTimeInJiffies; + private final long[] cpuUtilizationInJiffies; + + public Measurement(long heapMemoryUsed, long heapMemoryCommitted, long nonHeapMemoryUsed, + long nonHeapMemoryCommitted, float loadAverageLastMinute, long freePhysicalMemory, + long totalCpuIdleTimeInJiffies, long[] cpuUtilizationInJiffies) { + super(); + timeInNanos = System.nanoTime(); + this.heapMemoryUsed = heapMemoryUsed; + this.heapMemoryCommitted = heapMemoryCommitted; + this.nonHeapMemoryUsed = nonHeapMemoryUsed; + this.nonHeapMemoryCommitted = nonHeapMemoryCommitted; + this.loadAverageLastMinute = loadAverageLastMinute; + this.freePhysicalMemory = freePhysicalMemory; + this.totalCpuIdleTimeInJiffies = totalCpuIdleTimeInJiffies; + this.cpuUtilizationInJiffies = cpuUtilizationInJiffies; + } + + /** + * Returns the time of the measurement in jiffies. + */ + public long getTimeInJiffies() { + return timeInNanos / 10000000; + } + + /** + * Returns the time of the measurement in ms. + */ + public long getTimeInMs() { + return timeInNanos / 1000000; + } + + /** + * Returns the amount of used heap memory in bytes at the time of + * measurement. + * + * @see MemoryMXBean#getHeapMemoryUsage() + */ + public long getHeapMemoryUsed() { + return heapMemoryUsed; + } + + /** + * Returns the amount of used non heap memory in bytes at the time of + * measurement. + * + * @see MemoryMXBean#getNonHeapMemoryUsage() + */ + public long getHeapMemoryCommitted() { + return heapMemoryCommitted; + } + + /** + * Returns the amount of memory in bytes that is committed for the Java + * virtual machine to use for the heap at the time of measurement. + * + * @see MemoryMXBean#getHeapMemoryUsage() + */ + public long getNonHeapMemoryUsed() { + return nonHeapMemoryUsed; + } + + /** + * Returns the amount of memory in bytes that is committed for the Java + * virtual machine to use for non heap memory at the time of measurement. + * + * @see MemoryMXBean#getNonHeapMemoryUsage() + */ + public long getNonHeapMemoryCommitted() { + return nonHeapMemoryCommitted; + } + + /** + * Returns the system load average for the last minute at the time of + * measurement. + * + * @see OperatingSystemMXBean#getSystemLoadAverage() + */ + public float getLoadAverageLastMinute() { + return loadAverageLastMinute; + } + + /** + * Returns the free physical memmory in bytes at the time of measurement. + */ + public long getFreePhysicalMemory() { + return freePhysicalMemory; + } + + /** + * Returns the current total cpu idle since system boot in jiffies. + */ + public long getTotalCpuIdleTimeInJiffies() { + return totalCpuIdleTimeInJiffies; + } + + /** + * Returns the current cpu utilization of the current process in jiffies. + * The returned array contains the following information: The 1st entry is + * the number of jiffies that the process has executed in user mode, and the + * 2nd entry is the number of jiffies that the process has executed in + * kernel mode. Reads /proc/self/stat to obtain this information. + */ + public long[] getCpuUtilizationInJiffies() { + return cpuUtilizationInJiffies; + } + + /** + * Returns the current cpu utilization of the current process in ms. The + * returned array contains the following information: The 1st entry is the + * number of ms that the process has executed in user mode, and the 2nd + * entry is the number of ms that the process has executed in kernel mode. + * Reads /proc/self/stat to obtain this information. + */ + public long[] getCpuUtilizationInMs() { + return new long[] {cpuUtilizationInJiffies[0] * 10, cpuUtilizationInJiffies[1] * 10}; + } + } +} |