Skip to content

Commit e868b7b

Browse files
authored
feat(profiling): use color pallete on chart (#54101)
Collect all cpu measures and display them as a line chart. In case of android where avg is reported render the area chart instead of line chart. I reused the chart color palette for colors
1 parent e16cc94 commit e868b7b

File tree

5 files changed

+64
-45
lines changed

5 files changed

+64
-45
lines changed

static/app/components/profiling/flamegraph/flamegraph.tsx

+10-10
Original file line numberDiff line numberDiff line change
@@ -299,20 +299,20 @@ function Flamegraph(): ReactElement {
299299
return LOADING_OR_FALLBACK_CPU_CHART;
300300
}
301301

302+
const measures: Profiling.Measurement[] = [];
303+
304+
for (const key in profileGroup.measurements) {
305+
if (key.startsWith('cpu_usage')) {
306+
measures.push(profileGroup.measurements[key]!);
307+
}
308+
}
309+
302310
return new FlamegraphChart(
303311
Rect.From(flamegraph.configSpace),
304-
profileGroup.measurements?.cpu_usage_0 ?? {
305-
unit: 'percentage',
306-
values: [],
307-
},
312+
measures.length > 0 ? measures : [],
308313
flamegraphTheme.COLORS.CPU_CHART_COLORS
309314
);
310-
}, [
311-
profileGroup.measurements?.cpu_usage_0,
312-
flamegraph.configSpace,
313-
flamegraphTheme,
314-
hasCPUChart,
315-
]);
315+
}, [profileGroup.measurements, flamegraph.configSpace, flamegraphTheme, hasCPUChart]);
316316

