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