Diagram threading and ThreadLogger improvements 75/3275/5
authorAntti Villberg <antti.villberg@semantum.fi>
Tue, 24 Sep 2019 08:03:34 +0000 (11:03 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 16 Oct 2019 23:05:56 +0000 (02:05 +0300)
gitlab #387
gitlab #388

Conflicts:
bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java

Change-Id: Iff524dd3d8ebf66632772077a06dc10cae0c6f9c

bundles/org.simantics.db.common/src/org/simantics/db/common/request/AsyncReadRequest.java
bundles/org.simantics.db.common/src/org/simantics/db/common/request/BinaryAsyncRead.java
bundles/org.simantics.db.common/src/org/simantics/db/common/request/UnaryAsyncRead.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java
bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java
bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DiagramContentRequest.java
bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/GraphToDiagramSynchronizer.java
bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogVisualizer.java
bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogger.java

index 7f35618f871710a3ef77e71b33dbfa310e8d2ebd..4b92bbea1e0ac239dfd6102ad4268b1b7ac45fd7 100644 (file)
@@ -12,6 +12,7 @@
 package org.simantics.db.common.request;
 
 import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.db.request.AsyncRead;
 
@@ -19,8 +20,12 @@ public abstract class AsyncReadRequest implements AsyncRead<Object> {
 
     @Override
     final public void perform(AsyncReadGraph graph, AsyncProcedure<Object> procedure) {
-        run(graph);
-        procedure.execute(graph, null);
+        try {
+            run(graph);
+            procedure.execute(graph, null);
+        } catch (DatabaseException e) {
+            procedure.exception(graph, e);
+        }
     }
     
     @Override
@@ -33,6 +38,6 @@ public abstract class AsyncReadRequest implements AsyncRead<Object> {
        return hashCode();
     }
     
-    public abstract void run(AsyncReadGraph graph);
+    public abstract void run(AsyncReadGraph graph) throws DatabaseException;
 
 }
index 6f83967b2f692d6f10105b29d4c3418ff96b17d4..8747be66c57529b0306ba0be3001ed30d2dd1b17 100644 (file)
@@ -46,4 +46,9 @@ abstract public class BinaryAsyncRead<P1, P2, R> extends UnaryAsyncRead<P1, R> {
         this.parameter2 = parameter2;
     }
 
+    @Override
+    public String toString() {
+        return getClass().getName() + "[" + parameter + ", " + parameter2 + "]";
+    }
+
 }
index 783966464ca55271bbb4ae33c8bd8887cf56560f..49637f943fb83af989ef29432a5a586fd5556e0e 100644 (file)
@@ -63,37 +63,42 @@ public abstract class UnaryAsyncRead<P, R> implements AsyncRead<R>, ReadInterfac
 
     @Override
     public void request(AsyncRequestProcessor processor, AsyncProcedure<R> procedure) {
-       processor.asyncRequest(this, procedure);
+        processor.asyncRequest(this, procedure);
     }
     
     @Override
     public void request(AsyncRequestProcessor processor, Procedure<R> procedure) {
-       processor.asyncRequest(this, procedure);
+        processor.asyncRequest(this, procedure);
     }
     
     @Override
     public void request(AsyncRequestProcessor processor, SyncProcedure<R> procedure) {
-       processor.asyncRequest(this, procedure);
+        processor.asyncRequest(this, procedure);
     }
 
     @Override
     public void request(AsyncRequestProcessor processor, AsyncListener<R> procedure) {
-       processor.asyncRequest(this, procedure);
+        processor.asyncRequest(this, procedure);
     }
     
     @Override
     public void request(AsyncRequestProcessor processor, Listener<R> procedure) {
-       processor.asyncRequest(this, procedure);
+        processor.asyncRequest(this, procedure);
     }
     
     @Override
     public void request(AsyncRequestProcessor processor, SyncListener<R> procedure) {
-       processor.asyncRequest(this, procedure);
+        processor.asyncRequest(this, procedure);
     }
     
     @Override
     public R request(RequestProcessor processor) throws DatabaseException {
-       return processor.syncRequest(this);
+        return processor.syncRequest(this);
+    }
+    
+    @Override
+    public String toString() {
+        return getClass().getName() + "[" + parameter + "]";
     }
     
 }
