critical path: bug 489360 Build the critical path in a separate thread
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.graph.ui / src / org / eclipse / tracecompass / internal / analysis / graph / ui / criticalpath / view / CriticalPathView.java
index 64afc95099fae183f599e7ee0b54b34ecf61c279..1fab74e3e32850f1301989bdbede2e776dbd98b7 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015 École Polytechnique de Montréal
+ * Copyright (c) 2015, 2016 École Polytechnique de Montréal
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -15,9 +15,10 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
@@ -82,9 +83,9 @@ public class CriticalPathView extends AbstractTimeGraphView {
             COLUMN_PROCESS
     };
 
-    private final Table<ITmfTrace, Object, List<ILinkEvent>> fLinks = NonNullUtils.checkNotNull(HashBasedTable.<ITmfTrace, Object, List<ILinkEvent>> create());
+    private final Table<ITmfTrace, Object, List<ILinkEvent>> fLinks = HashBasedTable.create();
     /** The trace to entry list hash map */
-    private final Table<ITmfTrace, Object, TmfGraphStatistics> fObjectStatistics = NonNullUtils.checkNotNull(HashBasedTable.<ITmfTrace, Object, TmfGraphStatistics> create());
+    private final Table<ITmfTrace, Object, TmfGraphStatistics> fObjectStatistics = HashBasedTable.create();
 
     private final CriticalPathContentProvider fContentProvider = new CriticalPathContentProvider();
 
