package org.gridkit.jvmtool.win32;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Properties;
public class SjkWinHelper {
static {
try {
loadNative();
} catch (IOException e) {
throw new RuntimeException(e);
}
// System.load("C:/WarZone/spaces/_rust_jni/rust-jni-test/target/release/hello.dll");
// System.load("C:/WarZone/spaces/_rust_jni/rust-jni-test/src/lib.dll");
// System.load("C:/WarZone/spaces/_rust_jni/rust-jni-test/src/sjkwinh.dll");
}
private static void loadNative() throws IOException {
File tmp = File.createTempFile("java", "").getAbsoluteFile().getParentFile();
if (tmp.getPath().startsWith("/")) {
// this is not a windows
throw new RuntimeException("Cannot load on non Windows OS");
}
if ("x86".equals(ManagementFactory.getOperatingSystemMXBean().getArch())) {
load(tmp, "32");
}
else {
load(tmp, "64");
}
}
private static void load(File tmp, String arch) throws IOException {
InputStream is = SjkWinHelper.class.getClassLoader().getResourceAsStream("sjkwinh.prop");
Properties prop = new Properties();
prop.load(is);
String dllName = "sjkwinh" + arch + "." + prop.getProperty("dll" + arch + ".hash") + ".dll";
int len = Integer.valueOf(prop.getProperty("dll" + arch + ".len"));
File tgt = new File(tmp, dllName);
if (tgt.isFile() && tgt.length() == len) {
// dll is present
}
else {
tgt.delete();
InputStream dllis = SjkWinHelper.class.getClassLoader().getResourceAsStream("sjkwinh" + arch + ".dll");
byte[] buf = new byte[len];
int n = dllis.read(buf);
if (n != buf.length) {
throw new RuntimeException("Failed extract dll, size mismatch");
}
FileOutputStream fos = new FileOutputStream(tgt);
fos.write(buf);
fos.close();
}
System.load(tgt.getPath());
}
private native int GetProcessTimes(int pid, int[] buf);
private native int GetThreadTimes(int pid, int[] buf);
private native long QueryProcessCycleTime(int pid);
private native long QueryThreadCycleTime(int pid);
private native int EnumThreads(int pid, int[] buf);
int[] callBuf = new int[8];
/**
* Call kernel32::GetProcessTimes.
* If successful kernel and user times are set to
* first two slots in array.
* <p>
* Time units are microseconds.
*
* @param pid
* @return <code>false</code> is not successful
*/
public synchronized boolean getProcessCpuTimes(int pid, long[] result) {
int rc = GetProcessTimes(pid, callBuf);
if (rc == 0) {
long ktime = (0xFFFFFFFFl & callBuf[4]) | ((long)callBuf[5]) << 32;
long utime = (0xFFFFFFFFl & callBuf[6]) | ((long)callBuf[7]) << 32;
result[0] = ktime / 10;
result[1] = utime / 10;
return true;
}
else {
System.out.println("Error code: " + rc);
return false;
}
}
/**
* Call kernel32::GetThreadTimes.
* If successful kernel and user times are set to
* first two slots in array.
* <p>
* Time units are microseconds.
*
* @param pid
* @return <code>false</code> is not successful
*/
public synchronized boolean getThreadCpuTimes(int pid, long[] result) {
int rc = GetThreadTimes(pid, callBuf);
if (rc == 0) {
long ktime = (0xFFFFFFFFl & callBuf[4]) | ((long)callBuf[5]) << 32;
long utime = (0xFFFFFFFFl & callBuf[6]) | ((long)callBuf[7]) << 32;
result[0] = ktime / 10;
result[1] = utime / 10;
return true;
}
else {
System.out.println("Error code: " + rc);
return false;
}
}
public synchronized long getProcessCpuCycles(int pid) {
return QueryProcessCycleTime(pid);
}
public synchronized long getThreadCpuCycles(int pid) {
return QueryThreadCycleTime(pid);
}
public synchronized int[] enumThreads(int pid) {
int[] buf = new int[128];
int n = EnumThreads(pid, buf);
if (n < 0) {
throw new RuntimeException("Cannot enum threads. WinError: " + (-n));
}
while (n > buf.length) {
buf = new int[n + 16];
n = EnumThreads(pid, buf);
if (n < 0) {
throw new RuntimeException("Cannot enum threads. WinError: " + (-n));
}
}
return buf.length == n ? buf : Arrays.copyOf(buf, n);
}
}