Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand frame on single click #248

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
916944e
chore: Replace render config by setFrameRender
bric3 May 22, 2024
a0cae79
chore: tweak borders
bric3 May 22, 2024
de3a372
chore: Apply default config
bric3 May 22, 2024
fce036f
chore: cleanup
bric3 May 22, 2024
dd78f0e
feature: Expand frame horizontally only
bric3 May 21, 2024
e9cf1fa
fix: Move the horizontal bar detection later, when applying the zoom …
bric3 May 22, 2024
7c17ed9
chore: reformat
bric3 May 22, 2024
b2ef1c8
fix: Horizontal scrollbar was not always visible on zoom
bric3 May 22, 2024
b04b7ab
fix: Handle flamegraph visible depth change when resizing viewport
bric3 May 22, 2024
5ded60c
fix: Improves flamegraph zoom behavior
bric3 May 22, 2024
5d63289
docs: Update doc to new framerender
bric3 May 22, 2024
d4d07ae
fix: Handle single click rest zoom for taller viewport than flamegraph
bric3 May 23, 2024
12de751
fix: Rare case, in Flamegraph mode when resize could enter a loop
bric3 May 23, 2024
c40ba38
chore: Replace gradle wrapper validation coordinates
bric3 May 28, 2024
f17f149
fix: Now canvas at least vp height if fg height is inferior
bric3 Jun 1, 2024
e054f6d
chore: disable dimming non focused flames by default
bric3 Jun 1, 2024
8681ffd
chore: Tweak fireplace app build
bric3 Jun 1, 2024
aea300a
chore: Don't show tip if owner window is not active or focused
bric3 Jun 2, 2024
a4abd65
chore: Rename deinstall to uninstall
bric3 Jun 3, 2024
84f5ee2
chore: flamegraph mode now have the scrollbar at the top
bric3 Jun 5, 2024
e8a8aaf
chore: flamegraph mode now have the minimap at the top
bric3 Jun 5, 2024
402fcb2
chore: use nanoTime
bric3 Jun 10, 2024
b5accd6
chore(deps): Upgrade Gradle to 8.9
bric3 Aug 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ jobs:
# - name: debug
# run: echo "${{ toJSON(github.event)}}"

- name: Gradle Wrapper Validation
uses: gradle/actions/wrapper-validation@v3

- name: Set up JDK
uses: actions/setup-java@v4
with:
Expand Down
1 change: 1 addition & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ repositories {
}

dependencies {
implementation(libs.gradlePlugin.kotlin.jvm)
implementation(libs.gradlePlugin.bnd)
implementation(libs.gradlePlugin.semver)
implementation(libs.gradlePlugin.testLogger)
Expand Down
7 changes: 6 additions & 1 deletion build-logic/src/main/kotlin/fireplace.application.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@
plugins {
application
id("fireplace.tests")
id("org.jetbrains.kotlin.jvm")
}

val javaVersion = 21
val javaVersion = 22
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(javaVersion))
}
}

kotlin {
jvmToolchain(javaVersion)
}

