diff --git a/static/app/components/profiling/flamegraph/continuousFlamegraph.tsx b/static/app/components/profiling/flamegraph/continuousFlamegraph.tsx index 88fee609f9122e..b52c6d6f27f23b 100644 --- a/static/app/components/profiling/flamegraph/continuousFlamegraph.tsx +++ b/static/app/components/profiling/flamegraph/continuousFlamegraph.tsx @@ -1080,6 +1080,7 @@ export function ContinuousFlamegraph(): ReactElement { batteryChart={ hasBatteryChart ? ( | null; + configViewUnit: Profile['unit']; noMeasurementMessage: string | undefined; setChartCanvasRef: (ref: HTMLCanvasElement | null) => void; status: RequestState['type']; @@ -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(null); const [startInteractionVector, setStartInteractionVector] = useState(null); @@ -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( diff --git a/static/app/utils/profiling/flamegraphChart.tsx b/static/app/utils/profiling/flamegraphChart.tsx index 486746bd4c3aef..fe818e5ed6f6ea 100644 --- a/static/app/utils/profiling/flamegraphChart.tsx +++ b/static/app/utils/profiling/flamegraphChart.tsx @@ -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; @@ -35,6 +40,7 @@ interface ChartOptions { export class FlamegraphChart { configSpace: Rect; + unit: ProfilingFormatterUnit; formatter: ReturnType; tooltipFormatter: ReturnType; timelineFormatter: (value: number) => string; @@ -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; @@ -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]) diff --git a/static/app/utils/profiling/units/units.ts b/static/app/utils/profiling/units/units.ts index 11b344cb08a613..f33d4f236faab1 100644 --- a/static/app/utils/profiling/units/units.ts +++ b/static/app/utils/profiling/units/units.ts @@ -45,6 +45,13 @@ const durationMappings: Record = { 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; @@ -155,7 +162,7 @@ export function makeFormatter( }; } - return (value: number) => { + return function formatToDuration(value: number): string { const duration = value * multiplier; if (duration >= 1) {