index 3e955febc54743e25134184a2d7c3d9d85b9135c..a693b29228e026c1e1f6a5c7f3652c8d4320eb4c 100644 (file)
@@ -188,6 +188,8 @@ import org.simantics.utils.DataContainer;
 import org.simantics.utils.Development;
 import org.simantics.utils.datastructures.Pair;
 import org.simantics.utils.datastructures.collections.CollectionUtils;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
 import org.slf4j.LoggerFactory;
 
 import gnu.trove.map.hash.TObjectIntHashMap;
@@ -1923,7 +1925,12 @@ public class ReadGraphImpl implements AsyncReadGraph {
        @Override
        public <T> T syncRequest(final Read<T> request) throws DatabaseException {
                assert (request != null);
-               return (T)QueryCache.runnerReadEntry(this, request, parent, null, null, true);
+
+               ITask task = ThreadLogger.task(request);
+               T result = (T)QueryCache.runnerReadEntry(this, request, parent, null, null, true);
+               task.finish();
+               return result;
+               
        }
 
        @Override
@@ -1943,9 +1950,11 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                assert (request != null);
 
+               ITask task = ThreadLogger.task(request);
                ListenerBase listener = procedure != null ? getListenerBase(procedure) : null;
-
-               return QueryCache.resultReadEntry(this, request, parent, listener, procedure);
+               T result = QueryCache.resultReadEntry(this, request, parent, listener, procedure);
+               task.finish();
+               return result;
 
        }
 
@@ -2029,11 +2038,11 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                assert (request != null);
 
+               ITask task = ThreadLogger.task(request);
                ListenerBase listener = getListenerBase(procedure);
-
-//             BlockingAsyncProcedure<T> ap = new BlockingAsyncProcedure<>(this, procedure, request);
-               return (T)QueryCache.runnerAsyncReadEntry(this, request, parent, listener, procedure, true);
-//             return ap.get();
+               T result = (T)QueryCache.runnerAsyncReadEntry(this, request, parent, listener, procedure, true); 
+               task.finish();
+               return result;
 
        }
 
