/*******************************************************************************
* Copyright (c) 2016, 2017 Association for Decentralized Information Management
* in Industry THTH ry.
* 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:
* Semantum Oy - initial API and implementation
*******************************************************************************/
package org.simantics.nativemem;
import java.lang.reflect.InvocationTargetException;
import org.simantics.nativemem.internal.Arch;
import org.simantics.nativemem.internal.DummyProcessMemoryInfo;
import org.simantics.nativemem.internal.CMemoryInfo;
import org.simantics.nativemem.internal.OS;
import org.simantics.nativemem.internal.Resource;
import org.simantics.nativemem.internal.Resource32;
import org.simantics.nativemem.internal.Resource64;
import org.simantics.nativemem.internal.linux.Stat;
import org.simantics.nativemem.internal.win.ProcessMemoryCounters;
import org.simantics.nativemem.internal.win.Psapi32;
import org.simantics.nativemem.internal.win.Psapi64;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT.HANDLE;
/**
* @author Tuukka Lehtonen
*/
public class NativeMem {
/**
* @param out
* the structure to write the result into or null
to
* create a new structure
* @return the result structure
*/
public static ProcessMemoryInfo getMemoryInfo(ProcessMemoryInfo out) {
switch (OS.calculate()) {
case WINDOWS:
return getProcessMemoryCounters(out);
case APPLE:
return getCMemoryInfo(out);
case LINUX: {
CMemoryInfo info = getCMemoryInfo(out);
info.peakRSS *= 1024L;
getCurrentRSS(info);
return info;
}
default:
return DummyProcessMemoryInfo.INSTANCE;
}
}
private static ProcessMemoryCounters getProcessMemoryCounters(ProcessMemoryInfo out) {
ProcessMemoryCounters counters = castOrCreate(out, ProcessMemoryCounters.class);
HANDLE proc = Kernel32.INSTANCE.GetCurrentProcess();
switch (Arch.calculate()) {
case X86: {
Psapi32.PROCESS_MEMORY_COUNTERS_EX pmem = new Psapi32.PROCESS_MEMORY_COUNTERS_EX();
boolean ok = Psapi32.INSTANCE.GetProcessMemoryInfo(proc, pmem, pmem.size());
if (ok)
pmem.writeTo(counters);
return counters;
}
case X86_64: {
Psapi64.PROCESS_MEMORY_COUNTERS_EX pmem = new Psapi64.PROCESS_MEMORY_COUNTERS_EX();
boolean ok = Psapi64.INSTANCE.GetProcessMemoryInfo(proc, pmem, pmem.size());
if (ok)
pmem.writeTo(counters);
return counters;
}
default:
return counters;
}
}
private static CMemoryInfo getCMemoryInfo(ProcessMemoryInfo out) {
CMemoryInfo info = castOrCreate(out, CMemoryInfo.class);
switch (Arch.calculate()) {
case X86: {
Resource32.Rusage rusage = new Resource32.Rusage();
int ok = Resource32.INSTANCE.getrusage(Resource.RUSAGE_SELF, rusage);
if (ok == 0)
rusage.writeTo(info);
return info;
}
case X86_64: {
Resource64.Rusage rusage = new Resource64.Rusage();
int ok = Resource64.INSTANCE.getrusage(Resource.RUSAGE_SELF, rusage);
if (ok == 0)
rusage.writeTo(info);
return info;
}
default:
return info;
}
}
private static CMemoryInfo getCurrentRSS(ProcessMemoryInfo out) {
CMemoryInfo info = castOrCreate(out, CMemoryInfo.class);
switch (Arch.calculate()) {
case X86: {
long rss = Stat.getCurrentRSS(Resource32.INSTANCE);
if (rss >= 0)
info.currentRSS = rss;
return info;
}
case X86_64: {
long rss = Stat.getCurrentRSS(Resource64.INSTANCE);
if (rss >= 0)
info.currentRSS = rss;
return info;
}
default:
return info;
}
}
private static T castOrCreate(Object o, Class clazz) {
if (clazz.isInstance(o))
return clazz.cast(o);
try {
return clazz.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
throw new Error("Class " + clazz + " does not have a public parameterless constructor", e);
}
}
}