/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.tools;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Helper class to get system information.
*
* @author Nils Woehler
*/
public final class SystemInfoUtilities {
private static final int TENTH_POWER_OF_TWO = 1024;
private static final Logger LOGGER = Logger.getLogger(SystemInfoUtilities.class.getSimpleName());
/**
* Available JVM architectures.
*/
public enum JVMArch {
/**
* 32 bit
*/
THIRTY_TWO,
/**
* 64 bit
*/
SIXTY_FOUR,
}
/**
* Possible operating systems.
*/
public enum OperatingSystem {
/**
* Windows
*/
WINDOWS,
/**
* Apple OSX
*/
OSX,
/**
* Any Unix derivat
*/
UNIX,
/**
* Any Solaris derivat
*/
SOLARIS,
/**
* Unknown other operating system.
*/
OTHER,
}
/**
* Utility class constructor.
*/
private SystemInfoUtilities() {
throw new AssertionError();
}
private static OperatingSystemMXBean getOperatingSystemBean() {
return ManagementFactory.getOperatingSystemMXBean();
}
/**
* @return the current max heap memory size in MB
*/
public static long getMaxHeapMemorySize() {
long maxMem = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax();
maxMem /= TENTH_POWER_OF_TWO;
maxMem /= TENTH_POWER_OF_TWO;
return maxMem;
}
/**
* @return the number of processors
*/
public static int getNumberOfProcessors() {
return getOperatingSystemBean().getAvailableProcessors();
}
public static Integer getJavaVersion() {
return Integer.parseInt(System.getProperty("java.version").substring(0, 3).replace(".", ""));
}
/**
* @return the current {@link JVMArch}
*/
public static JVMArch getJVMArchitecture() {
if (getOperatingSystemBean().getArch().contains("64")) {
return JVMArch.SIXTY_FOUR;
} else {
return JVMArch.THIRTY_TWO;
}
}
/**
* Returns total physical memory in MB. If it is run in a 32-bit JVM it may return only a
* maximum of 4GB even if more memory is available.
*
* @return the amount of physical memory in MB
* @throws IOException
* if something goes wrong
*/
public static Long getTotalPhysicalMemorySize() throws IOException {
OperatingSystemMXBean operatingSystemBean = getOperatingSystemBean();
long memory = 0L;
// if the system bean is an implementation by sun, we are almost done
try {
memory = ((com.sun.management.OperatingSystemMXBean) operatingSystemBean).getTotalPhysicalMemorySize();
} catch (Throwable t) { // NOPMD
// // fallback because sun implementation is not available
switch (getOperatingSystem()) {
case OSX:
memory = readOSXTotalMemory();
break;
case WINDOWS:
memory = readWindowsTotalMemory();
break;
case UNIX:
memory = readUnixTotalMemory();
break;
case SOLARIS:
memory = readSolarisTotalMemory();
break;
case OTHER:
default:
memory = readOtherTotalMemory();
break;
}
}
memory /= TENTH_POWER_OF_TWO; // kbyte
memory /= TENTH_POWER_OF_TWO; // mbyte
return memory;
}
/**
* Returns free physical memory in MB. If it is run in a 32-bit JVM it may return only a maximum
* of 2GB even if more memory is available.
* <p>
* <strong>Attention:</strong> The returned value is dependant on the OS. For example on Linux
* you might see less memory than there is actually available due to the OS using it for disk
* caching. That memory is not actually blocked because the OS would release it if requested,
* however this method will return the free memory which does NOT contain the ram used for disk
* caching. Use with care!
* </p>
*
* @return the free phsycial memory in MB or <code>-1</code> if we cannot determine it
* @since 6.0.004
*
*/
public static Long getFreePhysicalMemorySize() {
OperatingSystemMXBean operatingSystemBean = getOperatingSystemBean();
long memory = 0L;
// if the system bean is an implementation by sun, we are almost done
try {
memory = ((com.sun.management.OperatingSystemMXBean) operatingSystemBean).getFreePhysicalMemorySize();
} catch (Throwable t) { // NOPMD
// fallback due to sun implementation not being available
// in this case we behave as before 6.0.004 where we did not take free memory into
// account
return -1L;
}
memory /= TENTH_POWER_OF_TWO; // kbyte
memory /= TENTH_POWER_OF_TWO; // mbyte
return memory;
}
private static String executeMemoryInfoProcess(String... command) throws IOException {
ProcessBuilder procBuilder = new ProcessBuilder(command);
Process process = procBuilder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isr);
try {
String line;
while ((line = br.readLine()) != null) {
if (line.trim().isEmpty()) {
continue;
} else {
return line;
}
}
} catch (IOException e1) { // NOPMD
throw e1;
} finally {
br.close();
}
throw new IOException("Could not read memory process output for command " + Arrays.toString(command));
}
/**
* @return total memory in bytes
*/
private static Long readWindowsTotalMemory() throws IOException {
String[] command = "wmic OS get TotalVisibleMemorySize /Value".split(" ");
// Output should be something like 'TotalVisibleMemorySize=8225260'
String line = executeMemoryInfoProcess(command);
// convert it to bytes
return Long.parseLong(line.substring(line.indexOf('=') + 1)) * TENTH_POWER_OF_TWO;
}
/**
* @return total memory in bytes
*/
private static Long readOSXTotalMemory() throws IOException {
String[] command = "sysctl -a | grep hw.memsize".split(" ");
String line = executeMemoryInfoProcess(command);
return Long.parseLong(line.substring(line.indexOf(':') + 2));
}
/**
* @return total memory in bytes
*/
private static Long readSolarisTotalMemory() throws IOException {
String[] command = "prtconf | grep Memory".split(" ");
// output should be something like 'Memorysize: 8192 Megabytes'
String line = executeMemoryInfoProcess(command);
line = line.substring(line.indexOf(':') + 2); // shorten output to '8192 Megabytes'
line = line.substring(0, line.indexOf(' ')); // shorten to just '8192'
return Long.parseLong(line) * TENTH_POWER_OF_TWO * TENTH_POWER_OF_TWO;
}
/**
* @return total memory in bytes
*/
private static Long readUnixTotalMemory() throws IOException {
String[] command = "grep MemTotal /proc/meminfo".split(" ");
// should output something like 'MemTotal: 12297204 kB'
String line = executeMemoryInfoProcess(command);
line = line.substring(line.indexOf(':') + 1).trim(); // shorten to '12297204 kB'
line = line.substring(0, line.indexOf(' ')); // shorten to just '12297204'
return Long.parseLong(line) * TENTH_POWER_OF_TWO;
}
/**
* @return total memory in bytes
*/
private static Long readOtherTotalMemory() throws IOException {
throw new IOException("Not yet implemented"); // TODO implement
}
public static String getOperatingSystemName() {
return getOperatingSystemBean().getName();
}
public static String getOperatingSystemVersion() {
return getOperatingSystemBean().getVersion();
}
/**
* @return the current operating system
*/
public static OperatingSystem getOperatingSystem() {
String systemName = getOperatingSystemName().toLowerCase();
if (isWindows(systemName)) {
return OperatingSystem.WINDOWS;
} else if (isMac(systemName)) {
return OperatingSystem.OSX;
} else if (isUnix(systemName)) {
return OperatingSystem.UNIX;
} else if (isSolaris(systemName)) {
return OperatingSystem.SOLARIS;
} else {
return OperatingSystem.OTHER;
}
}
private static boolean isWindows(String osName) {
return osName.indexOf("win") >= 0;
}
private static boolean isMac(String osName) {
return osName.indexOf("mac") >= 0;
}
private static boolean isUnix(String osName) {
return osName.indexOf("nix") >= 0 || osName.indexOf("nux") >= 0 || osName.indexOf("aix") > 0;
}
private static boolean isSolaris(String osName) {
return osName.indexOf("sunos") >= 0;
}
/**
* Uses the logger to write current environment infos to the log (with {@link Level#INFO}).
*/
public static void logEnvironmentInfos() {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Operating system: " + getOperatingSystemName() + ", Version: "
+ getOperatingSystemVersion());
LOGGER.log(Level.INFO, "Number of logical processors: " + getNumberOfProcessors());
LOGGER.log(Level.INFO, "Java version: " + getJavaVersion());
LOGGER.log(Level.INFO, "JVM Architecture: " + getJVMArchitecture());
}
try {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Maxmimum physical memory available for JVM: " + getTotalPhysicalMemorySize() + "mb");
}
} catch (IOException e) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, "Could not detect total physical memory.");
}
}
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Free physical memory available for JVM: " + getFreePhysicalMemorySize() + "mb");
}
}
/**
* @param args
* the arguments
*/
public static void main(String[] args) {
logEnvironmentInfos();
}
}