mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Profiling] Small improvements to the differential function view (#144824)
Improved the visualization of data in profiling by showing more details and using more nicely formatted numbers. Fixes https://github.com/elastic/prodfiler/issues/2772 Co-authored-by: Tim Rühsen <tim.ruhsen@elastic.co>
This commit is contained in:
parent
64c3c63e21
commit
0a5050bd37
1 changed files with 122 additions and 38 deletions
|
@ -32,19 +32,100 @@ interface Row {
|
|||
inclusiveCPU: number;
|
||||
diff?: {
|
||||
rank: number;
|
||||
samples: number;
|
||||
exclusiveCPU: number;
|
||||
inclusiveCPU: number;
|
||||
};
|
||||
}
|
||||
|
||||
function getColorLabel(percent: number) {
|
||||
const color = percent < 0 ? 'success' : 'danger';
|
||||
const prefix = percent < 0 ? '-' : '+';
|
||||
const label =
|
||||
Math.abs(percent) <= 0.01 ? '<0.01' : ' ' + prefix + Math.abs(percent).toFixed(2) + '%';
|
||||
|
||||
return [color, label] as const;
|
||||
}
|
||||
|
||||
function TotalSamplesStat({
|
||||
totalSamples,
|
||||
newSamples,
|
||||
}: {
|
||||
totalSamples: number;
|
||||
newSamples: number | undefined;
|
||||
}) {
|
||||
const sampleHeader = i18n.translate('xpack.profiling.functionsView.totalSampleCountLabel', {
|
||||
defaultMessage: ' Total sample estimate: ',
|
||||
});
|
||||
|
||||
if (newSamples === undefined || newSamples === 0) {
|
||||
return (
|
||||
<EuiText size="xs">
|
||||
<strong>{sampleHeader}</strong>
|
||||
{' ' + totalSamples.toLocaleString()}
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
|
||||
const diffSamples = totalSamples - newSamples;
|
||||
const percentDelta = (diffSamples / (totalSamples - diffSamples)) * 100;
|
||||
const [color, label] = getColorLabel(percentDelta);
|
||||
|
||||
return (
|
||||
<EuiText size="xs">
|
||||
<strong>{sampleHeader}</strong>
|
||||
{' ' + totalSamples.toLocaleString() + ' '}
|
||||
<EuiTextColor color={color}>({label})</EuiTextColor>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
|
||||
function SampleStat({
|
||||
samples,
|
||||
diffSamples,
|
||||
totalSamples,
|
||||
}: {
|
||||
samples: number;
|
||||
diffSamples: number | undefined;
|
||||
totalSamples: number;
|
||||
}) {
|
||||
const samplesLabel = `${samples.toLocaleString()}`;
|
||||
|
||||
if (diffSamples === undefined || diffSamples === 0 || totalSamples === 0) {
|
||||
return <>{samplesLabel}</>;
|
||||
}
|
||||
|
||||
const percentDelta = (diffSamples / (samples - diffSamples)) * 100;
|
||||
const [color, label] = getColorLabel(percentDelta);
|
||||
|
||||
const totalPercentDelta = (diffSamples / totalSamples) * 100;
|
||||
const [totalColor, totalLabel] = getColorLabel(totalPercentDelta);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem>{samplesLabel}</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText color={color} size="s">
|
||||
{label} rel
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText color={totalColor} size="s">
|
||||
{totalLabel} abs
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
function CPUStat({ cpu, diffCPU }: { cpu: number; diffCPU: number | undefined }) {
|
||||
const cpuLabel = `${cpu.toFixed(2)}%`;
|
||||
|
||||
if (diffCPU === undefined || diffCPU === 0) {
|
||||
return <>{cpuLabel}</>;
|
||||
}
|
||||
const color = diffCPU < 0 ? 'success' : 'danger';
|
||||
const label = Math.abs(diffCPU) <= 0.01 ? '<0.01' : Math.abs(diffCPU).toFixed(2);
|
||||
|
||||
const [color, label] = getColorLabel(diffCPU);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
|
@ -58,18 +139,6 @@ function CPUStat({ cpu, diffCPU }: { cpu: number; diffCPU: number | undefined })
|
|||
);
|
||||
}
|
||||
|
||||
function TotalDiff({ samples1, samples2 }: { samples1: number; samples2: number }) {
|
||||
if (samples1 === samples2 || samples1 === 0) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const diff = Math.abs(1 - samples2 / samples1) * 100;
|
||||
const text = (samples1 < samples2 ? '+' : '-') + `${diff.toFixed(2)}%`;
|
||||
const color = samples1 < samples2 ? 'danger' : 'success';
|
||||
|
||||
return <EuiTextColor color={color}> ({text})</EuiTextColor>;
|
||||
}
|
||||
|
||||
export const TopNFunctionsTable = ({
|
||||
sortDirection,
|
||||
sortField,
|
||||
|
@ -87,7 +156,7 @@ export const TopNFunctionsTable = ({
|
|||
comparisonTopNFunctions?: TopNFunctions;
|
||||
}) => {
|
||||
const totalCount: number = useMemo(() => {
|
||||
if (!topNFunctions || !topNFunctions.TotalCount || topNFunctions.TotalCount === 0) {
|
||||
if (!topNFunctions || !topNFunctions.TotalCount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -113,6 +182,7 @@ export const TopNFunctionsTable = ({
|
|||
comparisonTopNFunctions && comparisonRow
|
||||
? {
|
||||
rank: topN.Rank - comparisonRow.Rank,
|
||||
samples: topN.CountExclusive - comparisonRow.CountExclusive,
|
||||
exclusiveCPU:
|
||||
exclusiveCPU -
|
||||
(comparisonRow.CountExclusive / comparisonTopNFunctions.TotalCount) * 100,
|
||||
|
@ -154,18 +224,31 @@ export const TopNFunctionsTable = ({
|
|||
{
|
||||
field: TopNFunctionSortField.Samples,
|
||||
name: i18n.translate('xpack.profiling.functionsView.samplesColumnLabel', {
|
||||
defaultMessage: 'Samples',
|
||||
defaultMessage: 'Samples (estd.)',
|
||||
}),
|
||||
align: 'right',
|
||||
render: (_, { samples }) => {
|
||||
return <EuiText style={{ whiteSpace: 'nowrap', fontSize: 'inherit' }}>{samples}</EuiText>;
|
||||
render: (_, { samples, diff }) => {
|
||||
return (
|
||||
<SampleStat samples={samples} diffSamples={diff?.samples} totalSamples={totalCount} />
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: TopNFunctionSortField.ExclusiveCPU,
|
||||
name: i18n.translate('xpack.profiling.functionsView.exclusiveCpuColumnLabel', {
|
||||
defaultMessage: 'Exclusive CPU',
|
||||
}),
|
||||
name: (
|
||||
<EuiFlexGroup direction="column" gutterSize="xs">
|
||||
<EuiFlexItem>
|
||||
{i18n.translate('xpack.profiling.functionsView.cpuColumnLabel1Exclusive', {
|
||||
defaultMessage: 'CPU excl.',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{i18n.translate('xpack.profiling.functionsView.cpuColumnLabel2Exclusive', {
|
||||
defaultMessage: 'subfunctions',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
render: (_, { exclusiveCPU, diff }) => {
|
||||
return <CPUStat cpu={exclusiveCPU} diffCPU={diff?.exclusiveCPU} />;
|
||||
},
|
||||
|
@ -173,9 +256,20 @@ export const TopNFunctionsTable = ({
|
|||
},
|
||||
{
|
||||
field: TopNFunctionSortField.InclusiveCPU,
|
||||
name: i18n.translate('xpack.profiling.functionsView.inclusiveCpuColumnLabel', {
|
||||
defaultMessage: 'Inclusive CPU',
|
||||
}),
|
||||
name: (
|
||||
<EuiFlexGroup direction="column" gutterSize="xs">
|
||||
<EuiFlexItem>
|
||||
{i18n.translate('xpack.profiling.functionsView.cpuColumnLabel1Inclusive', {
|
||||
defaultMessage: 'CPU incl.',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{i18n.translate('xpack.profiling.functionsView.cpuColumnLabel2Inclusive', {
|
||||
defaultMessage: 'subfunctions',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
render: (_, { inclusiveCPU, diff }) => {
|
||||
return <CPUStat cpu={inclusiveCPU} diffCPU={diff?.inclusiveCPU} />;
|
||||
},
|
||||
|
@ -220,13 +314,6 @@ export const TopNFunctionsTable = ({
|
|||
});
|
||||
}
|
||||
|
||||
const totalSampleCountLabel = i18n.translate(
|
||||
'xpack.profiling.functionsView.totalSampleCountLabel',
|
||||
{
|
||||
defaultMessage: 'Total sample count',
|
||||
}
|
||||
);
|
||||
|
||||
const sortedRows = orderBy(
|
||||
rows,
|
||||
(row) => {
|
||||
|
@ -239,13 +326,10 @@ export const TopNFunctionsTable = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<EuiText size="xs">
|
||||
<strong>{totalSampleCountLabel}:</strong> {totalCount}
|
||||
{TotalDiff({
|
||||
samples1: comparisonTopNFunctions?.TotalCount ?? 0,
|
||||
samples2: totalCount,
|
||||
})}
|
||||
</EuiText>
|
||||
<TotalSamplesStat
|
||||
totalSamples={totalCount}
|
||||
newSamples={comparisonTopNFunctions?.TotalCount}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiHorizontalRule margin="none" style={{ height: 2 }} />
|
||||
<EuiBasicTable
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue