Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ function ProfilingMeasurements({
onMouseDown={onStartWindowSelection}
>
<MemoizedChart
data={data}
data={data as Profiling.Measurement}
type={measurementType}
transactionDuration={transactionDurationInMs}
/>
Expand Down
116 changes: 88 additions & 28 deletions static/app/components/profiling/flamegraph/continuousFlamegraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,19 @@ import {
initializeFlamegraphRenderer,
useResizeCanvasObserver,
} from 'sentry/utils/profiling/gl/utils';
import type {ProfileGroup} from 'sentry/utils/profiling/profile/importProfile';
import type {ContinuousProfileGroup} from 'sentry/utils/profiling/profile/importProfile';
import {FlamegraphRenderer2D} from 'sentry/utils/profiling/renderers/flamegraphRenderer2D';
import {FlamegraphRendererWebGL} from 'sentry/utils/profiling/renderers/flamegraphRendererWebGL';
import {Rect} from 'sentry/utils/profiling/speedscope';
import {UIFrames} from 'sentry/utils/profiling/uiFrames';
import {fromNanoJoulesToWatts} from 'sentry/utils/profiling/units/units';
import {
fromNanoJoulesToWatts,
type ProfilingFormatterUnit,
} from 'sentry/utils/profiling/units/units';
import {useDevicePixelRatio} from 'sentry/utils/useDevicePixelRatio';
import {useMemoWithPrevious} from 'sentry/utils/useMemoWithPrevious';
import {useContinuousProfile} from 'sentry/views/profiling/continuousProfileProvider';
import {useProfileGroup} from 'sentry/views/profiling/profileGroupProvider';
import {useContinuousProfileGroup} from 'sentry/views/profiling/profileGroupProvider';

import {FlamegraphDrawer} from './flamegraphDrawer/flamegraphDrawer';
import {FlamegraphWarnings} from './flamegraphOverlays/FlamegraphWarnings';
Expand All @@ -64,7 +67,7 @@ import {FlamegraphChart} from './flamegraphChart';
import {FlamegraphLayout} from './flamegraphLayout';
import {FlamegraphUIFrames} from './flamegraphUIFrames';

function getMaxConfigSpace(profileGroup: ProfileGroup): Rect {
function getMaxConfigSpace(profileGroup: ContinuousProfileGroup): Rect {
// We have a transaction, so we should do our best to align the profile
// with the transaction's timeline.
const maxProfileDuration = Math.max(...profileGroup.profiles.map(p => p.duration));
Expand Down Expand Up @@ -123,7 +126,7 @@ export function ContinuousFlamegraph(): ReactElement {
const dispatch = useDispatchFlamegraphState();

const profiles = useContinuousProfile();
const profileGroup = useProfileGroup();
const profileGroup = useContinuousProfileGroup();

const flamegraphTheme = useFlamegraphTheme();
const position = useFlamegraphZoomPosition();
Expand Down Expand Up @@ -229,7 +232,11 @@ export function ContinuousFlamegraph(): ReactElement {
}
return new UIFrames(
{
// @TODO
// @ts-expect-error
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these need to be updated, I'm going to tackle them in the next PR

slow: profileGroup.measurements?.slow_frame_renders,
// @TODO
// @ts-expect-error
frozen: profileGroup.measurements?.frozen_frame_renders,
},
{unit: flamegraph.profile.unit},
Expand All @@ -251,25 +258,31 @@ export function ContinuousFlamegraph(): ReactElement {

for (const key in profileGroup.measurements) {
if (key === 'cpu_energy_usage') {
measures.push({
...profileGroup.measurements[key]!,
values: profileGroup.measurements[key]!.values.map(v => {
return {
elapsed_since_start_ns: v.elapsed_since_start_ns,
value: fromNanoJoulesToWatts(v.value, 0.1),
};
}),
// some versions of cocoa send byte so we need to correct it to watt
unit: 'watt',
name: 'CPU energy usage',
});
const measurements = profileGroup.measurements[key]!;
const values: ProfileSeriesMeasurement['values'] = [];

let offset = 0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This computes the value offset to the start of the profile

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to put into a helper function that takes a formatted for the value? I see it's copied for all the other charts below.

for (let i = 0; i < measurements.values.length; i++) {
const value = measurements.values[i];
const next = measurements.values[i + 1] ?? value;
offset += (next.timestamp - value.timestamp) * 1e3;

values.push({
value: fromNanoJoulesToWatts(value.value, 0.1),
elapsed: offset,
});
}

// some versions of cocoa send byte so we need to correct it to watt
measures.push({name: 'CPU energy usage', unit: 'watt', values});
}
}

return new FlamegraphChartModel(
Rect.From(flamegraph.configSpace),
measures.length > 0 ? measures : [],
flamegraphTheme.COLORS.BATTERY_CHART_COLORS
flamegraphTheme.COLORS.BATTERY_CHART_COLORS,
{timelineUnit: 'milliseconds'}
);
}, [profileGroup.measurements, flamegraph.configSpace, flamegraphTheme, hasCPUChart]);

Expand All @@ -278,22 +291,39 @@ export function ContinuousFlamegraph(): ReactElement {
return LOADING_OR_FALLBACK_CPU_CHART;
}

const measures: ProfileSeriesMeasurement[] = [];
const cpuMeasurements: ProfileSeriesMeasurement[] = [];

for (const key in profileGroup.measurements) {
if (key.startsWith('cpu_usage')) {
const name =
key === 'cpu_usage'
? 'Average CPU usage'
: `CPU Core ${key.replace('cpu_usage_', '')}`;
measures.push({...profileGroup.measurements[key]!, name});

const measurements = profileGroup.measurements[key]!;
const values: ProfileSeriesMeasurement['values'] = [];

let offset = 0;
for (let i = 0; i < measurements.values.length; i++) {
const value = measurements.values[i];
const next = measurements.values[i + 1] ?? value;
offset += (next.timestamp - value.timestamp) * 1e3;

values.push({
value: value.value,
elapsed: offset,
});
}

cpuMeasurements.push({name, unit: measurements?.unit, values});
}
}

return new FlamegraphChartModel(
Rect.From(flamegraph.configSpace),
measures.length > 0 ? measures : [],
flamegraphTheme.COLORS.CPU_CHART_COLORS
cpuMeasurements.length > 0 ? cpuMeasurements : [],
flamegraphTheme.COLORS.CPU_CHART_COLORS,
{timelineUnit: 'milliseconds'}
);
}, [profileGroup.measurements, flamegraph.configSpace, flamegraphTheme, hasCPUChart]);

Expand All @@ -306,25 +336,55 @@ export function ContinuousFlamegraph(): ReactElement {

const memory_footprint = profileGroup.measurements?.memory_footprint;
if (memory_footprint) {
const values: ProfileSeriesMeasurement['values'] = [];

let offset = 0;
for (let i = 0; i < memory_footprint.values.length; i++) {
const value = memory_footprint.values[i];
const next = memory_footprint.values[i + 1] ?? value;
offset += (next.timestamp - value.timestamp) * 1e3;

values.push({
value: value.value,
elapsed: offset,
});
}

measures.push({
...memory_footprint!,
unit: memory_footprint.unit,
name: 'Heap Usage',
values,
});
}

const native_memory_footprint = profileGroup.measurements?.memory_native_footprint;
if (native_memory_footprint) {
const values: ProfileSeriesMeasurement['values'] = [];

let offset = 0;
for (let i = 0; i < native_memory_footprint.values.length; i++) {
const value = native_memory_footprint.values[i];
const next = native_memory_footprint.values[i + 1] ?? value;
offset += (next.timestamp - value.timestamp) * 1e3;

values.push({
value: value.value,
elapsed: offset,
});
}

measures.push({
...native_memory_footprint!,
unit: native_memory_footprint.unit,
name: 'Native Heap Usage',
values,
});
}

return new FlamegraphChartModel(
Rect.From(flamegraph.configSpace),
measures.length > 0 ? measures : [],
flamegraphTheme.COLORS.MEMORY_CHART_COLORS,
{type: 'area'}
{type: 'area', timelineUnit: 'milliseconds'}
);
}, [
profileGroup.measurements,
Expand Down Expand Up @@ -1080,7 +1140,7 @@ export function ContinuousFlamegraph(): ReactElement {
batteryChart={
hasBatteryChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
configViewUnit={flamegraph.profile.unit as ProfilingFormatterUnit}
status={profiles.type}
chartCanvasRef={batteryChartCanvasRef}
chartCanvas={batteryChartCanvas}
Expand All @@ -1102,7 +1162,7 @@ export function ContinuousFlamegraph(): ReactElement {
memoryChart={
hasMemoryChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
configViewUnit={flamegraph.profile.unit as ProfilingFormatterUnit}
status={profiles.type}
chartCanvasRef={memoryChartCanvasRef}
chartCanvas={memoryChartCanvas}
Expand All @@ -1128,7 +1188,7 @@ export function ContinuousFlamegraph(): ReactElement {
cpuChart={
hasCPUChart ? (
<FlamegraphChart
configViewUnit={flamegraph.profile.unit}
configViewUnit={flamegraph.profile.unit as ProfilingFormatterUnit}
status={profiles.type}
chartCanvasRef={cpuChartCanvasRef}
chartCanvas={cpuChartCanvas}
Expand Down
45 changes: 39 additions & 6 deletions static/app/components/profiling/flamegraph/flamegraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ function Flamegraph(): ReactElement {
...profileGroup.measurements[key]!,
values: profileGroup.measurements[key]!.values.map(v => {
return {
elapsed_since_start_ns: v.elapsed_since_start_ns,
elapsed: v.elapsed_since_start_ns,
value: fromNanoJoulesToWatts(v.value, 0.1),
};
}),
Expand All @@ -414,21 +414,32 @@ function Flamegraph(): ReactElement {
return LOADING_OR_FALLBACK_CPU_CHART;
}

const measures: ProfileSeriesMeasurement[] = [];
const cpuMeasurements: ProfileSeriesMeasurement[] = [];

for (const key in profileGroup.measurements) {
if (key.startsWith('cpu_usage')) {
const name =
key === 'cpu_usage'
? 'Average CPU usage'
: `CPU Core ${key.replace('cpu_usage_', '')}`;
measures.push({...profileGroup.measurements[key]!, name});

const measurements = profileGroup.measurements[key]!;
const values: ProfileSeriesMeasurement['values'] = [];

for (let i = 0; i < measurements.values.length; i++) {
const value = measurements.values[i];
values.push({
value: value.value,
elapsed: value.elapsed_since_start_ns,
});
}
cpuMeasurements.push({name, unit: measurements?.unit, values});
}
}

return new FlamegraphChartModel(
Rect.From(flamegraph.configSpace),
measures.length > 0 ? measures : [],
cpuMeasurements.length > 0 ? cpuMeasurements : [],
flamegraphTheme.COLORS.CPU_CHART_COLORS
);
}, [profileGroup.measurements, flamegraph.configSpace, flamegraphTheme, hasCPUChart]);
Expand All @@ -442,17 +453,39 @@ function Flamegraph(): ReactElement {

const memory_footprint = profileGroup.measurements?.memory_footprint;
if (memory_footprint) {
const values: ProfileSeriesMeasurement['values'] = [];

for (let i = 0; i < memory_footprint.values.length; i++) {
const value = memory_footprint.values[i];
values.push({
value: value.value,
elapsed: value.elapsed_since_start_ns,
});
}

measures.push({
...memory_footprint!,
unit: memory_footprint.unit,
name: 'Heap Usage',
values,
});
}

const native_memory_footprint = profileGroup.measurements?.memory_native_footprint;
if (native_memory_footprint) {
const values: ProfileSeriesMeasurement['values'] = [];

for (let i = 0; i < native_memory_footprint.values.length; i++) {
const value = native_memory_footprint.values[i];
values.push({
value: value.value,
elapsed: value.elapsed_since_start_ns,
});
}

measures.push({
...native_memory_footprint!,
unit: native_memory_footprint.unit,
name: 'Native Heap Usage',
values,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ 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 {formatTo, type ProfilingFormatterUnit} from 'sentry/utils/profiling/units/units';

import {useCanvasScroll} from './interactions/useCanvasScroll';
import {useCanvasZoomOrScroll} from './interactions/useCanvasZoomOrScroll';
Expand All @@ -38,7 +37,7 @@ interface FlamegraphChartProps {
chartCanvas: FlamegraphCanvas | null;
chartCanvasRef: HTMLCanvasElement | null;
chartView: CanvasView<FlamegraphChartModel> | null;
configViewUnit: Profile['unit'];
configViewUnit: ProfilingFormatterUnit;
noMeasurementMessage: string | undefined;
setChartCanvasRef: (ref: HTMLCanvasElement | null) => void;
status: RequestState<any>['type'];
Expand Down Expand Up @@ -310,6 +309,7 @@ export function FlamegraphChart({
chartView={chartView}
chartRenderer={chartRenderer}
canvasBounds={canvasBounds}
configViewUnit={configViewUnit}
/>
) : null}
{/* transaction loads after profile, so we want to show loading even if it's in initial state */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {FlamegraphCanvas} from 'sentry/utils/profiling/flamegraphCanvas';
import type {FlamegraphChart} from 'sentry/utils/profiling/flamegraphChart';
import type {FlamegraphChartRenderer} from 'sentry/utils/profiling/renderers/chartRenderer';
import type {Rect} from 'sentry/utils/profiling/speedscope';
import {formatTo, type ProfilingFormatterUnit} from 'sentry/utils/profiling/units/units';

import {
FlamegraphTooltipColorIndicator,
Expand All @@ -23,6 +24,7 @@ export interface FlamegraphChartTooltipProps {
chartRenderer: FlamegraphChartRenderer;
chartView: CanvasView<FlamegraphChart>;
configSpaceCursor: vec2;
configViewUnit: ProfilingFormatterUnit;
}

export function FlamegraphChartTooltip({
Expand All @@ -32,11 +34,14 @@ export function FlamegraphChartTooltip({
chart,
chartRenderer,
chartView,
}: // chartRenderer,
FlamegraphChartTooltipProps) {
configViewUnit,
}: FlamegraphChartTooltipProps) {
const series = useMemo(() => {
return chartRenderer.findHoveredSeries(configSpaceCursor, 6e7);
}, [chartRenderer, configSpaceCursor]);
return chartRenderer.findHoveredSeries(
configSpaceCursor,
formatTo(100, 'milliseconds', configViewUnit)
);
}, [chartRenderer, configSpaceCursor, configViewUnit]);

return series.length > 0 ? (
<BoundTooltip
Expand Down
Loading