@@ -5232,13 +5241,29 @@ public class ReadGraphImpl implements AsyncReadGraph {
                assert (request != null);
                assert (procedure != null);
 
+               ITask task = ThreadLogger.task(request);
+
                processor.scheduleNow(new SessionTask(this) {
 
                        @Override
                        public void run0(int thread) {
                                try {
                                        final ListenerBase listener = getListenerBase(procedure);
-                                       QueryCache.runnerAsyncReadEntry(ReadGraphImpl.this, request, parent, listener, procedure, false);
+                                       QueryCache.runnerAsyncReadEntry(ReadGraphImpl.this, request, parent, listener, new AsyncProcedure<T>() {
+
+                                               @Override
+                                               public void execute(AsyncReadGraph graph, T result) {
+                                                       task.finish();
+                                                       procedure.execute(graph, result);
+                                               }
+
+                                               @Override
+                                               public void exception(AsyncReadGraph graph, Throwable throwable) {
+                                                       task.finish();
+                                                       procedure.exception(graph, throwable);
+                                               }
+                                               
+                                       }, false);
                                } catch (DatabaseException e) {
                                        Logger.defaultLogError(e);
                                }
index b98b4dec643383d163cd05746427db59b6c523ea..8220ba74385221cfc2064d6ff368c023c72f42b0 100644 (file)
@@ -635,7 +635,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
     @Override
     public <T> void scheduleRequest(final DelayedWrite request, final Consumer<DatabaseException> callback, final Semaphore notify, Boolean combine) {
 
-        final ITask total = ThreadLogger.getInstance().begin("ScheduleDelayedWrite");
+        final ITask total = ThreadLogger.task("ScheduleDelayedWrite");
 
         assert (request != null);
 
@@ -682,7 +682,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
 
                 delayedWriteState = null;
 
-                ITask task2 = ThreadLogger.getInstance().begin("DelayedWriteCommit");
+                ITask task2 = ThreadLogger.task("DelayedWriteCommit");
                 fireSessionVariableChange(SessionVariables.QUEUED_WRITES);
 
                 flushCounter = 0;
@@ -1496,8 +1496,6 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
         assert (request != null);
         assert (procedure != null);
 
-        //int thread = request.hashCode() & queryProvider2.THREAD_MASK;
-
         requestManager.scheduleRead(new SessionRead(throwable, notify) {
 
             @Override
@@ -1505,6 +1503,8 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
 
                 fireSessionVariableChange(SessionVariables.QUEUED_READS);
 
+                ITask task = ThreadLogger.task(request);
+
                 ListenerBase listener = getListenerBase(procedure);
 
                 final ReadGraphImpl newGraph = ReadGraphImpl.create(getQueryProvider2());
@@ -1549,8 +1549,6 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
 
                         try {
 
-//                            newGraph.state.barrier.inc();
-
                             T t = request.perform(newGraph);
 
                             try {
@@ -1594,9 +1592,8 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
                             }
 
                         }
-
-//                        newGraph.state.barrier.dec();
-//                        newGraph.waitAsync(request);
+                        
+                        task.finish();
 
                     }
 
@@ -1626,6 +1623,8 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
 
                 fireSessionVariableChange(SessionVariables.QUEUED_READS);
 
+                ITask task = ThreadLogger.task(request);
+
                 final ReadGraphImpl newGraph = ReadGraphImpl.create(getQueryProvider2());
 
                 try {
@@ -1634,18 +1633,25 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
 
                         try {
                                QueryCacheBase.resultAsyncReadEntry(newGraph, request, null, listener, procedure);
-                               //QueryCache.runnerAsyncReadEntry(newGraph, request, null, listener, procedure, true);
-                                                       //newGraph.processor.query(newGraph, request, null, procedure, listener);
                                                } catch (DatabaseException e) {
                                                        Logger.defaultLogError(e);
                                                }
 
                     } else {
 
-//                        final ResultCallWrappedSingleQueryProcedure4<T> wrapper = new ResultCallWrappedSingleQueryProcedure4<T>(
-//                                procedure, "request");
-
-                       BlockingAsyncProcedure<T> wrap = new BlockingAsyncProcedure<T>(newGraph.asyncBarrier, newGraph, procedure, request);
+                       BlockingAsyncProcedure<T> wrap = new BlockingAsyncProcedure<T>(newGraph.asyncBarrier, newGraph, procedure, request) {
+                               
+                               public void execute(AsyncReadGraph graph_, T result) {
+                                       task.finish();
+                                       super.execute(graph_, result);
+                               }
+                               
+                               public void exception(AsyncReadGraph graph_, Throwable t) {
+                                       task.finish();
+                                       super.exception(graph_, t);
+                               }
+                               
+                       };
 
                        try {
 
index 8f5afab1ac5faee7115d3164827014c3bbd100fe..0dea37763e727d2ddc7c778395b20a3690beebe1 100644 (file)
@@ -91,8 +91,8 @@ public class DiagramContentRequest extends BaseRequest<Resource, DiagramContents
                 // keep their order the same as in the ordered set.
                 final int elementIndex = index.getAndIncrement();
                 result.elements.add(component);
-
-                graph.forTypes(component, new ProcedureAdapter<Set<Resource>>() {
+                
+                graph.asyncRequest(new org.simantics.db.common.primitiverequest.Types(component), new ProcedureAdapter<Set<Resource>>() {
 
                     @Override
                     public void execute(Set<Resource> types) {
index 03cedfcb39a66cae558ccd27f0431bffa3dadadf..226f47daa76b62ea90f572d561aa75e6bc830295 100644 (file)
@@ -1649,7 +1649,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             this.removedRouteGraphConnections.clear();
         }
 
-        void processNodes(ReadGraph graph) throws DatabaseException {
+        void processNodes(AsyncReadGraph graph) throws DatabaseException {
 
             for (Map.Entry<Resource, Change> entry : changes.elements.entrySet()) {
 
@@ -1741,7 +1741,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                                     }
                                 };
 
-                                graph.syncRequest(new ConnectionRequest(canvas, diagram, element, errorHandler, loadListener), new AsyncProcedure<IElement>() {
+                                graph.asyncRequest(new ConnectionRequest(canvas, diagram, element, errorHandler, loadListener), new AsyncProcedure<IElement>() {
                                     @Override
                                     public void execute(AsyncReadGraph graph, final IElement e) {
 
@@ -1850,7 +1850,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                                 };
 
                                 //System.out.println("NODE REQUEST: " + element);
-                                graph.syncRequest(new NodeRequest(canvas, diagram, element, loadListener), new AsyncProcedure<IElement>() {
+                                graph.asyncRequest(new NodeRequest(canvas, diagram, element, loadListener), new AsyncProcedure<IElement>() {
                                     @Override
                                     public void execute(AsyncReadGraph graph, IElement e) {
                                     }
@@ -2105,7 +2105,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             return assertMappedConnection(connection);
         }
 
-        void processBranchPoints(ReadGraph graph) throws DatabaseException {
+        void processBranchPoints(AsyncReadGraph graph) throws DatabaseException {
             for (Map.Entry<Resource, Change> entry : changes.branchPoints.entrySet()) {
 
                 final Resource element = entry.getKey();
@@ -2116,7 +2116,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                         IElement mappedElement = getMappedElement(element);
                         if (mappedElement == null) {
                             if (DebugPolicy.DEBUG_NODE_LOAD)
-                                graph.syncRequest(new ReadRequest() {
+                                graph.asyncRequest(new ReadRequest() {
                                     @Override
                                     public void run(ReadGraph graph) throws DatabaseException {
                                         System.out.println("    EXTERNALLY ADDED BRANCH POINT: "
@@ -2186,7 +2186,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                                 }
                             };
 
-                            graph.syncRequest(new NodeRequest(canvas, diagram, element, loadListener), new AsyncProcedure<IElement>() {
+                            graph.asyncRequest(new NodeRequest(canvas, diagram, element, loadListener), new AsyncProcedure<IElement>() {
                                 @Override
                                 public void execute(AsyncReadGraph graph, IElement e) {
                                 }
@@ -2220,7 +2220,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             }
         }
 
-        void processConnectionSegments(ReadGraph graph) throws DatabaseException {
+        void processConnectionSegments(AsyncReadGraph graph) throws DatabaseException {
             ConnectionSegmentAdapter adapter = connectionSegmentAdapter;
 
             for (Map.Entry<EdgeResource, Change> entry : changes.connectionSegments.entrySet()) {
@@ -2232,7 +2232,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                         IElement mappedElement = getMappedElement(seg);
                         if (mappedElement == null) {
                             if (DebugPolicy.DEBUG_EDGE_LOAD)
-                                graph.syncRequest(new ReadRequest() {
+                                graph.asyncRequest(new ReadRequest() {
                                     @Override
                                     public void run(ReadGraph graph) throws DatabaseException {
                                         System.out.println("    EXTERNALLY ADDED CONNECTION SEGMENT: " + seg.toString()
@@ -2240,7 +2240,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                                     }
                                 });
 
-                            graph.syncRequest(new EdgeRequest(GraphToDiagramSynchronizer.this, canvas, errorHandler, canvasListenerSupport, diagram, adapter, seg), new AsyncProcedure<IElement>() {
+                            graph.asyncRequest(new EdgeRequest(GraphToDiagramSynchronizer.this, canvas, errorHandler, canvasListenerSupport, diagram, adapter, seg), new AsyncProcedure<IElement>() {
                                 @Override
                                 public void execute(AsyncReadGraph graph, IElement e) {
                                     if (DebugPolicy.DEBUG_EDGE_LOAD)
@@ -2268,7 +2268,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                     case REMOVED: {
                         final IElement e = getMappedElement(seg);
                         if (DebugPolicy.DEBUG_EDGE_LOAD)
-                            graph.syncRequest(new ReadRequest() {
+                            graph.asyncRequest(new ReadRequest() {
                                 @Override
                                 public void run(ReadGraph graph) throws DatabaseException {
                                     System.out.println("    EXTERNALLY REMOVED CONNECTION SEGMENT: " + seg.toString() + " - "
@@ -2319,13 +2319,15 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             if (changes.isEmpty())
                 return;
 
+            ITask threadLog = ThreadLogger.task("processNodes");
+            
             // NOTE: This order is important.
             Object task = Timing.BEGIN("processNodesConnections");
             //System.out.println("---- PROCESS NODES & CONNECTIONS BEGIN");
             if (!changes.elements.isEmpty()) {
-                graph.syncRequest(new ReadRequest() {
+                graph.syncRequest(new AsyncReadRequest() {
                     @Override
-                    public void run(ReadGraph graph) throws DatabaseException {
+                    public void run(AsyncReadGraph graph) throws DatabaseException {
                         processNodes(graph);
                     }
                     @Override
@@ -2336,13 +2338,21 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             }
             //System.out.println("---- PROCESS NODES & CONNECTIONS END");
 
+            threadLog.finish();
+            
+            threadLog = ThreadLogger.task("processConnections");
+
             processConnections();
 
+            threadLog.finish();
+
+            threadLog = ThreadLogger.task("processBranchPoints");
+
             //System.out.println("---- PROCESS BRANCH POINTS BEGIN");
             if (!changes.branchPoints.isEmpty()) {
-                graph.syncRequest(new ReadRequest() {
+                graph.syncRequest(new AsyncReadRequest() {
                     @Override
-                    public void run(ReadGraph graph) throws DatabaseException {
+                    public void run(AsyncReadGraph graph) throws DatabaseException {
                         processBranchPoints(graph);
                     }
                     @Override
@@ -2353,14 +2363,19 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             }
             //System.out.println("---- PROCESS BRANCH POINTS END");
 
+            threadLog.finish();
+
             Timing.END(task);
+
+            threadLog = ThreadLogger.task("processConnectionSegments");
+
             task = Timing.BEGIN("processConnectionSegments");
 
             //System.out.println("---- PROCESS CONNECTION SEGMENTS BEGIN");
             if (!changes.connectionSegments.isEmpty()) {
-                graph.syncRequest(new ReadRequest() {
+                graph.syncRequest(new AsyncReadRequest() {
                     @Override
-                    public void run(ReadGraph graph) throws DatabaseException {
+                    public void run(AsyncReadGraph graph) throws DatabaseException {
                         processConnectionSegments(graph);
                     }
                     @Override
@@ -2371,8 +2386,12 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             }
             //System.out.println("---- PROCESS CONNECTION SEGMENTS END");
 
+            threadLog.finish();
+
             Timing.END(task);
 
+            threadLog = ThreadLogger.task("processRouteGraphConnections");
+
             task = Timing.BEGIN("processRouteGraphConnections");
             if (!changes.routeGraphConnections.isEmpty()) {
                 graph.syncRequest(new ReadRequest() {
@@ -2388,6 +2407,8 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             }
             Timing.END(task);
 
+            threadLog.finish();
+
             //System.out.println("---- AFTER LOADING");
             //for (IElement e : addedElements)
             //    System.out.println("    ADDED ELEMENT: " + e);
@@ -2395,7 +2416,12 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             //    System.out.println("    ADDED BRANCH POINTS: " + e);
 
             task = Timing.BEGIN("executeDeferredLoaders");
+            threadLog = ThreadLogger.task("executeDeferredLoaders");
+            
             executeDeferredLoaders(graph);
+
+            threadLog.finish();
+
             Timing.END(task);
         }
 
index 53d1a029d439617258d0d93c2265542325d8a14f..5a1bb23fbdb13b3ba9c517cd7cea3b9bbf662ba3 100644 (file)
@@ -27,17 +27,40 @@ import java.util.Map;
 public class ThreadLogVisualizer {
        
     // Do not show tasks shorter than 5ms
-    final public static long DISCARD_LIMIT = 0;
+    final public static long DISCARD_LIMIT = 2 * 1000 * 1000;
     // 1s columns
     final public static long COLUMN_WIDTH = 1000000000;
     
+    final int onlyOneThread = -1;
+    
+    final String colors[] = {
+               "#53c0a7",
+               "#ca49a1",
+               "#64b74e",
+               "#a159ca",
+               "#b6b345",
+               "#656bc5",
+               "#da943b",
+               "#5e99d3",
+               "#d1592b",
+               "#418a53",
+               "#e16182",
+               "#777d34",
+               "#ca89ca",
+               "#b7754c",
+               "#9e4b6b",
+               "#cb4347"
+    };
+    
        class Task implements Comparable<Task> {
                String name;
                long beginTime;
                long endTime;
                long threadId;
+               long combined = 0;
                
                public Task(String name, long threadId, long beginTime, long endTime) {
+                       if(name.length() > 100) name = name.substring(0, 99);
                        this.name = name;
                        this.threadId = threadId;
                        this.beginTime = beginTime;
@@ -55,16 +78,48 @@ public class ThreadLogVisualizer {
        
        ArrayList<Task> tasks = new ArrayList<Task>();
        
+       private boolean acceptThread(long threadId) {
+               if(onlyOneThread == -1) return true;
+               else return (threadId&15) == onlyOneThread;
+       }
+       
+       private Map<Long, Task> compositeTasks = new HashMap<>();
+       
        public void read(DataInput input) {
                try {
                        while(true) {
                                try {
-                    String taskName = input.readUTF();
+                                       String taskName = input.readUTF();
                                        long threadId = input.readLong();
                                        long beginTime = input.readLong();
                                        long endTime = input.readLong();
-                                       if((endTime-beginTime) > DISCARD_LIMIT)
-                                           tasks.add(new Task(taskName, threadId, beginTime, endTime));
+                                       if(!acceptThread(threadId)) continue;
+                                       if((endTime-beginTime) > DISCARD_LIMIT) {
+                                               tasks.add(new Task(taskName, threadId, beginTime, endTime));
+                                               Task t = compositeTasks.remove(threadId);
+                                               if(t != null) {
+                                                       if((t.endTime-t.beginTime) > DISCARD_LIMIT) {
+                                                               tasks.add(new Task(t.combined + " small tasks", t.threadId, t.beginTime, t.endTime));   
+                                                       }
+                                               }
+                                       } else {
+                                               Task t = compositeTasks.get(threadId);
+                                               if(t == null) {
+                                                       t = new Task("", threadId, beginTime, endTime);
+                                                       compositeTasks.put(threadId, t);
+                                               }
+                                               if(beginTime - t.endTime > DISCARD_LIMIT) {
+                                                       tasks.add(new Task(t.combined + " small tasks", t.threadId, t.beginTime, t.endTime));
+                                                       t = new Task("", threadId, beginTime, endTime);
+                                                       compositeTasks.put(threadId, t);
+                                               }
+                                               t.endTime = endTime;
+                                               t.combined++;
+                                               if((t.endTime-t.beginTime) > DISCARD_LIMIT) {
+                                                       tasks.add(new Task(t.combined + " small tasks", t.threadId, t.beginTime, t.endTime));
+                                                       compositeTasks.remove(threadId);
+                                               }
+                                       }
                                } catch(EOFException e) {       
                                        break;
                                }
@@ -143,18 +198,19 @@ public class ThreadLogVisualizer {
                         (task.beginTime-minTime)*timeScale,
                         (r+1)*rowHeight);
                 s.printf(locale,
-                        "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"green\"/>\n",
+                        "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"" + colors[(int)task.threadId & 15] + "\"/>\n",
                         (task.beginTime-minTime)*timeScale,
                         r*rowHeight,
                         (task.endTime-task.beginTime)*timeScale,
                         rowHeight);
             }
             for(Task task : lane.tasks) {
+               int time = (int)(1e-6 * (task.endTime-task.beginTime));
                 s.printf(locale,
                         "<text x=\"%f\" y=\"%f\">%s</text>\n",
                         (task.endTime-minTime)*timeScale,
                         (r+0.8)*rowHeight,
-                        task.name);
+                        Integer.toString(time) + "ms: " + task.name);
             }
         }   
         s.println("</svg>");
@@ -209,7 +265,7 @@ public class ThreadLogVisualizer {
                                                (task.beginTime-minTime)*timeScale,
                                                (r+1)*rowHeight);
                                s.printf(locale,
-                                               "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"green\"/>\n",
+                                               "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"" + colors[(int)task.threadId & 15] + "\"/>\n",
                                                (task.beginTime-minTime)*timeScale,
                                                r*rowHeight,
                                                (task.endTime-task.beginTime)*timeScale,
@@ -263,7 +319,7 @@ public class ThreadLogVisualizer {
                                        (task.beginTime-minTime)*timeScale,
                                        (r+1)*rowHeight);
                        s.printf(locale,
-                                       "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"green\"/>\n",
+                                       "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" fill=\"" + colors[(int)task.threadId & 15] + "\"/>\n",
                                        (task.beginTime-minTime)*timeScale,
                                        r*rowHeight,
                                        (task.endTime-task.beginTime)*timeScale,
index d569d4aad2a3c4b4c70fd7d95a3d0be9963c7b85..2f3425c58b5be1975c3014fb7a1aee03c41154fa 100644 (file)
@@ -19,7 +19,9 @@ import java.io.IOException;
 
 public class ThreadLogger implements IThreadLogger {
 
-    public static String LOG_FILE = "d:\\threads.log";
+    final private static ITask DUMMY = () -> {};
+
+    public static String LOG_FILE = "threads.log";
     
     public static boolean LOG = false;
 
@@ -44,7 +46,7 @@ public class ThreadLogger implements IThreadLogger {
             synchronized (loggerCreationLock) {
                 if(logger == null)
                     logger = new ThreadLogger();       
-            }                   
+            }
         }
         return logger;
     }
@@ -87,5 +89,12 @@ public class ThreadLogger implements IThreadLogger {
     public ITask begin(String taskName) {
         return new Task(taskName);
     }
+    
+    final public static ITask task(Object taskName) {
+        if(LOG)
+            return getInstance().begin(taskName.toString());
+        else
+            return DUMMY;
+    }
 
 }