@@ -154,7 +155,7 @@ public class CriticalPathView extends AbstractTimeGraphView {
             public void visit(TmfEdge link, boolean horizontal) {
                 if (horizontal) {
                     Object parent = fGraph.getParentOf(link.getVertexFrom());
-                    CriticalPathEntry entry = checkNotNull(fRootList.get(parent));
+                    CriticalPathEntry entry = fRootList.get(parent);
                     TimeEvent ev = new TimeEvent(entry, link.getVertexFrom().getTs(), link.getDuration(),
                             getMatchingState(link.getType()).ordinal());
                     entry.addEvent(ev);
@@ -197,13 +198,51 @@ public class CriticalPathView extends AbstractTimeGraphView {
             }
         }
 
-        private Map<Object, Map<Object, CriticalPathEntry>> workerMaps = new HashMap<>();
-        private Map<Object, List<TimeGraphEntry>> workerEntries = new HashMap<>();
-        private Map<Object, List<ILinkEvent>> linkMap = new HashMap<>();
+        private class BuildThread extends Thread {
+            private final ITmfTrace fBuildTrace;
+            private final IProgressMonitor fMonitor;
+
+            public BuildThread(final ITmfTrace trace) {
+                super("Critical path view build"); //$NON-NLS-1$
+                fBuildTrace = trace;
+                fMonitor = new NullProgressMonitor();
+            }
+
+            @Override
+            public void run() {
+                try {
+                    CriticalPathModule module = Iterables.<@Nullable CriticalPathModule> getFirst(
+                            TmfTraceUtils.getAnalysisModulesOfClass(fBuildTrace, CriticalPathModule.class),
+                            null);
+                    if (module == null) {
+                        return;
+                    }
+                    module.schedule();
+                    if (module.waitForCompletion(fMonitor)) {
+                        refresh();
+                    }
+
+                } finally {
+                    fSyncLock.lock();
+                    fBuildThread = null;
+                    fSyncLock.unlock();
+                }
+            }
+
+            public void cancel() {
+                fMonitor.setCanceled(true);
+            }
+        }
+
+        private final Lock fSyncLock = new ReentrantLock();
+        private final Map<Object, Map<Object, CriticalPathEntry>> workerMaps = new HashMap<>();
+        private final Map<Object, List<TimeGraphEntry>> workerEntries = new HashMap<>();
+        private final Map<Object, List<ILinkEvent>> linkMap = new HashMap<>();
         private @Nullable Object fCurrentObject;
+        private @Nullable BuildThread fBuildThread = null;
 
         @Override
-        public @Nullable ITimeGraphEntry[] getElements(@Nullable Object inputElement) {
+        public ITimeGraphEntry[] getElements(@Nullable Object inputElement) {
             ITimeGraphEntry[] ret = new ITimeGraphEntry[0];
             if (inputElement instanceof List) {
                 List<?> list = (List<?>) inputElement;
@@ -225,9 +264,10 @@ public class CriticalPathView extends AbstractTimeGraphView {
                 buildEntryList(worker);
                 entries = workerEntries.get(worker);
             }
+
             return (entries == null) ?
                 new ITimeGraphEntry[0] :
-                NonNullUtils.checkNotNull(entries.toArray(new ITimeGraphEntry[entries.size()]));
+                entries.toArray(new @NonNull ITimeGraphEntry[entries.size()]);
         }
 
         private void buildEntryList(IGraphWorker worker) {
@@ -268,21 +308,17 @@ public class CriticalPathView extends AbstractTimeGraphView {
                 list.add(defaultParent);
             }
 
-            for (TimeGraphEntry entry : list) {
-                buildStatusEvents(trace, (CriticalPathEntry) NonNullUtils.checkNotNull(entry));
-            }
             workerEntries.put(worker, list);
         }
 
         private @Nullable TmfGraph getGraph(final ITmfTrace trace) {
-            CriticalPathModule module = Iterables.getFirst(TmfTraceUtils.getAnalysisModulesOfClass(trace, CriticalPathModule.class), null);
+            CriticalPathModule module = Iterables.<@Nullable CriticalPathModule> getFirst(
+                    TmfTraceUtils.getAnalysisModulesOfClass(trace, CriticalPathModule.class),
+                    null);
             if (module == null) {
-                return null;
-            }
-            module.schedule();
-            if (!module.waitForCompletion()) {
-                return null;
+                throw new IllegalStateException("View requires an analysis module"); //$NON-NLS-1$
             }
+
             final TmfGraph graph = module.getCriticalPath();
             return graph;
         }
@@ -304,10 +340,12 @@ public class CriticalPathView extends AbstractTimeGraphView {
             if (trace == null) {
                 return null;
             }
-            CriticalPathModule module = Iterables.getFirst(TmfTraceUtils.getAnalysisModulesOfClass(trace, CriticalPathModule.class), null);
+            CriticalPathModule module = Iterables.<@Nullable CriticalPathModule> getFirst(
+                    TmfTraceUtils.getAnalysisModulesOfClass(trace, CriticalPathModule.class), null);
             if (module == null) {
-                return null;
+                throw new IllegalStateException("View requires an analysis module"); //$NON-NLS-1$
             }
+
             final TmfGraph graph = module.getCriticalPath();
             if (graph == null) {
                 return null;
@@ -323,7 +361,7 @@ public class CriticalPathView extends AbstractTimeGraphView {
 
             /* find vertical links */
             graph.scanLineTraverse(vertex, new VerticalLinksVisitor(graph, graphLinks, entryMap));
-            fLinks.put(trace, fCurrentObject, graphLinks);
+            fLinks.put(trace, checkNotNull(fCurrentObject), graphLinks);
             links = graphLinks;
 
             List<ILinkEvent> linksInRange = new ArrayList<>();
@@ -338,15 +376,50 @@ public class CriticalPathView extends AbstractTimeGraphView {
 
         @Override
         public void dispose() {
-
+            fSyncLock.lock();
+            try {
+                BuildThread buildThread = fBuildThread;
+                if (buildThread != null) {
+                    buildThread.cancel();
+                }
+            } finally {
+                fSyncLock.unlock();
+            }
         }
 
         @Override
         public void inputChanged(@Nullable Viewer viewer, @Nullable Object oldInput, @Nullable Object newInput) {
+            // The input has changed, the critical path will be re-computed,
+            // wait for the analysis to be finished, then call the refresh
+            // method of the view
+            if (!(newInput instanceof List)) {
+                return;
+            }
+            List<?> list = (List<?>) newInput;
+            if (list.isEmpty()) {
+                return;
+            }
+            final ITmfTrace trace = getTrace();
+            if (trace == null) {
+                return;
+            }
+
+            fSyncLock.lock();
+            try {
+                BuildThread buildThread = fBuildThread;
+                if (buildThread != null) {
+                    buildThread.cancel();
+                }
+                buildThread = new BuildThread(trace);
+                buildThread.start();
+                fBuildThread = buildThread;
+            } finally {
+                fSyncLock.unlock();
+            }
         }
 
         @Override
-        public @Nullable ITimeGraphEntry[] getChildren(@Nullable Object parentElement) {
+        public ITimeGraphEntry @Nullable [] getChildren(@Nullable Object parentElement) {
             if (parentElement instanceof CriticalPathEntry) {
                 List<? extends ITimeGraphEntry> children = ((CriticalPathEntry) parentElement).getChildren();
                 return children.toArray(new TimeGraphEntry[children.size()]);
@@ -452,6 +525,9 @@ public class CriticalPathView extends AbstractTimeGraphView {
         case USER_INPUT:
             state = State.USER_INPUT;
             break;
+        case IPI:
+            state = State.IPI;
+            break;
         case EPS:
         case UNKNOWN:
         case DEFAULT:
@@ -463,27 +539,8 @@ public class CriticalPathView extends AbstractTimeGraphView {
         return state;
     }
 
-    private void buildStatusEvents(ITmfTrace trace, CriticalPathEntry entry) {
-
-        long start = trace.getStartTime().getValue();
-        long end = trace.getEndTime().getValue() + 1;
-        long resolution = Math.max(1, (end - start) / getDisplayWidth());
-        List<ITimeEvent> eventList = getEventList(entry, entry.getStartTime(), entry.getEndTime(), resolution, new NullProgressMonitor());
-
-        entry.setZoomedEventList(eventList);
-
-        redraw();
-
-        for (ITimeGraphEntry child : entry.getChildren()) {
-            if (child == null) {
-                throw new NullPointerException();
-            }
-            buildStatusEvents(trace, (CriticalPathEntry) child);
-        }
-    }
-
     @Override
-    protected void buildEventList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor) {
+    protected void buildEntryList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor) {
         /* This class uses a content provider instead */
     }
 
@@ -491,31 +548,11 @@ public class CriticalPathView extends AbstractTimeGraphView {
     protected @Nullable List<ITimeEvent> getEventList(TimeGraphEntry entry,
             long startTime, long endTime, long resolution,
             IProgressMonitor monitor) {
-
-        final long realStart = Math.max(startTime, entry.getStartTime());
-        final long realEnd = Math.min(endTime, entry.getEndTime());
-        if (realEnd <= realStart) {
-            return null;
-        }
-        List<ITimeEvent> eventList = null;
-        entry.setZoomedEventList(null);
-        Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator();
-        eventList = new ArrayList<>();
-
-        while (iterator.hasNext()) {
-            ITimeEvent event = iterator.next();
-            /* is event visible */
-            if (intersects(realStart, realEnd, NonNullUtils.checkNotNull(event))) {
-                eventList.add(event);
-            }
-        }
-        return eventList;
-    }
-
-    private static boolean intersects(final long realStart, final long realEnd, ITimeEvent event) {
-        return ((event.getTime() >= realStart) && (event.getTime() <= realEnd)) ||
-                ((event.getTime() + event.getDuration() > realStart) &&
-                        (event.getTime() + event.getDuration() < realEnd));
+        /*
+         * The event list is built in the HorizontalLinksVisitor. This is called
+         * only from the zoom thread and only for the CriticalPathBaseEntry.
+         */
+        return null;
     }
 
     @Override
This page took 0.029484 seconds and 5 git commands to generate.