repositories {
mavenCentral()
maven {
Expand Down
1 change: 0 additions & 1 deletion fireplace-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ plugins {
// https://github.com/johnrengelman/shadow/pull/876
// https://github.com/johnrengelman/shadow/issues/908
id("io.github.goooler.shadow") version "8.1.7"
kotlin("jvm") version "2.0.0"
}

description = "Opens a JFR file to inspect its content."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ private static class DispatchInfo {
private final Thread eventDispatchThread = Thread.currentThread();

// The last time in milliseconds at which we saw a dispatch on the above thread.
private long lastDispatchTimeMillis = System.currentTimeMillis();
private long lastDispatchTimeNanos = System.nanoTime();

DispatchInfo() {
// All initialization is done by the field initializers.
Expand Down Expand Up @@ -272,7 +272,7 @@ private static boolean stacksEqual(StackTraceElement[] a, StackTraceElement[] b)
* Returns how long this dispatch has been going on (in milliseconds).
*/
private long timeSoFar() {
return (System.currentTimeMillis() - lastDispatchTimeMillis);
return (System.nanoTime() - lastDispatchTimeNanos) / 1000000;
}

public void dispose() {
Expand Down Expand Up @@ -349,7 +349,7 @@ private synchronized void postDispatchEvent() {
var currentEventDispatchThread = Thread.currentThread();
for (var dispatchInfo : dispatches) {
if (dispatchInfo.eventDispatchThread == currentEventDispatchThread) {
dispatchInfo.lastDispatchTimeMillis = System.currentTimeMillis();
dispatchInfo.lastDispatchTimeNanos = System.nanoTime();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ object Utils {
return block()
}

val start: Long = System.currentTimeMillis()
val start: Long = System.nanoTime()

try {
return block()
} finally {
val elapsed: Long = System.currentTimeMillis() - start
val elapsed: Long = (System.nanoTime() - start) / 1_000_000 // ns -> ms
println("[${Thread.currentThread().name}] $name took $elapsed ms")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
*/
package io.github.bric3.fireplace.ui

import com.formdev.flatlaf.FlatClientProperties
import io.github.bric3.fireplace.Utils
import io.github.bric3.fireplace.core.ui.Colors
import io.github.bric3.fireplace.core.ui.Colors.Palette
import io.github.bric3.fireplace.core.ui.LightDarkColor
import io.github.bric3.fireplace.core.ui.SwingUtils
import io.github.bric3.fireplace.flamegraph.ColorMapper
import io.github.bric3.fireplace.flamegraph.DefaultFrameRenderer
import io.github.bric3.fireplace.flamegraph.DimmingFrameColorProvider
import io.github.bric3.fireplace.flamegraph.FlamegraphView
import io.github.bric3.fireplace.flamegraph.FlamegraphView.FrameClickAction.EXPAND_FRAME
import io.github.bric3.fireplace.flamegraph.FlamegraphView.HoverListener
import io.github.bric3.fireplace.flamegraph.FrameBox
import io.github.bric3.fireplace.flamegraph.FrameFontProvider
Expand Down Expand Up @@ -77,6 +80,7 @@ class FlamegraphPane : JPanel(BorderLayout()) {
)
)
jfrFlamegraphView.frameColorProvider = DimmingFrameColorProvider(frameBoxColorFunction)
.withDimNonFocusedFlame(false)
jfrFlamegraphView.requestRepaint()
}.also {
colorPaletteJComboBox.addActionListener(it)
Expand Down Expand Up @@ -114,6 +118,9 @@ class FlamegraphPane : JPanel(BorderLayout()) {
addActionListener { jfrFlamegraphView.resetZoom() }
}
val searchField = JTextField("").apply {
putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "Search")
putClientProperty(FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON, true)

addActionListener {
val searched = text
if (searched.isEmpty()) {
Expand Down Expand Up @@ -240,33 +247,40 @@ class FlamegraphPane : JPanel(BorderLayout()) {
companion object {
private val defaultColorPalette = Colors.Palette.DATADOG
private val defaultFrameColorMode = BY_PACKAGE
private const val defaultPaintFrameBorder = true
private const val defaultPaintHoveredFrameBorder = false
private const val defaultShowMinimap = true
private const val defaultIcicleMode = true
private const val defaultRoundedFrame = true
private fun getJfrFlamegraphView(): FlamegraphView<Node> {
val flamegraphView = FlamegraphView<Node>()
flamegraphView.setRenderConfiguration(
FrameTextsProvider.of(
Function { frame -> if (frame.isRoot) "root" else frame.actualNode.frame.humanReadableShortString },
Function { frame ->
if (frame.isRoot) "" else FormatToolkit.getHumanReadable(
frame.actualNode.frame.method,
false,
false,
false,
false,
true,
false
flamegraphView.frameClickAction = EXPAND_FRAME
flamegraphView.setFrameRender(
DefaultFrameRenderer(
FrameTextsProvider.of(
Function { frame -> if (frame.isRoot) "root" else frame.actualNode.frame.humanReadableShortString },
Function { frame ->
if (frame.isRoot) "" else FormatToolkit.getHumanReadable(
frame.actualNode.frame.method,
false,
false,
false,
false,
true,
false
)
},
Function { frame -> if (frame.isRoot) "" else frame.actualNode.frame.method.methodName }
),
DimmingFrameColorProvider(
defaultFrameColorMode.colorMapperUsing(
ColorMapper.ofObjectHashUsing(*defaultColorPalette.colors())
)
},
Function { frame -> if (frame.isRoot) "" else frame.actualNode.frame.method.methodName }
),
DimmingFrameColorProvider(
defaultFrameColorMode.colorMapperUsing(
ColorMapper.ofObjectHashUsing(*defaultColorPalette.colors())
)
),
FrameFontProvider.defaultFontProvider()
).withDimNonFocusedFlame(false),
FrameFontProvider.defaultFontProvider()
).apply {
isPaintHoveredFrameBorder = defaultPaintHoveredFrameBorder
isRoundedFrame = defaultRoundedFrame
}
)

val ref = AtomicReference<FrameBox<Node>>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import java.awt.event.MouseEvent
import java.util.concurrent.CompletableFuture
import java.util.function.Supplier
import javax.swing.*
import javax.swing.border.EmptyBorder
import kotlin.collections.Map.Entry

abstract class ThreadFlamegraphView(protected val jfrBinder: JFRLoaderBinder) : ViewPanel {
Expand Down Expand Up @@ -126,7 +127,13 @@ abstract class ThreadFlamegraphView(protected val jfrBinder: JFRLoaderBinder) :
}
)

JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(threadList), charts).apply {
JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
JScrollPane(threadList).apply {
border = EmptyBorder(0, 0, 0, 0)
},
charts
).apply {
autoSize(0.2)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ object FollowingTipService {
}

fun disableFor(component: JComponent) {
followingTip.deinstall(component)
followingTip.uninstall(component)
}
}

Expand Down Expand Up @@ -69,6 +69,11 @@ private class FollowingTip {
val component: Component
when (e.id) {
MOUSE_ENTERED, MOUSE_MOVED, MOUSE_DRAGGED, MOUSE_WHEEL -> {
// Don't bother to show tip if the owner window is not focused or active
if (!ownerWindow.isActive || !ownerWindow.isFocused) {
tipWindow.isVisible = false
return@AWTEventListener
}
event = e as MouseEvent
component = e.component
if (ownerWindow.isAncestorOf(component) && component is JComponent) {
Expand All @@ -85,7 +90,7 @@ private class FollowingTip {
}

val content = contentProvider?.invoke(component, event)
if (content == null) {
if (content == null || !ownerWindow.isActive || !ownerWindow.isFocused) {
tipWindow.isVisible = false
return@AWTEventListener
}
Expand All @@ -101,7 +106,7 @@ private class FollowingTip {
event = e as MouseEvent
component = e.component
val p = SwingUtilities.convertPoint(component, event.point, ownerWindow)
if (!ownerWindow.contains(p)) {
if (!ownerWindow.contains(p) || !ownerWindow.isActive || !ownerWindow.isFocused) {
tipWindow.isVisible = false
}
}
Expand Down Expand Up @@ -138,7 +143,7 @@ private class FollowingTip {
}
}

fun deinstall(component: JComponent) {
fun uninstall(component: JComponent) {
val location = tipWindow.locationOnScreen.apply {
SwingUtilities.convertPointFromScreen(this, component)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class DimmingFrameColorProvider<T> implements FrameColorProvider<@NotNull

private Color rootBackGroundColor = ROOT_BACKGROUND_COLOR;
private Color dimmedTextColor = DIMMED_TEXT_COLOR;
private boolean dimmedNonFocusedFlames = false;

/**
* Builds a basic frame color provider.
Expand Down Expand Up @@ -106,7 +107,7 @@ public ColorModel getColors(@NotNull FrameBox<@NotNull T> frame, int flags) {
);
}

boolean shouldDimFocusedFlame = isFocusing(flags) && isInFocusedFlame(flags) && !isHighlightedFrame(flags);
var shouldDimFocusedFlame = shouldDimFocusedFlame(flags);
if (!rootNode && shouldDim(flags) && !shouldDimFocusedFlame) {
backgroundColor = dimmedBackground(baseBackgroundColor);
foreground = dimmedTextColor;
Expand Down Expand Up @@ -173,6 +174,19 @@ public ColorModel getColors(@NotNull FrameBox<@NotNull T> frame, int flags) {
return halfDimmedColorCache.computeIfAbsent(backgroundColor, Colors::halfDim);
}

/**
* Should dim the frame if it's in the focused flame.
*
* @param flags
* @return
*/
private boolean shouldDimFocusedFlame(int flags) {
return dimmedNonFocusedFlames
&& isFocusing(flags)
&& isInFocusedFlame(flags)
&& !isHighlightedFrame(flags);
}

/**
* Dim only if not highlighted or not focused
* <p>
Expand All @@ -192,10 +206,11 @@ private boolean shouldDim(int flags) {
var inFocusedFlame = isInFocusedFlame(flags);

var dimmedForHighlighting = highlighting && !highlightedFrame;
var dimmedForFocus = focusing && !inFocusedFlame;
var dimmedForFocus = dimmedNonFocusedFlames && focusing && !inFocusedFlame;
var dimmedInFocusedFlame = dimmedNonFocusedFlames && focusing && inFocusedFlame;

return (dimmedForHighlighting || dimmedForFocus)
&& !(focusing && inFocusedFlame) // don't dim frames that are in focused flame
&& !dimmedInFocusedFlame // don't dim frames that are in focused flame
// && !(highlighting && highlightedFrame) // this dim highlighted that are not in focused flame
;
}
Expand All @@ -211,4 +226,10 @@ public DimmingFrameColorProvider<T> withDimmedTextColor(@NotNull Color dimmedTex
this.dimmedTextColor = Objects.requireNonNull(dimmedTextColor);
return this;
}

@NotNull
public DimmingFrameColorProvider<T> withDimNonFocusedFlame(boolean dimmedNonFocusedFlames) {
this.dimmedNonFocusedFlames = dimmedNonFocusedFlames;
return this;
}
}
Loading