1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.utils.threads.logger;
14 import java.io.DataInput;
15 import java.io.DataInputStream;
16 import java.io.EOFException;
17 import java.io.FileInputStream;
18 import java.io.FileNotFoundException;
19 import java.io.IOException;
20 import java.io.PrintStream;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Locale;
27 public class ThreadLogVisualizer {
29 // Do not show tasks shorter than 5ms
30 final public static long DISCARD_LIMIT = 2 * 1000 * 1000;
32 final public static long COLUMN_WIDTH = 1000000000;
34 final int onlyOneThread = -1;
36 final String colors[] = {
55 class Task implements Comparable<Task> {
62 public Task(String name, long threadId, long beginTime, long endTime) {
63 if(name.length() > 100) name = name.substring(0, 99);
65 this.threadId = threadId;
66 this.beginTime = beginTime;
67 this.endTime = endTime;
71 // Differences will not fit into int
72 public int compareTo(Task o) {
73 if(beginTime > o.beginTime) return 1;
74 else if(beginTime == o.beginTime) return -1;
79 ArrayList<Task> tasks = new ArrayList<Task>();
81 private boolean acceptThread(long threadId) {
82 if(onlyOneThread == -1) return true;
83 else return (threadId&15) == onlyOneThread;
86 private Map<Long, Task> compositeTasks = new HashMap<>();
88 public void read(DataInput input) {
92 String taskName = input.readUTF();
93 long threadId = input.readLong();
94 long beginTime = input.readLong();
95 long endTime = input.readLong();
96 if(!acceptThread(threadId)) continue;
97 if((endTime-beginTime) > DISCARD_LIMIT) {
98 tasks.add(new Task(taskName, threadId, beginTime, endTime));
99 Task t = compositeTasks.remove(threadId);
101 if((t.endTime-t.beginTime) > DISCARD_LIMIT) {
102 tasks.add(new Task(t.combined + " small tasks", t.threadId, t.beginTime, t.endTime));
106 Task t = compositeTasks.get(threadId);
108 t = new Task("", threadId, beginTime, endTime);
109 compositeTasks.put(threadId, t);
111 if(beginTime - t.endTime > DISCARD_LIMIT) {
112 tasks.add(new Task(t.combined + " small tasks", t.threadId, t.beginTime, t.endTime));
113 t = new Task("", threadId, beginTime, endTime);
114 compositeTasks.put(threadId, t);
118 if((t.endTime-t.beginTime) > DISCARD_LIMIT) {
119 tasks.add(new Task(t.combined + " small tasks", t.threadId, t.beginTime, t.endTime));
120 compositeTasks.remove(threadId);
123 } catch(EOFException e) {
127 } catch(IOException e) {
130 Collections.sort(tasks);
134 ArrayList<Task> tasks = new ArrayList<Task>();
138 public void visualize3(PrintStream s) {
140 long minTime = Long.MAX_VALUE;
141 long maxTime = Long.MIN_VALUE;
143 ArrayList<Lane> lanes = new ArrayList<Lane>();
146 for(Task task : tasks) {
150 minTime = Math.min(minTime, task.beginTime);
151 maxTime = Math.max(maxTime, task.endTime);
153 for(int seek = laneId-1; seek >= 0; --seek) {
154 if(lanes.get(seek).nextTime < task.beginTime) {
161 if(laneId < lanes.size())
162 lane = lanes.get(laneId);
168 lane.tasks.add(task);
169 lane.nextTime = Math.max(task.endTime, task.beginTime+COLUMN_WIDTH);
170 System.out.println(task.name + " -> " + laneId + "[" + task.beginTime + "-" + task.endTime + "]");
176 double timeScale = 1e-6;
177 double rowHeight = 30.0;
178 Locale locale = Locale.US;
179 int row = lanes.size();
181 s.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
182 s.println("<svg xmlns=\"http://www.w3.org/2000/svg\" overflow=\"visible\" version=\"1.1\">");
183 for(long time = minTime ; time < maxTime ; time += 1000000000) {
185 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"grey\"/>\n",
186 (time-minTime)*timeScale,
188 (time-minTime)*timeScale,
191 for(int r = 0;r<lanes.size();++r) {
192 Lane lane = lanes.get(r);
193 for(Task task : lane.tasks) {
195 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"black\"/>\n",
196 (task.beginTime-minTime)*timeScale,
198 (task.beginTime-minTime)*timeScale,
201 "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"" + colors[(int)task.threadId & 15] + "\"/>\n",
202 (task.beginTime-minTime)*timeScale,
204 (task.endTime-task.beginTime)*timeScale,
207 for(Task task : lane.tasks) {
208 int time = (int)(1e-6 * (task.endTime-task.beginTime));
210 "<text x=\"%f\" y=\"%f\">%s</text>\n",
211 (task.endTime-minTime)*timeScale,
213 Integer.toString(time) + "ms: " + task.name);
219 public void visualize2(PrintStream s) {
220 long minTime = Long.MAX_VALUE;
221 long maxTime = Long.MIN_VALUE;
222 ArrayList<Lane> lanes = new ArrayList<Lane>();
224 for(Task task : tasks) {
225 minTime = Math.min(minTime, task.beginTime);
226 maxTime = Math.max(maxTime, task.endTime);
228 for(laneId=0;laneId<lanes.size();++laneId)
229 if(lanes.get(laneId).nextTime < task.beginTime)
232 if(laneId < lanes.size())
233 lane = lanes.get(laneId);
238 lane.tasks.add(task);
239 lane.nextTime = Math.max(task.endTime, task.beginTime+COLUMN_WIDTH);
240 System.out.println(task.name + " -> " + laneId + "[" + task.beginTime + "-" + task.endTime + "]");
243 double timeScale = 1e-7*5;
244 double rowHeight = 30.0;
245 Locale locale = Locale.US;
246 int row = lanes.size();
248 s.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
249 s.println("<svg xmlns=\"http://www.w3.org/2000/svg\" overflow=\"visible\" version=\"1.1\">");
250 for(long time = minTime ; time < maxTime ; time += 1000000000) {
252 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"grey\"/>\n",
253 (time-minTime)*timeScale,
255 (time-minTime)*timeScale,
258 for(int r = 0;r<lanes.size();++r) {
259 Lane lane = lanes.get(r);
260 for(Task task : lane.tasks) {
262 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"black\"/>\n",
263 (task.beginTime-minTime)*timeScale,
265 (task.beginTime-minTime)*timeScale,
268 "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"" + colors[(int)task.threadId & 15] + "\"/>\n",
269 (task.beginTime-minTime)*timeScale,
271 (task.endTime-task.beginTime)*timeScale,
274 for(Task task : lane.tasks) {
276 "<text x=\"%f\" y=\"%f\">%s</text>\n",
277 (task.endTime-minTime)*timeScale,
285 public void visualize(PrintStream s) {
286 long minTime = Long.MAX_VALUE;
287 long maxTime = Long.MIN_VALUE;
288 Map<Long, Integer> threads = new HashMap<Long, Integer>();
291 for(Task task : tasks) {
292 minTime = Math.min(minTime, task.beginTime);
293 maxTime = Math.max(maxTime, task.endTime);
294 if(!threads.containsKey(task.threadId))
295 threads.put(task.threadId, row++);
298 double timeScale = 1e-7*0.8;
299 double rowHeight = 60.0;
300 Locale locale = Locale.US;
301 int textPos[] = new int[row];
303 s.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
304 s.println("<svg xmlns=\"http://www.w3.org/2000/svg\" overflow=\"visible\" version=\"1.1\">");
305 for(long time = minTime ; time < maxTime ; time += 1000000000) {
307 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"grey\"/>\n",
308 (time-minTime)*timeScale,
310 (time-minTime)*timeScale,
313 for(Task task : tasks) {
314 int r = threads.get(task.threadId);
316 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"black\"/>\n",
317 (task.beginTime-minTime)*timeScale,
319 (task.beginTime-minTime)*timeScale,
322 "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"" + colors[(int)task.threadId & 15] + "\"/>\n",
323 (task.beginTime-minTime)*timeScale,
325 (task.endTime-task.beginTime)*timeScale,
328 for(Task task : tasks) {
329 int r = threads.get(task.threadId);
331 "<text x=\"%f\" y=\"%f\">%s</text>\n",
332 (task.endTime-minTime)*timeScale,
333 (r*3+(textPos[r]++)%2+0.5)*rowHeight/3,
339 public static void main(String[] args) {
341 ThreadLogVisualizer visualizer = new ThreadLogVisualizer();
342 visualizer.read(new DataInputStream(new FileInputStream(ThreadLogger.LOG_FILE)));
343 visualizer.visualize3(new PrintStream(ThreadLogger.LOG_FILE + ".svg"));
344 } catch (FileNotFoundException e) {
345 // TODO Auto-generated catch block