001: package tide.threadanalysis;
002:
003: import java.awt.EventQueue;
004: import java.util.*;
005:
006: /** Analysis of running threads over time. (Sampling analysis).
007: * Goal: discover places to parallelize, discover potential errors.
008: *
009: * IDEAS: create an @Parallel, @EDT, @NonEDT, @NonParallel and check them.
010: * IDEA: define prefilter (include, exclude, ...)
011: * IDEA: define postfilter (view only some...)
012: * IDEA: group by thread name or ref =
013: *
014: * USAGE:
015: ThreadSequencer tan = new ThreadSequencer();
016: tan.start();
017: SequencerViewer.view(tan);
018: */
019: public final class ThreadSequencer extends Thread {
020: // all existing threads and their histories
021: final Map<Thread, ThreadHistory> histories = new HashMap<Thread, ThreadHistory>();
022:
023: // is ignored !
024: static private final String name = "ThreadSequencer ##";
025:
026: // = start date
027: final private long t0Millis;
028: // nano time, used to compute the other times (relative to this)
029: final private long t0;
030: private long tEnd;
031:
032: boolean shouldRun = true, shouldPause = false;
033:
034: public ThreadSequencer() {
035: setDaemon(true); // don't cause the VM to live when alone alive.
036: setName(name);
037: t0 = System.nanoTime();
038: t0Millis = System.currentTimeMillis();
039:
040: // test
041: final Map<Thread, StackTraceElement[]> map = Thread
042: .getAllStackTraces();
043: for (final Thread ti : map.keySet()) {
044: System.out.println("Thread " + ti);
045: for (StackTraceElement si : map.get(ti)) {
046: System.out.println(" " + si);
047: }
048: // just show the first ?
049: //return;
050: }
051:
052: }
053:
054: /* Example:
055:
056: ThreadSequencer> Thread Thread[Reference Handler,10,system]
057: ThreadSequencer> java.lang.Object.wait(Native Method)
058: ThreadSequencer> java.lang.Object.wait(Object.java:485)
059: ThreadSequencer> java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
060: ThreadSequencer> Thread Thread[Finalizer,8,system]
061: ThreadSequencer> java.lang.Object.wait(Native Method)
062: ThreadSequencer> java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
063: ThreadSequencer> java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
064: ThreadSequencer> java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
065: ThreadSequencer> Thread Thread[main,5,main]
066: ThreadSequencer> java.lang.Thread.dumpThreads(Native Method)
067: ThreadSequencer> java.lang.Thread.getAllStackTraces(Thread.java:1477)
068: ThreadSequencer> tide.threadanalysis.ThreadSequencer.<init>(ThreadSequencer.java:21)
069: ThreadSequencer> tide.threadanalysis.ThreadSequencer.main(ThreadSequencer.java:102)
070: ThreadSequencer> Thread Thread[Signal Dispatcher,9,system]
071: ThreadSequencer> Thread Thread[Attach Listener,5,system]
072:
073: */
074:
075: public final long getT0() {
076: return t0;
077: }
078:
079: /** May change when active
080: */
081: public final long getTEnd() {
082: return tEnd;
083: }
084:
085: /** Start date */
086: public final long getT0Millis() {
087: return t0Millis;
088: }
089:
090: // REF !
091: public final Map<Thread, ThreadHistory> getHistoriesREF() {
092: return histories;
093: }
094:
095: @Override
096: public final String toString() {
097: StringBuilder sb = new StringBuilder();
098: sb.append("\n\n\n========== ThreadSequencer, "
099: + histories.size() + " various threads ==========");
100: synchronized (histories) {
101: for (Thread ti : histories.keySet()) {
102: final ThreadHistory hi = histories.get(ti);
103: //sb.append("\nThread "+ti.getName());
104: sb.append("\n\n" + hi);
105: }
106: }
107: //...
108: return sb.toString();
109: }
110:
111: public void stopSequencer() {
112: shouldRun = false;
113: synchronized (this ) {
114: this .notifyAll();
115: }
116: }
117:
118: public void pauseSequencer() {
119: shouldPause = true;
120: synchronized (this ) {
121: this .notifyAll();
122: }
123: }
124:
125: public void resumeSequencer() {
126: shouldPause = false;
127: synchronized (this ) {
128: this .notifyAll();
129: }
130: }
131:
132: /** this takes a snapshot each XX millis
133: */
134: @Override
135: public void run() {
136: while (shouldRun) {
137: try {
138: Thread.sleep(10);
139: } catch (InterruptedException ex) {
140: } // 10 => 100 per second.
141:
142: if (shouldPause) {
143: synchronized (this ) {
144: try {
145: this .wait();
146: } catch (Exception e) {
147: e.printStackTrace();
148: } // ignore
149: }
150: }
151:
152: //System.out.println("NT = "+ Thread.activeCount());
153: //Thread[] ts = new Thread[Thread.activeCount()];
154: //Thread.enumerate(ts);
155: final Map<Thread, StackTraceElement[]> map = Thread
156: .getAllStackTraces();
157: tEnd = System.nanoTime();
158:
159: for (Thread ti : map.keySet()) {
160: if (ti.getName().equals(name))
161: continue;
162: if (!histories.containsKey(ti)) {
163: histories.put(ti, new ThreadHistory(ti, t0));
164: }
165:
166: StackTraceElement[] si = map.get(ti);
167: histories.get(ti).add(si, ti.getState(), t0);
168: }
169:
170: }
171: }
172:
173: // TEST
174: static volatile int i = 0;
175:
176: final static class MTest extends Thread {
177: public MTest() {
178: }
179:
180: public void run() {
181: for (int u = 0; u < 10; u++) {
182: try {
183: Thread.sleep(1000);
184: } catch (InterruptedException ex) {
185: }
186: i++;
187: double s = 0;
188: for (int j = 0; j < 1000000; j++)
189: s += Math.sqrt(j + i);
190: System.out.println("" + s);
191: }
192: //System.out.println(""+(i++));
193: }
194: }
195:
196: // TEST
197: public static void main(String[] args) throws Exception {
198: // NO effect ?? Runtime.getRuntime().traceMethodCalls(true);
199: // Runtime.getRuntime().traceInstructions(true);
200:
201: ThreadSequencer tan = new ThreadSequencer();
202: tan.start();
203: SequencerViewer.view(tan);
204:
205: new MTest().start();
206:
207: Thread.sleep(2000);
208:
209: new MTest().start();
210: new MTest().start();
211:
212: Thread.sleep(2000);
213:
214: new MTest().start();
215: new MTest().start();
216: new MTest().start();
217: new MTest().start();
218:
219: EventQueue.invokeLater(new Runnable() {
220: public void run() {
221: try {
222: Thread.sleep(100);
223: } catch (InterruptedException ex) {
224: }
225: System.out.println("EDTHello");
226: try {
227: Thread.sleep(100);
228: } catch (InterruptedException ex) {
229: }
230: }
231: });
232:
233: Thread.sleep(4000);
234: // System.out.println(""+ tan);
235:
236: //System.exit(0);
237:
238: }
239:
240: }
|