1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
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 | |
|
34 | |
|
35 | |
|
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 | |
|
53 | |
|
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) { |
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 | |
|
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 | |
|
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 | |
|
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 | |
} |