/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.core.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.file.FileSystems; import java.nio.file.Files; /** * Provides information about operating system. * * @author <a href="mailto:aparfonov@codenvy.com">Andrey Parfonov</a> */ public class SystemInfo { private static final Logger LOG = LoggerFactory.getLogger(SystemInfo.class); public static final String OS = System.getProperty("os.name").toLowerCase(); private static final boolean linux = OS.startsWith("linux"); private static final boolean mac = OS.startsWith("mac"); private static final boolean windows = OS.startsWith("windows"); private static final boolean unix = !windows; public static boolean isLinux() { return linux; } public static boolean isWindows() { return windows; } public static boolean isMacOS() { return mac; } public static boolean isUnix() { return unix; } private static interface SystemResources { /** Get CPU load in percents (1-100). Return -1 when fails getting CPU load. */ int cpu(); /** Get free physical memory in bytes. Return -1 when fails getting amount of free memory. */ long freeMemory(); /** Get total physical memory in bytes. Return -1 when fails getting amount of total memory. */ long totalMemory(); } /* http://docs.oracle.com/javase/7/docs/jre/api/management/extension/com/sun/management/OperatingSystemMXBean.html */ private static final OperatingSystemMXBean OPERATING_SYSTEM_MX_BEAN = ManagementFactory.getOperatingSystemMXBean(); private static final Method CPU_USAGE; private static final Method TOTAL_MEMORY; private static final Method FREE_MEMORY; static { final Class<? extends OperatingSystemMXBean> clazz = OPERATING_SYSTEM_MX_BEAN.getClass(); CPU_USAGE = getMethodSafety(clazz, "getSystemCpuLoad"); FREE_MEMORY = getMethodSafety(clazz, "getFreePhysicalMemorySize"); TOTAL_MEMORY = getMethodSafety(clazz, "getTotalPhysicalMemorySize"); } private static Method getMethodSafety(Class<?> clazz, String name) { try { final Method m = clazz.getMethod(name); m.setAccessible(true); return m; } catch (NoSuchMethodException e) { return null; } } private static final SystemResources JDK_SYSTEM_RESOURCES = new SystemResources() { @Override public int cpu() { if (CPU_USAGE != null) { try { return (int)((Double)CPU_USAGE.invoke(OPERATING_SYSTEM_MX_BEAN) * 100); } catch (IllegalAccessException | InvocationTargetException e) { LOG.error(e.getMessage(), e); } } return -1; } @Override public long freeMemory() { if (FREE_MEMORY != null) { try { return (Long)FREE_MEMORY.invoke(OPERATING_SYSTEM_MX_BEAN); } catch (IllegalAccessException | InvocationTargetException e) { LOG.error(e.getMessage(), e); } } return -1L; } @Override public long totalMemory() { if (TOTAL_MEMORY != null) { try { return (Long)TOTAL_MEMORY.invoke(OPERATING_SYSTEM_MX_BEAN); } catch (IllegalAccessException | InvocationTargetException e) { LOG.error(e.getMessage(), e); } } return -1L; } }; /* Not sure about all unix and don't really need to care about it at this time */ private static final SystemResources LINUX_SYSTEM_RESOURCES = new SystemResources() { /* See 'man proc', section about '/proc/stat'. Values in array: [0] - user time [1] - nice time [2] - system time [3] - idle time For now do not count CPU usage for each available core. */ private int[] cpuTimes = {0, 0, 0, 0}; @Override public synchronized int cpu() { int[] newCpuTimes; try { newCpuTimes = readCpuTimes(); } catch (IOException e) { LOG.error(e.getMessage(), e); return -1; } int usage = 0; for (int i = 0; i < 3; i++) { usage += newCpuTimes[i] - cpuTimes[i]; } int idle = newCpuTimes[3] - cpuTimes[3]; int total = usage + idle; int percent = 0; if (total != 0) { percent = (100 * usage) / total; } cpuTimes = newCpuTimes; return percent; } private int[] readCpuTimes() throws IOException { final int[] times = new int[4]; final String line; try (BufferedReader reader = Files.newBufferedReader(FileSystems.getDefault().getPath("/proc/stat"), Charset.forName("UTF-8"))) { line = reader.readLine(); // need first line only } if (line.startsWith("cpu")) { // just to be sure we have correct line final String[] strings = line.split("\\s+"); for (int i = 1; i < 5; i++) { times[i - 1] = Integer.parseInt(strings[i]); } } return times; } @Override public long freeMemory() { try { return readMem("MemFree"); } catch (IOException e) { LOG.error(e.getMessage(), e); } return -1L; } @Override public long totalMemory() { try { return readMem("MemTotal"); } catch (IOException e) { LOG.error(e.getMessage(), e); } return -1L; } /* See 'man proc', section about '/proc/meminfo' */ private long readMem(String kindOf) throws IOException { String line; try (BufferedReader reader = Files.newBufferedReader(FileSystems.getDefault().getPath("/proc/meminfo"), Charset.forName("UTF-8"))) { line = reader.readLine(); while (line != null && !line.startsWith(kindOf)) { line = reader.readLine(); } } if (line != null) { final String[] strings = line.split("\\s+"); long mem = Long.parseLong(strings[1]); // never saw something different than 'kB', but man page says: "unit of measurement (e.g., "kB")" if (strings.length > 2) { final String unit = strings[2].toLowerCase(); if (unit.equals("kb")) { mem *= 1024; } // enough for the moment } return mem; } return -1; } }; /** Get CPU load in percents (1-100). Return -1 when fails getting CPU load. */ public static int cpu() { int cpuUsage = JDK_SYSTEM_RESOURCES.cpu(); if (cpuUsage < 0 && isLinux()) { cpuUsage = LINUX_SYSTEM_RESOURCES.cpu(); } return cpuUsage; } /** Get free physical memory in bytes. Return -1 when fails getting amount of free memory. */ public static long freeMemory() { long free = JDK_SYSTEM_RESOURCES.freeMemory(); if (free < 0 && isLinux()) { free = LINUX_SYSTEM_RESOURCES.freeMemory(); } return free; } /** Get total physical memory in bytes. Return -1 when fails getting amount of total memory. */ public static long totalMemory() { long total = JDK_SYSTEM_RESOURCES.totalMemory(); if (total < 0 && isLinux()) { total = LINUX_SYSTEM_RESOURCES.totalMemory(); } return total; } private SystemInfo() { } }