ThreadGroupMonitor gmonitor = new ThreadGroupMonitor(); while(true) { gmonitor.poll(); for(ThreadMonitor tmon: gmonitor.getAliveThreadMonitors()) { double avg = tmon.getCpuTimeStats().avg(); // avg of last polls double avg = tmon.getCpuTimeStats().avg(3); // avg of last 3 polls double avg = tmon.getCpuTimeStats().avg(5); // avg of last 5 polls } for(ThreadMonitor tmon: gmonitor.getDeadThreadMonitors()) { double total = tmon.getTotalCpuTime(); } // sleep for a bit }
Even dead threads...
public class ThreadMonitor { private static ThreadMXBean tmxb; static { tmxb = ManagementFactory.getThreadMXBean(); tmxb.setThreadCpuTimeEnabled(true); } // private long tid; private CyclicUsageHistory cpuTimeHistory; private CyclicUsageHistory userTimeHistory; private CyclicUsageHistory cpuUsageHistory; private CyclicUsageHistory userUsageHistory; public ThreadMonitor(long tid, int slots) { this.tid = tid; this.cpuTimeHistory = new CyclicUsageHistory(slots); this.userTimeHistory = new CyclicUsageHistory(slots); this.cpuUsageHistory = new CyclicUsageHistory(slots); this.userUsageHistory = new CyclicUsageHistory(slots); } public long getId() { return tid; } private double totalCpuTime; private double totalUserTime; public double getTotalCpuTime() { return this.totalCpuTime; } public double getTotalUserTime() { return this.totalUserTime; } public void poll() { // a time of -1 means not alive double cpuTime = tmxb.getThreadCpuTime(this.tid) / 1000000000.0; this.totalCpuTime += cpuTime < 0 ? 0 : cpuTime; cpuTimeHistory.log(cpuTime < 0 ? 0 : cpuTime); cpuUsageHistory.log(cpuTimeHistory.previous(0) - cpuTimeHistory.previous(1)); double userTime = tmxb.getThreadUserTime(this.tid) / 1000000000.0; this.totalUserTime += userTime < 0 ? 0 : userTime; userTimeHistory.log(userTime < 0 ? 0 : userTime); userUsageHistory.log(userTimeHistory.previous(0) - userTimeHistory.previous(1)); } public CyclicUsageHistory getCpuTimeStats() { return this.cpuUsageHistory; } public CyclicUsageHistory getUserTimeStats() { return this.userUsageHistory; } } public class ThreadGroupMonitor { public ThreadGroupMonitor() { this(Thread.currentThread().getThreadGroup()); } public ThreadGroupMonitor(ThreadGroup group) { this.group = group; this.lastThreadIds = new long[0]; this.aliveId2mon = new HashMap(); this.deadId2mon = new HashMap (); } // private final ThreadGroup group; public ThreadGroup getThreadGroup() { return group; } // private int totalDeadThreadCount = 0; public synchronized int getTotalDeadThreadCount() { return this.totalDeadThreadCount; } // private int regularThreadCount = 0; public synchronized int getRegularThreadCount() { return this.regularThreadCount; } // private int deamonThreadCount = 0; public synchronized int getDeamonThreadCount() { return this.deamonThreadCount; } // private static final int default_slots = 3600; private long[] lastThreadIds; private Map aliveId2mon; private Map deadId2mon; public synchronized void poll() { Thread[] threads = this.findAllThreads(); long[] currThreadIds = this.findAllThreadIds(threads); long[] newIds = this.findNewThreadIds(this.lastThreadIds, currThreadIds); long[] deadIds = this.findDeadThreadIds(this.lastThreadIds, currThreadIds); this.totalDeadThreadCount += deadIds.length; for (long newId : newIds) aliveId2mon.put(Long.valueOf(newId), new ThreadMonitor(newId, default_slots)); for (long deadId : deadIds) deadId2mon.put(Long.valueOf(deadId), aliveId2mon.remove(Long.valueOf(deadId))); for (ThreadMonitor mon : aliveId2mon.values()) mon.poll(); for (ThreadMonitor mon : deadId2mon.values()) mon.poll(); this.analyzeThreads(threads); this.lastThreadIds = currThreadIds; } public synchronized double getAvgCpuTimeStats(int pollCount) { double sum = 0.0; for (ThreadMonitor mon : aliveId2mon.values()) sum += mon.getCpuTimeStats().avg(pollCount); return sum; } public synchronized double getAvgUserTimeStats(int pollCount) { double sum = 0.0; for (ThreadMonitor mon : aliveId2mon.values()) sum += mon.getUserTimeStats().avg(pollCount); return sum; } public Collection getAliveThreadMonitors() { return Collections.unmodifiableCollection(this.aliveId2mon.values()); } public Collection getDeadThreadMonitors() { return Collections.unmodifiableCollection(this.deadId2mon.values()); } private void analyzeThreads(Thread[] threads) { int deamonThreadCount = 0; int regularThreadCount = 0; for (Thread thread : threads) { if (!thread.isAlive()) continue; if (thread.isDaemon()) deamonThreadCount++; else regularThreadCount++; } this.deamonThreadCount = deamonThreadCount; this.regularThreadCount = regularThreadCount; } public Thread[] findAllThreads() { int threadCount; Thread[] tempThreadArray = new Thread[8]; while ((threadCount = this.group.enumerate(tempThreadArray)) == tempThreadArray.length) tempThreadArray = ArrayUtil.growTo(tempThreadArray, tempThreadArray.length * 2); Thread[] threadArray = new Thread[threadCount]; System.arraycopy(tempThreadArray, 0, threadArray, 0, threadCount); return threadArray; } private long[] findAllThreadIds(Thread[] threads) { long[] allThreadIds = new long[threads.length]; for (int i = 0; i < allThreadIds.length; i++) allThreadIds[i] = threads[i].getId(); return allThreadIds; } private long[] findNewThreadIds(long[] lastThreads, long[] currThreads) { long[] newThreadIds = new long[currThreads.length]; int newThreadIndex = 0; outer: for (int i = 0; i < currThreads.length; i++) { for (int k = 0; k < lastThreads.length; k++) if (currThreads[i] == lastThreads[k]) continue outer; newThreadIds[newThreadIndex++] = currThreads[i]; } long[] ids = new long[newThreadIndex]; System.arraycopy(newThreadIds, 0, ids, 0, newThreadIndex); return ids; } private long[] findDeadThreadIds(long[] lastThreads, long[] currThreads) { long[] deadThreadIds = new long[lastThreads.length]; int deadThreadIndex = 0; outer: for (int i = 0; i < lastThreads.length; i++) { for (int k = 0; k < currThreads.length; k++) if (lastThreads[i] == currThreads[k]) continue outer; deadThreadIds[deadThreadIndex++] = lastThreads[i]; } long[] ids = new long[deadThreadIndex]; System.arraycopy(deadThreadIds, 0, ids, 0, deadThreadIndex); return ids; } } public class CyclicUsageHistory { private final double[] values; public CyclicUsageHistory(int slots) { this.values = new double[slots]; } private int addIndex; public void log(double value) { this.values[this.addIndex++ % this.values.length] = value; } // public double previous() { return this.previous(0); } public double previous(int age) { int len = this.values.length; return this.values[(((this.addIndex - 1 - age) % len) + len) % len]; } // public double max() { return this.max(this.values.length); } public double max(int slots) { int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1)); double max = 0.0; for (int i = 0; i < count; i++) if (this.previous(i) > max) max = this.previous(i); return max; } // public double sum() { return this.sum(this.values.length); } public double sum(int slots) { int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1)); double sum = 0.0; for (int i = 0; i < count; i++) sum += this.previous(i); return sum; } // public double avg() { return this.avg(this.values.length); } public double avg(int slots) { int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1)); return this.sum(slots) / count; } // public double nom() { return this.nom(this.values.length); } public double nom(int slots) { int count = Math.min(this.values.length, Math.min(slots, this.addIndex - 1)); if (count == 0) return 0.0; double[] arr = new double[count]; for (int i = 0; i < count; i++) arr[i] = this.previous(i); Arrays.sort(arr); return arr[arr.length / 2]; } }
No comments:
Post a Comment