tmf/ctf: Show trace read progress in the progress bar
authorMatthew Khouzam <matthew.khouzam@ericsson.com>
Thu, 3 Mar 2016 23:17:24 +0000 (18:17 -0500)
committerMatthew Khouzam <matthew.khouzam@ericsson.com>
Thu, 14 Jul 2016 19:34:17 +0000 (15:34 -0400)
This patch adds an interface : ITmfTraceKnownSize. This interface
has two methods:
- size()
- progress()

If a tracetype implements these methods, the progress will show a scrolling
bar instead of the night-rider/battlestar galactica style slider of an
unknown progress bar.

Change-Id: If1b61957f26c2dec26543f64cfb42e12b127391c
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/67779
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Reviewed-by: Hudson CI
ctf/org.eclipse.tracecompass.tmf.ctf.core/META-INF/MANIFEST.MF
ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/trace/CtfTmfTrace.java
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/ITmfTraceKnownSize.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/indexer/checkpoint/TmfCheckpointIndexer.java

index 6bbeda1c6bdbe8f9020a69169475a99d71be2904..179db87af842282b43b56a8e84a06522166ad655 100644 (file)
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
 Bundle-Vendor: %Bundle-Vendor
-Bundle-Version: 2.0.0.qualifier
+Bundle-Version: 2.1.0.qualifier
 Bundle-Localization: plugin
 Bundle-SymbolicName: org.eclipse.tracecompass.tmf.ctf.core;singleton:=true
 Bundle-Activator: org.eclipse.tracecompass.internal.tmf.ctf.core.Activator
index 8bbf4a8cde948fb00bdaad3142c410a188400fcd..d06abe13d23953327414049865d06767403025a8 100644 (file)
@@ -37,8 +37,10 @@ import org.eclipse.tracecompass.ctf.core.CTFException;
 import org.eclipse.tracecompass.ctf.core.event.CTFClock;
 import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration;
 import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
+import org.eclipse.tracecompass.ctf.core.trace.CTFStreamInput;
 import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
 import org.eclipse.tracecompass.ctf.core.trace.CTFTraceReader;
+import org.eclipse.tracecompass.ctf.core.trace.ICTFStream;
 import org.eclipse.tracecompass.ctf.core.trace.Metadata;
 import org.eclipse.tracecompass.internal.tmf.ctf.core.Activator;
 import org.eclipse.tracecompass.internal.tmf.ctf.core.trace.iterator.CtfIterator;
@@ -53,6 +55,7 @@ import org.eclipse.tracecompass.tmf.core.project.model.ITmfPropertiesProvider;
 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceKnownSize;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceWithPreDefinedEvents;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
 import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
@@ -83,7 +86,7 @@ import com.google.common.collect.ImmutableSet;
  */
 public class CtfTmfTrace extends TmfTrace
         implements ITmfPropertiesProvider, ITmfPersistentlyIndexable,
