All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gridkit.nimble.probe.jmx.threading.JmxThreadTracker Maven / Gradle / Ivy

package org.gridkit.nimble.probe.jmx.threading;

import java.lang.management.ThreadInfo;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.management.MBeanServerConnection;

import org.gridkit.lab.util.jmx.mxstruct.common.ExtendedThreadMXBean;
import org.gridkit.nimble.probe.jmx.MXBeanFactory;

class JmxThreadTracker {

	private ExtendedThreadMXBean mbean;
	private boolean hotspotExtentionsSupported = true;

	private Map notes = new HashMap();
	
	public JmxThreadTracker(MBeanServerConnection mserver) {
		this.mbean = MXBeanFactory.newThreadMXBean(mserver);
	}

	public synchronized void updateSnapshot() {
		long[] ids = mbean.getAllThreadIds();
		Arrays.sort(ids);
		long timestamp = System.nanoTime();
		long[] cpuTime = getThreadCpuTime(ids);
		long[] userTime = getThreadUserTime(ids);
		long[] alloc = getThreadAllocatedBytes(ids);
		ThreadInfo[] infos = mbean.getThreadInfo(ids, 0);

		Map nnotes = new HashMap();
		for(ThreadInfo i: infos) {
			if (i != null) {
				ThreadNote note = notes.get(i.getThreadId());
				if (note == null) {
					note = new ThreadNote();
					note.threadId = i.getThreadId();
				}
				else {
					note.push();
				}
				
				note.lastTimestamp = timestamp;
				note.lastThreadInfo = i;
				int n = Arrays.binarySearch(ids, i.getThreadId());
				note.lastCpuTime = cpuTime[n];
				note.lastUserTime = userTime[n];
				note.lastMemoryAllocated = alloc[n];
				
				nnotes.put(i.getThreadId(), note);
			}
		}	
		notes = nnotes;
	}

	private long[] getThreadCpuTime(long[] ids) {
		if (hotspotExtentionsSupported) {
			try {
				return mbean.getThreadCpuTime(ids);
			}
			catch(UndeclaredThrowableException e) {
				hotspotExtentionsSupported = false;
				return getThreadCpuTime(ids);
			}
		}
		else {
			long[] data = new long[ids.length];
			for(int i = 0; i != ids.length; ++i) {
				data[i] = mbean.getThreadCpuTime(ids[i]);
			}
			return data;
		}
	}
	
	private long[] getThreadUserTime(long[] ids) {
		if (hotspotExtentionsSupported) {
			try {
				return mbean.getThreadUserTime(ids);
			}
			catch(UndeclaredThrowableException e) {
				hotspotExtentionsSupported = false;
				return getThreadUserTime(ids);
			}
		}
		else {
			long[] data = new long[ids.length];
			for(int i = 0; i != ids.length; ++i) {
				data[i] = mbean.getThreadUserTime(ids[i]);
			}
			return data;
		}
	}

	private long[] getThreadAllocatedBytes(long[] ids) {
		if (hotspotExtentionsSupported) {
			try {
				return mbean.getThreadAllocatedBytes(ids);
			}
			catch(UndeclaredThrowableException e) {
				hotspotExtentionsSupported = false;
				return getThreadAllocatedBytes(ids);
			}
		}
		else {
			long[] data = new long[ids.length];
			for(int i = 0; i != ids.length; ++i) {
				data[i] = 0;
			}
			return data;
		}			
	}
	
	public synchronized List getAllThreads() {
		List result = new ArrayList();
		for(ThreadNote td: notes.values()) {
			if (td.prevThreadInfo != null) {
				result.add(td);
			}
		}
		return result;
	}

	public static interface TradeDetails {
		
		public long getThreadId();
		
		public String getThreadName();
		
		public long getPrevTimestamp();
		
		public long getLastTimestamp();
		
		public long getCpuTime();
		
		public long getUserTime();
		
		public long getAllocatedBytes();
		
		public long getWaitCount();
		
		public long getWaitTime();
		
		public long getBlockedCount();
		
		public long getBlockedTime();
		
	}
	
	private static class ThreadNote implements TradeDetails {
		
		long threadId;
		
		long prevTimestamp;
		long lastTimestamp;
		
		ThreadInfo prevThreadInfo;
		ThreadInfo lastThreadInfo;
		
		long prevCpuTime;
		long lastCpuTime;
		
		long prevUserTime;
		long lastUserTime;
		
		long prevMemoryAllocated;
		long lastMemoryAllocated;
		
		public void push() {
			prevThreadInfo = lastThreadInfo;
			prevCpuTime = lastCpuTime;
			prevUserTime = lastUserTime;
			prevTimestamp = lastTimestamp;
			prevMemoryAllocated = lastMemoryAllocated; 
		}

		@Override
		public long getThreadId() {
			return threadId;
		}

		@Override
		public String getThreadName() {
			return lastThreadInfo.getThreadName();
		}

		@Override
		public long getPrevTimestamp() {
			return prevTimestamp;
		}

		@Override
		public long getLastTimestamp() {
			return lastTimestamp;
		}

		@Override
		public long getCpuTime() {
			return lastCpuTime == -1 ? 0 : lastCpuTime - prevCpuTime;
		}

		@Override
		public long getUserTime() {
			return lastUserTime == -1 ? 0 : lastUserTime - prevUserTime;
		}

		@Override
		public long getAllocatedBytes() {
			return lastMemoryAllocated == -1 ? 0 : lastMemoryAllocated - prevMemoryAllocated;
		}

		@Override
		public long getWaitCount() {
			return lastThreadInfo.getWaitedCount() - prevThreadInfo.getWaitedCount();
		}

		@Override
		public long getWaitTime() {
			return TimeUnit.MILLISECONDS.toNanos(lastThreadInfo.getWaitedTime() - prevThreadInfo.getWaitedTime());
		}

		@Override
		public long getBlockedCount() {
			return lastThreadInfo.getBlockedCount() - prevThreadInfo.getBlockedCount();
		}

		@Override
		public long getBlockedTime() {
			return TimeUnit.MILLISECONDS.toNanos(lastThreadInfo.getBlockedTime() - prevThreadInfo.getBlockedTime());
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy