Coverage Report - net.admin4j.hotspot.ExecutionTracker
 
Classes in this File Line Coverage Branch Coverage Complexity
ExecutionTracker
84%
53/63
73%
34/46
4.25
 
 1  
 /*
 2  
  * This software is licensed under the Apache License, Version 2.0
 3  
  * (the "License") agreement; you may not use this file except in compliance with
 4  
  * the License.  You may obtain a copy of the License at
 5  
  * 
 6  
  *      http://www.apache.org/licenses/LICENSE-2.0
 7  
  * 
 8  
  * Unless required by applicable law or agreed to in writing, software
 9  
  * distributed under the License is distributed on an "AS IS" BASIS,
 10  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  
  * See the License for the specific language governing permissions and
 12  
  * limitations under the License.
 13  
  */
 14  
 package net.admin4j.hotspot;
 15  
 
 16  
 import java.lang.management.ThreadInfo;
 17  
 import java.util.HashMap;
 18  
 import java.util.HashSet;
 19  
 import java.util.Map;
 20  
 import java.util.Set;
 21  
 
 22  
 import net.admin4j.deps.commons.lang3.StringUtils;
 23  
 import net.admin4j.entity.ExecutionPoint;
 24  
 import net.admin4j.util.Admin4jRuntimeException;
 25  
 import net.admin4j.util.Daemon;
 26  
 import net.admin4j.util.StackTraceUtils;
 27  
 import net.admin4j.util.threaddumper.ThreadDumperFactory;
 28  
 
 29  
 import org.slf4j.Logger;
 30  
 import org.slf4j.LoggerFactory;
 31  
 
 32  
 /**
 33  
  * Will track execution points and collect statistics.
 34  
  * @author D. Ashmore
 35  
  * @since 1.0
 36  
  */
 37  0
 public class ExecutionTracker {
 38  6
     private static Logger logger = LoggerFactory.getLogger(ExecutionTracker.class);
 39  6
     private static Map<StackTraceElement, ExecutionPoint> executionMap = new HashMap<StackTraceElement, ExecutionPoint>();
 40  
     private static Daemon TRACKING_DAEMON;
 41  
     
 42  
     public synchronized static void startTracking(int trackingDaemonSleepTimeInMillis ) {
 43  3
         if (TRACKING_DAEMON != null) {
 44  0
             logger.info("Tracking Daemon already started. - duplicate Daemon start request ignored.");
 45  
         }
 46  
         else {
 47  3
             TRACKING_DAEMON = new Daemon(new ExecutionTrackingTask(), "Admin4J-ExecutionTrackingTask", trackingDaemonSleepTimeInMillis);
 48  
         }
 49  3
     }
 50  
     
 51  
     /**
 52  
      * Tracks statistics on a single running thread.
 53  
      * @param threadInfo
 54  
      */
 55  
     public synchronized static void track(ThreadInfo threadInfo) {
 56  30
         if (Thread.State.RUNNABLE.equals(threadInfo.getThreadState()) 
 57  
                 || Thread.State.BLOCKED.equals(threadInfo.getThreadState())) {
 58  18
             if (threadInfo.getStackTrace() != null) {
 59  
                 ExecutionPoint currentExecutionPoint;
 60  
                 StackTraceElement currentStack;
 61  
                 StackTraceElement calledStack;
 62  18
                 StackTraceElement callingStack = null;
 63  
                 
 64  189
                 for (int i = 0; i < threadInfo.getStackTrace().length; i++) {
 65  171
                     currentStack = StackTraceUtils.sanitize(threadInfo.getStackTrace()[i]);
 66  171
                     if (i + 1 < threadInfo.getStackTrace().length) {
 67  165
                         calledStack = StackTraceUtils.sanitize(threadInfo.getStackTrace()[i + 1]);
 68  
                         
 69  165
                         if (executionMap != null) { // Check seem superfluous , but did Null out at user site on JVM shutdown.
 70  165
                             currentExecutionPoint = executionMap.get(currentStack);
 71  165
                             if (currentExecutionPoint == null) {
 72  159
                                 currentExecutionPoint = new ExecutionPoint(currentStack);
 73  159
                                 executionMap.put(currentStack, currentExecutionPoint);
 74  
                             }
 75  
                             
 76  165
                             currentExecutionPoint.setNbrExecutions(currentExecutionPoint.getNbrExecutions() + 1);
 77  165
                             if (Thread.State.BLOCKED.equals(threadInfo.getThreadState())) {
 78  0
                                 currentExecutionPoint.setNbrBlockedExecutions(currentExecutionPoint.getNbrBlockedExecutions() + 1);
 79  
                             }
 80  165
                             if (calledStack != null) {
 81  165
                                 currentExecutionPoint.addCalledStackTraceElement(calledStack);
 82  
                             }
 83  165
                             if (callingStack != null) {
 84  159
                                 currentExecutionPoint.addCallingStackTraceElement(callingStack);
 85  
                             }
 86  
                             
 87  
                             // Execution point is blocked by synchronization
 88  0
                             if (callingStack == null 
 89  
                                     && Thread.State.BLOCKED.equals(threadInfo.getThreadState()) 
 90  
                                     && !StringUtils.isEmpty(threadInfo.getLockName())) {
 91  0
                                 currentExecutionPoint.addBlockingSynchronizedClassName(threadInfo.getLockName());
 92  
                             }
 93  
                         }
 94  
                     }
 95  6
                     else calledStack = null;
 96  
                                         
 97  171
                     callingStack = currentStack;
 98  
                 }
 99  
             }
 100  
         }
 101  30
     }
 102  
     
 103  
     /**
 104  
      * Initiates tracking of all curently running threads.
 105  
      */
 106  
     public static void trackAll() {
 107  6
         ThreadInfo[] tInfo = ThreadDumperFactory.getThreadDumper().dumpAllThreads();
 108  36
         for (ThreadInfo thread: tInfo) {
 109  30
             track(thread);
 110  
         }
 111  6
     }
 112  
     
 113  
     /**
 114  
      * Resets thread tracking.
 115  
      */
 116  
     public synchronized static void reset() {
 117  6
         executionMap.clear();
 118  6
     }
 119  
     
 120  
     public synchronized static Map<StackTraceElement, ExecutionPoint> getExecutionMap() {
 121  12
         Map<StackTraceElement, ExecutionPoint> localMap = new HashMap<StackTraceElement, ExecutionPoint>();
 122  
         try {
 123  12
             for (Map.Entry<StackTraceElement, ExecutionPoint> entry: executionMap.entrySet()) {
 124  234
                 localMap.put(entry.getKey(), (ExecutionPoint)entry.getValue().clone());
 125  
             }
 126  0
         } catch (CloneNotSupportedException e) {
 127  0
             throw new Admin4jRuntimeException(e);
 128  12
         }
 129  12
         return localMap;
 130  
     }
 131  
     
 132  
     public synchronized static Map<StackTraceElement, ExecutionPoint> getHotSpotMap() {
 133  3
         Map<StackTraceElement, ExecutionPoint> localMap = getExecutionMap();
 134  3
         Set<StackTraceElement> toBeRemovedSet = new HashSet<StackTraceElement>();
 135  
         
 136  3
         for (Map.Entry<StackTraceElement, ExecutionPoint> entry: localMap.entrySet() ) {
 137  78
             if (entry.getValue().getCallingStackTraceElementList().size() <= 1) {
 138  75
                 toBeRemovedSet.add(entry.getKey());
 139  
             }
 140  
         }
 141  
         
 142  3
         for (StackTraceElement element: toBeRemovedSet) {
 143  75
             localMap.remove(element);
 144  
         }
 145  
         
 146  3
         return localMap;
 147  
     }
 148  
     
 149  
     public synchronized static Map<StackTraceElement, ExecutionPoint> getBlockedExecutionMap() {
 150  3
         Map<StackTraceElement, ExecutionPoint> localMap = getExecutionMap();
 151  3
         Set<StackTraceElement> toBeRemovedSet = new HashSet<StackTraceElement>();
 152  
         
 153  3
         for (Map.Entry<StackTraceElement, ExecutionPoint> entry: localMap.entrySet() ) {
 154  78
             if (entry.getValue().getBlockingSynchronizedClassList().size() == 0) {
 155  78
                 toBeRemovedSet.add(entry.getKey());
 156  
             }
 157  
         }
 158  
         
 159  3
         for (StackTraceElement element: toBeRemovedSet) {
 160  78
             localMap.remove(element);
 161  
         }
 162  
         
 163  3
         return localMap;
 164  
     }
 165  
     
 166  
     public static long getNbrTrackingObservations() {
 167  0
         if (TRACKING_DAEMON == null) {
 168  0
             return 0;
 169  
         }
 170  0
         return ((ExecutionTrackingTask)TRACKING_DAEMON.getTask()).getNbrTaskExecutions();
 171  
     }
 172  
 
 173  
 }