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

feat(profiling): use color pallete on chart #54101

Merged
merged 2 commits into from
Aug 3, 2023
Merged
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
20 changes: 10 additions & 10 deletions static/app/components/profiling/flamegraph/flamegraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,20 +299,20 @@ function Flamegraph(): ReactElement {
return LOADING_OR_FALLBACK_CPU_CHART;
}

const measures: Profiling.Measurement[] = [];

for (const key in profileGroup.measurements) {
if (key.startsWith('cpu_usage')) {
measures.push(profileGroup.measurements[key]!);
}
}

return new FlamegraphChart(
Rect.From(flamegraph.configSpace),
profileGroup.measurements?.cpu_usage_0 ?? {
unit: 'percentage',
values: [],
},
measures.length > 0 ? measures : [],
flamegraphTheme.COLORS.CPU_CHART_COLORS
);
}, [
profileGroup.measurements?.cpu_usage_0,
flamegraph.configSpace,
flamegraphTheme,
hasCPUChart,
]);
}, [profileGroup.measurements, flamegraph.configSpace, flamegraphTheme, hasCPUChart]);

const flamegraphCanvas = useMemo(() => {
if (!flamegraphCanvasRef) {
Expand Down
4 changes: 3 additions & 1 deletion static/app/utils/profiling/flamegraph/flamegraphTheme.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {CHART_PALETTE} from 'sentry/constants/chartPalette';
import {
makeColorMapByApplicationFrame,
makeColorMapByFrequency,
Expand All @@ -11,6 +12,7 @@ import {
import {FlamegraphColorCodings} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/reducers/flamegraphPreferences';
import {FlamegraphFrame} from 'sentry/utils/profiling/flamegraphFrame';
import {Frame} from 'sentry/utils/profiling/frame';
import {hexToColorChannels} from 'sentry/utils/profiling/gl/utils';
import {darkTheme, lightTheme} from 'sentry/utils/theme';

import {makeColorBucketTheme} from '../speedscope';
Expand Down Expand Up @@ -189,7 +191,7 @@ export const LightFlamegraphTheme: FlamegraphTheme = {
'by frequency': makeColorMapByFrequency,
'by system vs application frame': makeColorMapBySystemVsApplicationFrame,
},
CPU_CHART_COLORS: [[0.96, 0.69, 0.0, 0.5]],
CPU_CHART_COLORS: CHART_PALETTE[12].map(c => hexToColorChannels(c, 0.8)),
CPU_CHART_LABEL_COLOR: 'rgba(31,35,58,.75)',
CURSOR_CROSSHAIR: '#bbbbbb',
DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
Expand Down
68 changes: 38 additions & 30 deletions static/app/utils/profiling/flamegraphChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,55 +23,63 @@ export class FlamegraphChart {
y: [0, 0],
};

static Empty = new FlamegraphChart(Rect.Empty(), {unit: 'percent', values: []}, [
[0, 0, 0, 0],
]);
static Empty = new FlamegraphChart(Rect.Empty(), [], [[0, 0, 0, 0]]);

constructor(
configSpace: Rect,
measurement: Profiling.Measurement,
measurements: Profiling.Measurement[],
colors: ColorChannels[]
) {
this.series = new Array<Series>();

if (!measurement || !measurement.values.length) {
if (!measurements || !measurements.length) {
this.formatter = makeFormatter('percent');
this.configSpace = configSpace.clone();
return;
}

this.series[0] = {
type: 'area',
lineColor: colorComponentsToRGBA(colors[0]),
fillColor: colorComponentsToRGBA(colors[0]),
points: new Array(measurement.values.length),
};
const type = measurements.length > 0 ? 'line' : 'area';

for (let i = 0; i < measurement.values.length; i++) {
const m = measurement.values[i];
for (let j = 0; j < measurements.length; j++) {
const measurement = measurements[j];
this.series[j] = {
type,
lineColor: colorComponentsToRGBA(colors[j]),
fillColor: colorComponentsToRGBA(colors[j]),
points: new Array(measurement.values.length).fill(0),
};

// Track and update Y max and min
if (m.value > this.domains.y[1]) {
this.domains.y[1] = m.value;
}
if (m.value < this.domains.y[0]) {
this.domains.y[0] = m.value;
}
for (let i = 0; i < measurement.values.length; i++) {
const m = measurement.values[i];

// Track and update X domain max and min
if (m.elapsed_since_start_ns > this.domains.x[1]) {
this.domains.x[1] = m.elapsed_since_start_ns;
}
if (m.elapsed_since_start_ns < this.domains.x[0]) {
this.domains.x[1] = m.elapsed_since_start_ns;
}
// Track and update Y max and min
if (m.value > this.domains.y[1]) {
this.domains.y[1] = m.value;
}
if (m.value < this.domains.y[0]) {
this.domains.y[0] = m.value;
}

this.series[0].points[i] = {x: m.elapsed_since_start_ns, y: m.value};
// Track and update X domain max and min
if (m.elapsed_since_start_ns > this.domains.x[1]) {
this.domains.x[1] = m.elapsed_since_start_ns;
}
if (m.elapsed_since_start_ns < this.domains.x[0]) {
this.domains.x[1] = m.elapsed_since_start_ns;
}

this.series[j].points[i] = {x: m.elapsed_since_start_ns, y: m.value};
}
}

this.series.sort((a, b) => {
const aAvg = a.points.reduce((acc, point) => acc + point.y, 0) / a.points.length;
const bAvg = b.points.reduce((acc, point) => acc + point.y, 0) / b.points.length;
return bAvg - aAvg;
});

this.domains.y[1] = 100;
this.configSpace = configSpace.withHeight(this.domains.y[1] - this.domains.y[0]);

this.formatter = makeFormatter(measurement.unit, 0);
this.formatter = makeFormatter(measurements[0].unit, 0);
}
}
9 changes: 9 additions & 0 deletions static/app/utils/profiling/gl/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Fuse from 'fuse.js';
import {mat3, vec2} from 'gl-matrix';

import {CanvasView} from 'sentry/utils/profiling/canvasView';
import {ColorChannels} from 'sentry/utils/profiling/flamegraph/flamegraphTheme';
import {FlamegraphFrame} from 'sentry/utils/profiling/flamegraphFrame';
import {FlamegraphRenderer} from 'sentry/utils/profiling/renderers/flamegraphRenderer';

Expand Down Expand Up @@ -382,6 +383,14 @@ export interface TrimTextCenter {
text: string;
}

export function hexToColorChannels(color: string, alpha: number): ColorChannels {
return [
parseInt(color.slice(1, 3), 16) / 255,
parseInt(color.slice(3, 5), 16) / 255,
parseInt(color.slice(5, 7), 16) / 255,
alpha,
];
}
// Utility function to compute a clamped view. This is essentially a bounds check
// to ensure that zoomed viewports stays in the bounds and does not escape the view.
export function computeClampedConfigView(
Expand Down
8 changes: 4 additions & 4 deletions static/app/utils/profiling/renderers/chartRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ export class FlamegraphChartRenderer {

// Draw series
for (let i = 0; i < this.chart.series.length; i++) {
this.context.lineWidth = 1;
this.context.lineWidth = 1 * window.devicePixelRatio;
this.context.fillStyle = this.chart.series[i].fillColor;
this.context.strokeStyle = this.chart.series[i].lineColor;
this.context.beginPath();
this.context.lineCap = 'round';
this.context.beginPath();
const serie = this.chart.series[i];

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

if (j === 0) {
if (serie.type === 'area' && j === 0) {
this.context.lineTo(r[0], origin[1]);
}
this.context.lineTo(r[0], r[1]);
if (j === serie.points.length - 1) {
if (serie.type === 'area' && j === serie.points.length - 1) {
this.context.lineTo(r[0], origin[1]);
}
}
Expand Down
Loading