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

[PARKED] Highlight all the occurrences for the selected frame #76

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 22 additions & 12 deletions visualizer/flame-graph-frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,16 @@ function renderStackFrame (globals, locals, rect) {
// Align with pixel grid to avoid fuzzy 2px lines of inconsistent stroke color
// Round everything towards being smaller so lines don't draw over each other

const left = Math.floor(x) + 1.5
const right = Math.ceil(left + width) - 1.5
const bottom = Math.floor(y + height) + 0.5
const top = Math.ceil(y) - 0.5
const left = Math.ceil(x) - 0.5
const right = Math.floor(x + width) - 0.5
const bottom = Math.floor(y + height) - 0.5

// For really tiny frames, draw a 1px thick pixel-aligned 'matchstick' line
if (width <= 1.5) {
const backgroundColor = this.ui.getFrameColor(nodeData, 'background', false)
const foregroundColor = this.ui.getFrameColor(nodeData, 'foreground', false)
renderAsLine(context, { x: left, y, height }, backgroundColor, foregroundColor, nodeData.highlight, heatHeight)
const borderColor = this.ui.getFrameColor(nodeData, 'border', false)
renderAsLine(context, { x: left, y, height }, backgroundColor, borderColor, nodeData.highlight, heatHeight)
return
}

Expand All @@ -52,7 +53,7 @@ function renderStackFrame (globals, locals, rect) {
}

const backgroundColor = this.ui.getFrameColor(nodeData, 'background')
const foregroundColor = this.ui.getFrameColor(nodeData, 'foreground')
const borderColor = this.ui.getFrameColor(nodeData, 'border')

context.fillStyle = backgroundColor

Expand All @@ -62,12 +63,12 @@ function renderStackFrame (globals, locals, rect) {

// Add a light stroke to left, bottom and right indicating code area
context.save()
context.globalAlpha = this.ui.presentationMode ? 0.6 : 0.4
context.strokeStyle = foregroundColor

context.strokeStyle = borderColor

context.beginPath()
context.lineWidth = thin
context.moveTo(left, y)
context.moveTo(left, top)
context.lineTo(left, bottom - lineWidth)
context.stroke()

Expand All @@ -80,8 +81,17 @@ function renderStackFrame (globals, locals, rect) {
context.beginPath()
context.lineWidth = thin
context.moveTo(right, bottom - lineWidth)
context.lineTo(right, y)
context.lineTo(right, top)
context.stroke()

if (nodeData.isOtherOccurrence && this.ui.showOccurrences) {
context.beginPath()
context.lineWidth = thick
context.moveTo(right, top)
context.lineTo(left, top)
context.stroke()
}

context.restore()
}

Expand All @@ -98,7 +108,7 @@ function renderHeatBar (context, nodeData, colorHash, rect, heatHeight) {
context.stroke()
}

function renderAsLine (context, rect, backgroundColor, foregroundColor, isHighlighted, heatHeight) {
function renderAsLine (context, rect, backgroundColor, borderColor, isHighlighted, heatHeight) {
const {
x,
y,
Expand All @@ -117,7 +127,7 @@ function renderAsLine (context, rect, backgroundColor, foregroundColor, isHighli

// Bolden any tiny active search matches
context.globalAlpha = isHighlighted ? 0.9 : 0.2
context.strokeStyle = foregroundColor
context.strokeStyle = borderColor
context.beginPath()
context.moveTo(x, y)
context.lineTo(x, y + height)
Expand Down
3 changes: 2 additions & 1 deletion visualizer/flame-graph.css
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ chart > div {
box-shadow: 0 1px 4px rgba(var(--grey-highlight-color-val), 0.3);
}

.presentation-mode .occurencies-wrapper .occurrence,
.presentation-mode .highlighter-box {
border-width: 2px;
}
}
7 changes: 7 additions & 0 deletions visualizer/flame-graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class FlameGraph extends HtmlContent {
this.initializeFromData()
})

this.ui.on('showOccurrences', () => {
this.flameGraph.update()
})

this.ui.on('zoomNode', (node, cb) => {
if (this.flameGraph) {
if (cb) this.onNextAnimationEnd = cb
Expand Down Expand Up @@ -109,6 +113,9 @@ class FlameGraph extends HtmlContent {
this.ui.on('highlightNode', node => {
this.hoveredNodeData = node || this.ui.selectedNode
this.highlightHoveredNodeOnGraph()

// when highlighting a frame we want to highilight also the other occurrences of that frame
this.flameGraph.update()
})

this.ui.on('selectNode', node => {
Expand Down
10 changes: 7 additions & 3 deletions visualizer/history.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,15 @@ class History extends EventEmitter {
const selectedNodeId = parseInt(params.selectedNode, 10)
const zoomedNodeId = parseInt(params.zoomedNode, 10)
const search = params.search || null
const showOccurrences = params.showOccurrences === 'true'
return {
exclude,
useMerged,
showOptimizationStatus,
selectedNodeId,
zoomedNodeId,
search
search,
showOccurrences
}
}

Expand All @@ -125,12 +127,14 @@ class History extends EventEmitter {
showOptimizationStatus,
selectedNodeId,
zoomedNodeId,
search
search,
showOccurrences
}) {
const params = {
selectedNode: selectedNodeId,
zoomedNode: zoomedNodeId,
exclude: this.serializeExcludes(exclude)
exclude: this.serializeExcludes(exclude),
showOccurrences
}

// Only add the below params if they contain information, to avoid cluttering
Expand Down
1 change: 1 addition & 0 deletions visualizer/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ui.initializeElements()

// TODO: see if there's a way to load this asyncronously (in case of huge data) that works with puppeteer
const dataTree = require('./data.json')

ui.setData(dataTree)

// Select hottest frame, after frame visibility has been set in d3-fg
Expand Down
54 changes: 54 additions & 0 deletions visualizer/occurrences-tooltip.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.occurrences-tooltip {
background: #000;
display: flex;
align-items: center;
flex-direction: column;
max-height: 70vh;
overflow: auto;
overflow-x: hidden;
padding: 3px;
}

.occurrences-tooltip::-webkit-scrollbar {
width: 8px;
background-color: var(--scrollbar-bg);
}

.occurrences-tooltip::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 2px var(--scrollbar-shadow);
}

.occurrences-tooltip::-webkit-scrollbar-thumb {
background-color: var(--scrollbar-thumb);
outline: 1px solid var(--scrollbar-thumb-outline);
border-radius: 2px;
box-shadow: 4px 1px 6px -2px var(--light-glare) inset;
}


.occurrences-tooltip .frame {
align-items: center;
background: rgb(48, 48, 48);
border-radius: 3px;
border: none;
color: white;
cursor: pointer;
display: flex;
font-size: var(--small-text-size);
margin: 3px;
padding: 3px 10px;
white-space: nowrap;
flex-shrink: 0;
}
.occurrences-tooltip .heatColor {
width: 10px;
height: 10px;
border-radius: 100%;
margin-right: 5px;
flex-shrink: 0;
}
.occurrences-tooltip .perc {
margin-left: 0.8em;
font-size: calc(var(--small-text-size) * 0.8);
opacity: 0.6;
}
29 changes: 29 additions & 0 deletions visualizer/occurrences-tooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict'

module.exports = {
getHtml ({ occurrences, isVisible, totalValue, getHeatColor }) {
const defaultMessage = `<div class='tooltip-default-message'>Show/hide all the occurrences for the highlighted frame</div>`

if (occurrences.length === 0) {
return isVisible
? `<div class='tooltip-default-message'>No other occurrences found for this frame</div>`
: defaultMessage
}

return !isVisible
? defaultMessage
: `<div class='occurrences-tooltip'>${
occurrences
.sort((a, b) => b.onStackTop.asViewed - a.onStackTop.asViewed)
.map(o => {
return `<button class='frame' data-id='${o.id}'>
<span class='heatColor' style='background-color:${getHeatColor(o)}'></span>
${o.onStackTop.asViewed}
<span class='perc'>
${Math.round(100 * (o.onStackTop.asViewed / totalValue) * 10) / 10}%
</span>
</button>`
}).join('')
}</div>`
}
}
15 changes: 14 additions & 1 deletion visualizer/options-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ class OptionsMenu extends HtmlContent {
this.ui.setShowOptimizationStatus(checked)
}
})
this.ui.on('showOccurrences', () => this.draw)

this.d3OccurrencesCheckbox = this.addFgOptionCheckbox({
id: 'option-showalloccurrences',
name: 'Show all the occurrences',
description: 'Highlight all the occurrences of the selected frame',
onChange: (checked) => {
this.ui.setOccurrencesVisibility(checked)
}
})

// preferences
this.d3Preferences = this.d3OptionsList.append('div')
Expand Down Expand Up @@ -316,7 +326,10 @@ class OptionsMenu extends HtmlContent {
super.draw()

// Update option checkbox values.
const { useMerged, showOptimizationStatus, exclude, appName } = this.ui.dataTree
const { useMerged, showOptimizationStatus, exclude, appName, showOccurrences } = this.ui.dataTree

this.d3OccurrencesCheckbox.property('checked', showOccurrences)

this.d3MergeCheckbox.property('checked', useMerged)
this.d3OptCheckbox
.attr('disabled', useMerged ? 'disabled' : null)
Expand Down
35 changes: 33 additions & 2 deletions visualizer/selection-controls.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,44 @@
display: none;
}

@media screen and (min-width: 530px) {
#selection-controls .occurrences-count{
display: flex;
align-items: center;
color: var(--max-contrast);
font-size: var(--small-text-size);
background-color: var(--opposite-contrast);
cursor: pointer;
border: none;
outline: none;
}

#selection-controls .occurrences-count .count{
display: inline-block;
margin-right: 0.8em;
}

#selection-controls .occurrences-count svg{
opacity: 0.6;
font-size: 1em;
margin-right: 0.3em;
}

#selection-controls .occurrences-count.on svg{
color: rgb(var(--occurrences-border-val));
opacity: 0.8;
}
#selection-controls .occurrences-count .perc{
font-size: calc(var(--small-text-size) * 0.8);
opacity: 0.6;
}

@media screen and (min-width: 400px) {
.visible-from-bp-1 {
display: initial;
}
}

@media screen and (min-width: 680px) {
@media screen and (min-width: 750px) {
.visible-from-bp-2 {
display: initial;
}
Expand Down
Loading