/******************************************************************************* * 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; 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); } } }