/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.system.profile; import icy.system.SystemUtil; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.lang.management.ThreadMXBean; import java.util.HashMap; import java.util.Map; /** * CPU monitor class.<br> * Use for profiling. * * @author Nicolas HERVE */ public class CPUMonitor { private class CPUTime { private long startTime; private long stopTime; private long startUserTime; private long startCPUTime; private long stopUserTime; private long stopCPUTime; public CPUTime() { super(); startUserTime = 0; startCPUTime = 0; stopUserTime = 0; stopCPUTime = 0; startTime = 0; stopTime = 0; } public void setStartTime(long startTime) { this.startTime = startTime; setStopTime(startTime); } public void setStopTime(long stopTime) { this.stopTime = stopTime; } public long getStartUserTime() { return startUserTime; } public void setStartUserTime(long startUserTime) { this.startUserTime = startUserTime; setStopUserTime(startUserTime); } public void setStartCPUTime(long startCPUTime) { this.startCPUTime = startCPUTime; setStopCPUTime(startCPUTime); } public long getStopUserTime() { return stopUserTime; } public void setStopUserTime(long stopUserTime) { this.stopUserTime = stopUserTime; } public void setStopCPUTime(long stopCPUTime) { this.stopCPUTime = stopCPUTime; } public long getCPUElapsedTimeNano() { return stopCPUTime - startCPUTime; } public long getUserElapsedTimeNano() { return stopUserTime - startUserTime; } public long getElapsedTimeMilli() { return stopTime - startTime; } } public final static int MONITOR_CURRENT_THREAD = 0; public final static int MONITOR_ALL_THREAD_ROUGHLY = 1; public final static int MONITOR_ALL_THREAD_FINELY = 2; private static final double NANO_TO_MILLI = 1d / 1000000d; private static final double MILLI_TO_SEC = 1d / 1000d; private static final double NANO_TO_SEC = NANO_TO_MILLI * MILLI_TO_SEC; private CPUTime time; private Map<Long, CPUTime> threadTimes; private ThreadMXBean bean; private OperatingSystemMXBean osBean; private int monitorType; public CPUMonitor() { this(MONITOR_CURRENT_THREAD); } public CPUMonitor(int type) { super(); this.monitorType = type; time = new CPUTime(); bean = ManagementFactory.getThreadMXBean(); osBean = ManagementFactory.getOperatingSystemMXBean(); } public void start() throws IllegalAccessError { if (!bean.isCurrentThreadCpuTimeSupported()) { throw new IllegalAccessError("This JVM does not support time benchmarking"); } switch (monitorType) { case MONITOR_CURRENT_THREAD: time.setStartUserTime(bean.getCurrentThreadUserTime()); time.setStartCPUTime(bean.getCurrentThreadCpuTime()); break; case MONITOR_ALL_THREAD_ROUGHLY: if (!(osBean instanceof com.sun.management.OperatingSystemMXBean)) { throw new IllegalAccessError( "This JVM does not support this version of multiple threads time benchmarking"); } time.setStartUserTime(((com.sun.management.OperatingSystemMXBean) osBean).getProcessCpuTime()); time.setStartCPUTime(time.getStartUserTime()); break; case MONITOR_ALL_THREAD_FINELY: threadTimes = new HashMap<Long, CPUTime>(); time.setStartUserTime(0); time.setStartCPUTime(0); long[] tids = bean.getAllThreadIds(); for (long id : tids) { CPUTime cput = new CPUTime(); cput.setStartCPUTime(bean.getThreadCpuTime(id)); cput.setStartUserTime(bean.getThreadUserTime(id)); threadTimes.put(id, cput); } break; } time.setStartTime(System.currentTimeMillis()); } public void stop() { switch (monitorType) { case MONITOR_CURRENT_THREAD: time.setStopUserTime(bean.getCurrentThreadUserTime()); time.setStopCPUTime(bean.getCurrentThreadCpuTime()); break; case MONITOR_ALL_THREAD_ROUGHLY: time.setStopUserTime(((com.sun.management.OperatingSystemMXBean) osBean).getProcessCpuTime()); time.setStopCPUTime(time.getStopUserTime()); break; case MONITOR_ALL_THREAD_FINELY: // Ignores threads that died during the monitoring long[] tids = bean.getAllThreadIds(); long c = 0; long u = 0; for (long id : tids) { CPUTime cput = threadTimes.get(id); if (cput == null) { cput = new CPUTime(); } cput.setStopCPUTime(bean.getThreadCpuTime(id)); cput.setStopUserTime(bean.getThreadUserTime(id)); c += cput.getCPUElapsedTimeNano(); u += cput.getUserElapsedTimeNano(); } time.setStopCPUTime(c); time.setStopUserTime(u); break; } time.setStopTime(System.currentTimeMillis()); } private long nanoToMilli(long nano) { return Math.round(nano * NANO_TO_MILLI); } private double nanoToSec(long nano) { return nano * NANO_TO_SEC; } private double milliToSec(long milli) { return milli * MILLI_TO_SEC; } public long getCPUElapsedTimeMilli() { return nanoToMilli(time.getCPUElapsedTimeNano()); } public long getUserElapsedTimeMilli() { return nanoToMilli(time.getUserElapsedTimeNano()); } public double getCPUElapsedTimeSec() { return nanoToSec(time.getCPUElapsedTimeNano()); } public double getUserElapsedTimeSec() { return nanoToSec(time.getUserElapsedTimeNano()); } public double getElapsedTimeSec() { return milliToSec(time.getElapsedTimeMilli()); } public int getThreadCount() { return bean.getThreadCount(); } /** * Uses SystemUtil.getAvailableProcessors() instead. * * @deprecated */ @Deprecated public static int getAvailableProcessors() { return SystemUtil.getNumberOfCPUs(); } public long getElapsedTimeMilli() { return time.getElapsedTimeMilli(); } }