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