From ed326d947277b25f1e708ce47636dd7e25a6ff6d Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 16 Mar 2022 13:30:25 +0100 Subject: [PATCH] perf(flamegraph): Only repaint hovered rectangle --- .../fireplace/flamegraph/FlameGraph.java | 11 +++--- .../flamegraph/FlameGraphPainter.java | 37 ++++++++++++++----- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraph.java b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraph.java index 455be491..eaba1cd5 100644 --- a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraph.java +++ b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraph.java @@ -187,6 +187,7 @@ public void setData(List> frames, canvas.setFlameGraphPainter(flameGraphPainter); canvas.setToolTipTextFunction(tooltipTextFunction); canvas.invalidate(); + canvas.repaint(); } /** @@ -287,9 +288,9 @@ public void mouseClicked(MouseEvent e) { .ifPresent(fgp -> { fgp.toggleSelectedFrameAt( (Graphics2D) viewPort.getView().getGraphics(), - point + point, + (frame, r) -> canvas.repaint() ); - scrollPane.repaint(); }); } } @@ -308,7 +309,7 @@ public void mouseExited(MouseEvent e) { var scrollPane = (JScrollPane) e.getComponent(); canvas.getFlameGraphPainter() .ifPresent(FlameGraphPainter::stopHover); - scrollPane.repaint(); + canvas.repaint(); } } @@ -328,9 +329,9 @@ public void mouseMoved(MouseEvent e) { .ifPresent(fgp -> fgp.hoverFrameAt( (Graphics2D) view.getGraphics(), point, - frame -> { + (frame, r) -> { canvas.setToolTipText(frame); - scrollPane.repaint(); + canvas.repaint(r); } )); } diff --git a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraphPainter.java b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraphPainter.java index 99c77684..634601a3 100644 --- a/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraphPainter.java +++ b/fireplace-swing/src/main/java/io/github/bric3/fireplace/flamegraph/FlameGraphPainter.java @@ -14,6 +14,7 @@ import java.awt.*; import java.util.List; import java.util.Optional; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -222,14 +223,14 @@ private void paint(Graphics2D g2, Rectangle visibleRect, boolean minimapMode) { var nowWidth = g2d.getFontMetrics().stringWidth(drawTimeMs); g2d.setColor(Color.DARK_GRAY); g2d.fillRect(visibleRect.x + visibleRect.width - nowWidth - textBorder * 2, - visibleRect.y + visibleRect.height - frameBoxHeight, - nowWidth + textBorder * 2, - frameBoxHeight); + visibleRect.y + visibleRect.height - frameBoxHeight, + nowWidth + textBorder * 2, + frameBoxHeight); g2d.setColor(Color.YELLOW); g2d.drawString(drawTimeMs, - visibleRect.x + visibleRect.width - nowWidth - textBorder, - visibleRect.y + visibleRect.height - textBorder); + visibleRect.x + visibleRect.width - nowWidth - textBorder, + visibleRect.y + visibleRect.height - textBorder); } g2d.dispose(); @@ -328,6 +329,17 @@ private Rectangle paintFrameRectangle(Graphics2D g2, Rectangle frameRect, Color return frameRect; } + public Rectangle getFrameRectangle(Graphics2D g2, FrameBox frame) { + var frameBoxHeight = getFrameBoxHeight(g2); + + var rect = new Rectangle(); + rect.x = (int) (flameGraphWidth * frame.startX); // + internalPadding; + rect.width = (int) (flameGraphWidth * frame.endX) - rect.x; // - internalPadding; + rect.y = frameBoxHeight * frame.stackDepth; + rect.height = frameBoxHeight; + return rect; + } + public Optional> getFrameAt(Graphics2D g2, Point point) { int depth = point.y / getFrameBoxHeight(g2); double xLocation = ((double) point.x) / flameGraphWidth; @@ -337,21 +349,28 @@ public Optional> getFrameAt(Graphics2D g2, Point point) { .findFirst(); } - public void toggleSelectedFrameAt(Graphics2D g2, Point point) { + public void toggleSelectedFrameAt(Graphics2D g2, Point point, BiConsumer, Rectangle> toggleConsumer) { getFrameAt( g2, point - ).ifPresent(frame -> selectedFrame = selectedFrame == frame ? null : frame); + ).ifPresent(frame -> { + selectedFrame = selectedFrame == frame ? null : frame; + toggleConsumer.accept(frame, getFrameRectangle(g2, frame)); + }); } - public void hoverFrameAt(Graphics2D g2, Point point, Consumer> hoverConsumer) { + public void hoverFrameAt(Graphics2D g2, Point point, BiConsumer, Rectangle> hoverConsumer) { getFrameAt( g2, point ).ifPresentOrElse(frame -> { + var oldHoveredFrame = hoveredFrame; hoveredFrame = frame; if (hoverConsumer != null) { - hoverConsumer.accept(frame); + hoverConsumer.accept(frame, getFrameRectangle(g2, frame)); + if (oldHoveredFrame != null) { + hoverConsumer.accept(oldHoveredFrame, getFrameRectangle(g2, oldHoveredFrame)); + } } }, this::stopHover);