Skip to content

ref(profiling) store unit on profile chart #74152

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

Merged
merged 11 commits into from
Jul 15, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,7 @@ export function ContinuousFlamegraph(): ReactElement {
batteryChart={
hasBatteryChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
status={profiles.type}
chartCanvasRef={batteryChartCanvasRef}
chartCanvas={batteryChartCanvas}
Expand All @@ -1101,6 +1102,7 @@ export function ContinuousFlamegraph(): ReactElement {
memoryChart={
hasMemoryChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
status={profiles.type}
chartCanvasRef={memoryChartCanvasRef}
chartCanvas={memoryChartCanvas}
Expand All @@ -1126,6 +1128,7 @@ export function ContinuousFlamegraph(): ReactElement {
cpuChart={
hasCPUChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
status={profiles.type}
chartCanvasRef={cpuChartCanvasRef}
chartCanvas={cpuChartCanvas}
Expand Down
3 changes: 3 additions & 0 deletions static/app/components/profiling/flamegraph/flamegraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,7 @@ function Flamegraph(): ReactElement {
batteryChart={
hasBatteryChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
status={profiles.type}
chartCanvasRef={batteryChartCanvasRef}
chartCanvas={batteryChartCanvas}
Expand All @@ -1406,6 +1407,7 @@ function Flamegraph(): ReactElement {
memoryChart={
hasMemoryChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
status={profiles.type}
chartCanvasRef={memoryChartCanvasRef}
chartCanvas={memoryChartCanvas}
Expand All @@ -1431,6 +1433,7 @@ function Flamegraph(): ReactElement {
cpuChart={
hasCPUChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
status={profiles.type}
chartCanvasRef={cpuChartCanvasRef}
chartCanvas={cpuChartCanvas}
Expand Down
15 changes: 12 additions & 3 deletions static/app/components/profiling/flamegraph/flamegraphChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import {
getPhysicalSpacePositionFromOffset,
transformMatrixBetweenRect,
} from 'sentry/utils/profiling/gl/utils';
import type {Profile} from 'sentry/utils/profiling/profile/profile';
import {FlamegraphChartRenderer} from 'sentry/utils/profiling/renderers/chartRenderer';
import type {Rect} from 'sentry/utils/profiling/speedscope';
import {formatTo} from 'sentry/utils/profiling/units/units';

import {useCanvasScroll} from './interactions/useCanvasScroll';
import {useCanvasZoomOrScroll} from './interactions/useCanvasZoomOrScroll';
Expand All @@ -36,6 +38,7 @@ interface FlamegraphChartProps {
chartCanvas: FlamegraphCanvas | null;
chartCanvasRef: HTMLCanvasElement | null;
chartView: CanvasView<FlamegraphChartModel> | null;
configViewUnit: Profile['unit'];
noMeasurementMessage: string | undefined;
setChartCanvasRef: (ref: HTMLCanvasElement | null) => void;
status: RequestState<any>['type'];
Expand All @@ -51,9 +54,10 @@ export function FlamegraphChart({
setChartCanvasRef,
canvasBounds,
noMeasurementMessage,
configViewUnit,
}: FlamegraphChartProps) {
const scheduler = useCanvasScheduler(canvasPoolManager);
const theme = useFlamegraphTheme();
const scheduler = useCanvasScheduler(canvasPoolManager);

const [configSpaceCursor, setConfigSpaceCursor] = useState<vec2 | null>(null);
const [startInteractionVector, setStartInteractionVector] = useState<vec2 | null>(null);
Expand Down Expand Up @@ -262,15 +266,20 @@ export function FlamegraphChart({
[configSpaceCursor, chartView]
);

const isInsufficientDuration = useMemo(() => {
if (!chart) return false;
return formatTo(chart?.configSpace.width, configViewUnit, 'millisecond') < 200;
}, [chart, configViewUnit]);

let message: string | undefined;

if (chart) {
if (
chart.configSpace.width < 200 * 1e6 &&
isInsufficientDuration &&
(chart.status === 'insufficient data' || chart.status === 'empty metrics')
) {
message = t('Profile duration was too short to collect enough metrics');
} else if (chart.configSpace.width >= 200 && chart.status === 'insufficient data') {
} else if (!isInsufficientDuration && chart.status === 'insufficient data') {
message =
noMeasurementMessage ||
t(
Expand Down
12 changes: 11 additions & 1 deletion static/app/utils/profiling/flamegraphChart.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type {ColorChannels} from 'sentry/utils/profiling/flamegraph/flamegraphTheme';
import {Rect} from 'sentry/utils/profiling/speedscope';
import type {ProfilingFormatterUnit} from 'sentry/utils/profiling/units/units';

import {colorComponentsToRGBA} from './colors/utils';
import {makeFormatter, makeTimelineFormatter} from './units/units';
import {
assertValidProfilingUnit,
makeFormatter,
makeTimelineFormatter,
} from './units/units';

interface Series {
fillColor: string;
Expand Down Expand Up @@ -35,6 +40,7 @@ interface ChartOptions {

export class FlamegraphChart {
configSpace: Rect;
unit: ProfilingFormatterUnit;
formatter: ReturnType<typeof makeFormatter>;
tooltipFormatter: ReturnType<typeof makeFormatter>;
timelineFormatter: (value: number) => string;
Expand Down Expand Up @@ -63,6 +69,7 @@ export class FlamegraphChart {
if (!measurements || !measurements.length) {
this.formatter = makeFormatter('percent');
this.tooltipFormatter = makeFormatter('percent');
this.unit = 'percent';
this.configSpace = configSpace.clone();
this.status = !measurements ? 'no metrics' : 'empty metrics';
return;
Expand Down Expand Up @@ -128,6 +135,9 @@ export class FlamegraphChart {
this.domains.y[1] = this.domains.y[1] + this.domains.y[1] * 0.1;
this.configSpace = configSpace.withHeight(this.domains.y[1] - this.domains.y[0]);

assertValidProfilingUnit(measurements[0].unit);
this.unit = measurements[0].unit;

this.formatter = makeFormatter(
measurements[0].unit,
computeLabelPrecision(this.domains.y[0], this.domains.y[1])
Expand Down
9 changes: 8 additions & 1 deletion static/app/utils/profiling/units/units.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ const durationMappings: Record<ProfilingFormatterUnit, number> = {
watts: 1,
};

export function assertValidProfilingUnit(
unit: string
): asserts unit is ProfilingFormatterUnit {
if (unit in durationMappings) return;
throw new Error(`Invalid profiling unit: ${unit}`);
}

export function fromNanoJoulesToWatts(nanojoules: number, seconds: number) {
const joules = nanojoules * durationMappings.nanojoules;
return joules / seconds;
Expand Down Expand Up @@ -155,7 +162,7 @@ export function makeFormatter(
};
}

return (value: number) => {
return function formatToDuration(value: number): string {
const duration = value * multiplier;

if (duration >= 1) {
Expand Down
Loading