From d8693cb01047434362cf7650b06331627fa8a287 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Mon, 18 Nov 2024 12:26:33 +0530 Subject: [PATCH 01/15] Extracting TimelineGuide from MetricGraphStrips and making it reusable --- .../MetricsGraphStrips/AreaGraph/index.tsx | 4 ++-- .../profile/src/MetricsGraphStrips/index.tsx | 20 +++++++++++++++---- .../TimelineGuide/index.tsx | 19 ++++-------------- ui/packages/shared/profile/src/utils.ts | 2 ++ 4 files changed, 24 insertions(+), 21 deletions(-) rename ui/packages/shared/profile/src/{MetricsGraphStrips => }/TimelineGuide/index.tsx (84%) diff --git a/ui/packages/shared/profile/src/MetricsGraphStrips/AreaGraph/index.tsx b/ui/packages/shared/profile/src/MetricsGraphStrips/AreaGraph/index.tsx index aa16dbcb98b..44b915280d4 100644 --- a/ui/packages/shared/profile/src/MetricsGraphStrips/AreaGraph/index.tsx +++ b/ui/packages/shared/profile/src/MetricsGraphStrips/AreaGraph/index.tsx @@ -17,13 +17,13 @@ import {Icon} from '@iconify/react'; import cx from 'classnames'; import * as d3 from 'd3'; +import {NumberDuo} from '../../utils'; + export interface DataPoint { timestamp: number; value: number; } -export type NumberDuo = [number, number]; - interface Props { width: number; height: number; diff --git a/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx b/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx index e3423f01700..638e2b1ba61 100644 --- a/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx +++ b/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx @@ -11,13 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -import {useState} from 'react'; +import {useMemo, useState} from 'react'; import {Icon} from '@iconify/react'; import * as d3 from 'd3'; -import {AreaGraph, DataPoint, NumberDuo} from './AreaGraph'; -import {TimelineGuide} from './TimelineGuide'; +import {TimelineGuide} from '../TimelineGuide'; +import {NumberDuo} from '../utils'; +import {AreaGraph, DataPoint} from './AreaGraph'; interface Props { cpus: string[]; @@ -44,10 +45,21 @@ export const MetricsGraphStrips = ({ // @ts-expect-error const color = d3.scaleOrdinal(d3.schemeObservable10); + const bounds = useMemo(() => { + const bounds: NumberDuo = [Infinity, -Infinity]; + data.forEach(cpuData => { + cpuData.forEach(dataPoint => { + bounds[0] = Math.min(bounds[0], dataPoint.timestamp); + bounds[1] = Math.max(bounds[1], dataPoint.timestamp); + }); + }); + return [0, bounds[1] - bounds[0]] as NumberDuo; + }, [data]); + return (
{ @@ -35,18 +35,7 @@ const alignBeforeAxisCorrection = (val: number): number => { return 0; }; -export const TimelineGuide = ({data, width, height, margin}: Props): JSX.Element => { - const bounds = useMemo(() => { - const bounds: NumberDuo = [Infinity, -Infinity]; - data.forEach(cpuData => { - cpuData.forEach(dataPoint => { - bounds[0] = Math.min(bounds[0], dataPoint.timestamp); - bounds[1] = Math.max(bounds[1], dataPoint.timestamp); - }); - }); - return [0, bounds[1] - bounds[0]]; - }, [data]); - +export const TimelineGuide = ({bounds, width, height, margin}: Props): JSX.Element => { const xScale = d3.scaleLinear().domain(bounds).range([0, width]); return ( diff --git a/ui/packages/shared/profile/src/utils.ts b/ui/packages/shared/profile/src/utils.ts index f1a22d98c77..6c09f355bca 100644 --- a/ui/packages/shared/profile/src/utils.ts +++ b/ui/packages/shared/profile/src/utils.ts @@ -59,3 +59,5 @@ export const truncateStringReverse = (str: string, num: number): string => { return '...' + str.slice(str.length - num); }; + +export type NumberDuo = [number, number]; From e4d332a1054647310fafbfbb91742c747b663a94 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Wed, 27 Nov 2024 19:35:21 +0530 Subject: [PATCH 02/15] Added ticks count to the props --- ui/packages/shared/profile/src/TimelineGuide/index.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/packages/shared/profile/src/TimelineGuide/index.tsx b/ui/packages/shared/profile/src/TimelineGuide/index.tsx index f9d8e73c64e..f63f1486eca 100644 --- a/ui/packages/shared/profile/src/TimelineGuide/index.tsx +++ b/ui/packages/shared/profile/src/TimelineGuide/index.tsx @@ -22,6 +22,7 @@ interface Props { height: number; margin: number; bounds: NumberDuo; + ticks?: number; } const alignBeforeAxisCorrection = (val: number): number => { @@ -35,7 +36,7 @@ const alignBeforeAxisCorrection = (val: number): number => { return 0; }; -export const TimelineGuide = ({bounds, width, height, margin}: Props): JSX.Element => { +export const TimelineGuide = ({bounds, width, height, margin, ticks}: Props): JSX.Element => { const xScale = d3.scaleLinear().domain(bounds).range([0, width]); return ( @@ -49,7 +50,7 @@ export const TimelineGuide = ({bounds, width, height, margin}: Props): JSX.Eleme textAnchor="middle" transform={`translate(0,${height - margin})`} > - {xScale.ticks().map((d, i) => ( + {xScale.ticks(ticks).map((d, i) => ( Date: Wed, 27 Nov 2024 19:36:31 +0530 Subject: [PATCH 03/15] Removed the unwanted styles --- ui/packages/shared/profile/src/TimelineGuide/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/packages/shared/profile/src/TimelineGuide/index.tsx b/ui/packages/shared/profile/src/TimelineGuide/index.tsx index f63f1486eca..6283cde2595 100644 --- a/ui/packages/shared/profile/src/TimelineGuide/index.tsx +++ b/ui/packages/shared/profile/src/TimelineGuide/index.tsx @@ -65,7 +65,7 @@ export const TimelineGuide = ({bounds, width, height, margin, ticks}: Props): JS Date: Wed, 4 Dec 2024 19:05:24 +0530 Subject: [PATCH 04/15] MetricsGraphStrips props renamed --- .../MetricsGraphStrips.stories.tsx | 14 +++--- .../profile/src/MetricsGraphStrips/index.tsx | 48 ++++++++++++++----- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx b/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx index c541550aac1..027193e85ba 100644 --- a/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx +++ b/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx @@ -48,19 +48,19 @@ export const ThreeCPUStrips = { args: { cpus: Array.from(mockData, (_, i) => `CPU ${i + 1}`), data: mockData, - selectedTimeline: {index: 1, bounds: [mockData[0][25].timestamp, mockData[0][100].timestamp]}, - onSelectedTimeline: (index: number, bounds: NumberDuo): void => { - console.log('onSelectedTimeline', index, bounds); + selectedTimeframe: {index: 1, bounds: [mockData[0][25].timestamp, mockData[0][100].timestamp]}, + onSelectedTimeframe: (index: number, bounds: NumberDuo): void => { + console.log('onSelectedTimeframe', index, bounds); }, }, render: function Component(args: any): JSX.Element { const [, setArgs] = useArgs(); - const onSelectedTimeline = (index: number, bounds: NumberDuo): void => { - args.onSelectedTimeline(index, bounds); - setArgs({...args, selectedTimeline: {index, bounds}}); + const onSelectedTimeframe = (index: number, bounds: NumberDuo): void => { + args.onSelectedTimeframe(index, bounds); + setArgs({...args, selectedTimeframe: {index, bounds}}); }; - return ; + return ; }, }; diff --git a/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx b/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx index 0dacc8952ca..62e9b2f60e3 100644 --- a/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx +++ b/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx @@ -16,30 +16,53 @@ import {useMemo, useState} from 'react'; import {Icon} from '@iconify/react'; import * as d3 from 'd3'; +import {LabelSet} from '@parca/client'; + import {TimelineGuide} from '../TimelineGuide'; import {NumberDuo} from '../utils'; import {AreaGraph, DataPoint} from './AreaGraph'; interface Props { - cpus: string[]; + cpus: LabelSet[]; data: DataPoint[][]; - selectedTimeline?: { - index: number; + selectedTimeframe?: { + labels: LabelSet; bounds: NumberDuo; }; - onSelectedTimeline: (index: number, bounds: NumberDuo | undefined) => void; + onSelectedTimeframe: (labels: LabelSet, bounds: NumberDuo | undefined) => void; width?: number; } -const getTimelineGuideHeight = (cpus: string[], collapsedIndices: number[]): number => { +const labelSetToString = (labelSet?: LabelSet): string => { + if (labelSet === undefined) { + return '{}'; + } + + let str = '{'; + + let isFirst = true; + for (const label of labelSet.labels) { + if (!isFirst) { + str += ', '; + isFirst = false; + } + str += `${label.name}: ${label.value}`; + } + + str += '}'; + + return str; +}; + +const getTimelineGuideHeight = (cpus: LabelSet[], collapsedIndices: number[]): number => { return 56 * (cpus.length - collapsedIndices.length) + 20 * collapsedIndices.length + 24; }; export const MetricsGraphStrips = ({ cpus, data, - selectedTimeline, - onSelectedTimeline, + selectedTimeframe, + onSelectedTimeframe, width, }: Props): JSX.Element => { const [collapsedIndices, setCollapsedIndices] = useState([]); @@ -68,8 +91,9 @@ export const MetricsGraphStrips = ({ /> {cpus.map((cpu, i) => { const isCollapsed = collapsedIndices.includes(i); + const labelStr = labelSetToString(cpu); return ( -
+
{ @@ -83,19 +107,19 @@ export const MetricsGraphStrips = ({ }} > - {cpu} + {labelStr}
{!isCollapsed ? ( { - onSelectedTimeline(i, bounds); + onSelectedTimeframe(cpu, bounds); }} /> ) : null} From 6b8e93f4e5bd26defc4cf813392c7b15f98766b9 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 5 Dec 2024 11:44:46 +0530 Subject: [PATCH 05/15] More refactoring and state integration --- .../IcicleGraphArrow/index.tsx | 1 + .../profile/src/ProfileIcicleGraph/index.tsx | 10 ++++------ .../components/DashboardItems/index.tsx | 3 --- .../ProfileView/context/ProfileViewContext.tsx | 13 +++++++++++++ .../shared/profile/src/ProfileView/index.tsx | 5 ++--- .../src/ProfileView/types/visualization.ts | 2 ++ .../shared/profile/src/ProfileViewWithData.tsx | 16 +++++++++++----- .../shared/profile/src/TimelineGuide/index.tsx | 5 ----- ui/packages/shared/profile/src/index.tsx | 1 + 9 files changed, 34 insertions(+), 22 deletions(-) diff --git a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx index d39d58a8aed..0de487550bb 100644 --- a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +++ b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx @@ -44,6 +44,7 @@ export const FIELD_MAPPING_BUILD_ID = 'mapping_build_id'; export const FIELD_LOCATION_ADDRESS = 'location_address'; export const FIELD_LOCATION_LINE = 'location_line'; export const FIELD_INLINED = 'inlined'; +export const FIELD_TIMESTAMP = 'timestamp'; export const FIELD_FUNCTION_NAME = 'function_name'; export const FIELD_FUNCTION_SYSTEM_NAME = 'function_system_name'; export const FIELD_FUNCTION_FILE_NAME = 'function_file_name'; diff --git a/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx b/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx index 4e81b029c3d..18ce880180c 100644 --- a/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx +++ b/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx @@ -46,7 +46,6 @@ interface ProfileIcicleGraphProps { isHalfScreen: boolean; metadataMappingFiles?: string[]; metadataLoading?: boolean; - showTimelineGuide?: boolean; } const ErrorContent = ({errorMessage}: {errorMessage: string}): JSX.Element => { @@ -66,10 +65,9 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ width, isHalfScreen, metadataMappingFiles, - showTimelineGuide = false, }: ProfileIcicleGraphProps): JSX.Element { const {onError, authenticationErrorMessage, isDarkMode} = useParcaContext(); - const {compareMode} = useProfileViewContext(); + const {compareMode, timelineGuide} = useProfileViewContext(); const [isLoading, setIsLoading] = useState(true); const mappingsList = useMappingList(metadataMappingFiles); @@ -169,9 +167,9 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ if (arrow !== undefined) return (
- {showTimelineGuide && ( + {timelineGuide?.show === true && ( { switch (type) { case 'icicle': @@ -100,7 +98,6 @@ export const getDashboardItem = ({ } metadataMappingFiles={flamegraphData.metadataMappingFiles} metadataLoading={flamegraphData.metadataLoading} - showTimelineGuide={showTimelineGuide} /> ); diff --git a/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx b/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx index 2354ae3b335..05518fa5022 100644 --- a/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx +++ b/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx @@ -13,16 +13,29 @@ import {ReactNode, createContext, useContext} from 'react'; +import {NumberDuo} from 'utils'; + import {ProfileSource} from '../../ProfileSource'; +export type TimelineGuideData = + | {show: false} + | { + show: true; + props: { + bounds: NumberDuo; + }; + }; + interface Props { profileSource?: ProfileSource; compareMode: boolean; + timelineGuide?: TimelineGuideData; } export const defaultValue: Props = { profileSource: undefined, compareMode: false, + timelineGuide: {show: false}, }; const ProfileViewContext = createContext(defaultValue); diff --git a/ui/packages/shared/profile/src/ProfileView/index.tsx b/ui/packages/shared/profile/src/ProfileView/index.tsx index c8414131ddc..96bf25dd778 100644 --- a/ui/packages/shared/profile/src/ProfileView/index.tsx +++ b/ui/packages/shared/profile/src/ProfileView/index.tsx @@ -42,7 +42,7 @@ export const ProfileView = ({ pprofDownloading, compare, showVisualizationSelector, - showTimelineGuide, + timelineGuide, }: ProfileViewProps): JSX.Element => { const { timezone, @@ -110,7 +110,6 @@ export const ProfileView = ({ setSearchString, callgraphSVG, perf, - showTimelineGuide, }); }; @@ -131,7 +130,7 @@ export const ProfileView = ({ return ( - + { const metadata = useGrpcMetadata(); const [dashboardItems] = useURLState('dashboard_items', { @@ -44,7 +47,10 @@ export const ProfileViewWithData = ({ const [sourceBuildID] = useURLState('source_buildid'); const [sourceFilename] = useURLState('source_filename'); const [groupBy] = useURLState('group_by', { - defaultValue: [FIELD_FUNCTION_NAME], + defaultValue: [ + isGroupByTimestamp === true ? FIELD_TIMESTAMP : (null as unknown as string), + FIELD_FUNCTION_NAME, + ].filter(Boolean), alwaysReturnArray: true, }); @@ -244,7 +250,7 @@ export const ProfileViewWithData = ({ onDownloadPProf={() => void downloadPProfClick()} pprofDownloading={pprofDownloading} showVisualizationSelector={showVisualizationSelector} - showTimelineGuide={showTimelineGuide} + timelineGuide={timelineGuide} /> ); }; diff --git a/ui/packages/shared/profile/src/TimelineGuide/index.tsx b/ui/packages/shared/profile/src/TimelineGuide/index.tsx index 44403be73ae..2b9035004df 100644 --- a/ui/packages/shared/profile/src/TimelineGuide/index.tsx +++ b/ui/packages/shared/profile/src/TimelineGuide/index.tsx @@ -88,11 +88,6 @@ export const TimelineGuide = ({bounds, width, height, margin, ticks}: Props): JS y1={-height + 20} y2={-height + 20} /> - {/* - - Time - - */}
diff --git a/ui/packages/shared/profile/src/index.tsx b/ui/packages/shared/profile/src/index.tsx index a5a31b4279d..69460afc323 100644 --- a/ui/packages/shared/profile/src/index.tsx +++ b/ui/packages/shared/profile/src/index.tsx @@ -25,6 +25,7 @@ export * from './ProfileViewWithData'; export * from './utils'; export * from './ProfileTypeSelector'; export * from './SourceView'; +export * from './ProfileMetricsGraph'; export {default as Callgraph} from './Callgraph'; export const DEFAULT_PROFILE_EXPLORER_PARAM_VALUES = { From 097f21bbe93688582535f2beea9cc2cbec509cf7 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 5 Dec 2024 11:55:58 +0530 Subject: [PATCH 06/15] Storybook sotry fix --- .../src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx b/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx index 027193e85ba..5627940b79c 100644 --- a/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx +++ b/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx @@ -46,7 +46,7 @@ export default meta; export const ThreeCPUStrips = { args: { - cpus: Array.from(mockData, (_, i) => `CPU ${i + 1}`), + cpus: Array.from(mockData, (_, i) => ({labels: {cpuid: i + 1}})), data: mockData, selectedTimeframe: {index: 1, bounds: [mockData[0][25].timestamp, mockData[0][100].timestamp]}, onSelectedTimeframe: (index: number, bounds: NumberDuo): void => { From 4abf0a549bde0a152a589bb63115a49728509cd0 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 5 Dec 2024 11:59:16 +0530 Subject: [PATCH 07/15] Type fix --- .../profile/src/ProfileView/context/ProfileViewContext.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx b/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx index 05518fa5022..8fbc5c9f5d6 100644 --- a/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx +++ b/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx @@ -13,9 +13,8 @@ import {ReactNode, createContext, useContext} from 'react'; -import {NumberDuo} from 'utils'; - import {ProfileSource} from '../../ProfileSource'; +import {NumberDuo} from '../../utils'; export type TimelineGuideData = | {show: false} From 5bd84b4b9117dd45cb08bbe126697bc2ce9f0acc Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 5 Dec 2024 12:06:14 +0530 Subject: [PATCH 08/15] Storybook mock data fix --- .../src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx b/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx index 5627940b79c..13fa0185908 100644 --- a/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx +++ b/ui/packages/shared/profile/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx @@ -46,7 +46,7 @@ export default meta; export const ThreeCPUStrips = { args: { - cpus: Array.from(mockData, (_, i) => ({labels: {cpuid: i + 1}})), + cpus: Array.from(mockData, (_, i) => ({labels: [{name: 'cpuid', value: i + 1}]})), data: mockData, selectedTimeframe: {index: 1, bounds: [mockData[0][25].timestamp, mockData[0][100].timestamp]}, onSelectedTimeframe: (index: number, bounds: NumberDuo): void => { From 6cef042ffc21697f57ae032cf19745726e6370dd Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 12 Dec 2024 15:28:39 +0530 Subject: [PATCH 09/15] ProfileView component supports flamechart visualization --- .../components/src/ParcaContext/index.tsx | 1 + .../profile/src/MetricsGraphStrips/index.tsx | 4 +- .../IcicleGraphArrow/IcicleChartRootNode.tsx | 157 ++++++++++++++++++ .../IcicleGraphArrow/IcicleGraphNodes.tsx | 6 +- .../IcicleGraphArrow/index.tsx | 58 +++++++ .../IcicleGraphArrow/utils.ts | 30 +++- .../profile/src/ProfileIcicleGraph/index.tsx | 22 ++- .../components/DashboardItems/index.tsx | 27 +++ .../components/ViewSelector/index.tsx | 6 +- .../context/ProfileViewContext.tsx | 12 -- .../shared/profile/src/ProfileView/index.tsx | 6 +- .../src/ProfileView/types/visualization.ts | 6 +- .../profile/src/ProfileViewWithData.tsx | 47 ++++-- .../profile/src/TimelineGuide/index.tsx | 72 ++++---- ui/packages/shared/profile/src/utils.ts | 1 + ui/packages/shared/utilities/src/bigint.ts | 38 ++++- ui/packages/shared/utilities/src/index.ts | 9 +- ui/packages/shared/utilities/src/time.ts | 26 ++- 18 files changed, 439 insertions(+), 89 deletions(-) create mode 100644 ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleChartRootNode.tsx diff --git a/ui/packages/shared/components/src/ParcaContext/index.tsx b/ui/packages/shared/components/src/ParcaContext/index.tsx index f4673f1b448..5d00a7f70ed 100644 --- a/ui/packages/shared/components/src/ParcaContext/index.tsx +++ b/ui/packages/shared/components/src/ParcaContext/index.tsx @@ -53,6 +53,7 @@ interface Props { queryServiceClient: QueryServiceClient; navigateTo: NavigateFunction; enableSourcesView?: boolean; + enableIciclechartView?: boolean; authenticationErrorMessage?: string; isDarkMode: boolean; flamegraphHint?: ReactNode; diff --git a/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx b/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx index 62e9b2f60e3..fce180ad442 100644 --- a/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx +++ b/ui/packages/shared/profile/src/MetricsGraphStrips/index.tsx @@ -71,7 +71,7 @@ export const MetricsGraphStrips = ({ const color = d3.scaleOrdinal(d3.schemeObservable10); const bounds = useMemo(() => { - const bounds: NumberDuo = [Infinity, -Infinity]; + const bounds: NumberDuo = data.length > 0 ? [Infinity, -Infinity] : [0, 1]; data.forEach(cpuData => { cpuData.forEach(dataPoint => { bounds[0] = Math.min(bounds[0], dataPoint.timestamp); @@ -84,7 +84,7 @@ export const MetricsGraphStrips = ({ return (
( + table.getChild(FIELD_CHILDREN)?.get(row) ?? [] + ).sort((a, b) => a - b); + + const tsBounds = boundsFromProfileSource(profileSource); + + const nextLevel = level + 1; + const nextCurPath = curPath.length === 0 ? [] : curPath.slice(1); + const tsXScale = scaleLinear([tsBounds[0], tsBounds[1]], [0, totalWidth]); + + const width: number = + nextCurPath.length > 0 || (nextCurPath.length === 0 && curPath.length === 1) + ? totalWidth + : xScale(BigInt(cumulative)); + + if (width <= 1) { + return <>{null}; + } + + return ( + <> + {childRows.map(row => { + const groupByFields = ( + groupByMetadata?.get(row) as StructRow> + ).toJSON(); + + const tsStr = arrowToString(groupByFields.timestamp) as string; + + const tsNanos = BigInt(parseInt(tsStr, 10)) * 1000000n; + const durationStr = arrowToString(groupByFields.duration) as string; + const duration = parseInt(durationStr, 10); + + const x = tsXScale(tsNanos); + const width = tsXScale(tsNanos + BigInt(Math.round(duration))) - x; + + const cumulative = + cumulativeColumn?.get(row) !== null ? BigInt(cumulativeColumn?.get(row)) : 0n; + const newXScale = scaleLinear([0n, BigInt(cumulative)], [0, width]); + + return ( + <> + + + + + root + + + + + + ); + })} + + ); +}); diff --git a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx index 5f7871f64d9..1ac01a33d02 100644 --- a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +++ b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx @@ -153,7 +153,7 @@ export interface colorByColors { [key: string]: string; } -interface IcicleNodeProps { +export interface IcicleNodeProps { x: number; y: number; height: number; @@ -184,11 +184,11 @@ interface IcicleNodeProps { highlightSimilarStacksPreference: boolean; } -const icicleRectStyles = { +export const icicleRectStyles = { cursor: 'pointer', transition: 'opacity .15s linear', }; -const fadedIcicleRectStyles = { +export const fadedIcicleRectStyles = { cursor: 'pointer', transition: 'opacity .15s linear', opacity: '0.5', diff --git a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx index 0de487550bb..411d755cdd9 100644 --- a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +++ b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx @@ -32,8 +32,10 @@ import {getLastItem, scaleLinear, type ColorConfig} from '@parca/utilities'; import GraphTooltipArrow from '../../GraphTooltipArrow'; import GraphTooltipArrowContent from '../../GraphTooltipArrow/Content'; import {DockedGraphTooltip} from '../../GraphTooltipArrow/DockedGraphTooltip'; +import {ProfileSource} from '../../ProfileSource'; import {useProfileViewContext} from '../../ProfileView/context/ProfileViewContext'; import ContextMenu from './ContextMenu'; +import {IcicleChartRootNode} from './IcicleChartRootNode'; import {IcicleNode, RowHeight, colorByColors} from './IcicleGraphNodes'; import {useFilenamesList} from './useMappingList'; import {arrowToString, extractFeature, extractFilenameFeature} from './utils'; @@ -45,6 +47,8 @@ export const FIELD_LOCATION_ADDRESS = 'location_address'; export const FIELD_LOCATION_LINE = 'location_line'; export const FIELD_INLINED = 'inlined'; export const FIELD_TIMESTAMP = 'timestamp'; +export const FIELD_DURATION = 'duration'; +export const FIELD_GROUPBY_METADATA = 'groupby_metadata'; export const FIELD_FUNCTION_NAME = 'function_name'; export const FIELD_FUNCTION_SYSTEM_NAME = 'function_system_name'; export const FIELD_FUNCTION_FILE_NAME = 'function_file_name'; @@ -60,6 +64,7 @@ interface IcicleGraphArrowProps { total: bigint; filtered: bigint; profileType?: ProfileType; + profileSource?: ProfileSource; width?: number; curPath: string[]; setCurPath: (path: string[]) => void; @@ -68,6 +73,7 @@ interface IcicleGraphArrowProps { isHalfScreen: boolean; mappingsListFromMetadata: string[]; compareAbsolute: boolean; + isIcicleChart?: boolean; } export const getMappingColors = ( @@ -108,10 +114,12 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ setCurPath, curPath, profileType, + profileSource, sortBy, flamegraphLoading, mappingsListFromMetadata, compareAbsolute, + isIcicleChart = false, }: IcicleGraphArrowProps): React.JSX.Element { const [isContextMenuOpen, setIsContextMenuOpen] = useState(false); const dispatch = useAppDispatch(); @@ -252,6 +260,54 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ // useMemo for the root graph as it otherwise renders the whole graph if the hoveringRow changes. const root = useMemo(() => { + if (isIcicleChart) { + return ( + + + + + + + + ); + } return ( { } return ''; }; + +export const boundsFromProfileSource = (profileSource?: ProfileSource): BigIntDuo => { + if (profileSource === undefined) { + return [0n, 1n]; + } + + if (!(profileSource instanceof MergedProfileSource)) { + return [0n, 1n]; + } + + const request = profileSource.QueryRequest(); + + if ( + request.options.oneofKind !== 'merge' || + request.options.merge.start === undefined || + request.options.merge.end === undefined + ) { + return [0n, 1n]; + } + + const start = + request.options.merge.start.seconds * 1000000000n + BigInt(request.options.merge.start.nanos); + const end = + request.options.merge.end.seconds * 1000000000n + BigInt(request.options.merge.end.nanos); + + return [start, end]; +}; diff --git a/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx b/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx index 18ce880180c..5e5ea8c1791 100644 --- a/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx +++ b/ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx @@ -20,12 +20,14 @@ import {IcicleGraphSkeleton, useParcaContext, useURLState} from '@parca/componen import {ProfileType} from '@parca/parser'; import {capitalizeOnlyFirstLetter, divide} from '@parca/utilities'; +import {ProfileSource} from '../ProfileSource'; import DiffLegend from '../ProfileView/components/DiffLegend'; import {useProfileViewContext} from '../ProfileView/context/ProfileViewContext'; import {TimelineGuide} from '../TimelineGuide'; import {IcicleGraph} from './IcicleGraph'; import {FIELD_FUNCTION_NAME, IcicleGraphArrow} from './IcicleGraphArrow'; import useMappingList from './IcicleGraphArrow/useMappingList'; +import {boundsFromProfileSource} from './IcicleGraphArrow/utils'; const numberFormatter = new Intl.NumberFormat('en-US'); @@ -38,6 +40,7 @@ interface ProfileIcicleGraphProps { total: bigint; filtered: bigint; profileType?: ProfileType; + profileSource?: ProfileSource; curPath: string[] | []; setNewCurPath: (path: string[]) => void; loading: boolean; @@ -46,6 +49,7 @@ interface ProfileIcicleGraphProps { isHalfScreen: boolean; metadataMappingFiles?: string[]; metadataLoading?: boolean; + isIcicleChart?: boolean; } const ErrorContent = ({errorMessage}: {errorMessage: string}): JSX.Element => { @@ -65,9 +69,11 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ width, isHalfScreen, metadataMappingFiles, + isIcicleChart = false, + profileSource, }: ProfileIcicleGraphProps): JSX.Element { const {onError, authenticationErrorMessage, isDarkMode} = useParcaContext(); - const {compareMode, timelineGuide} = useProfileViewContext(); + const {compareMode} = useProfileViewContext(); const [isLoading, setIsLoading] = useState(true); const mappingsList = useMappingList(metadataMappingFiles); @@ -167,15 +173,16 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ if (arrow !== undefined) return (
- {timelineGuide?.show === true && ( + {isIcicleChart ? ( - )} + ) : null}
); @@ -208,7 +217,8 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ isDarkMode, mappingsList, isCompareAbsolute, - timelineGuide, + isIcicleChart, + profileSource, ]); if (error != null) { diff --git a/ui/packages/shared/profile/src/ProfileView/components/DashboardItems/index.tsx b/ui/packages/shared/profile/src/ProfileView/components/DashboardItems/index.tsx index 2171c1ec714..7b75d0989f5 100644 --- a/ui/packages/shared/profile/src/ProfileView/components/DashboardItems/index.tsx +++ b/ui/packages/shared/profile/src/ProfileView/components/DashboardItems/index.tsx @@ -33,6 +33,7 @@ interface GetDashboardItemProps { isHalfScreen: boolean; dimensions: DOMRect | undefined; flamegraphData: FlamegraphData; + flamechartData: FlamegraphData; topTableData?: TopTableData; callgraphData?: CallgraphData; sourceData?: SourceData; @@ -54,6 +55,7 @@ export const getDashboardItem = ({ isHalfScreen, dimensions, flamegraphData, + flamechartData, topTableData, callgraphData, sourceData, @@ -101,6 +103,31 @@ export const getDashboardItem = ({ /> ); + case 'iciclechart': + return ( + + ); case 'callgraph': return callgraphData?.data !== undefined && callgraphSVG !== undefined && diff --git a/ui/packages/shared/profile/src/ProfileView/components/ViewSelector/index.tsx b/ui/packages/shared/profile/src/ProfileView/components/ViewSelector/index.tsx index 637fb9b6c54..f0634bdf259 100644 --- a/ui/packages/shared/profile/src/ProfileView/components/ViewSelector/index.tsx +++ b/ui/packages/shared/profile/src/ProfileView/components/ViewSelector/index.tsx @@ -22,12 +22,16 @@ const ViewSelector = (): JSX.Element => { alwaysReturnArray: true, } ); - const {enableSourcesView} = useParcaContext(); + const {enableSourcesView, enableIciclechartView} = useParcaContext(); const allItems: Array<{key: string; canBeSelected: boolean; supportingText?: string}> = [ {key: 'table', canBeSelected: !dashboardItems.includes('table')}, {key: 'icicle', canBeSelected: !dashboardItems.includes('icicle')}, ]; + if (enableIciclechartView === true) { + allItems.push({key: 'iciclechart', canBeSelected: !dashboardItems.includes('iciclechart')}); + } + if (enableSourcesView === true) { allItems.push({key: 'source', canBeSelected: false}); } diff --git a/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx b/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx index 8fbc5c9f5d6..2354ae3b335 100644 --- a/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx +++ b/ui/packages/shared/profile/src/ProfileView/context/ProfileViewContext.tsx @@ -14,27 +14,15 @@ import {ReactNode, createContext, useContext} from 'react'; import {ProfileSource} from '../../ProfileSource'; -import {NumberDuo} from '../../utils'; - -export type TimelineGuideData = - | {show: false} - | { - show: true; - props: { - bounds: NumberDuo; - }; - }; interface Props { profileSource?: ProfileSource; compareMode: boolean; - timelineGuide?: TimelineGuideData; } export const defaultValue: Props = { profileSource: undefined, compareMode: false, - timelineGuide: {show: false}, }; const ProfileViewContext = createContext(defaultValue); diff --git a/ui/packages/shared/profile/src/ProfileView/index.tsx b/ui/packages/shared/profile/src/ProfileView/index.tsx index 96bf25dd778..a7e352d2283 100644 --- a/ui/packages/shared/profile/src/ProfileView/index.tsx +++ b/ui/packages/shared/profile/src/ProfileView/index.tsx @@ -33,6 +33,7 @@ export const ProfileView = ({ total, filtered, flamegraphData, + flamechartData, topTableData, callgraphData, sourceData, @@ -42,7 +43,6 @@ export const ProfileView = ({ pprofDownloading, compare, showVisualizationSelector, - timelineGuide, }: ProfileViewProps): JSX.Element => { const { timezone, @@ -98,6 +98,7 @@ export const ProfileView = ({ isHalfScreen, dimensions, flamegraphData, + flamechartData, topTableData, callgraphData, sourceData, @@ -130,14 +131,13 @@ export const ProfileView = ({ return ( - + - void; pprofDownloading?: boolean; showVisualizationSelector?: boolean; - showTimelineGuide?: boolean; - timelineGuide?: TimelineGuideData; } diff --git a/ui/packages/shared/profile/src/ProfileViewWithData.tsx b/ui/packages/shared/profile/src/ProfileViewWithData.tsx index 5406183d280..89f6bdcfaf5 100644 --- a/ui/packages/shared/profile/src/ProfileViewWithData.tsx +++ b/ui/packages/shared/profile/src/ProfileViewWithData.tsx @@ -17,10 +17,9 @@ import {QueryRequest_ReportType, QueryServiceClient} from '@parca/client'; import {useGrpcMetadata, useParcaContext, useURLState} from '@parca/components'; import {saveAsBlob} from '@parca/utilities'; -import {FIELD_FUNCTION_NAME, FIELD_TIMESTAMP} from './ProfileIcicleGraph/IcicleGraphArrow'; +import {FIELD_FUNCTION_NAME} from './ProfileIcicleGraph/IcicleGraphArrow'; import {ProfileSource} from './ProfileSource'; import {ProfileView} from './ProfileView'; -import {TimelineGuideData} from './ProfileView/context/ProfileViewContext'; import {useQuery} from './useQuery'; import {downloadPprof} from './utils'; @@ -29,16 +28,12 @@ interface ProfileViewWithDataProps { profileSource: ProfileSource; compare?: boolean; showVisualizationSelector?: boolean; - isGroupByTimestamp?: boolean; - timelineGuide?: TimelineGuideData; } export const ProfileViewWithData = ({ queryClient, profileSource, showVisualizationSelector, - isGroupByTimestamp, - timelineGuide, }: ProfileViewWithDataProps): JSX.Element => { const metadata = useGrpcMetadata(); const [dashboardItems] = useURLState('dashboard_items', { @@ -47,10 +42,7 @@ export const ProfileViewWithData = ({ const [sourceBuildID] = useURLState('source_buildid'); const [sourceFilename] = useURLState('source_filename'); const [groupBy] = useURLState('group_by', { - defaultValue: [ - isGroupByTimestamp === true ? FIELD_TIMESTAMP : (null as unknown as string), - FIELD_FUNCTION_NAME, - ].filter(Boolean), + defaultValue: [FIELD_FUNCTION_NAME].filter(Boolean), alwaysReturnArray: true, }); @@ -86,6 +78,18 @@ export const ProfileViewWithData = ({ binaryFrameFilter, }); + const { + isLoading: flamechartLoading, + response: flamechartResponse, + error: flamechartError, + } = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMECHART, { + skip: !dashboardItems.includes('iciclechart'), + nodeTrimThreshold, + groupBy, + invertCallStack, + binaryFrameFilter, + }); + const {isLoading: profileMetadataLoading, response: profileMetadataResponse} = useQuery( queryClient, profileSource, @@ -188,6 +192,9 @@ export const ProfileViewWithData = ({ } else if (sourceResponse !== null) { total = BigInt(sourceResponse.total); filtered = BigInt(sourceResponse.filtered); + } else if (flamechartResponse !== null) { + total = BigInt(flamechartResponse.total); + filtered = BigInt(flamechartResponse.filtered); } return ( @@ -217,6 +224,25 @@ export const ProfileViewWithData = ({ : undefined, metadataLoading: profileMetadataLoading, }} + flamechartData={{ + loading: flamechartLoading && profileMetadataLoading, + arrow: + flamechartResponse?.report.oneofKind === 'flamegraphArrow' + ? flamechartResponse?.report?.flamegraphArrow + : undefined, + total: BigInt(flamechartResponse?.total ?? '0'), + filtered: BigInt(flamechartResponse?.filtered ?? '0'), + error: flamechartError, + metadataMappingFiles: + profileMetadataResponse?.report.oneofKind === 'profileMetadata' + ? profileMetadataResponse?.report?.profileMetadata?.mappingFiles + : undefined, + metadataLabels: + profileMetadataResponse?.report.oneofKind === 'profileMetadata' + ? profileMetadataResponse?.report?.profileMetadata?.labels + : undefined, + metadataLoading: profileMetadataLoading, + }} topTableData={{ loading: tableLoading, arrow: @@ -250,7 +276,6 @@ export const ProfileViewWithData = ({ onDownloadPProf={() => void downloadPProfClick()} pprofDownloading={pprofDownloading} showVisualizationSelector={showVisualizationSelector} - timelineGuide={timelineGuide} /> ); }; diff --git a/ui/packages/shared/profile/src/TimelineGuide/index.tsx b/ui/packages/shared/profile/src/TimelineGuide/index.tsx index 2b9035004df..723f949b71e 100644 --- a/ui/packages/shared/profile/src/TimelineGuide/index.tsx +++ b/ui/packages/shared/profile/src/TimelineGuide/index.tsx @@ -13,19 +13,20 @@ import {Fragment} from 'react'; -import * as d3 from 'd3'; +import {scaleLinear, valueFormatter} from '@parca/utilities'; -import {NumberDuo} from '../utils'; +import {BigIntDuo} from '../utils'; interface Props { width: number; height: number; margin: number; - bounds: NumberDuo; + bounds: BigIntDuo; ticks?: number; + timeUnit?: string; } -const alignBeforeAxisCorrection = (val: number): number => { +const alignBeforeAxisCorrection = (val: bigint): number => { if (val < 10000) { return -24; } @@ -36,11 +37,18 @@ const alignBeforeAxisCorrection = (val: number): number => { return 0; }; -export const TimelineGuide = ({bounds, width, height, margin, ticks}: Props): JSX.Element => { - const xScale = d3.scaleLinear().domain(bounds).range([0, width]); +export const TimelineGuide = ({ + bounds, + width, + height, + margin, + ticks, + timeUnit = 'milliseconds', +}: Props): JSX.Element => { + const xScale = scaleLinear(bounds, [0, width]); return ( -
+
- {xScale.ticks(ticks).map((d, i) => ( - - - {/* */} - - {d} ms - - - - - - - ))} + {xScale.ticks(ticks).map((d, i) => { + return ( + + + {/* */} + + {valueFormatter(d - bounds[0], timeUnit, 2, true).toString()} + + + + + + + ); + })} { }; export type NumberDuo = [number, number]; +export type BigIntDuo = [bigint, bigint]; diff --git a/ui/packages/shared/utilities/src/bigint.ts b/ui/packages/shared/utilities/src/bigint.ts index abf1731a2a7..bbad7dd1575 100644 --- a/ui/packages/shared/utilities/src/bigint.ts +++ b/ui/packages/shared/utilities/src/bigint.ts @@ -37,18 +37,50 @@ export const abs = (a: bigint): bigint => { return a < 0n ? -a : a; }; -export type ScaleFunction = (x: bigint) => number; +export interface ScaleFunction { + ticks: (count?: number) => bigint[]; + (x: bigint): number; +} -export const scaleLinear = (domain: [bigint, bigint], range: [number, number]): ScaleFunction => { +export const scaleLinear = ( + domain: [bigint, bigint], + range: [number, number], + debugLog = false +): ScaleFunction => { const [domainMin, domainMax] = domain; const [rangeMin, rangeMax] = range; const domainRange = domainMax - domainMin; const rangeRange = BigInt(Math.floor(rangeMax - rangeMin)); + if (debugLog) { + console.log('domainRange', domainRange, rangeRange, divide(rangeRange, domainRange)); + } // rate * MULTIPLE to retain the decimal places in BigInt format, then divide by MULTIPLE to get the final result const rate = BigInt(Math.round(divide(rangeRange, domainRange) * MULTIPLE)); - return x => { + const func = (x: bigint): number => { + if (debugLog) { + console.log( + 'x', + x, + domainMin, + domainMax, + rate, + Number(BigInt(rangeMin) + (x - domainMin) * rate) / MULTIPLE + ); + } + return Number(BigInt(rangeMin) + (x - domainMin) * rate) / MULTIPLE; }; + + func.ticks = (count = 5): bigint[] => { + const step = domainRange / BigInt(count - 1); + const ticks: bigint[] = []; + for (let i = 0; i < count; i++) { + ticks.push(domainMin + step * BigInt(i)); + } + return ticks; + }; + + return func; }; diff --git a/ui/packages/shared/utilities/src/index.ts b/ui/packages/shared/utilities/src/index.ts index 8be80d93979..cdf23c28e2a 100644 --- a/ui/packages/shared/utilities/src/index.ts +++ b/ui/packages/shared/utilities/src/index.ts @@ -16,7 +16,7 @@ import colors from 'tailwindcss/colors'; import {Label} from '@parca/client'; import {abs, divide} from './bigint'; -import {unitsInTime} from './time'; +import {unitsInTimeMs, unitsInTimeNs} from './time'; export * from './time'; export * from './string'; @@ -78,9 +78,10 @@ const unitsInCores = { const knownValueFormatters = { bytes: unitsInBytes, - nanoseconds: unitsInTime, + nanoseconds: unitsInTimeNs, count: unitsInCount, 'CPU Cores': unitsInCores, + milliseconds: unitsInTimeMs, }; export const roundToDecimals = (n: number, decimals: number): number => { @@ -174,9 +175,9 @@ export const selectQueryParam = (key: string): string | string[] | undefined => const router = parseParams(window.location.search); if (key === 'dashboard_items') { - let dashboardItems = router[key]; + let dashboardItems = router[key] ?? []; if (typeof dashboardItems === 'string') { - dashboardItems = [dashboardItems] ?? []; + dashboardItems = [dashboardItems]; } return dashboardItems; } diff --git a/ui/packages/shared/utilities/src/time.ts b/ui/packages/shared/utilities/src/time.ts index 32f69dbbc24..30fbe62fb08 100644 --- a/ui/packages/shared/utilities/src/time.ts +++ b/ui/packages/shared/utilities/src/time.ts @@ -50,7 +50,7 @@ export const TimeUnits = { export type TimeUnit = (typeof TimeUnits)[keyof typeof TimeUnits]; -export const unitsInTime = { +export const unitsInTimeNs = { [TimeUnits.Nanos]: {multiplier: 1, symbol: 'ns'}, [TimeUnits.Micros]: {multiplier: 1e3, symbol: 'µs'}, [TimeUnits.Milliseconds]: {multiplier: 1e6, symbol: 'ms'}, @@ -62,9 +62,19 @@ export const unitsInTime = { [TimeUnits.Years]: {multiplier: 365 * 24 * 60 * 60 * 1e9, symbol: 'y'}, }; +export const unitsInTimeMs = { + [TimeUnits.Milliseconds]: {multiplier: 1, symbol: 'ms'}, + [TimeUnits.Seconds]: {multiplier: 1e3, symbol: 's'}, + [TimeUnits.Minutes]: {multiplier: 6 * 1e4, symbol: 'm'}, + [TimeUnits.Hours]: {multiplier: 60 * 60 * 1e3, symbol: 'h'}, + [TimeUnits.Days]: {multiplier: 24 * 60 * 60 * 1e3, symbol: 'd'}, + [TimeUnits.Weeks]: {multiplier: 7 * 24 * 60 * 60 * 1e3, symbol: 'w'}, + [TimeUnits.Years]: {multiplier: 365 * 24 * 60 * 60 * 1e3, symbol: 'y'}, +}; + export const convertTime = (value: number, from: TimeUnit, to: TimeUnit): number => { - const startUnit = unitsInTime[from]; - const endUnit = unitsInTime[to]; + const startUnit = unitsInTimeNs[from]; + const endUnit = unitsInTimeNs[to]; if (startUnit === undefined || endUnit === undefined) { console.error('invalid start or end unit provided'); return value; @@ -89,24 +99,24 @@ export const formatDuration = (timeObject: TimeObject, to?: number): string => { } // for more than one second, just show up until whole seconds; otherwise, show whole micros - if (Math.floor(nanos / unitsInTime[TimeUnits.Seconds].multiplier) > 0) { + if (Math.floor(nanos / unitsInTimeNs[TimeUnits.Seconds].multiplier) > 0) { for (let i = 0; i < unitsLargeToSmall.length; i++) { - const multiplier = unitsInTime[unitsLargeToSmall[i]].multiplier; + const multiplier = unitsInTimeNs[unitsLargeToSmall[i]].multiplier; if (nanos > multiplier) { if (unitsLargeToSmall[i] === TimeUnits.Milliseconds) { break; } else { const amount = Math.floor(nanos / multiplier); - values = [...values, `${amount}${unitsInTime[unitsLargeToSmall[i]].symbol}`]; + values = [...values, `${amount}${unitsInTimeNs[unitsLargeToSmall[i]].symbol}`]; nanos -= amount * multiplier; } } } } else { - const milliseconds = Math.floor(nanos / unitsInTime[TimeUnits.Milliseconds].multiplier); + const milliseconds = Math.floor(nanos / unitsInTimeNs[TimeUnits.Milliseconds].multiplier); if (milliseconds > 0) { - values = [`${milliseconds}${unitsInTime[TimeUnits.Milliseconds].symbol}`]; + values = [`${milliseconds}${unitsInTimeNs[TimeUnits.Milliseconds].symbol}`]; } else { return '<1ms'; } From becd70f94505b18d692476f10f877ecb90114c87 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 12 Dec 2024 18:16:32 +0530 Subject: [PATCH 10/15] Query api supports flamecharts report --- gen/proto/go/parca/query/v1alpha1/query.pb.go | 776 +++++++++--------- .../parca/query/v1alpha1/query.swagger.json | 10 +- .../parca/share/v1alpha1/share.swagger.json | 5 +- go.mod | 1 + go.sum | 2 + pkg/profile/profile.go | 16 +- pkg/profile/reader.go | 6 + pkg/profile/writer.go | 6 + pkg/query/columnquery.go | 13 +- pkg/query/columnquery_test.go | 12 + pkg/query/flamegraph_arrow.go | 194 ++++- pkg/query/flamegraph_arrow_test.go | 189 +++++ proto/buf.lock | 4 +- proto/parca/query/v1alpha1/query.proto | 3 + .../client/src/parca/query/v1alpha1/query.ts | 8 +- 15 files changed, 825 insertions(+), 420 deletions(-) diff --git a/gen/proto/go/parca/query/v1alpha1/query.pb.go b/gen/proto/go/parca/query/v1alpha1/query.pb.go index d66e87484d9..f672d6b13ec 100644 --- a/gen/proto/go/parca/query/v1alpha1/query.pb.go +++ b/gen/proto/go/parca/query/v1alpha1/query.pb.go @@ -151,6 +151,8 @@ const ( QueryRequest_REPORT_TYPE_TABLE_ARROW QueryRequest_ReportType = 7 // REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels QueryRequest_REPORT_TYPE_PROFILE_METADATA QueryRequest_ReportType = 8 + // REPORT_TYPE_FLAMECHART contains flamechart representation of the report + QueryRequest_REPORT_TYPE_FLAMECHART QueryRequest_ReportType = 9 ) // Enum value maps for QueryRequest_ReportType. @@ -165,6 +167,7 @@ var ( 6: "REPORT_TYPE_SOURCE", 7: "REPORT_TYPE_TABLE_ARROW", 8: "REPORT_TYPE_PROFILE_METADATA", + 9: "REPORT_TYPE_FLAMECHART", } QueryRequest_ReportType_value = map[string]int32{ "REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED": 0, @@ -176,6 +179,7 @@ var ( "REPORT_TYPE_SOURCE": 6, "REPORT_TYPE_TABLE_ARROW": 7, "REPORT_TYPE_PROFILE_METADATA": 8, + "REPORT_TYPE_FLAMECHART": 9, } ) @@ -3710,7 +3714,7 @@ var file_parca_query_v1alpha1_query_proto_rawDesc = []byte{ 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x4d, 0x45, 0x52, 0x47, 0x45, 0x10, 0x01, - 0x42, 0x09, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe2, 0x09, 0x0a, 0x0c, + 0x42, 0x09, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xfe, 0x09, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, @@ -3763,7 +3767,7 @@ var file_parca_query_v1alpha1_query_proto_rawDesc = []byte{ 0x5f, 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x44, 0x49, 0x46, 0x46, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x4d, 0x45, 0x52, - 0x47, 0x45, 0x10, 0x02, 0x22, 0x9a, 0x02, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, + 0x47, 0x45, 0x10, 0x02, 0x22, 0xb6, 0x02, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x22, 0x52, 0x45, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4c, 0x41, 0x4d, 0x45, 0x47, 0x52, 0x41, 0x50, 0x48, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x1a, 0x02, 0x08, 0x01, 0x12, @@ -3781,401 +3785,403 @@ var file_parca_query_v1alpha1_query_proto_rawDesc = []byte{ 0x45, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x41, 0x52, 0x52, 0x4f, 0x57, 0x10, 0x07, 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x45, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x10, - 0x08, 0x42, 0x09, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0f, 0x0a, 0x0d, - 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x42, 0x16, 0x0a, - 0x14, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x74, 0x72, 0x69, 0x6d, 0x5f, 0x74, 0x68, 0x72, 0x65, - 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, - 0x62, 0x79, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, - 0x6e, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, - 0x22, 0xa2, 0x01, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x0c, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x66, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, - 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x85, 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x6c, 0x0a, 0x1a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x66, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x61, 0x72, 0x63, - 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, - 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x17, 0x66, 0x75, 0x6e, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x47, 0x0a, - 0x17, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, - 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x75, 0x6e, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, - 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x72, 0x0a, 0x0b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x59, 0x0a, 0x13, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, - 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x11, 0x62, - 0x69, 0x6e, 0x61, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x3e, 0x0a, 0x11, 0x42, 0x69, - 0x6e, 0x61, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, - 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, - 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x22, 0x81, 0x01, 0x0a, 0x0d, 0x52, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, - 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x73, 0x68, 0x6f, 0x77, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, - 0x09, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x72, 0x75, 0x62, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x73, 0x68, 0x6f, 0x77, 0x52, 0x75, 0x62, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x68, - 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, - 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x73, 0x68, 0x6f, 0x77, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x69, - 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, - 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x21, 0x0a, 0x07, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x42, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x82, 0x01, 0x0a, - 0x03, 0x54, 0x6f, 0x70, 0x12, 0x31, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4e, 0x6f, 0x64, - 0x65, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, 0x0a, - 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, - 0x74, 0x22, 0x88, 0x01, 0x0a, 0x07, 0x54, 0x6f, 0x70, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x35, 0x0a, - 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, - 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, - 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, - 0x76, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, - 0x74, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x22, 0xfe, 0x01, 0x0a, - 0x0b, 0x54, 0x6f, 0x70, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x08, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x07, - 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, - 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x04, 0x6c, 0x69, 0x6e, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, + 0x08, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x46, 0x4c, 0x41, 0x4d, 0x45, 0x43, 0x48, 0x41, 0x52, 0x54, 0x10, 0x09, 0x42, 0x09, 0x0a, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x6e, 0x6f, + 0x64, 0x65, 0x5f, 0x74, 0x72, 0x69, 0x6d, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, + 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x62, 0x79, 0x42, 0x13, + 0x0a, 0x11, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x69, 0x6e, 0x76, 0x65, 0x72, + 0x74, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x22, 0xa2, 0x01, 0x0a, + 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x63, 0x6b, + 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, + 0x46, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x22, 0x85, 0x01, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x12, 0x6c, 0x0a, 0x1a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x17, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, + 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x47, 0x0a, 0x17, 0x46, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x10, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x46, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x22, 0x72, 0x0a, 0x0b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x12, 0x59, 0x0a, 0x13, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, + 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x11, 0x62, 0x69, 0x6e, 0x61, 0x72, + 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x08, 0x0a, 0x06, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x3e, 0x0a, 0x11, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, + 0x46, 0x72, 0x61, 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x69, + 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x22, 0x81, 0x01, 0x0a, 0x0d, 0x52, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x68, 0x6f, 0x77, + 0x5f, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, + 0x68, 0x6f, 0x77, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x68, 0x6f, + 0x77, 0x5f, 0x72, 0x75, 0x62, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x68, + 0x6f, 0x77, 0x52, 0x75, 0x62, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x69, 0x0a, 0x0f, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x19, 0x0a, + 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6f, + 0x6e, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x21, 0x0a, 0x07, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, + 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x82, 0x01, 0x0a, 0x03, 0x54, 0x6f, 0x70, + 0x12, 0x31, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6c, + 0x69, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, + 0x18, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x02, + 0x18, 0x01, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x88, 0x01, + 0x0a, 0x07, 0x54, 0x6f, 0x70, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x04, 0x6d, 0x65, 0x74, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x54, + 0x6f, 0x70, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, + 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, + 0x66, 0x6c, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x22, 0xfe, 0x01, 0x0a, 0x0b, 0x54, 0x6f, 0x70, + 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, + 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, + 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0xb9, 0x03, - 0x0a, 0x0a, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x3c, 0x0a, 0x04, - 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x61, 0x72, - 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x2e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x52, 0x6f, 0x6f, 0x74, - 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x12, 0x18, 0x0a, 0x05, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, - 0x62, 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, - 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, - 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, - 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, - 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, - 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x0f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x5f, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, - 0x0e, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, - 0x18, 0x0a, 0x07, 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x07, 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x22, 0x6f, 0x0a, 0x0f, 0x46, 0x6c, 0x61, - 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x12, 0x16, 0x0a, 0x06, - 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x07, 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x22, 0x4c, 0x0a, 0x06, 0x53, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x8a, 0x01, 0x0a, 0x12, 0x46, 0x6c, 0x61, - 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x64, - 0x69, 0x66, 0x66, 0x12, 0x40, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x6c, 0x61, - 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, - 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0xc4, 0x01, 0x0a, 0x0e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, + 0x61, 0x31, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, + 0x69, 0x6e, 0x65, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x0a, 0x46, 0x6c, + 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x3c, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x6c, - 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, - 0x74, 0x69, 0x76, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, - 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x12, 0x40, 0x0a, 0x08, 0x63, 0x68, - 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, - 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x31, 0x2e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0xcb, 0x02, 0x0a, - 0x12, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, - 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, - 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, - 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x12, 0x3e, 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x32, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, - 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x04, - 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, - 0x69, 0x6e, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x09, 0x6c, 0x69, 0x6e, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x90, 0x01, 0x0a, 0x0d, 0x43, - 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x04, - 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x61, 0x72, - 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, - 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, - 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x74, 0x22, 0x84, 0x02, - 0x0a, 0x11, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, - 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, - 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, - 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x12, 0x3e, 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x64, 0x65, + 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x12, 0x18, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x6e, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x21, 0x0a, 0x0c, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, + 0x40, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x32, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4d, 0x61, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3e, + 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, + 0x0a, 0x0f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x75, 0x6e, 0x74, + 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x74, + 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x72, + 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x22, 0x6f, 0x0a, 0x0f, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x6e, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x74, 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, + 0x72, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x22, 0x4c, 0x0a, 0x06, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x6e, 0x69, 0x74, 0x22, 0x8a, 0x01, 0x0a, 0x12, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, + 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x69, 0x66, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x12, + 0x40, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, + 0x6e, 0x22, 0xc4, 0x01, 0x0a, 0x0e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, + 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x12, 0x40, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, + 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, + 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, + 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, + 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0xcb, 0x02, 0x0a, 0x12, 0x46, 0x6c, 0x61, + 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, + 0x3e, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x3b, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x04, - 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x45, 0x64, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, - 0x74, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, - 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6c, - 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, - 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x22, 0xa5, 0x01, 0x0a, 0x09, 0x43, 0x61, - 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x39, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x04, + 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x61, 0x72, + 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, + 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x69, 0x6e, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x90, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x6c, 0x6c, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x61, - 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, - 0x65, 0x73, 0x12, 0x39, 0x0a, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x45, 0x64, 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x12, 0x22, 0x0a, - 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, - 0x65, 0x22, 0xbc, 0x04, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, - 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x48, 0x00, 0x52, 0x0a, 0x66, 0x6c, 0x61, - 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x16, 0x0a, 0x05, 0x70, 0x70, 0x72, 0x6f, 0x66, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x70, 0x70, 0x72, 0x6f, 0x66, 0x12, - 0x2d, 0x0a, 0x03, 0x74, 0x6f, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, - 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x48, 0x00, 0x52, 0x03, 0x74, 0x6f, 0x70, 0x12, 0x3f, - 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x48, 0x00, 0x52, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, - 0x52, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x61, 0x72, - 0x72, 0x6f, 0x77, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x61, 0x72, 0x63, - 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x2e, 0x46, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, - 0x48, 0x00, 0x52, 0x0f, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x41, 0x72, - 0x72, 0x6f, 0x77, 0x12, 0x36, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x48, 0x00, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x43, 0x0a, 0x0b, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x72, 0x72, - 0x6f, 0x77, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x72, 0x72, 0x6f, 0x77, - 0x12, 0x52, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x61, 0x72, - 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x48, 0x00, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x22, 0x85, 0x01, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xbe, 0x01, 0x0a, 0x0d, 0x4c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, - 0x63, 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, - 0x6e, 0x64, 0x12, 0x26, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4d, 0x0a, 0x0e, 0x4c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, - 0x0b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xdd, 0x01, 0x0a, 0x0d, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, - 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, - 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, - 0x64, 0x12, 0x26, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4f, 0x0a, 0x0e, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, - 0x1a, 0x0a, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x33, 0x0a, 0x09, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x75, 0x6e, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, - 0x22, 0x95, 0x01, 0x0a, 0x13, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x52, 0x0c, 0x71, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2a, 0x0a, 0x14, 0x53, 0x68, 0x61, 0x72, - 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x38, 0x0a, 0x0a, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x72, 0x72, - 0x6f, 0x77, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, - 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x4e, - 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x32, 0xdf, - 0x06, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x7e, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x27, 0x2e, + 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x74, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x74, 0x22, 0x84, 0x02, 0x0a, 0x11, 0x43, 0x61, + 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, + 0x3e, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x3b, 0x0a, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4d, 0x61, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x52, 0x07, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x04, + 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x61, 0x72, + 0x63, 0x61, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, + 0x22, 0x92, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x45, 0x64, + 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, + 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x43, 0x6f, 0x6c, 0x6c, + 0x61, 0x70, 0x73, 0x65, 0x64, 0x22, 0xa5, 0x01, 0x0a, 0x09, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x12, 0x39, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x39, + 0x0a, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x73, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x12, - 0x69, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x45, 0x64, + 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0a, 0x63, 0x75, 0x6d, + 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x0a, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x22, 0xbc, 0x04, + 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x42, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x6c, 0x61, 0x6d, 0x65, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x48, 0x00, 0x52, 0x0a, 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x12, 0x16, 0x0a, 0x05, 0x70, 0x70, 0x72, 0x6f, 0x66, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x70, 0x70, 0x72, 0x6f, 0x66, 0x12, 0x2d, 0x0a, 0x03, 0x74, + 0x6f, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, + 0x54, 0x6f, 0x70, 0x48, 0x00, 0x52, 0x03, 0x74, 0x6f, 0x70, 0x12, 0x3f, 0x0a, 0x09, 0x63, 0x61, + 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x48, 0x00, + 0x52, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x52, 0x0a, 0x10, 0x66, + 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46, 0x6c, 0x61, + 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x48, 0x00, 0x52, 0x0f, + 0x66, 0x6c, 0x61, 0x6d, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x12, + 0x36, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x00, 0x52, + 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x43, 0x0a, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x6d, 0x0a, 0x06, 0x53, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, + 0x68, 0x61, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x48, 0x00, + 0x52, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x12, 0x52, 0x0a, 0x10, + 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, + 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x85, 0x01, 0x0a, + 0x0d, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x03, 0x65, 0x6e, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xbe, 0x01, 0x0a, 0x0d, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x30, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x26, + 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4d, 0x0a, 0x0e, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x61, + 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x77, 0x61, + 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xdd, 0x01, 0x0a, 0x0d, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x30, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, + 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x26, 0x0a, + 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4f, 0x0a, 0x0e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x77, + 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x77, + 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x33, 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x95, 0x01, 0x0a, + 0x13, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x61, + 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, + 0x0c, 0x71, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2a, 0x0a, 0x14, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, + 0x22, 0x38, 0x0a, 0x0a, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x74, 0x22, 0x4e, 0x0a, 0x0f, 0x50, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x23, 0x0a, + 0x0d, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x6c, + 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x32, 0xdf, 0x06, 0x0a, 0x0c, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x0a, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x27, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x7e, 0x0a, 0x0c, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x70, 0x61, 0x72, 0x63, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x69, 0x0a, 0x05, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x12, 0x22, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, + 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x6d, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x12, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x73, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x7e, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2a, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x06, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, + 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x06, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, + 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x26, 0x12, 0x24, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x0c, 0x53, 0x68, 0x61, + 0x72, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x29, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, - 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x06, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x12, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, - 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x06, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, - 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x2f, 0x7b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x81, 0x01, 0x0a, - 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x29, 0x2e, - 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, - 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, - 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, - 0x0f, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, - 0x42, 0xe4, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0a, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x4a, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2d, 0x64, 0x65, - 0x76, 0x2f, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x71, 0x75, 0x65, 0x72, 0x79, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x50, 0x51, 0x58, 0xaa, 0x02, 0x14, - 0x50, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x14, 0x50, 0x61, 0x72, 0x63, 0x61, 0x5c, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x20, 0x50, 0x61, - 0x72, 0x63, 0x61, 0x5c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x16, 0x50, 0x61, 0x72, 0x63, 0x61, 0x3a, 0x3a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x3a, 0x3a, 0x56, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x79, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x72, + 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x70, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x42, 0xe4, 0x01, 0x0a, + 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x70, 0x61, + 0x72, 0x63, 0x61, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, + 0x2f, 0x70, 0x61, 0x72, 0x63, 0x61, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x71, 0x75, 0x65, 0x72, 0x79, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x50, 0x51, 0x58, 0xaa, 0x02, 0x14, 0x50, 0x61, 0x72, 0x63, + 0x61, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, + 0xca, 0x02, 0x14, 0x50, 0x61, 0x72, 0x63, 0x61, 0x5c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x5c, 0x56, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xe2, 0x02, 0x20, 0x50, 0x61, 0x72, 0x63, 0x61, 0x5c, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x50, 0x61, 0x72, + 0x63, 0x61, 0x3a, 0x3a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/gen/proto/swagger/parca/query/v1alpha1/query.swagger.json b/gen/proto/swagger/parca/query/v1alpha1/query.swagger.json index 74778ccf712..651057dc822 100644 --- a/gen/proto/swagger/parca/query/v1alpha1/query.swagger.json +++ b/gen/proto/swagger/parca/query/v1alpha1/query.swagger.json @@ -320,7 +320,7 @@ }, { "name": "reportType", - "description": "report_type is the type of report to return\n\n - REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels", + "description": "report_type is the type of report to return\n\n - REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels\n - REPORT_TYPE_FLAMECHART: REPORT_TYPE_FLAMECHART contains flamechart representation of the report", "in": "query", "required": false, "type": "string", @@ -333,7 +333,8 @@ "REPORT_TYPE_FLAMEGRAPH_ARROW", "REPORT_TYPE_SOURCE", "REPORT_TYPE_TABLE_ARROW", - "REPORT_TYPE_PROFILE_METADATA" + "REPORT_TYPE_PROFILE_METADATA", + "REPORT_TYPE_FLAMECHART" ], "default": "REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED" }, @@ -613,10 +614,11 @@ "REPORT_TYPE_FLAMEGRAPH_ARROW", "REPORT_TYPE_SOURCE", "REPORT_TYPE_TABLE_ARROW", - "REPORT_TYPE_PROFILE_METADATA" + "REPORT_TYPE_PROFILE_METADATA", + "REPORT_TYPE_FLAMECHART" ], "default": "REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED", - "description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels", + "description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels\n - REPORT_TYPE_FLAMECHART: REPORT_TYPE_FLAMECHART contains flamechart representation of the report", "title": "ReportType is the type of report to return" }, "metastorev1alpha1Function": { diff --git a/gen/proto/swagger/parca/share/v1alpha1/share.swagger.json b/gen/proto/swagger/parca/share/v1alpha1/share.swagger.json index 6a4ae807bbf..b8efa64318e 100644 --- a/gen/proto/swagger/parca/share/v1alpha1/share.swagger.json +++ b/gen/proto/swagger/parca/share/v1alpha1/share.swagger.json @@ -28,10 +28,11 @@ "REPORT_TYPE_FLAMEGRAPH_ARROW", "REPORT_TYPE_SOURCE", "REPORT_TYPE_TABLE_ARROW", - "REPORT_TYPE_PROFILE_METADATA" + "REPORT_TYPE_PROFILE_METADATA", + "REPORT_TYPE_FLAMECHART" ], "default": "REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED", - "description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels", + "description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels\n - REPORT_TYPE_FLAMECHART: REPORT_TYPE_FLAMECHART contains flamechart representation of the report", "title": "ReportType is the type of report to return" }, "metastorev1alpha1Function": { diff --git a/go.mod b/go.mod index 1c6d63d9945..c73f1c11b48 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd github.com/improbable-eng/grpc-web v0.15.0 github.com/klauspost/compress v1.17.11 + github.com/m1gwings/treedrawer v0.3.3-beta github.com/nanmu42/limitio v1.0.0 github.com/oklog/run v1.1.0 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index f21d3e7ed1e..fc04fd936b1 100644 --- a/go.sum +++ b/go.sum @@ -574,6 +574,8 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U github.com/linode/linodego v1.40.0 h1:7ESY0PwK94hoggoCtIroT1Xk6b1flrFBNZ6KwqbTqlI= github.com/linode/linodego v1.40.0/go.mod h1:NsUw4l8QrLdIofRg1NYFBbW5ZERnmbZykVBszPZLORM= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/m1gwings/treedrawer v0.3.3-beta h1:VeeQ4I90+NL0G2Tga3H4EY4hbOyVP3ID4T93r21oLbQ= +github.com/m1gwings/treedrawer v0.3.3-beta/go.mod h1:Sebh5tCtjQWAG/B9xWct163vB9pCbBcA1ykaUErDUTY= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= diff --git a/pkg/profile/profile.go b/pkg/profile/profile.go index 531a40283fb..5bc70a37c82 100644 --- a/pkg/profile/profile.go +++ b/pkg/profile/profile.go @@ -72,18 +72,26 @@ func LocationsArrowSchema() *arrow.Schema { } func ArrowSamplesField(profileLabelFields []arrow.Field) []arrow.Field { - numFields := len(profileLabelFields) + 3 // +3 for stacktraces, value and diff + numFields := len(profileLabelFields) + 5 // +5 for stacktraces, value, diff, timestamp and duration fields := make([]arrow.Field, numFields) copy(fields, profileLabelFields) - fields[numFields-3] = LocationsField - fields[numFields-2] = arrow.Field{ + fields[numFields-5] = LocationsField + fields[numFields-3] = arrow.Field{ Name: "value", Type: arrow.PrimitiveTypes.Int64, } - fields[numFields-1] = arrow.Field{ + fields[numFields-3] = arrow.Field{ Name: "diff", Type: arrow.PrimitiveTypes.Int64, } + fields[numFields-2] = arrow.Field{ + Name: ColumnTimestamp, + Type: arrow.PrimitiveTypes.Int64, + } + fields[numFields-1] = arrow.Field{ + Name: ColumnDuration, + Type: arrow.PrimitiveTypes.Int64, + } return fields } diff --git a/pkg/profile/reader.go b/pkg/profile/reader.go index 6d7341eda7b..9c8d09c537d 100644 --- a/pkg/profile/reader.go +++ b/pkg/profile/reader.go @@ -39,6 +39,8 @@ type RecordReader struct { Locations *array.List Location *array.Struct Address *array.Uint64 + Timestamp *array.Int64 + Duration *array.Int64 MappingStart *array.Uint64 MappingLimit *array.Uint64 MappingOffset *array.Uint64 @@ -120,6 +122,8 @@ func NewRecordReader(ar arrow.Record) *RecordReader { lineFunctionStartLine := line.Field(4).(*array.Int64) valueColumn := ar.Column(labelNum + 1).(*array.Int64) diffColumn := ar.Column(labelNum + 2).(*array.Int64) + timestamp := ar.Column(labelNum + 3).(*array.Int64) + duration := ar.Column(labelNum + 4).(*array.Int64) return &RecordReader{ Record: ar, @@ -147,5 +151,7 @@ func NewRecordReader(ar arrow.Record) *RecordReader { LineFunctionStartLine: lineFunctionStartLine, Value: valueColumn, Diff: diffColumn, + Timestamp: timestamp, + Duration: duration, } } diff --git a/pkg/profile/writer.go b/pkg/profile/writer.go index 1549c4d9367..36a2f2eed08 100644 --- a/pkg/profile/writer.go +++ b/pkg/profile/writer.go @@ -40,6 +40,8 @@ type Writer struct { FunctionStartLine *array.Int64Builder Value *array.Int64Builder Diff *array.Int64Builder + Timestamp *array.Int64Builder + Duration *array.Int64Builder } func (w *Writer) Release() { @@ -87,6 +89,8 @@ func NewWriter(pool memory.Allocator, labelNames []string) Writer { value := b.Field(labelNum + 1).(*array.Int64Builder) diff := b.Field(labelNum + 2).(*array.Int64Builder) + timestamp := b.Field(labelNum + 3).(*array.Int64Builder) + duration := b.Field(labelNum + 4).(*array.Int64Builder) return Writer{ RecordBuilder: b, @@ -109,6 +113,8 @@ func NewWriter(pool memory.Allocator, labelNames []string) Writer { FunctionStartLine: functionStartLine, Value: value, Diff: diff, + Timestamp: timestamp, + Duration: duration, } } diff --git a/pkg/query/columnquery.go b/pkg/query/columnquery.go index 2a1d5e82060..d686f103c69 100644 --- a/pkg/query/columnquery.go +++ b/pkg/query/columnquery.go @@ -236,11 +236,20 @@ func (q *ColumnQueryAPI) Query(ctx context.Context, req *pb.QueryRequest) (*pb.Q groupBy := req.GetGroupBy().GetFields() allowedGroupBy := map[string]struct{}{ + profile.ColumnTimestamp: {}, + profile.ColumnDuration: {}, FlamegraphFieldFunctionName: {}, FlamegraphFieldLocationAddress: {}, FlamegraphFieldMappingFile: {}, FlamegraphFieldFunctionFileName: {}, } + + if req.GetReportType() == pb.QueryRequest_REPORT_TYPE_FLAMECHART { + groupBy = append(groupBy, profile.ColumnTimestamp, profile.ColumnDuration) + } + + fmt.Println("groupBy", groupBy) + groupByLabels := make([]string, 0, len(groupBy)) for _, f := range groupBy { if strings.HasPrefix(f, FlamegraphFieldLabels+".") { @@ -255,6 +264,8 @@ func (q *ColumnQueryAPI) Query(ctx context.Context, req *pb.QueryRequest) (*pb.Q return nil, status.Errorf(codes.InvalidArgument, "invalid group by field: %s", f) } + fmt.Println("groupByLabels", groupByLabels) + switch req.Mode { case pb.QueryRequest_MODE_SINGLE_UNSPECIFIED: p, err = q.selectSingle(ctx, req.GetSingle(), isInvert) @@ -592,7 +603,7 @@ func RenderReport( Flamegraph: fg, }, }, nil - case pb.QueryRequest_REPORT_TYPE_FLAMEGRAPH_ARROW: + case pb.QueryRequest_REPORT_TYPE_FLAMEGRAPH_ARROW, pb.QueryRequest_REPORT_TYPE_FLAMECHART: fa, total, err := GenerateFlamegraphArrow(ctx, mem, tracer, p, groupBy, nodeTrimFraction) if err != nil { return nil, status.Errorf(codes.Internal, "failed to generate arrow flamegraph: %v", err.Error()) diff --git a/pkg/query/columnquery_test.go b/pkg/query/columnquery_test.go index eebbe6f4ecd..4be57786b89 100644 --- a/pkg/query/columnquery_test.go +++ b/pkg/query/columnquery_test.go @@ -1244,6 +1244,8 @@ func PprofToSymbolizedProfile(meta profile.Meta, prof *pprofprofile.Profile, ind w.Value.Append(prof.Sample[i].Value[index]) w.Diff.Append(0) + w.Timestamp.Append(prof.TimeNanos) + w.Duration.Append(prof.DurationNanos) for labelName, labelBuilder := range w.LabelBuildersMap { if prof.Sample[i].Label == nil { @@ -1359,6 +1361,8 @@ func TestFilterData(t *testing.T) { w.FunctionStartLine.Append(1) w.Value.Append(1) w.Diff.Append(0) + w.Timestamp.Append(1) + w.Duration.Append(1) frameFilter := map[string]struct{}{"test": {}} originalRecord := w.RecordBuilder.NewRecord() @@ -1405,6 +1409,8 @@ func TestFilterUnsymbolized(t *testing.T) { w.Lines.Append(false) w.Value.Append(1) w.Diff.Append(0) + w.Timestamp.Append(1) + w.Duration.Append(1) originalRecord := w.RecordBuilder.NewRecord() recs, _, err := FilterProfileData( @@ -1485,6 +1491,8 @@ func TestFilterDataWithPath(t *testing.T) { w.FunctionStartLine.Append(0) w.Value.Append(1) w.Diff.Append(0) + w.Timestamp.Append(1) + w.Duration.Append(1) frameFilter := map[string]struct{}{"libpython3.11.so.1.0": {}, "interpreter": {}} originalRecord := w.RecordBuilder.NewRecord() @@ -1567,6 +1575,8 @@ func TestFilterDataFrameFilter(t *testing.T) { w.FunctionStartLine.Append(0) w.Value.Append(1) w.Diff.Append(0) + w.Timestamp.Append(1) + w.Duration.Append(1) frameFilter := map[string]struct{}{"interpreter": {}} originalRecord := w.RecordBuilder.NewRecord() @@ -1649,6 +1659,8 @@ func BenchmarkFilterData(t *testing.B) { w.FunctionStartLine.Append(1) w.Value.Append(1) w.Diff.Append(0) + w.Timestamp.Append(1) + w.Duration.Append(1) } originalRecord := w.RecordBuilder.NewRecord() diff --git a/pkg/query/flamegraph_arrow.go b/pkg/query/flamegraph_arrow.go index 56c155aa347..2c3235b46d5 100644 --- a/pkg/query/flamegraph_arrow.go +++ b/pkg/query/flamegraph_arrow.go @@ -58,6 +58,8 @@ const ( FlamegraphFieldCumulative = "cumulative" FlamegraphFieldFlat = "flat" FlamegraphFieldDiff = "diff" + + FlamegraphFieldGroupByMetadata = "groupby_metadata" ) func GenerateFlamegraphArrow( @@ -122,6 +124,7 @@ func generateFlamegraphArrowRecord(ctx context.Context, mem memory.Allocator, tr profileReader := profile.NewReader(p) labelHasher := xxh3.New() + tsHasher := xxh3.New() for _, r := range profileReader.RecordReaders { fb.cumulative += math.Int64.Sum(r.Value) fb.diff += math.Int64.Sum(r.Diff) @@ -143,6 +146,7 @@ func generateFlamegraphArrowRecord(ctx context.Context, mem memory.Allocator, tr hasLabels := false labelHash := uint64(0) + tsHash := uint64(0) for _, field := range fb.builderLabelFields { if r.LabelColumns[fb.labelNameIndex[field.Name]].Col.IsValid(i) { hasLabels = true @@ -194,6 +198,43 @@ func generateFlamegraphArrowRecord(ctx context.Context, mem memory.Allocator, tr fb.parent.Set(rootRow) row = fb.builderCumulative.Len() } + if fb.aggregationConfig.aggregateByTimestamp { + tsHasher.Reset() + tsStr := strconv.FormatInt(r.Timestamp.Value(i), 10) + durationStr := strconv.FormatInt(r.Duration.Value(i), 10) + tsHasher.Write([]byte(tsStr)) + tsHasher.Write([]byte(durationStr)) + tsHash = tsHasher.Sum64() + + sampleTsRow := row + if row, ok := fb.rootsRow[tsHash]; ok { + // We want to compare against this found root's children. + rootRowChildren = fb.children[row] + rootRow = row + fb.compareRows = rootRowChildren + fb.addRowValues(r, row, i, false) // adds the cumulative and diff values to the existing row + } else { + rootRowChildren = map[uint64]int{} + err := fb.AppendTimestampRow( + r, + t, + sampleTsRow, + i, + tsHash, + rootRowChildren, + false, // timestamps will never actually have a flat value themselves. + ) + if err != nil { + return nil, 0, 0, 0, fmt.Errorf("failed to inject timestamp row: %w", err) + } + rootRow = sampleTsRow + } + fb.maxHeight = max(fb.maxHeight, fb.height) + fb.height = 1 + + fb.parent.Set(rootRow) + row = fb.builderCumulative.Len() + } // every new sample resets the childRow to -1 indicating that we start with a leaf again. // pprof stores locations in reverse order, thus we loop over locations in reverse order. @@ -284,6 +325,10 @@ func generateFlamegraphArrowRecord(ctx context.Context, mem memory.Allocator, tr if fb.aggregationConfig.aggregateByLocationAddress { key = hashCombine(key, r.Address.Value(j)) } + if fb.aggregationConfig.aggregateByTimestamp { + key = hashCombine(key, uint64(r.Timestamp.Value(i))) + key = hashCombine(key, uint64(r.Duration.Value(i))) + } if fb.aggregationConfig.aggregateByFunctionFilename { translatedFunctionFilenameIndex := t.functionFilename.indices.Value(int(r.LineFunctionFilenameIndices.Value(k))) key = hashCombine(key, uint64(translatedFunctionFilenameIndex)) @@ -792,6 +837,8 @@ type flamegraphBuilder struct { // height keeps track of the current stack trace's height of the flame graph. height int32 + groupByMetadataFields []arrow.Field + builderLabelsOnly *array.BooleanBuilder builderMappingFileIndices *array.Int32Builder builderMappingFileDictUnifier array.DictionaryUnifier @@ -811,6 +858,7 @@ type flamegraphBuilder struct { builderLabelsExist *builder.OptBooleanBuilder builderLabels []*builder.OptInt32Builder builderLabelsDictUnifiers []array.DictionaryUnifier + builderGroupByMetadata *array.StructBuilder builderChildren *builder.ListBuilder builderChildrenValues *array.Uint32Builder builderCumulative *builder.OptInt64Builder @@ -847,6 +895,7 @@ type aggregationConfig struct { aggregateByMappingFile bool aggregateByLocationAddress bool aggregateByFunctionFilename bool + aggregateByTimestamp bool } func maxInt64(a, b int64) int64 { @@ -862,6 +911,11 @@ func newFlamegraphBuilder( groupBy []string, ) (*flamegraphBuilder, error) { builderChildren := builder.NewListBuilder(pool, arrow.PrimitiveTypes.Uint32) + groupByMetadataStructFields := make([]arrow.Field, 0, len(groupBy)) + for _, f := range groupBy { + groupByMetadataStructFields = append(groupByMetadataStructFields, arrow.Field{Name: f, Type: arrow.BinaryTypes.Binary}) + } + fb := &flamegraphBuilder{ pool: pool, @@ -897,6 +951,9 @@ func newFlamegraphBuilder( builderCumulative: builder.NewOptInt64Builder(arrow.PrimitiveTypes.Int64), builderFlat: builder.NewOptInt64Builder(arrow.PrimitiveTypes.Int64), builderDiff: builder.NewOptInt64Builder(arrow.PrimitiveTypes.Int64), + + groupByMetadataFields: groupByMetadataStructFields, + builderGroupByMetadata: array.NewStructBuilder(pool, arrow.StructOf(groupByMetadataStructFields...)), } fb.aggregationConfig = aggregationConfig{aggregateByLabels: map[string]struct{}{}} @@ -914,6 +971,9 @@ func newFlamegraphBuilder( if f == FlamegraphFieldFunctionFileName { fb.aggregationConfig.aggregateByFunctionFilename = true } + if f == profile.ColumnTimestamp { + fb.aggregationConfig.aggregateByTimestamp = true + } } rootRow := map[uint64]int{} @@ -942,6 +1002,8 @@ func newFlamegraphBuilder( // the root will never have a flat value fb.builderFlat.Append(0) + fb.builderGroupByMetadata.AppendNull() + return fb, nil } @@ -1053,7 +1115,29 @@ func (fb *flamegraphBuilder) prepareNewRecord() error { // It adds the children to the children column and the labels intersection to the labels column. // Finally, it assembles all columns from the builders into an arrow record. func (fb *flamegraphBuilder) NewRecord() (arrow.Record, error) { - const numCols = 14 + fields := []arrow.Field{ + // Location + {Name: FlamegraphFieldLabelsOnly, Type: arrow.FixedWidthTypes.Boolean}, + {Name: FlamegraphFieldLocationAddress, Type: arrow.PrimitiveTypes.Uint64}, + {Name: FlamegraphFieldMappingFile, Type: fb.mappingFile.DataType()}, + {Name: FlamegraphFieldMappingBuildID, Type: fb.mappingBuildID.DataType()}, + // Function + {Name: FlamegraphFieldLocationLine, Type: fb.trimmedLocationLine.Type()}, + {Name: FlamegraphFieldInlined, Type: arrow.FixedWidthTypes.Boolean, Nullable: true}, + {Name: FlamegraphFieldFunctionStartLine, Type: fb.trimmedFunctionStartLine.Type()}, + {Name: FlamegraphFieldFunctionName, Type: fb.functionName.DataType()}, + {Name: FlamegraphFieldFunctionSystemName, Type: fb.functionSystemName.DataType()}, + {Name: FlamegraphFieldFunctionFileName, Type: fb.functionFilename.DataType()}, + // Values + {Name: FlamegraphFieldChildren, Type: arrow.ListOf(arrow.PrimitiveTypes.Uint32)}, + {Name: FlamegraphFieldCumulative, Type: fb.trimmedCumulative.Type()}, + {Name: FlamegraphFieldFlat, Type: fb.trimmedFlat.Type()}, + {Name: FlamegraphFieldDiff, Type: fb.trimmedDiff.Type()}, + // Metadata + {Name: FlamegraphFieldGroupByMetadata, Type: fb.builderGroupByMetadata.Type().(*arrow.StructType)}, + } + + numCols := len(fields) cleanupArrs := make([]arrow.Array, 0, numCols+1+(2*len(fb.builderLabelFields))) defer func() { @@ -1080,26 +1164,6 @@ func (fb *flamegraphBuilder) NewRecord() (arrow.Record, error) { // the builder is reset. numRows := fb.trimmedCumulative.Len() - fields := []arrow.Field{ - // Location - {Name: FlamegraphFieldLabelsOnly, Type: arrow.FixedWidthTypes.Boolean}, - {Name: FlamegraphFieldLocationAddress, Type: arrow.PrimitiveTypes.Uint64}, - {Name: FlamegraphFieldMappingFile, Type: fb.mappingFile.DataType()}, - {Name: FlamegraphFieldMappingBuildID, Type: fb.mappingBuildID.DataType()}, - // Function - {Name: FlamegraphFieldLocationLine, Type: fb.trimmedLocationLine.Type()}, - {Name: FlamegraphFieldInlined, Type: arrow.FixedWidthTypes.Boolean, Nullable: true}, - {Name: FlamegraphFieldFunctionStartLine, Type: fb.trimmedFunctionStartLine.Type()}, - {Name: FlamegraphFieldFunctionName, Type: fb.functionName.DataType()}, - {Name: FlamegraphFieldFunctionSystemName, Type: fb.functionSystemName.DataType()}, - {Name: FlamegraphFieldFunctionFileName, Type: fb.functionFilename.DataType()}, - // Values - {Name: FlamegraphFieldChildren, Type: arrow.ListOf(arrow.PrimitiveTypes.Uint32)}, - {Name: FlamegraphFieldCumulative, Type: fb.trimmedCumulative.Type()}, - {Name: FlamegraphFieldFlat, Type: fb.trimmedFlat.Type()}, - {Name: FlamegraphFieldDiff, Type: fb.trimmedDiff.Type()}, - } - arrays := make([]arrow.Array, numCols+len(fb.labels)) arrays[0] = fb.builderLabelsOnly.NewArray() cleanupArrs = append(cleanupArrs, arrays[0]) @@ -1124,6 +1188,8 @@ func (fb *flamegraphBuilder) NewRecord() (arrow.Record, error) { cleanupArrs = append(cleanupArrs, arrays[12]) arrays[13] = fb.trimmedDiff.NewArray() cleanupArrs = append(cleanupArrs, arrays[13]) + arrays[14] = fb.builderGroupByMetadata.NewArray() + cleanupArrs = append(cleanupArrs, arrays[14]) for i, field := range fb.builderLabelFields { field.Type = fb.labels[i].DataType() // overwrite for variable length uint types @@ -1164,6 +1230,8 @@ func (fb *flamegraphBuilder) Release() { fb.builderFlat.Release() fb.builderDiff.Release() + fb.builderGroupByMetadata.Release() + if fb.trimmedLocationLine != nil { fb.trimmedLocationLine.Release() } @@ -1330,9 +1398,29 @@ func (fb *flamegraphBuilder) appendRow( fb.builderDiff.AppendNull() } + appendGroupByMetadata(fb, r, sampleRow) + return nil } +func appendGroupByMetadata(fb *flamegraphBuilder, r *profile.RecordReader, sampleRow int) { + fb.builderGroupByMetadata.Append(true) + for i := 0; i < fb.builderGroupByMetadata.NumField(); i++ { + n := fb.groupByMetadataFields[i].Name + b := fb.builderGroupByMetadata.FieldBuilder(i).(*array.BinaryBuilder) + switch n { + case profile.ColumnTimestamp: + ts := r.Timestamp.Value(sampleRow) + b.Append([]byte(fmt.Sprint(ts))) + case profile.ColumnDuration: + duration := r.Duration.Value(sampleRow) + b.Append([]byte(fmt.Sprint(duration))) + default: + b.AppendNull() + } + } +} + func (fb *flamegraphBuilder) AppendLabelRow( r *profile.RecordReader, t *transpositions, @@ -1394,6 +1482,51 @@ func (fb *flamegraphBuilder) AppendLabelRow( return nil } +func (fb *flamegraphBuilder) AppendTimestampRow( + r *profile.RecordReader, + t *transpositions, + row int, + sampleRow int, + hash uint64, + children map[uint64]int, + leaf bool, +) error { + if len(fb.children) == row { + // We need to grow the children slice + newChildren := make([]map[uint64]int, len(fb.children)*2) + newChildrenList := make([][]int, len(fb.children)*2) + copy(newChildren, fb.children) + copy(newChildrenList, fb.childrenList) + fb.children = newChildren + fb.childrenList = newChildrenList + } + + fb.rootsRow[hash] = row + fb.childrenList[0] = append(fb.childrenList[0], row) + fb.children[row] = children + + fb.builderLabelsExist.AppendSingle(false) + fb.builderLabelsOnly.Append(false) + fb.builderMappingFileIndices.AppendNull() + fb.builderMappingBuildIDIndices.AppendNull() + fb.builderLocationAddress.AppendNull() + fb.builderInlined.AppendNull() + fb.builderLocationLine.AppendNull() + fb.builderFunctionStartLine.AppendNull() + fb.builderFunctionNameIndices.AppendNull() + fb.builderFunctionSystemNameIndices.AppendNull() + fb.builderFunctionFilenameIndices.AppendNull() + appendGroupByMetadata(fb, r, sampleRow) + + // Append both cumulative and diff values and overwrite them below. + fb.builderCumulative.Append(0) + fb.builderDiff.Append(0) + fb.builderFlat.Append(0) + fb.addRowValues(r, row, sampleRow, leaf) + + return nil +} + // addRowValues updates the existing row's values and potentially adding existing values on top. func (fb *flamegraphBuilder) addRowValues(r *profile.RecordReader, row, sampleRow int, leaf bool) { value := r.Value.Value(sampleRow) @@ -1480,6 +1613,7 @@ func (fb *flamegraphBuilder) trim(ctx context.Context, tracer trace.Tracer, thre trimmedFlat := array.NewBuilder(fb.pool, trimmedFlatType) trimmedDiffType := smallestSignedTypeFor(smallestDiffValue, largestDiffValue) trimmedDiff := array.NewBuilder(fb.pool, trimmedDiffType) + trimmedGroupByMetadata := array.NewStructBuilder(fb.pool, fb.builderGroupByMetadata.Type().(*arrow.StructType)) releasers = append(releasers, trimmedMappingFileIndices, @@ -1512,6 +1646,7 @@ func (fb *flamegraphBuilder) trim(ctx context.Context, tracer trace.Tracer, thre trimmedCumulative.Reserve(row) trimmedFlat.Reserve(row) trimmedDiff.Reserve(row) + trimmedGroupByMetadata.Reserve(row) for _, l := range trimmedLabelsIndices { l.Reserve(row) @@ -1536,6 +1671,7 @@ func (fb *flamegraphBuilder) trim(ctx context.Context, tracer trace.Tracer, thre appendDictionaryIndexInt32(fb.functionNameIndices, trimmedFunctionNameIndices, te.row) appendDictionaryIndexInt32(fb.functionSystemNameIndices, trimmedFunctionSystemNameIndices, te.row) appendDictionaryIndexInt32(fb.functionFilenameIndices, trimmedFunctionFilenameIndices, te.row) + copyStructBuilderValue(fb.builderGroupByMetadata, trimmedGroupByMetadata, te.row) for i := range fb.labels { appendDictionaryIndexInt32(fb.labelsIndices[i], trimmedLabelsIndices[i], te.row) } @@ -1706,6 +1842,7 @@ func (fb *flamegraphBuilder) trim(ctx context.Context, tracer trace.Tracer, thre fb.builderDiff, fb.builderLocationLine, fb.builderFunctionStartLine, + fb.builderGroupByMetadata, ) fb.builderLabelsOnly = trimmedLabelsOnly fb.builderLabelsExist = trimmedLabelsExist @@ -1716,6 +1853,7 @@ func (fb *flamegraphBuilder) trim(ctx context.Context, tracer trace.Tracer, thre fb.trimmedCumulative = trimmedCumulative fb.trimmedFlat = trimmedFlat fb.trimmedDiff = trimmedDiff + fb.builderGroupByMetadata = trimmedGroupByMetadata fb.trimmedChildren = trimmedChildren return nil @@ -1796,6 +1934,20 @@ func appendDictionaryIndexInt32(dict *array.Int32, index *array.Int32Builder, ro index.Append(dict.Value(row)) } +func copyStructBuilderValue(old, new *array.StructBuilder, row int) { + if old.IsNull(row) { + new.AppendNull() + return + } + + new.Append(true) + for i := 0; i < old.NumField(); i++ { + old := old.FieldBuilder(i).(*array.BinaryBuilder) + new := new.FieldBuilder(i).(*array.BinaryBuilder) + new.Append(old.Value(row)) + } +} + func isLocationRoot(beg, end, i int64, list *array.List) bool { for j := end - 1; j >= beg; j-- { if !list.ListValues().IsNull(int(j)) { diff --git a/pkg/query/flamegraph_arrow_test.go b/pkg/query/flamegraph_arrow_test.go index da7ef9655db..7993cb601ff 100644 --- a/pkg/query/flamegraph_arrow_test.go +++ b/pkg/query/flamegraph_arrow_test.go @@ -17,11 +17,13 @@ import ( "bytes" "compress/gzip" "context" + "encoding/base64" "fmt" "io" "os" "slices" "sort" + "strconv" "strings" "testing" "time" @@ -31,6 +33,7 @@ import ( "github.com/apache/arrow/go/v16/arrow/ipc" "github.com/apache/arrow/go/v16/arrow/memory" pprofprofile "github.com/google/pprof/profile" + "github.com/m1gwings/treedrawer/tree" "github.com/prometheus/prometheus/model/labels" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" @@ -1168,3 +1171,189 @@ func TestAllFramesFiltered(t *testing.T) { err = w.Write(record) require.NoError(t, err) } + +func TestFlamechartGroupByTimestamp(t *testing.T) { + ctx := context.Background() + tracer := noop.NewTracerProvider().Tracer("") + + mem := memory.NewCheckedAllocator(memory.NewGoAllocator()) + defer mem.AssertSize(t, 0) + + np, err := foldedStacksWithTsToProfile(mem, []byte(` +main;func_fib 10 1000 20 +main;func_fib 10 2000 20 +main;func_fib 10 3000 20 +runtime;gc 20 2000 30 +runtime;gc 20 3000 30 +main;func_add 30 1000 20 +main;func_add 30 3000 20 +`)) + require.NoError(t, err) + defer func() { + for _, r := range np.Samples { + r.Release() + } + }() + + // Group by function_name, timestamp, duration + record, _, _, _, err := generateFlamegraphArrowRecord( + ctx, + mem, + tracer, + np, + []string{FlamegraphFieldFunctionName, profile.ColumnTimestamp, profile.ColumnDuration}, + 0, + ) + require.NoError(t, err) + defer record.Release() + // drawFlamegraphToConsole(t, record) + + row := 0 + schema := record.Schema() + childrenColIdx := schema.FieldIndices("children")[0] + childrenCol := record.Column(childrenColIdx).(*array.List) + ChildrenValues := childrenCol.ListValues().(*array.Uint32) + + offsetStart, offsetEnd := childrenCol.ValueOffsets(row) + + groupByMetadataColIdx := schema.FieldIndices("groupby_metadata")[0] + groupByMetadataCol := record.Column(groupByMetadataColIdx).(*array.Struct) + tsValues := groupByMetadataCol.Field(1).(*array.Binary) + durationValues := groupByMetadataCol.Field(2).(*array.Binary) + + nums := offsetEnd - offsetStart + + type metadata struct { + ts int64 + duration int64 + } + rootNodesMetadata := make([]metadata, 0) + + for j := int64(0); j < nums; j++ { + row = int(ChildrenValues.Value(int(offsetStart + j))) + tsBytes := tsValues.Value(int(row)) + durationBytes := durationValues.Value(int(row)) + ts, err := strconv.ParseInt(string(tsBytes), 10, 64) + require.NoError(t, err) + duration, err := strconv.ParseInt(string(durationBytes), 10, 64) + require.NoError(t, err) + + rootNodesMetadata = append(rootNodesMetadata, metadata{ts: ts, duration: duration}) + } + + require.Equal(t, []metadata{{1000, 20}, {2000, 20}, {3000, 20}, {2000, 30}, {3000, 30}}, rootNodesMetadata) +} + +// split the line into 4 parts: stack, value, timestamp, duration +// +// example line: +// +// main;do;some;work 123 1732617178462 duration +func splitLine(line string) (string, string, string, string, error) { + parts := strings.Split(line, " ") + if len(parts) != 4 { + return "", "", "", "", fmt.Errorf("invalid line format") + } + + return parts[0], parts[1], parts[2], parts[3], nil +} + +func foldedStacksWithTsToProfile(pool memory.Allocator, input []byte) (profile.Profile, error) { + w := profile.NewWriter(pool, nil) + defer w.RecordBuilder.Release() + + for n, line := range strings.Split(string(input), "\n") { + if strings.TrimSpace(line) == "" { + continue + } + + stack, valueStr, timstampStr, durationStr, err := splitLine(line) + if err != nil { + return profile.Profile{}, err + } + + val, err := strconv.ParseInt(valueStr, 10, 64) + if err != nil { + return profile.Profile{}, fmt.Errorf("bad line: %d: %q: %s", n, line, err) + } + + ts, err := strconv.ParseInt(timstampStr, 10, 64) + if err != nil { + return profile.Profile{}, fmt.Errorf("bad line: %d: %q: %s", n, line, err) + } + + duration, err := strconv.ParseInt(durationStr, 10, 64) + if err != nil { + return profile.Profile{}, fmt.Errorf("bad line: %d: %q: %s", n, line, err) + } + + stackFrames := strings.Split(stack, ";") + if len(stackFrames) == 0 { + return profile.Profile{}, fmt.Errorf("bad line: %d: %q: no stack frames", n, line) + } + + w.Value.Append(val) + w.Diff.Append(0) + w.Timestamp.Append(ts) + w.Duration.Append(duration) + w.LocationsList.Append(true) + + for i := len(stackFrames) - 1; i >= 0; i-- { + w.Locations.Append(true) + w.Addresses.Append(0) + w.MappingStart.AppendNull() + w.MappingLimit.AppendNull() + w.MappingOffset.AppendNull() + w.MappingFile.AppendNull() + w.MappingBuildID.AppendNull() + w.Lines.Append(true) + w.Line.Append(true) + w.LineNumber.Append(0) + w.FunctionName.Append([]byte(stackFrames[i])) + w.FunctionSystemName.Append([]byte("")) + w.FunctionFilename.Append([]byte("")) + w.FunctionStartLine.Append(0) + } + } + + return profile.Profile{ + Samples: []arrow.Record{w.RecordBuilder.NewRecord()}, + }, nil +} + +func drawFlamegraphToConsole(testing *testing.T, record arrow.Record) { + schema := record.Schema() + childrenColIdx := schema.FieldIndices("children")[0] + functionNameColIdx := schema.FieldIndices("function_name")[0] + childrenCol := record.Column(childrenColIdx).(*array.List) + functionNameCol := record.Column(functionNameColIdx).(*array.Dictionary) + ChildrenValues := childrenCol.ListValues().(*array.Uint32) + groupByMetadataColIdx := schema.FieldIndices("groupby_metadata")[0] + groupByMetadataCol := record.Column(groupByMetadataColIdx).(*array.Struct) + tsValues := groupByMetadataCol.Field(1).(*array.Binary) + durationValues := groupByMetadataCol.Field(2).(*array.Binary) + + t := tree.NewTree(tree.NodeString("root" + " " + string(tsValues.Value(0)))) + + var populateChild func(t *tree.Tree, row int) + + populateChild = func(t *tree.Tree, row int) { + offsetStart, offsetEnd := childrenCol.ValueOffsets(row) + nums := offsetEnd - offsetStart + for j := int64(0); j < nums; j++ { + child := ChildrenValues.Value(int(offsetStart + j)) + fBytes := functionNameCol.ValueStr(int(child)) + funcName, err := base64.StdEncoding.DecodeString(fBytes) + if err != nil { + funcName = []byte("N/A") + } + tsBytes := tsValues.Value(int(child)) + durationBytes := durationValues.Value(int(child)) + childT := t.AddChild(tree.NodeString(string(funcName) + " " + string(tsBytes) + " " + string(durationBytes))) + populateChild(childT, int(child)) + } + } + + populateChild(t, 0) + fmt.Println(t) +} diff --git a/proto/buf.lock b/proto/buf.lock index c5c24b2df84..ccc8af7b084 100644 --- a/proto/buf.lock +++ b/proto/buf.lock @@ -4,8 +4,8 @@ deps: - remote: buf.build owner: googleapis repository: googleapis - commit: c0913f24652a4cfc95f77d97443a5005 - digest: shake256:0ef3248c6235d420fe61f373154adcde6b94e3297f82472b1d8d8c3747240b61b4a10405e2a6f8ac1c98816ac6e690ea7871024aa5ae0e035cd540214667ceed + commit: acd896313c55464b993332136ded1b6e + digest: shake256:66626d5e4d9c8ecf25cd72bdbfbbf62b9a68e9e9c33dab6b9b39a53a67063eeba6b8493247dd6d6240b1ac1c32eb2dc311484e67dd7d271884a960c2e5ce8c9a - remote: buf.build owner: grpc-ecosystem repository: grpc-gateway diff --git a/proto/parca/query/v1alpha1/query.proto b/proto/parca/query/v1alpha1/query.proto index 81c552680aa..67bb581fd8b 100644 --- a/proto/parca/query/v1alpha1/query.proto +++ b/proto/parca/query/v1alpha1/query.proto @@ -247,6 +247,9 @@ message QueryRequest { // REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels REPORT_TYPE_PROFILE_METADATA = 8; + + // REPORT_TYPE_FLAMECHART contains flamechart representation of the report + REPORT_TYPE_FLAMECHART = 9; } // report_type is the type of report to return diff --git a/ui/packages/shared/client/src/parca/query/v1alpha1/query.ts b/ui/packages/shared/client/src/parca/query/v1alpha1/query.ts index 37125db6de2..748347f10af 100644 --- a/ui/packages/shared/client/src/parca/query/v1alpha1/query.ts +++ b/ui/packages/shared/client/src/parca/query/v1alpha1/query.ts @@ -500,7 +500,13 @@ export enum QueryRequest_ReportType { * * @generated from protobuf enum value: REPORT_TYPE_PROFILE_METADATA = 8; */ - PROFILE_METADATA = 8 + PROFILE_METADATA = 8, + /** + * REPORT_TYPE_FLAMECHART contains flamechart representation of the report + * + * @generated from protobuf enum value: REPORT_TYPE_FLAMECHART = 9; + */ + FLAMECHART = 9 } /** * Filter to apply to the query request From 5e5e55f1b96a0c85e736502ae842d85ff37656a7 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 12 Dec 2024 18:24:34 +0530 Subject: [PATCH 11/15] Removed unwanted println --- pkg/query/columnquery.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/query/columnquery.go b/pkg/query/columnquery.go index c849ff77a0a..c42ec2a5b1c 100644 --- a/pkg/query/columnquery.go +++ b/pkg/query/columnquery.go @@ -248,8 +248,6 @@ func (q *ColumnQueryAPI) Query(ctx context.Context, req *pb.QueryRequest) (*pb.Q groupBy = append(groupBy, profile.ColumnTimestamp, profile.ColumnDuration) } - fmt.Println("groupBy", groupBy) - groupByLabels := make([]string, 0, len(groupBy)) for _, f := range groupBy { if strings.HasPrefix(f, FlamegraphFieldLabels+".") { @@ -264,8 +262,6 @@ func (q *ColumnQueryAPI) Query(ctx context.Context, req *pb.QueryRequest) (*pb.Q return nil, status.Errorf(codes.InvalidArgument, "invalid group by field: %s", f) } - fmt.Println("groupByLabels", groupByLabels) - switch req.Mode { case pb.QueryRequest_MODE_SINGLE_UNSPECIFIED: p, err = q.selectSingle(ctx, req.GetSingle(), isInvert) From 70b20d39d141e159e5f22255a29573f066867e37 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 12 Dec 2024 18:34:14 +0530 Subject: [PATCH 12/15] Type fix --- .../shared/profile/src/ProfileIcicleGraph/IcicleGraph/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraph/index.tsx b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraph/index.tsx index c98b16a3cdc..c99468131a8 100644 --- a/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraph/index.tsx +++ b/ui/packages/shared/profile/src/ProfileIcicleGraph/IcicleGraph/index.tsx @@ -62,7 +62,7 @@ export const IcicleGraph = memo(function IcicleGraph({ const xScale = useMemo(() => { if (width === undefined) { - return () => 0; + return scaleLinear([0n, total], [0, 1]); } return scaleLinear([0n, total], [0, width]); }, [total, width]); From 115e0a8ee124f3578ed6086ac7d82bea8b9f4227 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 12 Dec 2024 18:47:48 +0530 Subject: [PATCH 13/15] Go linter fixes --- pkg/query/flamegraph_arrow.go | 4 ++-- pkg/query/flamegraph_arrow_test.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/query/flamegraph_arrow.go b/pkg/query/flamegraph_arrow.go index de094e21354..834fdc24b5b 100644 --- a/pkg/query/flamegraph_arrow.go +++ b/pkg/query/flamegraph_arrow.go @@ -202,8 +202,8 @@ func generateFlamegraphArrowRecord(ctx context.Context, mem memory.Allocator, tr tsHasher.Reset() tsStr := strconv.FormatInt(r.Timestamp.Value(i), 10) durationStr := strconv.FormatInt(r.Duration.Value(i), 10) - tsHasher.Write([]byte(tsStr)) - tsHasher.Write([]byte(durationStr)) + _, _ = tsHasher.Write([]byte(tsStr)) + _, _ = tsHasher.Write([]byte(durationStr)) tsHash = tsHasher.Sum64() sampleTsRow := row diff --git a/pkg/query/flamegraph_arrow_test.go b/pkg/query/flamegraph_arrow_test.go index 02d3c1ae2fd..7a128ca8d1e 100644 --- a/pkg/query/flamegraph_arrow_test.go +++ b/pkg/query/flamegraph_arrow_test.go @@ -1249,6 +1249,7 @@ main;func_add 30 3000 20 // example line: // // main;do;some;work 123 1732617178462 duration +// end. func splitLine(line string) (string, string, string, string, error) { parts := strings.Split(line, " ") if len(parts) != 4 { @@ -1321,6 +1322,7 @@ func foldedStacksWithTsToProfile(pool memory.Allocator, input []byte) (profile.P }, nil } +//lint:ignore U1000 Used for debugging purposes func drawFlamegraphToConsole(testing *testing.T, record arrow.Record) { schema := record.Schema() childrenColIdx := schema.FieldIndices("children")[0] From 90435a0de8231779751bb3e7fb71a17972c3a849 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Thu, 12 Dec 2024 20:12:58 +0530 Subject: [PATCH 14/15] unit test failure fixed --- pkg/parcacol/querier.go | 25 ++++- pkg/profile/profile.go | 2 +- pkg/query/flamegraph_arrow_test.go | 148 +++++++++++++++-------------- 3 files changed, 99 insertions(+), 76 deletions(-) diff --git a/pkg/parcacol/querier.go b/pkg/parcacol/querier.go index 2ad7bc86a6a..37d8fd92f73 100644 --- a/pkg/parcacol/querier.go +++ b/pkg/parcacol/querier.go @@ -969,6 +969,20 @@ func (q *Querier) SymbolizeArrowRecord( defer valuePerSecondColumn.Release() } + indices = schema.FieldIndices(profile.ColumnTimestamp) + var timestampColumn *array.Int64 + if len(indices) != 1 { + timestampColumn = arrowutils.MakeNullArray(q.pool, arrow.PrimitiveTypes.Int64, valueColumn.Len()).(*array.Int64) + defer timestampColumn.Release() + } + + indices = schema.FieldIndices(profile.ColumnDuration) + var durationColumn *array.Int64 + if len(indices) != 1 { + durationColumn = arrowutils.MakeNullArray(q.pool, arrow.PrimitiveTypes.Int64, valueColumn.Len()).(*array.Int64) + defer durationColumn.Release() + } + profileLabels := []arrow.Field{} profileLabelColumns := []arrow.Array{} for i, field := range schema.Fields() { @@ -984,14 +998,17 @@ func (q *Querier) SymbolizeArrowRecord( } defer locationsRecord.Release() - columns := make([]arrow.Array, len(profileLabels)+3) // +3 for stacktrace locations, value and diff + columns := make([]arrow.Array, len(profileLabels)+5) // +5 for stacktrace locations, value, diff, timestamp and duration copy(columns, profileLabelColumns) - columns[len(columns)-3] = locationsRecord.Column(0) - columns[len(columns)-2] = valueColumn + columns[len(columns)-5] = locationsRecord.Column(0) + columns[len(columns)-4] = valueColumn diffColumn := CreateDiffColumn(q.pool, int(r.NumRows())) defer diffColumn.Release() - columns[len(columns)-1] = diffColumn + columns[len(columns)-3] = diffColumn + + columns[len(columns)-2] = timestampColumn + columns[len(columns)-1] = durationColumn res[i] = array.NewRecord(profile.ArrowSchema(profileLabels), columns, r.NumRows()) } diff --git a/pkg/profile/profile.go b/pkg/profile/profile.go index 76aecd97492..2f8b61db46e 100644 --- a/pkg/profile/profile.go +++ b/pkg/profile/profile.go @@ -76,7 +76,7 @@ func ArrowSamplesField(profileLabelFields []arrow.Field) []arrow.Field { fields := make([]arrow.Field, numFields) copy(fields, profileLabelFields) fields[numFields-5] = LocationsField - fields[numFields-3] = arrow.Field{ + fields[numFields-4] = arrow.Field{ Name: "value", Type: arrow.PrimitiveTypes.Int64, } diff --git a/pkg/query/flamegraph_arrow_test.go b/pkg/query/flamegraph_arrow_test.go index 7a128ca8d1e..b8abba8c9e2 100644 --- a/pkg/query/flamegraph_arrow_test.go +++ b/pkg/query/flamegraph_arrow_test.go @@ -62,6 +62,7 @@ type flamegraphRow struct { Cumulative uint8 Flat uint8 Diff int8 + GroupByMetadata map[string]string } type flamegraphColumns struct { @@ -80,6 +81,7 @@ type flamegraphColumns struct { cumulative []uint8 flat []uint8 diff []int8 + groupByMetadata []map[string]string } func rowsToColumn(rows []flamegraphRow) flamegraphColumns { @@ -100,6 +102,7 @@ func rowsToColumn(rows []flamegraphRow) flamegraphColumns { columns.cumulative = append(columns.cumulative, row.Cumulative) columns.flat = append(columns.flat, row.Flat) columns.diff = append(columns.diff, row.Diff) + columns.groupByMetadata = append(columns.groupByMetadata, row.GroupByMetadata) } return columns } @@ -365,14 +368,14 @@ func TestGenerateFlamegraphArrow(t *testing.T) { cumulative: 11, height: 5, trimmed: 0, - cols: 14, + cols: 15, rows: []flamegraphRow{ - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: array.NullValueStr, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1}}, // 0 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{2}}, // 1 - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0x0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 3, Labels: nil, Children: []uint32{3}}, // 2 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 8, Flat: 0, Labels: nil, Children: []uint32{4, 5}}, // 3 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil}, // 4 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 5, Flat: 5, Labels: nil, Children: nil}, // 5 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: array.NullValueStr, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1}, GroupByMetadata: nil}, // 0 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{2}, GroupByMetadata: nil}, // 1 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0x0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 3, Labels: nil, Children: []uint32{3}, GroupByMetadata: nil}, // 2 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 8, Flat: 0, Labels: nil, Children: []uint32{4, 5}, GroupByMetadata: nil}, // 3 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil, GroupByMetadata: nil}, // 4 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 5, Flat: 5, Labels: nil, Children: nil, GroupByMetadata: nil}, // 5 }, }, { name: "aggregate-labels-first-of-two", @@ -381,27 +384,27 @@ func TestGenerateFlamegraphArrow(t *testing.T) { cumulative: 11, height: 6, trimmed: 0, - cols: 15, + cols: 16, rows: []flamegraphRow{ // root - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1, 6, 11}}, // 0 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1, 6, 11}, GroupByMetadata: nil}, // 0 // stack 1 -- labels: goroutine=foo - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 3, Flat: 0, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{2}, LabelsOnly: true}, // 1 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 3, Flat: 0, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{3}}, // 2 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 3, Flat: 2, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{4}}, // 3 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 1, Flat: 0, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{5}}, // 4 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 1, Flat: 1, Labels: map[string]string{"goroutine": "app"}, Children: nil}, // 5 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 3, Flat: 0, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{2}, LabelsOnly: true, GroupByMetadata: nil}, // 1 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 3, Flat: 0, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{3}, GroupByMetadata: nil}, // 2 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 3, Flat: 2, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{4}, GroupByMetadata: nil}, // 3 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 1, Flat: 0, Labels: map[string]string{"goroutine": "app"}, Children: []uint32{5}, GroupByMetadata: nil}, // 4 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 1, Flat: 1, Labels: map[string]string{"goroutine": "app"}, Children: nil, GroupByMetadata: nil}, // 5 // stack 2 -- labels: goroutine=bar - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{7}, LabelsOnly: true}, // 6 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{8}}, // 7 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{9}}, // 8 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{10}}, // 9 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 4, Flat: 4, Labels: map[string]string{"goroutine": "container"}, Children: nil}, // 10 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{7}, LabelsOnly: true, GroupByMetadata: nil}, // 6 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{8}, GroupByMetadata: nil}, // 7 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{9}, GroupByMetadata: nil}, // 8 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{10}, GroupByMetadata: nil}, // 9 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 4, Flat: 4, Labels: map[string]string{"goroutine": "container"}, Children: nil, GroupByMetadata: nil}, // 10 // stack 3 -- no labels - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: nil, Children: []uint32{12}}, // 11 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 1, Labels: nil, Children: []uint32{13}}, // 12 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 3, Flat: 0, Labels: nil, Children: []uint32{14}}, // 13 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil}, // 14 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: nil, Children: []uint32{12}, GroupByMetadata: nil}, // 11 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 1, Labels: nil, Children: []uint32{13}, GroupByMetadata: nil}, // 12 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 3, Flat: 0, Labels: nil, Children: []uint32{14}, GroupByMetadata: nil}, // 13 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil, GroupByMetadata: nil}, // 14 }, }, { name: "aggregate-labels-last-of-two", @@ -410,26 +413,26 @@ func TestGenerateFlamegraphArrow(t *testing.T) { cumulative: 11, height: 6, trimmed: 0, - cols: 15, + cols: 16, rows: []flamegraphRow{ // root - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1, 4, 9}}, // 0 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1, 4, 9}, GroupByMetadata: nil}, // 0 // stack 1 -- labels: cpu=0 - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0"}, Children: []uint32{2}, LabelsOnly: true}, // 1 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0"}, Children: []uint32{3}}, // 2 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 2, Flat: 2, Labels: map[string]string{"cpu": "0"}, Children: nil}, // 3 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0"}, Children: []uint32{2}, LabelsOnly: true, GroupByMetadata: nil}, // 1 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0"}, Children: []uint32{3}, GroupByMetadata: nil}, // 2 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 2, Flat: 2, Labels: map[string]string{"cpu": "0"}, Children: nil, GroupByMetadata: nil}, // 3 // stack 2 -- labels: cpu=1 - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{5}, LabelsOnly: true}, // 4 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{6}}, // 5 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{7}}, // 6 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{8}}, // 7 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 1, Flat: 1, Labels: map[string]string{"cpu": "1"}, Children: nil}, // 8 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{5}, LabelsOnly: true, GroupByMetadata: nil}, // 4 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{6}, GroupByMetadata: nil}, // 5 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{7}, GroupByMetadata: nil}, // 6 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1"}, Children: []uint32{8}, GroupByMetadata: nil}, // 7 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 1, Flat: 1, Labels: map[string]string{"cpu": "1"}, Children: nil, GroupByMetadata: nil}, // 8 // stack 3 -- no labels - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 8, Flat: 0, Labels: nil, Children: []uint32{10}}, // 9 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 8, Flat: 1, Labels: nil, Children: []uint32{11}}, // 10 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 7, Flat: 0, Labels: nil, Children: []uint32{12, 13}}, // 11 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil}, // 12 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 4, Flat: 4, Labels: nil, Children: nil}, // 13 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 8, Flat: 0, Labels: nil, Children: []uint32{10}, GroupByMetadata: nil}, // 9 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 8, Flat: 1, Labels: nil, Children: []uint32{11}, GroupByMetadata: nil}, // 10 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 7, Flat: 0, Labels: nil, Children: []uint32{12, 13}, GroupByMetadata: nil}, // 11 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil, GroupByMetadata: nil}, // 12 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 4, Flat: 4, Labels: nil, Children: nil, GroupByMetadata: nil}, // 13 }, }, { name: "aggregate-labels-two-of-two", @@ -438,31 +441,31 @@ func TestGenerateFlamegraphArrow(t *testing.T) { cumulative: 11, height: 6, trimmed: 0, - cols: 16, + cols: 17, rows: []flamegraphRow{ // root - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1, 4, 9, 14}}, // 0 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1, 4, 9, 14}, GroupByMetadata: nil}, // 0 // stack 1 -- labels: cpu=0, goroutine=1 - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0", "goroutine": "app"}, Children: []uint32{2}, LabelsOnly: true}, // 1 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0", "goroutine": "app"}, Children: []uint32{3}}, // 2 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 2, Flat: 2, Labels: map[string]string{"cpu": "0", "goroutine": "app"}, Children: nil}, // 3 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0", "goroutine": "app"}, Children: []uint32{2}, LabelsOnly: true, GroupByMetadata: nil}, // 1 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 2, Flat: 0, Labels: map[string]string{"cpu": "0", "goroutine": "app"}, Children: []uint32{3}, GroupByMetadata: nil}, // 2 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 2, Flat: 2, Labels: map[string]string{"cpu": "0", "goroutine": "app"}, Children: nil, GroupByMetadata: nil}, // 3 // stack 1 -- labels: cpu=1, goroutine=1 - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{5}, LabelsOnly: true}, // 4 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{6}}, // 5 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{7}}, // 6 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{8}}, // 7 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 1, Flat: 1, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: nil}, // 8 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{5}, LabelsOnly: true, GroupByMetadata: nil}, // 4 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{6}, GroupByMetadata: nil}, // 5 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{7}, GroupByMetadata: nil}, // 6 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 1, Flat: 0, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: []uint32{8}, GroupByMetadata: nil}, // 7 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 1, Flat: 1, Labels: map[string]string{"cpu": "1", "goroutine": "app"}, Children: nil, GroupByMetadata: nil}, // 8 // stack 3 -- labels: goroutine=2 - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{10}, LabelsOnly: true}, // 9 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{11}}, // 10 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{12}}, // 11 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{13}}, // 12 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 4, Flat: 4, Labels: map[string]string{"goroutine": "container"}, Children: nil}, // 13 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: `(null)`, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{10}, LabelsOnly: true, GroupByMetadata: nil}, // 9 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{11}, GroupByMetadata: nil}, // 10 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{12}, GroupByMetadata: nil}, // 11 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 4, Flat: 0, Labels: map[string]string{"goroutine": "container"}, Children: []uint32{13}, GroupByMetadata: nil}, // 12 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 4, Flat: 4, Labels: map[string]string{"goroutine": "container"}, Children: nil, GroupByMetadata: nil}, // 13 // stack 4 -- no labels - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: nil, Children: []uint32{15}}, // 14 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 1, Labels: nil, Children: []uint32{16}}, // 15 - the nulls in this are due to merging with different underlying values - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 3, Flat: 0, Labels: nil, Children: []uint32{17}}, // 16 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil}, // 17 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 4, Flat: 0, Labels: nil, Children: []uint32{15}, GroupByMetadata: nil}, // 14 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: "2", FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 4, Flat: 1, Labels: nil, Children: []uint32{16}, GroupByMetadata: nil}, // 15 - the nulls in this are due to merging with different underlying values + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 3, Flat: 0, Labels: nil, Children: []uint32{17}, GroupByMetadata: nil}, // 16 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil, GroupByMetadata: nil}, // 17 }, }, { name: "aggregate-mapping-file", @@ -471,16 +474,16 @@ func TestGenerateFlamegraphArrow(t *testing.T) { cumulative: 11, height: 5, trimmed: 0, - cols: 14, + cols: 15, rows: []flamegraphRow{ // This aggregates all the rows with the same mapping file, meaning that we only keep one flamegraphRow per stack depth in this example. - {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: array.NullValueStr, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1}}, // 0 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{2, 6}}, // 1 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 10, Flat: 2, Labels: nil, Children: []uint32{3}}, // 2 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 8, Flat: 0, Labels: nil, Children: []uint32{4, 5}}, // 3 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil}, // 4 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 5, Flat: 5, Labels: nil, Children: nil}, // 5 - {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "b", MappingBuildID: "bID", LocationAddress: 0xa6, LocationLine: 6, FunctionStartLine: 6, FunctionName: "2", FunctionSystemName: "6", FunctionFilename: "6", Cumulative: 1, Flat: 1, Labels: nil, Children: nil}, // 5 + {MappingStart: 0, MappingLimit: 0, MappingOffset: 0, MappingFile: array.NullValueStr, MappingBuildID: array.NullValueStr, LocationAddress: 0, LocationLine: 0, FunctionStartLine: 0, FunctionName: array.NullValueStr, FunctionSystemName: array.NullValueStr, FunctionFilename: array.NullValueStr, Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{1}, GroupByMetadata: nil}, // 0 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa1, LocationLine: 1, FunctionStartLine: 1, FunctionName: "1", FunctionSystemName: "1", FunctionFilename: "1", Cumulative: 11, Flat: 0, Labels: nil, Children: []uint32{2, 6}, GroupByMetadata: nil}, // 1 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa2, LocationLine: 2, FunctionStartLine: 2, FunctionName: "2", FunctionSystemName: "2", FunctionFilename: "2", Cumulative: 10, Flat: 2, Labels: nil, Children: []uint32{3}, GroupByMetadata: nil}, // 2 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa3, LocationLine: 3, FunctionStartLine: 3, FunctionName: "3", FunctionSystemName: "3", FunctionFilename: "3", Cumulative: 8, Flat: 0, Labels: nil, Children: []uint32{4, 5}, GroupByMetadata: nil}, // 3 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa4, LocationLine: 4, FunctionStartLine: 4, FunctionName: "4", FunctionSystemName: "4", FunctionFilename: "4", Cumulative: 3, Flat: 3, Labels: nil, Children: nil, GroupByMetadata: nil}, // 4 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "a", MappingBuildID: "aID", LocationAddress: 0xa5, LocationLine: 5, FunctionStartLine: 5, FunctionName: "5", FunctionSystemName: "5", FunctionFilename: "5", Cumulative: 5, Flat: 5, Labels: nil, Children: nil, GroupByMetadata: nil}, // 5 + {MappingStart: 1, MappingLimit: 1, MappingOffset: 0x1234, MappingFile: "b", MappingBuildID: "bID", LocationAddress: 0xa6, LocationLine: 6, FunctionStartLine: 6, FunctionName: "2", FunctionSystemName: "6", FunctionFilename: "6", Cumulative: 1, Flat: 1, Labels: nil, Children: nil, GroupByMetadata: nil}, // 5 }, }} { t.Run(tc.name, func(t *testing.T) { @@ -658,7 +661,7 @@ func TestGenerateFlamegraphArrowEmpty(t *testing.T) { require.Equal(t, int64(0), total) require.Equal(t, int32(1), height) require.Equal(t, int64(0), trimmed) - require.Equal(t, int64(14), record.NumCols()) + require.Equal(t, int64(15), record.NumCols()) require.Equal(t, int64(1), record.NumRows()) } @@ -708,7 +711,7 @@ func TestGenerateFlamegraphArrowWithInlined(t *testing.T) { require.Equal(t, int32(5), height) require.Equal(t, int64(0), trimmed) - require.Equal(t, int64(14), record.NumCols()) + require.Equal(t, int64(15), record.NumCols()) require.Equal(t, int64(5), record.NumRows()) rows := []flamegraphRow{ @@ -809,7 +812,7 @@ func TestGenerateFlamegraphArrowUnsymbolized(t *testing.T) { require.Equal(t, tc.height, height) require.Equal(t, tc.trimmed, trimmed) require.Equal(t, int64(len(tc.rows)), fa.NumRows()) - require.Equal(t, int64(14), fa.NumCols()) + require.Equal(t, int64(15), fa.NumCols()) // Convert the numRows to columns for easier access when testing below. expectedColumns := rowsToColumn(tc.rows) @@ -896,7 +899,7 @@ func TestGenerateFlamegraphArrowTrimming(t *testing.T) { require.Equal(t, int32(5), height) require.Equal(t, int64(4), trimmed) require.Equal(t, int64(3), fa.NumRows()) - require.Equal(t, int64(14), fa.NumCols()) + require.Equal(t, int64(15), fa.NumCols()) // TODO: MappingBuildID and FunctionSystemNames shouldn't be "" but null? rows := []flamegraphRow{ @@ -1185,7 +1188,7 @@ main;func_fib 10 2000 20 main;func_fib 10 3000 20 runtime;gc 20 2000 30 runtime;gc 20 3000 30 -main;func_add 30 1000 20 +runtime;gc 30 1000 20 main;func_add 30 3000 20 `)) require.NoError(t, err) @@ -1330,6 +1333,8 @@ func drawFlamegraphToConsole(testing *testing.T, record arrow.Record) { childrenCol := record.Column(childrenColIdx).(*array.List) functionNameCol := record.Column(functionNameColIdx).(*array.Dictionary) ChildrenValues := childrenCol.ListValues().(*array.Uint32) + cumulativeColIdx := schema.FieldIndices("cumulative")[0] + cumulativeCol := record.Column(cumulativeColIdx).(*array.Uint8) groupByMetadataColIdx := schema.FieldIndices("groupby_metadata")[0] groupByMetadataCol := record.Column(groupByMetadataColIdx).(*array.Struct) tsValues := groupByMetadataCol.Field(1).(*array.Binary) @@ -1344,6 +1349,7 @@ func drawFlamegraphToConsole(testing *testing.T, record arrow.Record) { nums := offsetEnd - offsetStart for j := int64(0); j < nums; j++ { child := ChildrenValues.Value(int(offsetStart + j)) + cumulativeValue := cumulativeCol.Value(int(child)) fBytes := functionNameCol.ValueStr(int(child)) funcName, err := base64.StdEncoding.DecodeString(fBytes) if err != nil { @@ -1351,7 +1357,7 @@ func drawFlamegraphToConsole(testing *testing.T, record arrow.Record) { } tsBytes := tsValues.Value(int(child)) durationBytes := durationValues.Value(int(child)) - childT := t.AddChild(tree.NodeString(string(funcName) + " " + string(tsBytes) + " " + string(durationBytes))) + childT := t.AddChild(tree.NodeString(string(funcName) + " " + string(tsBytes) + " " + string(durationBytes) + " " + fmt.Sprint(cumulativeValue))) populateChild(childT, int(child)) } } From 3d59941e16dfe3bd3060e5584fe2abf43e5b2e71 Mon Sep 17 00:00:00 2001 From: Manoj Vivek Date: Fri, 13 Dec 2024 11:07:37 +0530 Subject: [PATCH 15/15] Fixed diff computation --- pkg/query/columnquery.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pkg/query/columnquery.go b/pkg/query/columnquery.go index c42ec2a5b1c..eb4cf3d8c58 100644 --- a/pkg/query/columnquery.go +++ b/pkg/query/columnquery.go @@ -804,13 +804,13 @@ func ComputeDiff(ctx context.Context, tracer trace.Tracer, mem memory.Allocator, compareCumulativeTotal := int64(0) for _, r := range compare.Samples { cols := r.Columns() - compareCumulativeTotal += math.Int64.Sum(cols[len(cols)-2].(*array.Int64)) + compareCumulativeTotal += math.Int64.Sum(cols[len(cols)-4].(*array.Int64)) } baseCumulativeTotal := int64(0) for _, r := range base.Samples { cols := r.Columns() - baseCumulativeTotal += math.Int64.Sum(cols[len(cols)-2].(*array.Int64)) + baseCumulativeTotal += math.Int64.Sum(cols[len(cols)-4].(*array.Int64)) } // Scale up base if compare is bigger @@ -835,12 +835,12 @@ func ComputeDiff(ctx context.Context, tracer trace.Tracer, mem memory.Allocator, if compareCumulativeRatio > 1.0 { // If compareCumulativeRatio is bigger than 1.0 we have to scale all values - multi := multiplyInt64By(mem, cols[len(cols)-2].(*array.Int64), compareCumulativeRatio) - cols[len(cols)-1] = multi + multi := multiplyInt64By(mem, cols[len(cols)-4].(*array.Int64), compareCumulativeRatio) + cols[len(cols)-3] = multi cleanupArrs = append(cleanupArrs, multi) } else { // otherwise we simply use the original values. - cols[len(cols)-1] = cols[len(cols)-2] // value as diff + cols[len(cols)-3] = cols[len(cols)-4] // value as diff } records = append(records, array.NewRecord( @@ -856,16 +856,22 @@ func ComputeDiff(ctx context.Context, tracer trace.Tracer, mem memory.Allocator, cols := make([]arrow.Array, len(columns)) copy(cols, columns) - diff := multiplyInt64By(mem, columns[len(columns)-2].(*array.Int64), -1*baseCumulativeRatio) + diff := multiplyInt64By(mem, columns[len(columns)-4].(*array.Int64), -1*baseCumulativeRatio) defer diff.Release() value := zeroInt64Array(mem, int(r.NumRows())) defer value.Release() + timestamp := zeroInt64Array(mem, int(r.NumRows())) + defer timestamp.Release() + duration := zeroInt64Array(mem, int(r.NumRows())) + defer duration.Release() records = append(records, array.NewRecord( r.Schema(), append( - cols[:len(cols)-2], // all other columns like locations + cols[:len(cols)-4], // all other columns like locations value, diff, + timestamp, + duration, ), r.NumRows(), ))