Skip to content

Commit

Permalink
[Lens] add performance journey to track rendering time for XY visuali…
Browse files Browse the repository at this point in the history
…zation and suggestions panel (elastic#163412)

## Summary

Related to elastic#163089

Adding the first performance journey for the Lens Editor. It simulated
loading existing Lens visualisation with data view having 10k fields.

We collect the following metrics:
- `fetchFieldsExistenceInfo` reports time it takes to fetch fields in
Data Panel
- `lensVisualizationRenderTime` reports both time it takes to fetch the
data (`time_to_data`) and render the main visualization
(`time_to_render`)
- `lensSuggestionsRenderTime` reports time it takes to render
suggestions panel

Metrics consistency

<img width="568" alt="image"
src="https://github.com/elastic/kibana/assets/10977896/3384bb8e-6152-4bae-93dc-4f7f4167ed07">

Run locally with
```
node scripts/functional_tests --config x-pack/performance/journeys/many_fields_lens_editor.ts
```

Metrics will be available here

https://telemetry-v2-staging.elastic.dev/s/kibana-performance/app/dashboards#/view/dd0473ac-826f-5621-9a10-25319700326e?_g=h@61c5ac8

---------

Co-authored-by: Drew Tate <[email protected]>
(cherry picked from commit 15b118c)
  • Loading branch information
dmlemeshko committed Aug 17, 2023
1 parent 69667f3 commit 75e4dc5
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 27 deletions.
1 change: 1 addition & 0 deletions .buildkite/ftr_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ enabled:
- x-pack/performance/journeys/flight_dashboard.ts
- x-pack/performance/journeys/login.ts
- x-pack/performance/journeys/many_fields_discover.ts
- x-pack/performance/journeys/many_fields_lens_editor.ts
- x-pack/performance/journeys/many_fields_transform.ts
- x-pack/performance/journeys/promotion_tracking_dashboard.ts
- x-pack/performance/journeys/web_logs_dashboard.ts
Expand Down
16 changes: 15 additions & 1 deletion packages/kbn-unified-field-list/src/hooks/use_existing_fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { AggregateQuery, EsQueryConfig, Filter, Query } from '@kbn/es-query
import { type DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { DataView, DataViewsContract } from '@kbn/data-views-plugin/common';
import { getEsQueryConfig } from '@kbn/data-service/src/es_query';
import { reportPerformanceMetricEvent } from '@kbn/ebt-tools';
import { loadFieldExisting } from '../services/field_existing';
import { ExistenceFetchStatus } from '../types';

Expand All @@ -35,7 +36,7 @@ export interface ExistingFieldsFetcherParams {
query: Query | AggregateQuery | undefined;
filters: Filter[] | undefined;
services: {
core: Pick<CoreStart, 'uiSettings'>;
core: Pick<CoreStart, 'uiSettings' | 'analytics'>;
data: DataPublicPluginStart;
dataViews: DataViewsContract;
};
Expand Down Expand Up @@ -178,6 +179,8 @@ export const useExistingFieldsFetcher = (
const dataViewsHash = getDataViewsHash(params.dataViews);
const refetchFieldsExistenceInfo = useCallback(
async (dataViewId?: string) => {
const startTime = window.performance.now();
const metricEventName = 'fetchFieldsExistenceInfo';
const fetchId = generateId();
lastFetchId = fetchId;

Expand All @@ -192,6 +195,11 @@ export const useExistingFieldsFetcher = (
...options,
dataViewId,
});
reportPerformanceMetricEvent(params.services.core.analytics, {
eventName: metricEventName,
duration: window.performance.now() - startTime,
meta: { dataViewsCount: 1 },
});
return;
}
// refetch for all mentioned data views
Expand All @@ -203,6 +211,11 @@ export const useExistingFieldsFetcher = (
})
)
);
reportPerformanceMetricEvent(params.services.core.analytics, {
eventName: metricEventName,
duration: window.performance.now() - startTime,
meta: { dataViewsCount: params.dataViews.length },
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
Expand All @@ -212,6 +225,7 @@ export const useExistingFieldsFetcher = (
params.filters,
params.fromDate,
params.toDate,
params.services.core,
]
);

Expand Down
1 change: 1 addition & 0 deletions packages/kbn-unified-field-list/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@kbn/dom-drag-drop",
"@kbn/shared-ux-utility",
"@kbn/discover-utils",
"@kbn/ebt-tools",
],
"exclude": ["target/**/*"]
}
28 changes: 28 additions & 0 deletions x-pack/performance/journeys/many_fields_lens_editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { Journey } from '@kbn/journeys';
import { subj } from '@kbn/test-subj-selector';

