From a839e1659750c2e89976f7aa9ed431c315abbac4 Mon Sep 17 00:00:00 2001 From: Matthew Khouzam Date: Wed, 3 May 2023 18:24:43 -0400 Subject: [PATCH] tmf.ui: Cache size and bounds on resize or move It is impossible to resize while in a paint operation, so the getSize() and getBounds() operation can be cached. In doing this, each link does not call the getSize() and getBounds() functions twice per draw. Accelerates from 15s/draw to 500ms/draw on "bar code" style images. This is very evident on trace compass traces, especially while using LogLevel#Finest [Changed] Improve performance of timegraph with many links/markers Change-Id: I7e228056ef28a988d4c8d7fb3803f16e1b1bfb6d Signed-off-by: Matthew Khouzam Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/201710 Tested-by: Trace Compass Bot Tested-by: Patrick Tasse Reviewed-by: Patrick Tasse --- .../timegraph/widgets/TimeGraphControl.java | 65 +++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java index 2000a47edf..82f60be406 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java @@ -57,6 +57,7 @@ import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.FocusEvent; @@ -152,7 +153,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener, MouseTrackListener, TraverseListener, ISelectionProvider, - MenuDetectListener, ITmfTimeGraphDrawingHelper, ITimeGraphColorListener, Listener { + MenuDetectListener, ITmfTimeGraphDrawingHelper, ITimeGraphColorListener, ControlListener, Listener { /** * Default state width ratio @@ -301,6 +302,9 @@ public class TimeGraphControl extends TimeGraphBaseControl private List fSelectedRectangles = new ArrayList<>(); + private @Nullable Point fSize = null; + private @Nullable Rectangle fBounds = null; + private final @NonNull String fPaintScopeLabel = getClass().getCanonicalName() + "#paint"; //$NON-NLS-1$ private final @NonNull String fBackgroundScopeLabel = getClass().getCanonicalName() + "#drawBackground"; //$NON-NLS-1$ private final @NonNull String fGridLinesScopeLabel = getClass().getCanonicalName() + "#drawGridlines"; //$NON-NLS-1$ @@ -328,6 +332,7 @@ public TimeGraphControl(Composite parent, TimeGraphColorScheme colors) { fItemData = new ItemData(); + addControlListener(this); addFocusListener(this); addMouseListener(this); addMouseMoveListener(this); @@ -1772,12 +1777,49 @@ public int getXForTime(long time) { } long time0 = fTimeProvider.getTime0(); long time1 = fTimeProvider.getTime1(); - int width = getSize().x; + int width = getWidth(); int nameSpace = fTimeProvider.getNameSpace(); double pixelsPerNanoSec = (width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (width - nameSpace - RIGHT_MARGIN) / (time1 - time0); return SaturatedArithmetic.add(getBounds().x + nameSpace, (int) ((time - time0) * pixelsPerNanoSec)); } + @Override + public Point getSize() { + Point size = fSize; + if (size == null) { + size = Objects.requireNonNull(super.getSize()); + fSize = size; + } + return new Point(size.x, size.y); + } + + @Override + public Rectangle getBounds() { + Rectangle bounds = fBounds; + if (bounds == null) { + bounds = Objects.requireNonNull(super.getBounds()); + fBounds = bounds; + } + return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height); + } + + /** + * Returns a integer describing the receiver's width in points. + * + * @return the receiver's width + * + * @exception SWTException + *
    + *
  • ERROR_WIDGET_DISPOSED - if the receiver has been + * disposed
  • + *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the + * thread that created the receiver
  • + *
+ */ + private int getWidth() { + return getSize().x; + } + @Override public long getTimeAtX(int coord) { if (null == fTimeProvider) { @@ -3422,7 +3464,7 @@ public void mouseDown(MouseEvent e) { } if (fTimeProvider == null || fTimeProvider.getTime0() == fTimeProvider.getTime1() || - getSize().x - fTimeProvider.getNameSpace() <= 0) { + getWidth() - fTimeProvider.getNameSpace() <= 0) { return; } if (1 == e.button && ((e.stateMask & SWT.MODIFIER_MASK) == 0 || (e.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT)) { @@ -3485,7 +3527,7 @@ public void mouseDown(MouseEvent e) { } else if (3 == e.button) { if (e.x >= fTimeProvider.getNameSpace()) { setCapture(true); - fDragX = Math.min(Math.max(e.x, fTimeProvider.getNameSpace()), getSize().x - RIGHT_MARGIN); + fDragX = Math.min(Math.max(e.x, fTimeProvider.getNameSpace()), getWidth() - RIGHT_MARGIN); fDragX0 = fDragX; fDragTime0 = getTimeAtX(fDragX0); fDragState = DRAG_ZOOM; @@ -4291,4 +4333,19 @@ public boolean isHideEmptyRowsFilterActive() { public void setHideEmptyRowsFilterActive(boolean hideEmptyRowsFilterActive) { fHideEmptyRowsFilterActive = hideEmptyRowsFilterActive; } + + @Override + public void controlMoved(ControlEvent e) { + resetCache(); + } + + @Override + public void controlResized(ControlEvent e) { + resetCache(); + } + + private void resetCache() { + fBounds = null; + fSize = null; + } }