"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getFlamegraphModel = getFlamegraphModel; var _i18n = require("@kbn/i18n"); var _d = _interopRequireDefault(require("d3")); var _lodash = require("lodash"); var _columnar_view_model = require("../../../common/columnar_view_model"); var _frame_type_colors = require("../../../common/frame_type_colors"); var _profiling = require("../../../common/profiling"); var _normalization_menu = require("../../components/normalization_menu"); var _get_interpolation_value = require("./get_interpolation_value"); /* * 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. */ const nullColumnarViewModel = { label: [], value: new Float64Array(), color: new Float32Array(), position0: new Float32Array(), position1: new Float32Array(), size0: new Float32Array(), size1: new Float32Array() }; function getFlamegraphModel({ primaryFlamegraph, comparisonFlamegraph, colorSuccess, colorDanger, colorNeutral, comparisonMode = _normalization_menu.ComparisonMode.Absolute, comparison, baseline }) { const comparisonNodesById = {}; if (!primaryFlamegraph || !primaryFlamegraph.Label || primaryFlamegraph.Label.length === 0) { return { key: (0, _lodash.uniqueId)(), viewModel: nullColumnarViewModel, comparisonNodesById, legendItems: [] }; } const viewModel = (0, _columnar_view_model.createColumnarViewModel)(primaryFlamegraph, comparisonFlamegraph === undefined); let legendItems; if (!comparisonFlamegraph) { const usedFrameTypes = new Set([...primaryFlamegraph.FrameType]); legendItems = (0, _lodash.compact)(Object.entries(_frame_type_colors.FRAME_TYPE_COLOR_MAP).map(([frameTypeKey, colors]) => { const frameType = Number(frameTypeKey); return usedFrameTypes.has(frameType) ? { color: `#${colors[0].toString(16)}`, label: (0, _profiling.describeFrameType)(frameType) } : undefined; })); } else { const positiveChangeInterpolator = _d.default.interpolateRgb(colorNeutral, colorSuccess); const negativeChangeInterpolator = _d.default.interpolateRgb(colorNeutral, colorDanger); function getColor(interpolationValue) { const nodeColor = interpolationValue >= 0 ? positiveChangeInterpolator(interpolationValue) : negativeChangeInterpolator(Math.abs(interpolationValue)); return nodeColor; } legendItems = (0, _lodash.range)(1, -1, -0.2).concat(-1).map(value => { const rounded = Math.round(value * 100) / 100; const color = getColor(rounded); return { color, label: rounded === 0 ? _i18n.i18n.translate('xpack.profiling.flamegraphModel.noChange', { defaultMessage: 'No change' }) : '' }; }); comparisonFlamegraph.ID.forEach((nodeID, index) => { comparisonNodesById[nodeID] = { CountInclusive: comparisonFlamegraph.CountInclusive[index], CountExclusive: comparisonFlamegraph.CountExclusive[index] }; }); // per @thomasdullien: // In "relative" mode: Take the percentage of CPU time consumed by block A and subtract // the percentage of CPU time consumed by block B. If the number is positive, linearly // interpolate a color between grey and green, with the delta relative to the size of // block A as percentage. // Example 1: BlockA 8%, BlockB 5%, delta 3%. This represents a 3/8th reduction, 37.5% // of the original time, so the color should be 37.5% "green". // Example 2: BlockA 5%, BlockB 8%, delta -3%. This represents a 3/5th worsening of BlockA, // so the color should be 62.5% "red". In "absolute" mode: Take the number of samples in // blockA, subtract the number of samples in blockB. Divide the result by the number of // samples in the first graph. The result is the amount of saturation for the color. // Example 3: BlockA 10k samples, BlockB 8k samples, total samples 50k. 10k-8k = 2k, 2k/50k // = 4%, therefore 4% "green". const totalSamples = (0, _lodash.sum)(primaryFlamegraph.CountExclusive); const comparisonTotalSamples = (0, _lodash.sum)(comparisonFlamegraph.CountExclusive); const weightComparisonSide = comparisonMode === _normalization_menu.ComparisonMode.Relative ? 1 : (comparison !== null && comparison !== void 0 ? comparison : 1) / (baseline !== null && baseline !== void 0 ? baseline : 1); primaryFlamegraph.ID.forEach((nodeID, index) => { var _comparisonNodesById$; const samples = primaryFlamegraph.CountInclusive[index]; const comparisonSamples = (_comparisonNodesById$ = comparisonNodesById[nodeID]) === null || _comparisonNodesById$ === void 0 ? void 0 : _comparisonNodesById$.CountInclusive; const foreground = comparisonMode === _normalization_menu.ComparisonMode.Absolute ? samples : samples / totalSamples; const background = comparisonMode === _normalization_menu.ComparisonMode.Absolute ? comparisonSamples : (comparisonSamples !== null && comparisonSamples !== void 0 ? comparisonSamples : 0) / comparisonTotalSamples; const denominator = comparisonMode === _normalization_menu.ComparisonMode.Absolute ? totalSamples : foreground; const interpolationValue = (0, _get_interpolation_value.getInterpolationValue)(foreground, background === undefined ? undefined : background * weightComparisonSide, denominator); const nodeColor = getColor(interpolationValue); const rgba = (0, _frame_type_colors.rgbToRGBA)(Number(nodeColor.replace('#', '0x'))); viewModel.color.set(rgba, 4 * index); }); } return { key: (0, _lodash.uniqueId)(), viewModel, comparisonNodesById, legendItems }; }