export const journey = new Journey({
kbnArchives: ['x-pack/performance/kbn_archives/lens_many_fields'],
esArchives: ['test/functional/fixtures/es_archiver/stress_test'],
})
.step('Go to Visualize Library landing page', async ({ page, kbnUrl }) => {
await page.goto(
kbnUrl.get(
`/app/visualize#/?_g=(filters:!(),time:(from:'2022-09-07T10:53:30.262Z',to:'2022-09-07T10:55:09.280Z'))`
)
);
await page.waitForSelector(subj('table-is-ready'));
// wait extra 5 seconds: we're not sure why, but the extra sleep before loading the editor makes the metrics more consistent
await page.waitForTimeout(5000);
})
.step('Open existing Lens visualization', async ({ page, kibanaPage }) => {
await page.click(subj('visListingTitleLink-Lens-Stress-Test'));
await kibanaPage.waitForCharts(6);
});
209 changes: 209 additions & 0 deletions x-pack/performance/kbn_archives/lens_many_fields.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
{
"attributes":{
"fieldAttrs":"{}",
"fields":"[]",
"runtimeFieldMap":"{}",
"title":"stresstest",
"typeMeta":"{}"
},
"coreMigrationVersion":"8.8.0",
"created_at":"2023-07-27T16:21:31.312Z",
"id":"6244bd06-f711-44db-b756-bc25e4a32a60",
"managed":false,
"references":[],
"type":"index-pattern",
"typeMigrationVersion":"8.0.0",
"updated_at":"2023-07-27T16:21:31.312Z",
"version":"WzIxLDFd"
}

