kibana/x-pack/plugins/profiling/public/components/topn_functions/utils.ts
Cauê Marcondes 12695646cf
[Profiling] New settings to control CO2 calculation (#166637)
- Added new Profiling settings so users can customize the CO2 variables
- Fixed Embeddable components to also read the new settings
- Moved code from APM to obs-shared to create the custom settings page
in Profiling.
- New Settings Page was created in Profiling UI so users can easily find
the settings:
<img width="2053" alt="Screenshot 2023-09-22 at 11 18 35"
src="6969b079-745d-4302-8ff2-4f0f256c7f51">

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
2023-09-30 02:25:55 -07:00

179 lines
5 KiB
TypeScript

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { keyBy } from 'lodash';
import type { StackFrameMetadata, TopNFunctions } from '@kbn/profiling-utils';
import {
CalculateImpactEstimates,
ImpactEstimates,
} from '../../hooks/use_calculate_impact_estimates';
export function getColorLabel(percent: number) {
if (percent === 0) {
return { color: 'text', label: `0%`, icon: undefined };
}
const color = percent < 0 ? 'success' : 'danger';
const icon = percent < 0 ? 'sortUp' : 'sortDown';
const isSmallPercent = Math.abs(percent) <= 0.01;
const value = isSmallPercent ? '<0.01' : Math.abs(percent).toFixed(2);
if (isFinite(percent)) {
return { color, label: `${value}%`, icon };
}
return { color: 'text', label: undefined, icon: undefined };
}
export function scaleValue({ value, scaleFactor = 1 }: { value: number; scaleFactor?: number }) {
return value * scaleFactor;
}
export interface IFunctionRow {
rank: number;
frame: StackFrameMetadata;
samples: number;
selfCPU: number;
totalCPU: number;
selfCPUPerc: number;
totalCPUPerc: number;
impactEstimates?: ImpactEstimates;
diff?: {
rank: number;
samples: number;
selfCPU: number;
totalCPU: number;
selfCPUPerc: number;
totalCPUPerc: number;
impactEstimates?: ImpactEstimates;
};
}
export function getFunctionsRows({
baselineScaleFactor,
comparisonScaleFactor,
comparisonTopNFunctions,
topNFunctions,
totalSeconds,
calculateImpactEstimates,
}: {
baselineScaleFactor?: number;
comparisonScaleFactor?: number;
comparisonTopNFunctions?: TopNFunctions;
topNFunctions?: TopNFunctions;
totalSeconds: number;
calculateImpactEstimates: CalculateImpactEstimates;
}): IFunctionRow[] {
if (!topNFunctions || !topNFunctions.TotalCount || topNFunctions.TotalCount === 0) {
return [];
}
const comparisonDataById = comparisonTopNFunctions
? keyBy(comparisonTopNFunctions.TopN, 'Id')
: {};
return topNFunctions.TopN.filter((topN) => topN.CountExclusive >= 0).map((topN, i) => {
const comparisonRow = comparisonDataById?.[topN.Id];
const scaledSelfCPU = scaleValue({
value: topN.CountExclusive,
scaleFactor: baselineScaleFactor,
});
const totalCPUPerc = (topN.CountInclusive / topNFunctions.TotalCount) * 100;
const selfCPUPerc = (topN.CountExclusive / topNFunctions.TotalCount) * 100;
const impactEstimates =
totalSeconds > 0
? calculateImpactEstimates({
countExclusive: topN.CountExclusive,
countInclusive: topN.CountInclusive,
totalSamples: topNFunctions.TotalCount,
totalSeconds,
})
: undefined;
function calculateDiff() {
if (comparisonTopNFunctions && comparisonRow) {
const comparisonScaledSelfCPU = scaleValue({
value: comparisonRow.CountExclusive,
scaleFactor: comparisonScaleFactor,
});
const scaledDiffSamples = scaledSelfCPU - comparisonScaledSelfCPU;
return {
rank: topN.Rank - comparisonRow.Rank,
samples: scaledDiffSamples,
selfCPU: comparisonRow.CountExclusive,
totalCPU: comparisonRow.CountInclusive,
selfCPUPerc:
selfCPUPerc - (comparisonRow.CountExclusive / comparisonTopNFunctions.TotalCount) * 100,
totalCPUPerc:
totalCPUPerc -
(comparisonRow.CountInclusive / comparisonTopNFunctions.TotalCount) * 100,
};
}
}
return {
rank: topN.Rank,
frame: topN.Frame,
samples: scaledSelfCPU,
selfCPUPerc,
totalCPUPerc,
selfCPU: topN.CountExclusive,
totalCPU: topN.CountInclusive,
impactEstimates,
diff: calculateDiff(),
};
});
}
export function calculateBaseComparisonDiff({
baselineValue,
baselineScaleFactor,
comparisonValue,
comparisonScaleFactor,
formatValue,
}: {
baselineValue: number;
baselineScaleFactor?: number;
comparisonValue: number;
comparisonScaleFactor?: number;
formatValue?: (value: number) => string;
}) {
const scaledBaselineValue = scaleValue({
value: baselineValue,
scaleFactor: baselineScaleFactor,
});
const baseValue = formatValue
? formatValue(scaledBaselineValue)
: scaledBaselineValue.toLocaleString();
if (comparisonValue === 0) {
return { baseValue };
}
const scaledComparisonValue = scaleValue({
value: comparisonValue,
scaleFactor: comparisonScaleFactor,
});
const diffSamples = scaledComparisonValue - scaledBaselineValue;
const percentDiffDelta = (diffSamples / (scaledComparisonValue - diffSamples)) * 100;
const { color, icon, label } = getColorLabel(percentDiffDelta);
return {
baseValue,
comparisonValue: formatValue
? formatValue(scaledComparisonValue)
: scaledComparisonValue.toLocaleString(),
percentDiffDelta,
color,
icon,
label,
};
}