Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package gov.nist.javax.sip.stack;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Timer;
This class is a simple thread analysis utility which tracks the time each request is stuck inside a JAIN SIP thread. It also runs periodic audits. If a request is stuck for too long a thread dump is logged. The parameters are specified in the MetricAnalysisConfiguration class and is dynamically reconfigurable. All fields are public without getters and setters for performance. Most of the synchronization is achieved without locks

Author(s):
Vladimir Ralev
 
 public  class CallAnalyzer {
 	private static StackLogger logger;
 	
 	/*
 	 * This is a Thread -> Hashmap association, each hashmap can contain multiple metricts for the thread
 	 */
 	
 	/*
 	 * Here we collect statistics about each metric over all threads (sum, avg, etc)
 	 */
 	
 	private Timer timer = new Timer();
 	private SipStackImpl stack;
 	
 	public CallAnalyzer(SipStackImpl stack) {
 		this. = stack;
 		 = stack.getStackLogger();
 	}
 	
 	public static class TImeMetricInfo {
 		public Long totalTime = new Long(0);
 		public Long numberOfEvents = new Long(0);
 		public Long averageTime = new Long(1);
 		public Long lastLoggedEventTime = new Long(0);
 		protected TimerTask task;
 		protected MetricAnalysisConfiguration config = new MetricAnalysisConfiguration(5000, 5000, 5000); // default config
 	}

Call this method to reconfigure the given metric

Parameters:
ref
config
 
 	public void configure(MetricReference refMetricAnalysisConfiguration config) {
 		.get(ref). = config;
 		if(isAnalyssStarted(ref)) {
 		}
 	}

If the startAnalysis method was called and not stopped

Parameters:
ref
Returns:
 
 	public boolean isAnalyssStarted(MetricReference ref) {
 		return .get(ref). != null;
 	}

Get the current stats for the metric over all threads

Parameters:
ref
Returns:
 
 		return .get(ref);
 	}

This is the configuration for the analysis task. The analysis job will be run every checkingInterval milliseconds. If an error occurs a thread dump will be logged, but there will be only one dump per minimumDumpInterval milliseconds. The dump will be logged only if a request is stuck in some thread for more than stuckTimeBeforeDump milliseconds.

Author(s):
vladimirralev
 
	public static class MetricAnalysisConfiguration {
		public MetricAnalysisConfiguration(Long checkingIntervalLong minDumpIntervalLong stuckTimerBeforeDump) {
			this. = checkingInterval;
			this. = minDumpInterval;
			this. = stuckTimerBeforeDump;
		}
		public MetricAnalysisConfiguration(int checkingIntervalint minDumpIntervalint stuckTimerBeforeDump) {
			this. = new Long(checkingInterval);
			this. = new Long(minDumpInterval);
			this. = new Long(stuckTimerBeforeDump);
		}
	}

This is just a name for certain statistic item. Such as a timestmp of request associated with a thread

Author(s):
vladimirralev
	public static class MetricReference {
		public MetricReference(String name) {
			this. = name;
		}
		public boolean equals(Object other) {
			if(other instanceof MetricReference) {
				return stat.name.equals(this.);
			}
			return false;
		}
		public int hashCode() {
			return this..hashCode();
		}
		public String name;
	}
	public static class MetricReferenceMap extends WeakHashMap<MetricReferenceTImeMetricInfo> {
		private static final long serialVersionUID = 393231609328924828L;
		public TImeMetricInfo get(Object key) {
			if(super.get(key) == null) {
				super.put((MetricReference) key, new TImeMetricInfo());
			}
			return super.get(key);
		}
	}
	public static class StackTrace {
		public StackTrace(int deltaString trace) {
			this. = delta;
			this. = trace;
		}
		public int delta;
		public String trace;
	}
	public static class ThreadInfo {
		public Object data;
	}

Rest all stats and start over with sum, average, etc

Parameters:
metricReference
	public void resetStats(MetricReference metricReference) {
		TImeMetricInfo info = .get(metricReference);
		info.totalTime = new Long(0);
		info.numberOfEvents = new Long(0);
		info.averageTime = new Long(1);
		info.lastLoggedEventTime = new Long(0);
	}
	public CallAnalyzer() {
	}

Stop the analysis for a given metric, the analysis periodic job will be stopped and stack traces will no longer be produced.

Parameters:
metricReference
	public void stopAnalysis(final MetricReference metricReference) {
		final TImeMetricInfo statInfo = .get(metricReference);
		if(statInfo.task != null) {
			statInfo.task.cancel();
			statInfo.task = null;
		}
	}

Start the analysis job that will check the status of the requests periodically and make thread dumps if some request is stuck.

