/*
* Copyright 2016 higherfrequencytrading.com
*
* 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 net.openhft.lang;
import net.openhft.lang.io.NativeBytes;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author peter.lawrey
*/
public enum Jvm {
;
private static final boolean IS64BIT = is64Bit0();
private static final int PROCESS_ID = getProcessId0();
private static final String OS = System.getProperty("os.name").toLowerCase();
public static final int PID_BITS = Maths.intLog2(getPidMax());
public static String TMP = System.getProperty("java.io.tmpdir");
public static boolean is64Bit() {
return IS64BIT;
}
private static boolean is64Bit0() {
String systemProp;
systemProp = System.getProperty("com.ibm.vm.bitmode");
if (systemProp != null) {
return "64".equals(systemProp);
}
systemProp = System.getProperty("sun.arch.data.model");
if (systemProp != null) {
return "64".equals(systemProp);
}
systemProp = System.getProperty("java.vm.version");
return systemProp != null && systemProp.contains("_64");
}
public static int getProcessId() {
return PROCESS_ID;
}
private static int getProcessId0() {
String pid = null;
final File self = new File("/proc/self");
try {
if (self.exists()) {
pid = self.getCanonicalFile().getName();
}
} catch (IOException ignored) {
}
if (pid == null) {
pid = ManagementFactory.getRuntimeMXBean().getName().split("@", 0)[0];
}
if (pid == null) {
int rpid = new Random().nextInt(1 << 16);
LoggerHolder.LOGGER.log(Level.WARNING, "Unable to determine PID, picked a random number=" + rpid);
return rpid;
} else {
return Integer.parseInt(pid);
}
}
/**
* This may or may not be the OS thread id, but should be unique across processes
*
* @return a unique tid of up to 48 bits.
*/
public static long getUniqueTid() {
return getUniqueTid(Thread.currentThread());
}
public static long getUniqueTid(Thread thread) {
// Assume 48 bit for 16 to 24-bit process id and 16 million threads from the start.
return ((long) getProcessId() << 24) | thread.getId();
}
public static boolean isWindows() {
return OS.startsWith("win");
}
public static boolean isWindows10() {
return OS.startsWith("win") && OS.endsWith("10");
}
public static boolean isMacOSX() {
return OS.contains("mac");
}
public static boolean isLinux() {
return OS.startsWith("linux");
}
public static boolean isUnix() {
return OS.contains("nix") ||
OS.contains("nux") ||
OS.contains("aix") ||
OS.contains("bsd") ||
OS.contains("sun") ||
OS.contains("hpux");
}
public static boolean isSolaris() {
return OS.startsWith("sun");
}
public static long getPidMax() {
if (isLinux()) {
File file = new File("/proc/sys/kernel/pid_max");
if (file.canRead()) {
Scanner scanner = null;
try{
scanner = new Scanner(file);
return Maths.nextPower2(scanner.nextLong(), 1 << 16);
} catch (FileNotFoundException e) {
LoggerHolder.LOGGER.log(Level.WARNING, "", e);
}finally {
if(scanner != null)
scanner.close();
}
}
} else if (isMacOSX()) {
return 1L << 24;
}
// the default.
return isWindows10() ? 1L << 24 : 1L << 16;
}
private static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
public static long freePhysicalMemoryOnWindowsInBytes() throws IOException {
if (!isWindows()) {
throw new IllegalStateException("Method freePhysicalMemoryOnWindowsInBytes() should " +
"be called only on windows. Use Jvm.isWindows() to check the OS.");
}
Process pr = Runtime.getRuntime().exec("wmic OS get FreePhysicalMemory /Value");
try {
int result = pr.waitFor();
String output = convertStreamToString(pr.getInputStream());
if (result != 0) {
String errorOutput = convertStreamToString(pr.getErrorStream());
throw new IOException("Couldn't get free physical memory on windows. " +
"Command \"wmic OS get FreePhysicalMemory /Value\" exited with " +
result + " code, output: \"" + output + "\", error output: \"" +
errorOutput + "\"");
}
String[] parts = output.trim().split("=");
if (parts.length != 2) {
throw new IOException("Couldn't get free physical memory on windows. " +
"Command \"wmic OS get FreePhysicalMemory /Value\" output has unexpected " +
"format: \"" + output + "\"");
}
try {
return MemoryUnit.KILOBYTES.toBytes(Long.parseLong(parts[1]));
} catch (NumberFormatException e) {
throw new IOException("Couldn't get free physical memory on windows. " +
"Command \"wmic OS get FreePhysicalMemory /Value\" output has unexpected " +
"format: \"" + output + "\"", e);
}
} catch (InterruptedException e) {
throw new IOException(e);
}
}
public static void checkInterrupted() {
if (Thread.currentThread().isInterrupted()) throw new InterruptedRuntimeException();
}
/**
* Utility method to support throwing checked exceptions out of the streams API
*
* @param t the exception to rethrow
* @return the exception
*/
public static RuntimeException rethrow(Throwable t) {
NativeBytes.UNSAFE.throwException(t);
throw new AssertionError();
}
public static void trimStackTrace(StringBuilder sb, StackTraceElement... stes) {
int first = trimFirst(stes);
int last = trimLast(first, stes);
for (int i = first; i <= last; i++)
sb.append("\n\tat ").append(stes[i]);
}
private static int trimFirst(StackTraceElement[] stes) {
int first = 0;
for (; first < stes.length; first++)
if (!isInternal(stes[first].getClassName()))
break;
if (first > 0) first--;
if (first > 0) first--;
return first;
}
private static int trimLast(int first, StackTraceElement[] stes) {
int last = stes.length - 1;
for (; first < last; last--)
if (!isInternal(stes[last].getClassName()))
break;
if (last < stes.length - 1) last++;
return last;
}
public static boolean isInternal(String className) {
return className.startsWith("jdk.") || className.startsWith("sun.") || className.startsWith("java.");
}
static class LoggerHolder {
public static final Logger LOGGER = Logger.getLogger(Jvm.class.getName());
}
}