-        ITmfTraceWithPreDefinedEvents {
+        ITmfTraceWithPreDefinedEvents, ITmfTraceKnownSize {
 
     // -------------------------------------------
     // Constants
@@ -91,6 +94,7 @@ public class CtfTmfTrace extends TmfTrace
 
     /**
      * Clock offset property
+     *
      * @since 1.2
      */
     public static final String CLOCK_OFFSET = "clock_offset"; //$NON-NLS-1$
@@ -102,16 +106,15 @@ public class CtfTmfTrace extends TmfTrace
 
     /**
      * Event aspects available for all CTF traces
+     *
      * @since 1.0
      */
-    protected static final @NonNull Collection<@NonNull ITmfEventAspect<?>> CTF_ASPECTS =
-            ImmutableList.of(
-                    TmfBaseAspects.getTimestampAspect(),
-                    new CtfChannelAspect(),
-                    new CtfCpuAspect(),
-                    TmfBaseAspects.getEventTypeAspect(),
-                    TmfBaseAspects.getContentsAspect()
-                    );
+    protected static final @NonNull Collection<@NonNull ITmfEventAspect<?>> CTF_ASPECTS = ImmutableList.of(
+            TmfBaseAspects.getTimestampAspect(),
+            new CtfChannelAspect(),
+            new CtfCpuAspect(),
+            TmfBaseAspects.getEventTypeAspect(),
+            TmfBaseAspects.getContentsAspect());
 
     /**
      * The Ctf clock unique identifier field
@@ -120,12 +123,26 @@ public class CtfTmfTrace extends TmfTrace
     private static final int CONFIDENCE = 10;
     private static final int MIN_CONFIDENCE = 1;
 
+    /**
+     * This is a reduction factor to avoid overflows.
+     */
+    private static final long REDUCTION_FACTOR = 4096;
+
+    /**
+     * Average CTF event size, used to estimate the trace size. (Inspired by
+     * empirical observations with LTTng kernel traces, to avoid hanging at 100%
+     * for too long)
+     *
+     * TODO: Find a more suitable approximation, perhaps per concrete trace type
+     * or per trace directly with the metadata
+     */
+    private static final int CTF_AVG_EVENT_SIZE = 16;
+
     // -------------------------------------------
     // Fields
     // -------------------------------------------
 
-    private final Map<@NonNull String, @NonNull CtfTmfEventType> fContainedEventTypes =
-            Collections.synchronizedMap(new HashMap<>());
+    private final Map<@NonNull String, @NonNull CtfTmfEventType> fContainedEventTypes = Collections.synchronizedMap(new HashMap<>());
 
     private final CtfIteratorManager fIteratorManager = new CtfIteratorManager(this);
 
@@ -270,11 +287,11 @@ public class CtfTmfTrace extends TmfTrace
      * Firstly a weak validation of the metadata is done to determine if the
      * path is actually for a CTF trace. After that a full validation is done.
      *
-     * If the weak and full validation are successful the confidence is set
-     * to 10.
+     * If the weak and full validation are successful the confidence is set to
+     * 10.
      *
-     * If the weak validation was successful, but the full validation fails
-     * TraceValidationStatus with severity warning and confidence of 1 is
+     * If the weak validation was successful, but the full validation fails a
+     * TraceValidationStatus with severity warning and confidence of 1 is
      * returned.
      *
      * If both weak and full validation fails an error status is returned.
@@ -300,12 +317,14 @@ public class CtfTmfTrace extends TmfTrace
                 }
 
                 // Validate using reader initialization
-                try (CTFTraceReader ctfTraceReader = new CTFTraceReader(trace)) {}
+                try (CTFTraceReader ctfTraceReader = new CTFTraceReader(trace)) {
+                    // do nothing
+                }
 
                 // Trace is validated, return with confidence
                 return new CtfTraceValidationStatus(CONFIDENCE, Activator.PLUGIN_ID, trace.getEnvironment());
 
-            } catch (final CTFException | BufferOverflowException e ) {
+            } catch (final CTFException | BufferOverflowException e) {
                 // return warning since it's a CTF trace but with errors in it
                 return new TraceValidationStatus(MIN_CONFIDENCE, IStatus.WARNING, Activator.PLUGIN_ID, Messages.CtfTmfTrace_ReadingError + ": " + e.toString(), e); //$NON-NLS-1$
             }
@@ -690,4 +709,32 @@ public class CtfTmfTrace extends TmfTrace
             Activator.getDefault().logError(e.getMessage(), e);
         }
     }