Parameters:
metricReference
	public void startAnalysis(final MetricReference metricReference) {
		stopAnalysis(metricReference);
		resetStats(metricReference);
		final TImeMetricInfo statInfo = .get(metricReference);
		statInfo.task = new TimerTask() {
			public void run() {
				try {
					Long lastDump = statInfo.lastLoggedEventTime;
					// if there has been enough time since the last dump proceed with the check
					if(System.currentTimeMillis() - lastDump>statInfo.config.minimumDumpInterval) {
						// check all threads for requests that are stuck for too long
						while(threadInfos.hasNext()) {
							Entry<ThreadHashMap<MetricReferenceObject>> info = threadInfos.next();
							Long entryTime = (Longinfo.getValue().get(metricReference);
							if(!entryTime.equals(.)) {
								Long delta = System.currentTimeMillis() - entryTime;
								// if a thread is stuck for too long log it
								if( != null && delta>statInfo.config.stuckTimeBeforeDump) {
									.logWarning("Offending thread:\n" + getCurrentStack(info.getKey()));
									Thread[] threads = new Thread[5000];
									int count = Thread.enumerate(threads);
									for(int q=0; q<countq++) {
										long threadStuck = 0;
										HashMap<MetricReference,ObjectsubInfo = .get(threads[q]);
										if(subInfo != null) {
											Long stamp = (Long.get(threads[q]).get(metricReference);
											if(stamp != null) {
												threadStuck = System.currentTimeMillis() - stamp;
											}
											if(stamp != .) {
												sb.append("->Stuck time:" + threadStuck  + " " + getCurrentStack(threads[q]));
											}
										}
									}
									threads = null;
									break;
								}
							}
						}
					}
catch (Exception ex) {
					//Ignore excpetions here - even concurrent modification exceptions are not critical
				}}
		};
		.scheduleAtFixedRate(statInfo.taskstatInfo.config.checkingIntervalstatInfo.config.checkingInterval);
	}

Stop everything
	public void stop() {
		 = null;
	}
	public Long getTime(Thread threadIdMetricReference metricReference) {
		return (Longattribs.get(metricReference);
	}

You can associate Objects for a given thread and display them later for more analysis items.

Parameters:
threadId
objectName
object
	public void setObject(Thread threadIdMetricReference objectNameObject object) {
		getAttributes(threadId).put(objectNameobject);
	}

Retrieve items associated with the thread

Parameters:
threadId
objectName
Returns:
	public Object getObject(Thread threadIdString objectName) {
		return getAttributes(threadId).get(objectName);
	}
	public synchronized HashMap<MetricReference,ObjectgetAttributes(Thread threadId) {
		HashMap<MetricReference,ObjectthreadLocal = .get(threadId);
		if(threadLocal == null) {
			threadLocal = new HashMap<MetricReference,Object>();
			.put(threadIdthreadLocal);
		}
		return threadLocal;
	}

Enter a traced zone by the name of metricReference for the current thread. This puts the enter timestamp and all lost call calculations will be based on this timestamp

Parameters:
threadId
metricReference
	public void enter(MetricReference metricReference) {
		Thread threadId = Thread.currentThread();
		enter(threadIdmetricReference);
	}

Leave a traced zone by the name of metricReference for the specified thread. This puts the timestamp in inactive mode. No more analysis will be done on this thread.

Parameters:
threadId
metricReference
	public void leave(MetricReference metricReference) {
		Thread threadId = Thread.currentThread();
		leave(threadIdmetricReference);
	}

Enter a traced zone by the name of metricReference for the specified thread. This puts the enter timestamp and all lost call calculations will be based on this timestamp.

Parameters:
threadId
metricReference
	public void enter(Thread threadIdMetricReference metricReference) {
		attribs.put(metricReference, System.currentTimeMillis());
	}

Leave a traced zone by the name of metricReference for the specifed thread. No more analysis will be done on this thread.

Parameters:
threadId
metricReference
	public void leave(Thread threadIdMetricReference metricReference) {
		TImeMetricInfo info = .get(metricReference);
		long delta = System.currentTimeMillis() - (Longattribs.get(metricReference);
		info.totalTime += delta;
		info.numberOfEvents ++;
		info.averageTime = info.totalTime/info.numberOfEvents;
		attribs.put(metricReference.);
	}

Current stacktrace of the thread

Parameters:
thread
Returns:
	public String getCurrentStack(Thread thread) {
		sb.append("\n" + thread.getName() + " " + thread.getId() + " " + thread.getState().toString() + "\n");
		StackTraceElement[] ste = thread.getStackTrace();
		forStackTraceElement el : ste ) {
			sb.append(" " + el.toString() + "\n");
		}
		return sb.toString();
	}

Returns the stacktraces of all threads

Returns:
	public String getThreadDump() {
		Thread[] threads = new Thread[5000];
		int count = Thread.enumerate(threads);
		for(int q=0; q<countq++) {
			sb.append(getCurrentStack(threads[q]));
		}
		return sb.toString();
	}

Number of threads that are executing requests right now or have executed requests and are idle and not garbage collected. You can check for leaks here.

Returns:
	public int getNumberOfThreads() {
		return .size();
	}
	public static void main(String[] argthrows InterruptedException {
		ExecutorService ex = Executors.newFixedThreadPool(1000);
		final CallAnalyzer tp = new CallAnalyzer();
		final MetricReference sec = new MetricReference("sec");
		MetricReference se1c = new MetricReference("se111c");
		tp.configure(secnew MetricAnalysisConfiguration(500,500,500));
		tp.startAnalysis(se1c);
		Runnable r = new Runnable() {
			public void run() {
				tp.enter(sec);
				try {
					if(++ % 10000==0) {
						Thread.sleep(1000);
					}
					Thread.sleep(100);
catch (InterruptedException e) {
					// TODO Auto-generated catch block
				}
				tp.leave(sec);
			}
		};
		for(int q=0; q<2000000; q++) {
			ex.execute(r);
		}
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		//Thread.sleep(5000);
		System.gc();
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		System.gc();Thread.sleep(5000);
		System.gc();
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		System.gc();
		se1c = null;
		System.gc();Thread.sleep(5000);
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		System.gc();
		System.gc();Thread.sleep(5000);
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		System.gc();Thread.sleep(5000);
		System.gc();
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		System.gc();
		System.gc();Thread.sleep(5000);
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		System.gc();
		System.gc();Thread.sleep(5000);
		..println("size:" + tp.threadMap.size() + " " + tp.metricStatisticsMap.size());
		System.gc();
		if(tp.threadMap.size() >0) {
			throw new RuntimeException("Should be zero by this point. Leak.");
		}
	}
	static int count =0;
New to GrepCode? Check out our FAQ X