Skip to content
This repository was archived by the owner on Apr 27, 2023. It is now read-only.

Commit f8ade17

Browse files
committed
add resize handling
1 parent b74f930 commit f8ade17

File tree

2 files changed

+24
-23
lines changed

2 files changed

+24
-23
lines changed

src/SimplePanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) =
1414
return (
1515
<>
1616
<div className={styles.app}>
17-
<div className={styles.appContainer}>
17+
<div className={`${styles.appContainer} flamegraph-wrapper`}>
1818
<FlameGraphRenderer viewType="single" renderURL="/render?name=pyroscope.server.alloc_objects%7B%7D" />
1919
</div>
2020
</div>

src/components/FlameGraphRenderer.tsx

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ import {
1212
getFormatter,
1313
} from "../util/format";
1414
import { colorBasedOnPackageName, colorGreyscale } from "../util/color";
15+
import { deltaDiff } from '../util/flamebearer';
1516

16-
17-
const PX_PER_LEVEL = 18;
18-
const COLLAPSE_THRESHOLD = 0;
17+
const COLLAPSE_THRESHOLD = 10;
1918
const LABEL_THRESHOLD = 10;
2019
const HIGHLIGHT_NODE_COLOR = "#48CE73"; // green
2120
const GAP = 0.5;
@@ -66,7 +65,9 @@ class FlameGraphRenderer extends React.Component {
6665
this.rangeMax = 1;
6766
this.query = "";
6867

69-
window.addEventListener("resize", this.resizeHandler);
68+
const panelContainer = document.querySelector('.flamegraph-wrapper')?.closest('.panel-wrapper');
69+
const panelContanerResizeObserver = new ResizeObserver(this.resizeHandler);
70+
panelContanerResizeObserver.observe(panelContainer);
7071
window.addEventListener("focus", this.focusHandler);
7172

7273
if (this.props.shortcut) {
@@ -110,9 +111,11 @@ class FlameGraphRenderer extends React.Component {
110111
}
111112

112113
fetchFlameBearerData(url) {
113-
this.setState({"flamebearer":{"names":["total","runtime.mstart","runtime.mstart1","runtime.sysmon","runtime.usleep","runtime.startm","runtime.notewakeup","runtime.futexwakeup","runtime.futex","runtime.notetsleep","runtime.notetsleep_internal","runtime.futexsleep","runtime.nanotime","runtime.lockWithRank","runtime.lock2","runtime.morestack","runtime.newstack","runtime.gopreempt_m","runtime.goschedImpl","runtime.schedule","runtime.resetspinning","runtime.wakep","runtime.mcall","runtime.park_m","runtime.findrunnable","runtime.write","runtime.write1","runtime.stopm","runtime.notesleep","runtime.runqsteal","runtime.runqgrab","runtime.pidleput","runtime.netpoll","runtime.epollwait","runtime.checkTimers","runtime.runtimer","runtime.runOneTimer","time.sendTime","time.Now","runtime.walltime","net/http.(*conn).serve","net/http.serverHandler.ServeHTTP","net/http.(*ServeMux).ServeHTTP","net/http.HandlerFunc.ServeHTTP","github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).ingestHandler","github.com/pyroscope-io/pyroscope/pkg/server.ingestParamsFromRequest","runtime.newobject","runtime.nextFreeFast","github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).Start.func1","net/http.(*fileHandler).ServeHTTP","net/http.serveFile","net/http.serveContent","io.Copy","io.copyBuffer","net/http.(*response).ReadFrom","io.CopyBuffer","net/http.(*response).Write","net/http.(*response).write","bufio.(*Writer).Write","net/http.(*chunkWriter).Write","net/http.checkConnErrorWriter.Write","net.(*conn).Write","net.(*netFD).Write","internal/poll.(*FD).Write","internal/poll.ignoringEINTR","syscall.Write","syscall.write","syscall.Syscall","net/http.(*conn).readRequest","net/http.readRequest","net/textproto.(*Reader).ReadMIMEHeader","runtime.slicebytetostring","runtime.memmove","github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop","github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload","github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile","github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put","github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).Get","github.com/pyroscope-io/pyroscope/pkg/storage/dimension.FromBytes","github.com/pyroscope-io/pyroscope/pkg/storage/dimension.Deserialize","io.ReadAtLeast","github.com/dgraph-io/badger/v2/y.(*WaterMark).process","runtime.selectgo","github.com/dgraph-io/badger/v2.(*levelsController).runCompactor","github.com/dgraph-io/badger/v2.(*levelsController).pickCompactLevels","sort.Slice","sort.quickSort_func"],"levels":[[0,78,0,0],[0,2,1,83,0,1,0,81,0,1,0,73,0,3,0,40,0,49,0,22,0,1,0,15,0,21,0,1],[1,1,0,84,0,1,1,82,0,1,0,74,0,1,0,68,0,2,0,41,0,49,0,23,0,1,0,16,0,21,0,2],[1,1,0,85,1,1,0,75,0,1,0,69,0,2,0,42,0,49,0,19,0,1,0,17,0,6,6,12,0,15,0,3],[1,1,1,86,1,1,0,76,0,1,0,70,0,2,0,43,0,36,1,24,0,6,6,12,0,7,0,20,0,1,0,18,6,1,0,13,0,7,0,9,0,4,0,5,0,3,3,4],[3,1,0,77,0,1,0,71,0,1,0,48,0,1,0,44,1,8,0,34,0,13,13,12,0,8,0,32,0,1,1,31,0,1,0,29,0,3,0,27,0,1,0,25,6,7,0,21,0,1,0,19,6,1,1,14,0,4,4,12,0,3,0,10,0,4,0,6],[3,1,0,78,0,1,1,72,0,1,0,49,0,1,0,45,1,8,0,35,13,8,8,33,1,1,1,30,0,3,1,28,0,1,1,26,6,7,0,5,0,1,0,20,11,3,0,11,0,4,0,7],[3,1,0,79,1,1,0,50,0,1,0,46,1,8,0,36,24,2,0,11,7,7,0,6,0,1,0,21,11,3,3,8,0,4,4,8],[3,1,1,80,1,1,0,51,0,1,1,47,1,8,0,37,24,2,2,8,7,7,0,7,0,1,0,5],[5,1,0,52,2,8,0,38,33,7,7,8,0,1,0,6],[5,1,0,53,2,6,6,12,0,2,2,39,40,1,0,7],[5,1,0,54,50,1,1,8],[5,1,0,55],[5,1,0,53],[5,1,0,56],[5,1,0,57],[5,1,0,58],[5,1,0,59],[5,1,0,58],[5,1,0,60],[5,1,0,61],[5,1,0,62],[5,1,0,63],[5,1,0,64],[5,1,0,65],[5,1,0,66],[5,1,1,67]],"numTicks":78,"maxSelf":13,"spyName":"gospy","sampleRate":100,"units":"samples"},"metadata":{"sampleRate":100,"spyName":"gospy","units":"samples"},"timeline":{"startTime":1621014100,"samples":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,16,18,19,17,0],"durationDelta":10}}
114-
, () => {
115-
this.updateData();
114+
const flamebearer = {names:["total","runtime.mstart","runtime.mstart1","runtime.sysmon","runtime.usleep","runtime.startm","runtime.notewakeup","runtime.futexwakeup","runtime.futex","runtime.notetsleep","runtime.notetsleep_internal","runtime.futexsleep","runtime.nanotime","runtime.lockWithRank","runtime.lock2","runtime.morestack","runtime.newstack","runtime.gopreempt_m","runtime.goschedImpl","runtime.schedule","runtime.resetspinning","runtime.wakep","runtime.mcall","runtime.park_m","runtime.findrunnable","runtime.write","runtime.write1","runtime.stopm","runtime.notesleep","runtime.runqsteal","runtime.runqgrab","runtime.pidleput","runtime.netpoll","runtime.epollwait","runtime.checkTimers","runtime.runtimer","runtime.runOneTimer","time.sendTime","time.Now","runtime.walltime","net/http.(*conn).serve","net/http.serverHandler.ServeHTTP","net/http.(*ServeMux).ServeHTTP","net/http.HandlerFunc.ServeHTTP","github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).ingestHandler","github.com/pyroscope-io/pyroscope/pkg/server.ingestParamsFromRequest","runtime.newobject","runtime.nextFreeFast","github.com/pyroscope-io/pyroscope/pkg/server.(*Controller).Start.func1","net/http.(*fileHandler).ServeHTTP","net/http.serveFile","net/http.serveContent","io.Copy","io.copyBuffer","net/http.(*response).ReadFrom","io.CopyBuffer","net/http.(*response).Write","net/http.(*response).write","bufio.(*Writer).Write","net/http.(*chunkWriter).Write","net/http.checkConnErrorWriter.Write","net.(*conn).Write","net.(*netFD).Write","internal/poll.(*FD).Write","internal/poll.ignoringEINTR","syscall.Write","syscall.write","syscall.Syscall","net/http.(*conn).readRequest","net/http.readRequest","net/textproto.(*Reader).ReadMIMEHeader","runtime.slicebytetostring","runtime.memmove","github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadLoop","github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).safeUpload","github.com/pyroscope-io/pyroscope/pkg/agent/upstream/direct.(*Direct).uploadProfile","github.com/pyroscope-io/pyroscope/pkg/storage.(*Storage).Put","github.com/pyroscope-io/pyroscope/pkg/storage/cache.(*Cache).Get","github.com/pyroscope-io/pyroscope/pkg/storage/dimension.FromBytes","github.com/pyroscope-io/pyroscope/pkg/storage/dimension.Deserialize","io.ReadAtLeast","github.com/dgraph-io/badger/v2/y.(*WaterMark).process","runtime.selectgo","github.com/dgraph-io/badger/v2.(*levelsController).runCompactor","github.com/dgraph-io/badger/v2.(*levelsController).pickCompactLevels","sort.Slice","sort.quickSort_func"],levels:[[0,78,0,0],[0,2,1,83,0,1,0,81,0,1,0,73,0,3,0,40,0,49,0,22,0,1,0,15,0,21,0,1],[1,1,0,84,0,1,1,82,0,1,0,74,0,1,0,68,0,2,0,41,0,49,0,23,0,1,0,16,0,21,0,2],[1,1,0,85,1,1,0,75,0,1,0,69,0,2,0,42,0,49,0,19,0,1,0,17,0,6,6,12,0,15,0,3],[1,1,1,86,1,1,0,76,0,1,0,70,0,2,0,43,0,36,1,24,0,6,6,12,0,7,0,20,0,1,0,18,6,1,0,13,0,7,0,9,0,4,0,5,0,3,3,4],[3,1,0,77,0,1,0,71,0,1,0,48,0,1,0,44,1,8,0,34,0,13,13,12,0,8,0,32,0,1,1,31,0,1,0,29,0,3,0,27,0,1,0,25,6,7,0,21,0,1,0,19,6,1,1,14,0,4,4,12,0,3,0,10,0,4,0,6],[3,1,0,78,0,1,1,72,0,1,0,49,0,1,0,45,1,8,0,35,13,8,8,33,1,1,1,30,0,3,1,28,0,1,1,26,6,7,0,5,0,1,0,20,11,3,0,11,0,4,0,7],[3,1,0,79,1,1,0,50,0,1,0,46,1,8,0,36,24,2,0,11,7,7,0,6,0,1,0,21,11,3,3,8,0,4,4,8],[3,1,1,80,1,1,0,51,0,1,1,47,1,8,0,37,24,2,2,8,7,7,0,7,0,1,0,5],[5,1,0,52,2,8,0,38,33,7,7,8,0,1,0,6],[5,1,0,53,2,6,6,12,0,2,2,39,40,1,0,7],[5,1,0,54,50,1,1,8],[5,1,0,55],[5,1,0,53],[5,1,0,56],[5,1,0,57],[5,1,0,58],[5,1,0,59],[5,1,0,58],[5,1,0,60],[5,1,0,61],[5,1,0,62],[5,1,0,63],[5,1,0,64],[5,1,0,65],[5,1,0,66],[5,1,1,67]],"numTicks":78,"maxSelf":13,"spyName":"gospy","sampleRate":100,"units":"samples"},metadata:{sampleRate:100,spyName:"gospy",units:"samples"},timeline:{startTime:1621014100,samples:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,16,18,19,17,0],durationDelta:10};
115+
deltaDiff(flamebearer.levels);
116+
this.setState({ ...this.state, flamebearer },
117+
() => {
118+
this.updateData();
116119
})
117120
}
118121

@@ -225,7 +228,7 @@ class FlameGraphRenderer extends React.Component {
225228
};
226229

227230
xyToBar = (x, y) => {
228-
const i = Math.floor(y / PX_PER_LEVEL) + this.topLevel;
231+
const i = Math.floor(y / this.pxPerLevel) + this.topLevel;
229232
if (i >= 0 && i < this.state.levels.length) {
230233
const j = this.binarySearchLevel(x, this.state.levels[i], this.tickToX);
231234
return { i, j };
@@ -242,11 +245,12 @@ class FlameGraphRenderer extends React.Component {
242245
this.mouseOutHandler();
243246
};
244247

245-
resizeHandler = () => {
248+
resizeHandler = (el) => {
246249
// this is here to debounce resize events (see: https://css-tricks.com/debouncing-throttling-explained-examples/)
247250
// because rendering is expensive
248251
clearTimeout(this.resizeFinish);
249-
this.resizeFinish = setTimeout(this.renderCanvas, 100);
252+
this.pxPerLevel = (el[0].contentRect.height - 60) / this.state.flamebearer.levels.length;
253+
this.resizeFinish = setTimeout(this.renderCanvas, 50);
250254
};
251255

252256
focusHandler = () => {
@@ -279,13 +283,11 @@ class FlameGraphRenderer extends React.Component {
279283
this.graphWidth = this.canvas.offsetWidth;
280284
this.pxPerTick =
281285
this.graphWidth / numTicks / (this.rangeMax - this.rangeMin);
282-
this.canvas.height = PX_PER_LEVEL * (levels.length - this.topLevel);
283-
286+
this.canvas.height = this.pxPerLevel * (levels.length - this.topLevel);
284287
this.canvas.style.width='100%';
285288
this.canvas.style.height='100%';
286289
this.canvas.width = this.canvas.offsetWidth;
287290
this.canvas.height = this.canvas.offsetHeight;
288-
289291
if (devicePixelRatio > 1) {
290292
this.canvas.width *= 2;
291293
this.canvas.height *= 2;
@@ -294,7 +296,7 @@ class FlameGraphRenderer extends React.Component {
294296

295297
this.ctx.textBaseline = "middle";
296298
this.ctx.font =
297-
'400 12px system-ui, -apple-system, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"';
299+
'400 11px system-ui, -apple-system, "Segoe UI", "Roboto", "Ubuntu", "Cantarell", "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"';
298300

299301
const formatter = this.createFormatter();
300302
// i = level
@@ -306,17 +308,16 @@ class FlameGraphRenderer extends React.Component {
306308
// j = 2: position in the main index
307309

308310
const barIndex = level[j];
309-
const x = this.tickToX(barIndex + j*1.2);
310-
const y = i * PX_PER_LEVEL;
311+
const x = this.tickToX(barIndex);
312+
const y = i * this.pxPerLevel;
311313
let numBarTicks = level[j + 1];
312314

313315
// For this particular bar, there is a match
314316
const queryExists = this.query.length > 0;
315317
const nodeIsInQuery =
316318
(this.query && names[level[j + 3]].indexOf(this.query) >= 0) || false;
317319
// merge very small blocks into big "collapsed" ones for performance
318-
// const collapsed = numBarTicks * this.pxPerTick <= COLLAPSE_THRESHOLD;
319-
const collapsed = false;
320+
const collapsed = numBarTicks * this.pxPerTick <= COLLAPSE_THRESHOLD;
320321

321322
// const collapsed = false;
322323
if (collapsed) {
@@ -334,7 +335,7 @@ class FlameGraphRenderer extends React.Component {
334335
}
335336
// ticks are samples
336337
const sw = numBarTicks * this.pxPerTick - (collapsed ? 0 : GAP);
337-
const sh = PX_PER_LEVEL - GAP;
338+
const sh = this.pxPerLevel - GAP;
338339

339340
// if (x < -1 || x + sw > this.graphWidth + 1 || sw < HIDE_THRESHOLD) continue;
340341

@@ -364,7 +365,7 @@ class FlameGraphRenderer extends React.Component {
364365
this.ctx.fillStyle = nodeColor;
365366
this.ctx.fill();
366367

367-
if (!collapsed /* && sw >= LABEL_THRESHOLD */) {
368+
if (!collapsed && sw >= LABEL_THRESHOLD) {
368369
const percent = formatPercent(ratio);
369370
const name = `${names[level[j + 3]]} (${percent}, ${formatter.format(numBarTicks, sampleRate)})`;
370371

@@ -394,7 +395,7 @@ class FlameGraphRenderer extends React.Component {
394395

395396
const level = this.state.levels[i];
396397
const x = Math.max(this.tickToX(level[j]), 0);
397-
const y = (i - this.topLevel) * PX_PER_LEVEL;
398+
const y = (i - this.topLevel) * this.pxPerLevel;
398399
const sw = Math.min(
399400
this.tickToX(level[j] + level[j + 1]) - x,
400401
this.graphWidth
@@ -417,7 +418,7 @@ class FlameGraphRenderer extends React.Component {
417418
left: `${this.canvas.offsetLeft + x}px`,
418419
top: `${this.canvas.offsetTop + y}px`,
419420
width: `${sw}px`,
420-
height: `${PX_PER_LEVEL}px`,
421+
height: `${this.pxPerLevel}px`,
421422
},
422423
tooltipStyle: {
423424
maxWidth: '80%',

0 commit comments

Comments
 (0)