+
+    /**
+     * @return the number of estimated chunks of events read. This reads the
+     *         file size of the trace and divides it by a factor and the average
+     *         event size, this is not accurate but can give a ball park figure
+     *         of how much is done.
+     * @since 2.1
+     */
+    @Override
+    public int size() {
+        long size = 0;
+        Iterable<ICTFStream> streams = fTrace.getStreams();
+        for (ICTFStream stream : streams) {
+            for (CTFStreamInput si : stream.getStreamInputs()) {
+                size += si.getFile().length();
+            }
+        }
+        return (int) (size / REDUCTION_FACTOR / CTF_AVG_EVENT_SIZE);
+    }
+
+    /**
+     * @return the number of events divided a reduction factor. Is monotonic.
+     * @since 2.1
+     */
+    @Override
+    public int progress() {
+        return (int) (getNbEvents() / REDUCTION_FACTOR);
+    }
 }
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/ITmfTraceKnownSize.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/ITmfTraceKnownSize.java
new file mode 100644 (file)
index 0000000..8a671c3
--- /dev/null
@@ -0,0 +1,38 @@
+/**********************************************************************
+ * Copyright (c) 2016 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.core.trace;
+
+/**
+ * An interface that trace classes can implement if they have a known size, so
+ * that reading progress can be shown.
+ *
+ * @author Matthew Khouzam
+ * @since 2.1
+ */
+public interface ITmfTraceKnownSize {
+    /**
+     * Get the size of the trace. The units of this value are not important, but
+     * they should always be the same as {@link #progress()}
+     *
+     * @return the size of the trace. This can change from one call to the
+     *         other, but a later call to this method should not see a decrease
+     *         in size.
+     */
+    int size();
+
+    /**
+     * How much of the trace is read. The units of this value are not important,
+     * but they should always be the same as {@link #size()}
+     *
+     * @return how much of the trace is read. This should not exceed
+     *         {@link #size()}
+     */
+    int progress();
+}
index 355f67e04125323f5b4f9be867174b42dcaba7ce..01f9098389131f826497ca9a834adaaa535338f9 100644 (file)
@@ -16,6 +16,7 @@ package org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.tracecompass.internal.tmf.core.Activator;
@@ -32,6 +33,7 @@ import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceKnownSize;
 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
 import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
 
@@ -347,27 +349,42 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
 
     private final class TmfIndexingJob extends Job {
         private Exception fException = null;
+        private final ITmfTraceKnownSize fTraceWithSize;
 
         private TmfIndexingJob(String name) {
             super(name);
+            fTraceWithSize = (fTrace instanceof ITmfTraceKnownSize) ? (ITmfTraceKnownSize) fTrace : null;
         }
 
         @Override
         protected IStatus run(final IProgressMonitor monitor) {
-            monitor.beginTask("", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
+            int alreadyDone = 0;
+            SubMonitor subMonitor = SubMonitor.convert(monitor);
+            if (fTraceWithSize != null) {
+                subMonitor.beginTask("", fTraceWithSize.size()); //$NON-NLS-1$
+            } else {
+                subMonitor.beginTask("", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
+            }
             while (!monitor.isCanceled()) {
                 try {
                     long prevNbEvents = fTrace.getNbEvents();
                     Thread.sleep(250);
                     long nbEvents = fTrace.getNbEvents();
+                    if (fTraceWithSize != null) {
+                        final int done = fTraceWithSize.progress();
+                        subMonitor.setWorkRemaining(fTraceWithSize.size() - done);
+                        subMonitor.worked(done - alreadyDone);
+                        alreadyDone = done;
+                    }
                     setName(Messages.TmfCheckpointIndexer_Indexing + ' ' + fTrace.getName() + " (" + String.format("%,d", nbEvents) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                     // setName doesn't refresh the UI, setTaskName does
                     long rate = (nbEvents - prevNbEvents) * 4;
-                    monitor.setTaskName(String.format("%,d", rate) + " " + Messages.TmfCheckpointIndexer_EventsPerSecond); //$NON-NLS-1$ //$NON-NLS-2$
+                    subMonitor.setTaskName(String.format("%,d", rate) + " " + Messages.TmfCheckpointIndexer_EventsPerSecond); //$NON-NLS-1$ //$NON-NLS-2$
                 } catch (final InterruptedException e) {
                     return Status.OK_STATUS;
                 }
             }
+            subMonitor.done();
             monitor.done();
             return fException != null ? new Status(IStatus.ERROR, Activator.PLUGIN_ID, fException.getMessage(), fException) : Status.OK_STATUS;
         }
This page took 0.029688 seconds and 5 git commands to generate.