317317
const flamegraphCanvas = useMemo(() => {
318318
if (!flamegraphCanvasRef) {

static/app/utils/profiling/flamegraph/flamegraphTheme.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {CHART_PALETTE} from 'sentry/constants/chartPalette';
12
import {
23
makeColorMapByApplicationFrame,
34
makeColorMapByFrequency,
@@ -11,6 +12,7 @@ import {
1112
import {FlamegraphColorCodings} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/reducers/flamegraphPreferences';
1213
import {FlamegraphFrame} from 'sentry/utils/profiling/flamegraphFrame';
1314
import {Frame} from 'sentry/utils/profiling/frame';
15+
import {hexToColorChannels} from 'sentry/utils/profiling/gl/utils';
1416
import {darkTheme, lightTheme} from 'sentry/utils/theme';
1517

1618
import {makeColorBucketTheme} from '../speedscope';
@@ -189,7 +191,7 @@ export const LightFlamegraphTheme: FlamegraphTheme = {
189191
'by frequency': makeColorMapByFrequency,
190192
'by system vs application frame': makeColorMapBySystemVsApplicationFrame,
191193
},
192-
CPU_CHART_COLORS: [[0.96, 0.69, 0.0, 0.5]],
194+
CPU_CHART_COLORS: CHART_PALETTE[12].map(c => hexToColorChannels(c, 0.8)),
193195
CPU_CHART_LABEL_COLOR: 'rgba(31,35,58,.75)',
194196
CURSOR_CROSSHAIR: '#bbbbbb',
195197
DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],

static/app/utils/profiling/flamegraphChart.tsx

+38-30
Original file line numberDiff line numberDiff line change
@@ -23,55 +23,63 @@ export class FlamegraphChart {
2323
y: [0, 0],
2424
};
2525

26-
static Empty = new FlamegraphChart(Rect.Empty(), {unit: 'percent', values: []}, [
27-
[0, 0, 0, 0],
28-
]);
26+
static Empty = new FlamegraphChart(Rect.Empty(), [], [[0, 0, 0, 0]]);
2927

3028
constructor(
3129
configSpace: Rect,
32-
measurement: Profiling.Measurement,
30+
measurements: Profiling.Measurement[],
3331
colors: ColorChannels[]
3432
) {
3533
this.series = new Array<Series>();
3634

37-
if (!measurement || !measurement.values.length) {
35+
if (!measurements || !measurements.length) {
3836
this.formatter = makeFormatter('percent');
3937
this.configSpace = configSpace.clone();
4038
return;
4139
}
4240

43-
this.series[0] = {
44-
type: 'area',
45-
lineColor: colorComponentsToRGBA(colors[0]),
46-
fillColor: colorComponentsToRGBA(colors[0]),
47-
points: new Array(measurement.values.length),
48-
};
41+
const type = measurements.length > 0 ? 'line' : 'area';
4942

50-
for (let i = 0; i < measurement.values.length; i++) {
51-
const m = measurement.values[i];
43+
for (let j = 0; j < measurements.length; j++) {
44+
const measurement = measurements[j];
45+
this.series[j] = {
46+
type,
47+
lineColor: colorComponentsToRGBA(colors[j]),
48+
fillColor: colorComponentsToRGBA(colors[j]),
49+
points: new Array(measurement.values.length).fill(0),
50+
};
5251

53-
// Track and update Y max and min
54-
if (m.value > this.domains.y[1]) {
55-
this.domains.y[1] = m.value;
56-
}
57-
if (m.value < this.domains.y[0]) {
58-
this.domains.y[0] = m.value;
59-
}
52+
for (let i = 0; i < measurement.values.length; i++) {
53+
const m = measurement.values[i];
6054

61-
// Track and update X domain max and min
62-
if (m.elapsed_since_start_ns > this.domains.x[1]) {
63-
this.domains.x[1] = m.elapsed_since_start_ns;
64-
}
65-
if (m.elapsed_since_start_ns < this.domains.x[0]) {
66-
this.domains.x[1] = m.elapsed_since_start_ns;
67-
}
55+
// Track and update Y max and min
56+
if (m.value > this.domains.y[1]) {
57+
this.domains.y[1] = m.value;
58+
}
59+
if (m.value < this.domains.y[0]) {
60+
this.domains.y[0] = m.value;
61+
}
6862

69-
this.series[0].points[i] = {x: m.elapsed_since_start_ns, y: m.value};
63+
// Track and update X domain max and min
64+
if (m.elapsed_since_start_ns > this.domains.x[1]) {
65+
this.domains.x[1] = m.elapsed_since_start_ns;
66+
}
67+
if (m.elapsed_since_start_ns < this.domains.x[0]) {
68+
this.domains.x[1] = m.elapsed_since_start_ns;
69+
}
70+
71+
this.series[j].points[i] = {x: m.elapsed_since_start_ns, y: m.value};
72+
}
7073
}
7174

75+
this.series.sort((a, b) => {
76+
const aAvg = a.points.reduce((acc, point) => acc + point.y, 0) / a.points.length;
77+
const bAvg = b.points.reduce((acc, point) => acc + point.y, 0) / b.points.length;
78+
return bAvg - aAvg;
79+
});
80+
7281
this.domains.y[1] = 100;
7382
this.configSpace = configSpace.withHeight(this.domains.y[1] - this.domains.y[0]);
74-
75-
this.formatter = makeFormatter(measurement.unit, 0);
83+
this.formatter = makeFormatter(measurements[0].unit, 0);
7684
}
7785
}

static/app/utils/profiling/gl/utils.ts

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Fuse from 'fuse.js';
33
import {mat3, vec2} from 'gl-matrix';
44

55
import {CanvasView} from 'sentry/utils/profiling/canvasView';
6+
import {ColorChannels} from 'sentry/utils/profiling/flamegraph/flamegraphTheme';
67
import {FlamegraphFrame} from 'sentry/utils/profiling/flamegraphFrame';
78
import {FlamegraphRenderer} from 'sentry/utils/profiling/renderers/flamegraphRenderer';
89

@@ -382,6 +383,14 @@ export interface TrimTextCenter {
382383
text: string;
383384
}
384385

386+
export function hexToColorChannels(color: string, alpha: number): ColorChannels {
387+
return [
388+
parseInt(color.slice(1, 3), 16) / 255,
389+
parseInt(color.slice(3, 5), 16) / 255,
390+
parseInt(color.slice(5, 7), 16) / 255,
391+
alpha,
392+
];
393+
}
385394
// Utility function to compute a clamped view. This is essentially a bounds check
386395
// to ensure that zoomed viewports stays in the bounds and does not escape the view.
387396
export function computeClampedConfigView(

static/app/utils/profiling/renderers/chartRenderer.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ export class FlamegraphChartRenderer {
100100

101101
// Draw series
102102
for (let i = 0; i < this.chart.series.length; i++) {
103-
this.context.lineWidth = 1;
103+
this.context.lineWidth = 1 * window.devicePixelRatio;
104104
this.context.fillStyle = this.chart.series[i].fillColor;
105105
this.context.strokeStyle = this.chart.series[i].lineColor;
106-
this.context.beginPath();
107106
this.context.lineCap = 'round';
107+
this.context.beginPath();
108108
const serie = this.chart.series[i];
109109

110110
const origin = vec3.fromValues(0, 0, 1);
@@ -116,11 +116,11 @@ export class FlamegraphChartRenderer {
116116
const r = vec3.fromValues(point.x, point.y, 1);
117117
vec3.transformMat3(r, r, configViewToPhysicalSpace);
118118

119-
if (j === 0) {
119+
if (serie.type === 'area' && j === 0) {
120120
this.context.lineTo(r[0], origin[1]);
121121
}
122122
this.context.lineTo(r[0], r[1]);
123-
if (j === serie.points.length - 1) {
123+
if (serie.type === 'area' && j === serie.points.length - 1) {
124124
this.context.lineTo(r[0], origin[1]);
125125
}
126126
}

0 commit comments

Comments
 (0)