001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.system.profile; 020 021import icy.system.SystemUtil; 022 023import java.lang.management.ManagementFactory; 024import java.lang.management.OperatingSystemMXBean; 025import java.lang.management.ThreadMXBean; 026import java.util.HashMap; 027import java.util.Map; 028 029/** 030 * CPU monitor class.<br> 031 * Use for profiling. 032 * 033 * @author Nicolas HERVE 034 */ 035public class CPUMonitor 036{ 037 private class CPUTime 038 { 039 private long startTime; 040 private long stopTime; 041 private long startUserTime; 042 private long startCPUTime; 043 private long stopUserTime; 044 private long stopCPUTime; 045 046 public CPUTime() 047 { 048 super(); 049 050 startUserTime = 0; 051 startCPUTime = 0; 052 stopUserTime = 0; 053 stopCPUTime = 0; 054 startTime = 0; 055 stopTime = 0; 056 } 057 058 public void setStartTime(long startTime) 059 { 060 this.startTime = startTime; 061 setStopTime(startTime); 062 } 063 064 public void setStopTime(long stopTime) 065 { 066 this.stopTime = stopTime; 067 } 068 069 public long getStartUserTime() 070 { 071 return startUserTime; 072 } 073 074 public void setStartUserTime(long startUserTime) 075 { 076 this.startUserTime = startUserTime; 077 setStopUserTime(startUserTime); 078 } 079 080 public void setStartCPUTime(long startCPUTime) 081 { 082 this.startCPUTime = startCPUTime; 083 setStopCPUTime(startCPUTime); 084 } 085 086 public long getStopUserTime() 087 { 088 return stopUserTime; 089 } 090 091 public void setStopUserTime(long stopUserTime) 092 { 093 this.stopUserTime = stopUserTime; 094 } 095 096 public void setStopCPUTime(long stopCPUTime) 097 { 098 this.stopCPUTime = stopCPUTime; 099 } 100 101 public long getCPUElapsedTimeNano() 102 { 103 return stopCPUTime - startCPUTime; 104 } 105 106 public long getUserElapsedTimeNano() 107 { 108 return stopUserTime - startUserTime; 109 } 110 111 public long getElapsedTimeMilli() 112 { 113 return stopTime - startTime; 114 } 115 } 116 117 public final static int MONITOR_CURRENT_THREAD = 0; 118 public final static int MONITOR_ALL_THREAD_ROUGHLY = 1; 119 public final static int MONITOR_ALL_THREAD_FINELY = 2; 120 121 private static final double NANO_TO_MILLI = 1d / 1000000d; 122 private static final double MILLI_TO_SEC = 1d / 1000d; 123 private static final double NANO_TO_SEC = NANO_TO_MILLI * MILLI_TO_SEC; 124 125 private CPUTime time; 126 private Map<Long, CPUTime> threadTimes; 127 128 private ThreadMXBean bean; 129 private OperatingSystemMXBean osBean; 130 131 private int monitorType; 132 133 public CPUMonitor() 134 { 135 this(MONITOR_CURRENT_THREAD); 136 } 137 138 public CPUMonitor(int type) 139 { 140 super(); 141 142 this.monitorType = type; 143 144 time = new CPUTime(); 145 146 bean = ManagementFactory.getThreadMXBean(); 147 osBean = ManagementFactory.getOperatingSystemMXBean(); 148 } 149 150 public void start() throws IllegalAccessError 151 { 152 if (!bean.isCurrentThreadCpuTimeSupported()) 153 { 154 throw new IllegalAccessError("This JVM does not support time benchmarking"); 155 } 156 157 switch (monitorType) 158 { 159 case MONITOR_CURRENT_THREAD: 160 time.setStartUserTime(bean.getCurrentThreadUserTime()); 161 time.setStartCPUTime(bean.getCurrentThreadCpuTime()); 162 break; 163 case MONITOR_ALL_THREAD_ROUGHLY: 164 if (!(osBean instanceof com.sun.management.OperatingSystemMXBean)) 165 { 166 throw new IllegalAccessError( 167 "This JVM does not support this version of multiple threads time benchmarking"); 168 } 169 170 time.setStartUserTime(((com.sun.management.OperatingSystemMXBean) osBean).getProcessCpuTime()); 171 time.setStartCPUTime(time.getStartUserTime()); 172 break; 173 case MONITOR_ALL_THREAD_FINELY: 174 threadTimes = new HashMap<Long, CPUTime>(); 175 time.setStartUserTime(0); 176 time.setStartCPUTime(0); 177 long[] tids = bean.getAllThreadIds(); 178 for (long id : tids) 179 { 180 CPUTime cput = new CPUTime(); 181 cput.setStartCPUTime(bean.getThreadCpuTime(id)); 182 cput.setStartUserTime(bean.getThreadUserTime(id)); 183 threadTimes.put(id, cput); 184 } 185 186 break; 187 } 188 189 time.setStartTime(System.currentTimeMillis()); 190 } 191 192 public void stop() 193 { 194 switch (monitorType) 195 { 196 case MONITOR_CURRENT_THREAD: 197 time.setStopUserTime(bean.getCurrentThreadUserTime()); 198 time.setStopCPUTime(bean.getCurrentThreadCpuTime()); 199 break; 200 case MONITOR_ALL_THREAD_ROUGHLY: 201 time.setStopUserTime(((com.sun.management.OperatingSystemMXBean) osBean).getProcessCpuTime()); 202 time.setStopCPUTime(time.getStopUserTime()); 203 break; 204 case MONITOR_ALL_THREAD_FINELY: 205 // Ignores threads that died during the monitoring 206 long[] tids = bean.getAllThreadIds(); 207 long c = 0; 208 long u = 0; 209 for (long id : tids) 210 { 211 CPUTime cput = threadTimes.get(id); 212 if (cput == null) 213 { 214 cput = new CPUTime(); 215 } 216 cput.setStopCPUTime(bean.getThreadCpuTime(id)); 217 cput.setStopUserTime(bean.getThreadUserTime(id)); 218 219 c += cput.getCPUElapsedTimeNano(); 220 u += cput.getUserElapsedTimeNano(); 221 } 222 time.setStopCPUTime(c); 223 time.setStopUserTime(u); 224 break; 225 } 226 time.setStopTime(System.currentTimeMillis()); 227 } 228 229 private long nanoToMilli(long nano) 230 { 231 return Math.round(nano * NANO_TO_MILLI); 232 } 233 234 private double nanoToSec(long nano) 235 { 236 return nano * NANO_TO_SEC; 237 } 238 239 private double milliToSec(long milli) 240 { 241 return milli * MILLI_TO_SEC; 242 } 243 244 public long getCPUElapsedTimeMilli() 245 { 246 return nanoToMilli(time.getCPUElapsedTimeNano()); 247 } 248 249 public long getUserElapsedTimeMilli() 250 { 251 return nanoToMilli(time.getUserElapsedTimeNano()); 252 } 253 254 public double getCPUElapsedTimeSec() 255 { 256 return nanoToSec(time.getCPUElapsedTimeNano()); 257 } 258 259 public double getUserElapsedTimeSec() 260 { 261 return nanoToSec(time.getUserElapsedTimeNano()); 262 } 263 264 public double getElapsedTimeSec() 265 { 266 return milliToSec(time.getElapsedTimeMilli()); 267 } 268 269 public int getThreadCount() 270 { 271 return bean.getThreadCount(); 272 } 273 274 /** 275 * Uses SystemUtil.getAvailableProcessors() instead. 276 * 277 * @deprecated 278 */ 279 @Deprecated 280 public static int getAvailableProcessors() 281 { 282 return SystemUtil.getNumberOfCPUs(); 283 } 284 285 public long getElapsedTimeMilli() 286 { 287 return time.getElapsedTimeMilli(); 288 } 289}