Skip to content
This repository has been archived by the owner on Nov 20, 2023. It is now read-only.

Commit

Permalink
timegraph: Implement "event owner" navigation mode
Browse files Browse the repository at this point in the history
Continue using an Eclipse Job for this action, it is important to report
progress in this case.

Refs #8.

Signed-off-by: Alexandre Montplaisir <[email protected]>
  • Loading branch information
Alexandre Montplaisir committed Mar 31, 2017
1 parent 1d3920a commit f55ca7f
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 56 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package org.lttng.scope.lttng.kernel.core.views.controlflow2;

import java.util.List;
import java.util.function.Predicate;

import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.lttng.scope.lttng.kernel.core.analysis.os.Attributes;
import org.lttng.scope.lttng.kernel.core.event.aspect.KernelTidAspect;
import org.lttng.scope.tmf2.views.core.timegraph.model.provider.statesystem.StateSystemTimeGraphTreeElement;
import org.lttng.scope.tmf2.views.core.timegraph.model.render.tree.TimeGraphTreeElement;

Expand Down Expand Up @@ -48,4 +51,16 @@ public String getThreadName() {
return fThreadName;
}

@Override
public @Nullable Predicate<ITmfEvent> getEventMatching() {
/*
* This tree element represents a thread ID. Return true for events
* whose TID aspect is the same as the TID of this element.
*/
return event -> {
Integer eventTid = KernelTidAspect.INSTANCE.resolve(event);
return (eventTid != null && eventTid.intValue() == fTid);
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ public void dispose() {
// Accessors
// ------------------------------------------------------------------------

@Nullable ITmfTrace getCurrentTrace() {
/**
* Get the trace currently being tracked by this control.
*
* @return The trace, may be null if there is no trace
*/
public @Nullable ITmfTrace getCurrentTrace() {
return fCurrentTrace;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ public LineThickness getLineThickness() {
return fLineThickness;
}

public TimeGraphTreeElement getTreeElement() {
return getStartEvent().getTreeElement();
}

@Override
public int hashCode() {
return Objects.hash(fStartEvent, fEndEvent, fStateName, fLabel, fColor, fLineThickness);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
Expand All @@ -35,12 +37,21 @@ public List<TimeGraphTreeElement> getChildElements() {
return fChildElements;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("fName", fName) //$NON-NLS-1$
.add("fChildElements", fChildElements.toString()) //$NON-NLS-1$
.toString();
/**
* Determine if and how this tree element corresponds to a component of a
* trace event.
*
* For example, if this tree element represents "CPU #2", then the predicate
* should return true for all trace events belonging to CPU #2.
*
* The method returns null if this tree element does not correspond to a
* particular aspect of trace events.
*
* @return The event matching predicate, if there is one
*/
public @Nullable Predicate<ITmfEvent> getEventMatching() {
/* Sub-classes can override */
return null;
}

@Override
Expand All @@ -64,6 +75,12 @@ public boolean equals(@Nullable Object obj) {
&& Objects.equals(fChildElements, other.fChildElements);
}


@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("fName", fName) //$NON-NLS-1$
.add("fChildElements", fChildElements.toString()) //$NON-NLS-1$
.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public class Messages extends NLS {
public static String sfFollowArrowsNavModeName;
public static String sfFollowBookmarksNavModeName;

public static String sfNextEventJobName;
public static String sfPreviousEventJobName;

static {
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2017 EfficiOS Inc., Alexandre Montplaisir <[email protected]>
*
* 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.lttng.scope.tmf2.views.ui.timegraph.swtjfx.toolbar.nav;

import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.lttng.scope.tmf2.views.core.TimeRange;
import org.lttng.scope.tmf2.views.ui.timegraph.swtjfx.SwtJfxTimeGraphViewer;

/**
* Common utilities for navigation actions.
*
* @author Alexandre Montplaisir
*/
final class NavUtils {

private NavUtils() {}

/**
* Move the selection to the target timestamp. Also update the visible range
* to be centered on that timestamp, but only if it is outside of the
* current visible range.
*
* This should only be called when reaching the new timestamp is caused by a
* user action (ie, not simply because another view sent a signal).
*
* @param viewer
* The viewer on which to work
* @param timestamp
* The timestamp to select, and potentially move to
*/
public static void selectNewTimestamp(SwtJfxTimeGraphViewer viewer, long timestamp) {
/* Update the selection to the new timestamp. */
viewer.getControl().updateTimeRangeSelection(TimeRange.of(timestamp, timestamp));

TimeRange fullTimeGraphRange = viewer.getControl().getFullTimeGraphRange();
TmfTimeRange windowRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
long windowStart = windowRange.getStartTime().toNanos();
long windowEnd = windowRange.getEndTime().toNanos();
if (windowStart <= timestamp && timestamp <= windowEnd) {
/* Timestamp is still in the visible range, don't touch anything. */
return;
}
/* Update the visible range to the requested timestamp. */
/* The "span" of the window (aka zoom level) will remain constant. */
long windowSpan = windowEnd - windowStart;
if (windowSpan > fullTimeGraphRange.getDuration()) {
/* Should never happen, but just to be mathematically safe. */
windowSpan = fullTimeGraphRange.getDuration();
}

long newStart = timestamp - (windowSpan / 2);
long newEnd = newStart + windowSpan;

/* Clamp the range to the borders of the pane/trace. */
if (newStart < fullTimeGraphRange.getStart()) {
newStart = fullTimeGraphRange.getStart();
newEnd = newStart + windowSpan;
} else if (newEnd > fullTimeGraphRange.getEnd()) {
newEnd = fullTimeGraphRange.getEnd();
newStart = newEnd - windowSpan;
}

viewer.getControl().updateVisibleTimeRange(TimeRange.of(newStart, newEnd), true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@

import static java.util.Objects.requireNonNull;

import java.util.function.Predicate;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
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.TmfTraceManager;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.lttng.scope.tmf2.views.ui.timegraph.swtjfx.StateRectangle;
import org.lttng.scope.tmf2.views.ui.timegraph.swtjfx.SwtJfxTimeGraphViewer;

/**
Expand All @@ -26,6 +41,21 @@ public class NavigationModeFollowEvents extends NavigationMode {
private static final String BACK_ICON_PATH = "/icons/toolbar/nav_event_back.gif"; //$NON-NLS-1$
private static final String FWD_ICON_PATH = "/icons/toolbar/nav_event_fwd.gif"; //$NON-NLS-1$

/**
* Mutex rule for search action jobs, making sure they execute sequentially
*/
private final ISchedulingRule fSearchActionMutexRule = new ISchedulingRule() {
@Override
public boolean isConflicting(@Nullable ISchedulingRule rule) {
return (rule == this);
}

@Override
public boolean contains(@Nullable ISchedulingRule rule) {
return (rule == this);
}
};

/**
* Constructor
*/
Expand All @@ -37,14 +67,51 @@ public NavigationModeFollowEvents() {

@Override
public void navigateBackwards(SwtJfxTimeGraphViewer viewer) {
// TODO NYI
System.out.println("Follow events backwards");
navigate(viewer, false);
}

@Override
public void navigateForwards(SwtJfxTimeGraphViewer viewer) {
// TODO NYI
System.out.println("Follow events forwards");
navigate(viewer, true);
}

private void navigate(SwtJfxTimeGraphViewer viewer, boolean forward) {
StateRectangle state = viewer.getSelectedState();
ITmfTrace trace = viewer.getControl().getCurrentTrace();
if (state == null || trace == null) {
return;
}
Predicate<ITmfEvent> predicate = state.getStateInterval().getTreeElement().getEventMatching();
if (predicate == null) {
/* The tree element does not support navigating by events. */
return;
}

String jobName = (forward ? Messages.sfNextEventJobName : Messages.sfPreviousEventJobName);

Job job = new Job(jobName) {
@Override
protected IStatus run(@Nullable IProgressMonitor monitor) {
long currentTime = TmfTraceManager.getInstance().getCurrentTraceContext().getSelectionRange().getStartTime().toNanos();
ITmfContext ctx = trace.seekEvent(TmfTimestamp.fromNanos(currentTime));
long rank = ctx.getRank();
ctx.dispose();

ITmfEvent event = (forward ?
TmfTraceUtils.getNextEventMatching(trace, rank, predicate, monitor) :
TmfTraceUtils.getPreviousEventMatching(trace, rank, predicate, monitor));
if (event != null) {
NavUtils.selectNewTimestamp(viewer, event.getTimestamp().toNanos());
}
return Status.OK_STATUS;
}
};

/*
* Make subsequent jobs not run concurrently, but wait after one
* another.
*/
job.setRule(fSearchActionMutexRule);
job.schedule();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.lttng.scope.tmf2.views.core.TimeRange;
import org.lttng.scope.tmf2.views.core.timegraph.model.render.tree.TimeGraphTreeElement;
import org.lttng.scope.tmf2.views.ui.timegraph.swtjfx.MultiStateInterval;
import org.lttng.scope.tmf2.views.ui.timegraph.swtjfx.StateRectangle;
Expand Down Expand Up @@ -82,8 +79,7 @@ private static void navigate(SwtJfxTimeGraphViewer viewer, boolean forward) {
* Go to the end/start of the current state.
*/
long bound = (forward ? stateEndTime : stateStartTime);
viewer.getControl().updateTimeRangeSelection(TimeRange.of(bound, bound));
updateVisibleRange(viewer, bound);
NavUtils.selectNewTimestamp(viewer, bound);
return;
}

Expand Down Expand Up @@ -123,9 +119,7 @@ private static void navigate(SwtJfxTimeGraphViewer viewer, boolean forward) {
}

viewer.setSelectedState(newState);

viewer.getControl().updateTimeRangeSelection(TimeRange.of(targetTimestamp, targetTimestamp));
updateVisibleRange(viewer, targetTimestamp);
NavUtils.selectNewTimestamp(viewer, targetTimestamp);
}

/**
Expand Down Expand Up @@ -214,40 +208,4 @@ private static Optional<StateRectangle> getBestPotentialState(List<StateRectangl
.findFirst();
}

/**
* Update the visible range to be centered on 'timestamp', but only if it is
* outside of the current visible range.
*/
private static void updateVisibleRange(SwtJfxTimeGraphViewer viewer, long timestamp) {
TimeRange fullTimeGraphRange = viewer.getControl().getFullTimeGraphRange();
TmfTimeRange windowRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
long windowStart = windowRange.getStartTime().toNanos();
long windowEnd = windowRange.getEndTime().toNanos();
if (windowStart <= timestamp && timestamp <= windowEnd) {
/* Timestamp is still in the visible range, don't touch anything. */
return;
}
/* Update the visible range to the requested timestamp. */
/* The "span" of the window (aka zoom level) will remain constant. */
long windowSpan = windowEnd - windowStart;
if (windowSpan > fullTimeGraphRange.getDuration()) {
/* Should never happen, but just to be mathematically safe. */
windowSpan = fullTimeGraphRange.getDuration();
}

long newStart = timestamp - (windowSpan / 2);
long newEnd = newStart + windowSpan;

/* Clamp the range to the borders of the pane/trace. */
if (newStart < fullTimeGraphRange.getStart()) {
newStart = fullTimeGraphRange.getStart();
newEnd = newStart + windowSpan;
} else if (newEnd > fullTimeGraphRange.getEnd()) {
newEnd = fullTimeGraphRange.getEnd();
newStart = newEnd - windowSpan;
}

viewer.getControl().updateVisibleTimeRange(TimeRange.of(newStart, newEnd), true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ sfFollowStateChangesNavModeName = Follow State Changes
sfFollowEventsNavModeName = Follow Events
sfFollowArrowsNavModeName = Follow Arrows
sfFollowBookmarksNavModeName = Follow Bookmarks

sfNextEventJobName = Searching for next matching event
sfPreviousEventJobName = Searching for previous matching event

0 comments on commit f55ca7f

Please sign in to comment.