+/*******************************************************************************
+ * 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.Psapi32;
-import org.simantics.nativemem.internal.Psapi64;
+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 {
/**
* create a new structure
* @return the result structure
*/
- public static ProcessMemoryCounters getMemoryCounters(ProcessMemoryCounters out) {
- if (out == null)
- out = new ProcessMemoryCounters();
-
- OS os = OS.calculate();
- Arch arch = Arch.calculate();
- switch (os) {
- case WINDOWS: {
- HANDLE proc = Kernel32.INSTANCE.GetCurrentProcess();
- switch (arch) {
- 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(out);
- return out;
- }
-
- 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(out);
- return out;
- }
-
- default:
- throw new UnsupportedOperationException("Architecture " + arch + " not supported on operating system " + os);
- }
+ 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:
- throw new UnsupportedOperationException("Operating system " + os + " not supported");
+ 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> T castOrCreate(Object o, Class<T> 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);
}
}