{
"attributes":{
"description":"",
"state":{
"adHocDataViews":{},
"datasourceStates":{
"formBased":{
"layers":{
"591b8a11-31f9-41e5-87ba-f0b6f5face08":{
"columnOrder":[
"fed7a521-30ac-4696-bf2d-85a26ba6db58",
"5bcdbfd2-c4c0-4b27-891e-d848ea468cbe",
"532742da-8bea-4357-a5e1-9319111a61e7",
"4707670e-1c99-4e86-a09c-7801490131a1",
"e822b0fa-1c95-44fa-8a5a-06c339f841ca",
"881198db-8a3d-497b-b662-d7f5835775af",
"fc484025-c6c3-47e5-8a2d-428d6d6e3dbb"
],
"columns":{
"4707670e-1c99-4e86-a09c-7801490131a1":{
"dataType":"number",
"isBucketed":false,
"label":"Moving average of Unique count of field1",
"operationType":"moving_average",
"params":{
"window":5
},
"references":[
"e822b0fa-1c95-44fa-8a5a-06c339f841ca"
],
"scale":"ratio"
},
"532742da-8bea-4357-a5e1-9319111a61e7":{
"dataType":"number",
"isBucketed":false,
"label":"Count of records",
"operationType":"count",
"params":{
"emptyAsNull":true
},
"scale":"ratio",
"sourceField":"___records___"
},
"5bcdbfd2-c4c0-4b27-891e-d848ea468cbe":{
"dataType":"date",
"isBucketed":true,
"label":"@timestamp",
"operationType":"date_histogram",
"params":{
"dropPartials":false,
"includeEmptyRows":true,
"interval":"ms"
},
"scale":"interval",
"sourceField":"@timestamp"
},
"881198db-8a3d-497b-b662-d7f5835775af":{
"dataType":"number",
"isBucketed":false,
"label":"Cumulative sum of Records",
"operationType":"cumulative_sum",
"references":[
"fc484025-c6c3-47e5-8a2d-428d6d6e3dbb"
],
"scale":"ratio"
},
"e822b0fa-1c95-44fa-8a5a-06c339f841ca":{
"dataType":"number",
"isBucketed":false,
"label":"Unique count of field1",
"operationType":"unique_count",
"params":{
"emptyAsNull":true
},
"scale":"ratio",
"sourceField":"field1"
},
"fc484025-c6c3-47e5-8a2d-428d6d6e3dbb":{
"dataType":"number",
"isBucketed":false,
"label":"Count of records",
"operationType":"count",
"params":{
"emptyAsNull":true
},
"scale":"ratio",
"sourceField":"___records___"
},
"fed7a521-30ac-4696-bf2d-85a26ba6db58":{
"dataType":"string",
"isBucketed":true,
"label":"Top 1000 values of field0",
"operationType":"terms",
"params":{
"missingBucket":false,
"orderBy":{
"columnId":"532742da-8bea-4357-a5e1-9319111a61e7",
"type":"column"
},
"orderDirection":"desc",
"otherBucket":false,
"parentFormat":{
"id":"terms"
},
"size":1000
},
"scale":"ordinal",
"sourceField":"field0"
}
},
"incompleteColumns":{}
}
}
}
},
"filters":[],
"internalReferences":[],
"query":{
"language":"kuery",
"query":""
},
"visualization":{
"axisTitlesVisibilitySettings":{
"x":true,
"yLeft":true,
"yRight":true
},
"fittingFunction":"None",
"gridlinesVisibilitySettings":{
"x":true,
"yLeft":true,
"yRight":true
},
"labelsOrientation":{
"x":0,
"yLeft":0,
"yRight":0
},
"layers":[
{
"accessors":[
"532742da-8bea-4357-a5e1-9319111a61e7",
"4707670e-1c99-4e86-a09c-7801490131a1",
"881198db-8a3d-497b-b662-d7f5835775af"
],
"layerId":"591b8a11-31f9-41e5-87ba-f0b6f5face08",
"layerType":"data",
"position":"top",
"seriesType":"bar_stacked",
"showGridlines":false,
"splitAccessor":"fed7a521-30ac-4696-bf2d-85a26ba6db58",
"xAccessor":"5bcdbfd2-c4c0-4b27-891e-d848ea468cbe"
}
],
"legend":{
"isVisible":true,
"legendSize":"auto",
"position":"right"
},
"preferredSeriesType":"bar_stacked",
"tickLabelsVisibilitySettings":{
"x":true,
"yLeft":true,
"yRight":true
},
"valueLabels":"hide"
}
},
"title":"Lens Stress Test",
"visualizationType":"lnsXY"
},
"coreMigrationVersion":"8.8.0",
"created_at":"2023-07-27T16:58:15.808Z",
"id":"c7787800-2c9e-11ee-b1db-6df582ca24e0",
"managed":false,
"references":[
{
"id":"6244bd06-f711-44db-b756-bc25e4a32a60",
"name":"indexpattern-datasource-layer-591b8a11-31f9-41e5-87ba-f0b6f5face08",
"type":"index-pattern"
}
],
"timeFrom": "2022-09-07T12:53:30.262Z",
"timeTo": "2022-09-07T12:55:09.280Z",
"timeRestore": true,
"type":"lens",
"typeMigrationVersion":"8.9.0",
"updated_at":"2023-07-27T16:58:15.808Z",
"version":"WzYyLDFd"
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export function EditorFrame(props: EditorFrameProps) {
frame={framePublicAPI}
getUserMessages={props.getUserMessages}
nowProvider={props.plugins.data.nowProvider}
core={props.core}
/>
</ErrorBoundary>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { getSuggestions } from './suggestion_helpers';
import { EuiIcon, EuiPanel, EuiToolTip, EuiAccordion } from '@elastic/eui';
import { IconChartDatatable } from '@kbn/chart-icons';
import { mountWithProvider } from '../../mocks';
import { coreMock } from '@kbn/core/public/mocks';

import {
applyChanges,
LensAppState,
Expand Down Expand Up @@ -106,6 +108,7 @@ describe('suggestion_panel', () => {
frame: createMockFramePublicAPI(),
getUserMessages: () => [],
nowProvider: { get: jest.fn(() => new Date()) },
core: coreMock.createStart(),
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
ReactExpressionRendererProps,
ReactExpressionRendererType,
} from '@kbn/expressions-plugin/public';
import { reportPerformanceMetricEvent } from '@kbn/ebt-tools';
import { CoreStart } from '@kbn/core/public';
import { DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS } from '../../utils';
import {
Datasource,
Expand Down Expand Up @@ -100,6 +102,7 @@ export interface SuggestionPanelProps {
frame: FramePublicAPI;
getUserMessages: UserMessagesGetter;
nowProvider: DataPublicPluginStart['nowProvider'];
core: CoreStart;
}

const PreviewRenderer = ({
Expand Down Expand Up @@ -226,6 +229,7 @@ export function SuggestionPanel({
ExpressionRenderer: ExpressionRendererComponent,
getUserMessages,
nowProvider,
core,
}: SuggestionPanelProps) {
const dispatchLens = useLensDispatch();
const activeDatasourceId = useLensSelector(selectActiveDatasourceId);
Expand Down Expand Up @@ -368,16 +372,19 @@ export function SuggestionPanel({
const suggestionsRendered = useRef<boolean[]>([]);
const totalSuggestions = suggestions.length + 1;

const onSuggestionRender = useCallback((suggestionIndex: number) => {
suggestionsRendered.current[suggestionIndex] = true;
if (initialRenderComplete.current === false && suggestionsRendered.current.every(Boolean)) {
initialRenderComplete.current = true;
// console.log(
// 'time to fetch data and perform initial render for all suggestions',
// performance.now() - startTime.current
// );
}
}, []);
const onSuggestionRender = useCallback(
(suggestionIndex: number) => {
suggestionsRendered.current[suggestionIndex] = true;
if (initialRenderComplete.current === false && suggestionsRendered.current.every(Boolean)) {
initialRenderComplete.current = true;
reportPerformanceMetricEvent(core.analytics, {
eventName: 'lensSuggestionsRenderTime',
duration: performance.now() - startTime.current,
});
}
},
[core.analytics]
);

const rollbackToCurrentVisualization = useCallback(() => {
if (lastSelectedSuggestion !== -1) {
Expand Down
Loading

0 comments on commit 75e4dc5

Please sign in to comment.