From 00ea26596f4e84901e39aec7829d55066cd21572 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Tue, 29 Sep 2020 17:16:15 -0400 Subject: [PATCH 1/2] [Expressions] Finish connecting debug mode on expressions --- .../expressions/common/executor/executor.ts | 9 +++++++-- .../common/service/expressions_services.ts | 17 ++++++++++++----- src/plugins/expressions/public/loader.ts | 18 +++++++++++++----- src/plugins/expressions/public/types/index.ts | 2 ++ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/plugins/expressions/common/executor/executor.ts b/src/plugins/expressions/common/executor/executor.ts index 2b5f9f2556d89..963801317a8d4 100644 --- a/src/plugins/expressions/common/executor/executor.ts +++ b/src/plugins/expressions/common/executor/executor.ts @@ -165,8 +165,13 @@ export class Executor = Record = Record - >(ast: string | ExpressionAstExpression, input: Input, context?: ExtraContext) { - const execution = this.createExecution(ast, context); + >( + ast: string | ExpressionAstExpression, + input: Input, + context?: ExtraContext, + options?: ExpressionExecOptions + ) { + const execution = this.createExecution(ast, context, options); execution.start(input); return (await execution.result) as Output; } diff --git a/src/plugins/expressions/common/service/expressions_services.ts b/src/plugins/expressions/common/service/expressions_services.ts index f1053c7bb8411..e138c6dc1e707 100644 --- a/src/plugins/expressions/common/service/expressions_services.ts +++ b/src/plugins/expressions/common/service/expressions_services.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Executor } from '../executor'; +import { Executor, ExpressionExecOptions } from '../executor'; import { ExpressionRendererRegistry } from '../expression_renderers'; import { ExpressionAstExpression } from '../ast'; import { ExecutionContract } from '../execution/execution_contract'; @@ -169,8 +169,10 @@ export class ExpressionsService { >( ast: string | ExpressionAstExpression, input: Input, - context?: ExtraContext - ): Promise => this.executor.run(ast, input, context); + context?: ExtraContext, + options?: ExpressionExecOptions + ): Promise => + this.executor.run(ast, input, context, options); /** * Get a registered `ExpressionFunction` by its name, which was registered @@ -232,9 +234,14 @@ export class ExpressionsService { ast: string | ExpressionAstExpression, // This any is for legacy reasons. input: Input = { type: 'null' } as any, - context?: ExtraContext + context?: ExtraContext, + options?: ExpressionExecOptions ): ExecutionContract => { - const execution = this.executor.createExecution(ast, context); + const execution = this.executor.createExecution( + ast, + context, + options + ); execution.start(input); return execution.contract; }; diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index c4c40e0812e48..aef4b73f86e34 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -145,11 +145,18 @@ export class ExpressionLoader { this.execution.cancel(); } this.setParams(params); - this.execution = getExpressionsService().execute(expression, params.context, { - search: params.searchContext, - variables: params.variables || {}, - inspectorAdapters: params.inspectorAdapters, - }); + this.execution = getExpressionsService().execute( + expression, + params.context, + { + search: params.searchContext, + variables: params.variables || {}, + inspectorAdapters: params.inspectorAdapters, + }, + { + debug: params.debug, + } + ); const prevDataHandler = this.execution; const data = await prevDataHandler.getData(); @@ -181,6 +188,7 @@ export class ExpressionLoader { if (params.variables && this.params) { this.params.variables = params.variables; } + this.params.debug = Boolean(params.debug); this.params.inspectorAdapters = (params.inspectorAdapters || this.execution?.inspect()) as Adapters; diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index 5e349c95d2555..cff8b5d2dd8fa 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -45,6 +45,8 @@ export interface IExpressionLoaderParams { searchContext?: ExecutionContextSearch; context?: ExpressionValue; variables?: Record; + // Enables debug tracking on each expression in the AST + debug?: boolean; disableCaching?: boolean; customFunctions?: []; customRenderers?: []; From d7f62ae75483bc30c65d39eab16b797de5959eb2 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Tue, 29 Sep 2020 18:45:47 -0400 Subject: [PATCH 2/2] Write debug timing for all expressions to console --- .../expressions/common/execution/execution.ts | 4 +- src/plugins/expressions/public/loader.ts | 42 ++++++++++++++++- .../public/embeddable/visualize_embeddable.ts | 2 + .../canvas/public/lib/run_interpreter.ts | 45 +++++++++++++++++-- .../workspace_panel/workspace_panel.tsx | 1 + .../embeddable/expression_wrapper.tsx | 1 + 6 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index d4c9b0a25d45b..e192ff8ebbe7c 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -237,8 +237,8 @@ export class Execution< success: true, fn: fn.name, input, - args: resolvedArgs, - output, + // args: resolvedArgs, + // output, duration: timeEnd - timeStart, }; } diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index aef4b73f86e34..b4711fffb21f9 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -22,7 +22,7 @@ import { filter, map } from 'rxjs/operators'; import { defaults } from 'lodash'; import { Adapters } from '../../inspector/public'; import { IExpressionLoaderParams } from './types'; -import { ExpressionAstExpression } from '../common'; +import { ExpressionAstExpression, ExpressionAstFunction } from '../common'; import { ExecutionContract } from '../common/execution/execution_contract'; import { ExpressionRenderHandler } from './render'; @@ -163,9 +163,49 @@ export class ExpressionLoader { if (this.execution !== prevDataHandler) { return; } + if (params.debug) { + this.displayTiming(this.execution.getAst()); + } this.dataSubject.next(data); }; + private forEachAst( + ast: ExpressionAstExpression, + cb: (fn: ExpressionAstFunction, depth: number) => void, + depth: number + ) { + ast.chain.forEach((f) => { + cb(f, depth); + Object.values(f.arguments).forEach((args) => { + args.forEach((arg) => { + if (typeof arg === 'object' && arg && arg.type === 'expression') { + this.forEachAst(arg, cb, depth + 1); + } + }); + }); + }); + } + + private displayTiming(ast: ExpressionAstExpression) { + const times: any[] = []; + this.forEachAst( + ast, + (fn: ExpressionAstFunction, depth) => { + times.push({ + name: fn.debug?.fn, + duration_ms: fn.debug?.duration ?? 0, + depth, + }); + }, + 0 + ); + console.table(times); + console.log( + 'Total time', + times.reduce((prev, current) => prev + current.duration_ms, 0) + ); + } + private render(data: Data): void { this.renderHandler.render(data, this.params.uiState); } diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index c091d396b4924..da6c249020788 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -295,6 +295,7 @@ export class VisualizeEmbeddable onRenderError: (element: HTMLElement, error: ExpressionRenderError) => { this.onContainerError(error); }, + debug: true, }); this.subscriptions.push( @@ -376,6 +377,7 @@ export class VisualizeEmbeddable }, uiState: this.vis.uiState, inspectorAdapters: this.inspectorAdapters, + debug: true, }; if (this.abortController) { this.abortController.abort(); diff --git a/x-pack/plugins/canvas/public/lib/run_interpreter.ts b/x-pack/plugins/canvas/public/lib/run_interpreter.ts index 12e07ed3535f6..c63c9090482ce 100644 --- a/x-pack/plugins/canvas/public/lib/run_interpreter.ts +++ b/x-pack/plugins/canvas/public/lib/run_interpreter.ts @@ -20,7 +20,10 @@ export async function interpretAst( variables: Record ): Promise { const context = { variables }; - return await expressionsService.getService().execute(ast, null, context).getData(); + const executor = expressionsService.getService().execute(ast, null, context, { debug: true }); + const finalData = await executor.getData(); + displayTiming(executor.getAst()); + return finalData; } /** @@ -39,14 +42,17 @@ export async function runInterpreter( variables: Record, options: Options = {} ): Promise { - const context = { variables }; + const context = { variables, debug: true }; try { - const renderable = await expressionsService.getService().execute(ast, input, context).getData(); + const executor = expressionsService.getService().execute(ast, input, context, { debug: true }); + const renderable = await executor.getData(); + displayTiming(executor.getAst()); if (getType(renderable) === 'render') { return renderable; } + debugger; if (options.castToRender) { return runInterpreter(fromExpression('render'), renderable, variables, { @@ -60,3 +66,36 @@ export async function runInterpreter( throw err; } } + +function forEachAst(ast, cb, depth) { + ast.chain.forEach((f) => { + cb(f, depth); + Object.values(f.arguments).forEach((args) => { + args.forEach((arg) => { + if (typeof arg === 'object' && arg && arg.type === 'expression') { + forEachAst(arg, cb, depth + 1); + } + }); + }); + }); +} + +function displayTiming(ast) { + const times = []; + forEachAst( + ast, + (fn, depth) => { + times.push({ + name: fn.debug?.fn, + duration_ms: fn.debug?.duration ?? 0, + depth, + }); + }, + 0 + ); + console.table(times); + console.log( + 'Total time', + times.reduce((prev, current) => prev + current.duration_ms, 0) + ); +} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index e56e55fdd5d6c..9984f882093f4 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -281,6 +281,7 @@ export function InnerWorkspacePanel({ searchContext={context} reload$={autoRefreshFetch$} onEvent={onEvent} + debug={true} renderError={(errorMessage?: string | null) => { return ( diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx index d0d2360ddc107..31b34007b63bc 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx @@ -52,6 +52,7 @@ export function ExpressionWrapper({ searchContext={searchContext} renderError={(error) =>
{error}
} onEvent={handleEvent} + debug={true} /> )}