diff --git a/integration/standalone/src/app.ts b/integration/standalone/src/app.ts index a3c83d51..ebaf3f2c 100644 --- a/integration/standalone/src/app.ts +++ b/integration/standalone/src/app.ts @@ -22,6 +22,7 @@ const sourceUri = parameters.get('file') ?? ''; const select = parameters.get('select'); const theme = (parameters.get('theme') as ThemeMode) ?? SwitchThemeActionHandler.prefsColorScheme(); const debug = parameters.has('debug', 'true'); +const measurePerformance = parameters.has('performance', 'true'); const id = 'ivy-glsp-process-editor'; const diagramType = 'ivy-glsp-process'; @@ -50,7 +51,8 @@ async function initialize(connectionProvider: MessageConnection, isReconnecting app, pmv, server: webSocketBase - } + }, + measurePerformance }); const diagramLoader = container.get(DiagramLoader); diff --git a/integration/standalone/src/di.config.ts b/integration/standalone/src/di.config.ts index 7f91b357..0246ffdf 100644 --- a/integration/standalone/src/di.config.ts +++ b/integration/standalone/src/di.config.ts @@ -1,4 +1,4 @@ -import { createIvyDiagramContainer, ivyThemeModule } from '@axonivy/process-editor'; +import { createIvyDiagramContainer, createPerformanceModule, ivyThemeModule } from '@axonivy/process-editor'; import { ivyInscriptionModule } from '@axonivy/process-editor-inscription'; import { IDiagramOptions, @@ -20,12 +20,14 @@ export interface IvyDiagramOptions extends IDiagramOptions { select: string | null; theme: ThemeMode; inscriptionContext: InscriptionContext & { server: string }; + measurePerformance?: boolean; } export default function createContainer(options: IvyDiagramOptions): Container { const container = createIvyDiagramContainer( 'sprotty', createDiagramOptionsModule(options), + createPerformanceModule(options.measurePerformance), // standalone modules standaloneSelectModule, standaloneExportModule, diff --git a/integration/viewer/src/app.ts b/integration/viewer/src/app.ts index c40d392c..9c2fb647 100644 --- a/integration/viewer/src/app.ts +++ b/integration/viewer/src/app.ts @@ -22,6 +22,7 @@ const highlight = parameters.get('highlight') ?? ''; const select = parameters.get('select'); const zoom = parameters.get('zoom') ?? ''; const theme = (parameters.get('theme') as ThemeMode) ?? SwitchThemeActionHandler.prefsColorScheme(); +const measurePerformance = parameters.has('performance', 'true'); const id = 'ivy-glsp-process-viewer'; const diagramType = 'ivy-glsp-process'; @@ -46,7 +47,8 @@ async function initialize(connectionProvider: MessageConnection, isReconnecting highlight, select, zoom, - theme + theme, + measurePerformance }); const diagramLoader = container.get(DiagramLoader); diff --git a/integration/viewer/src/di.config.ts b/integration/viewer/src/di.config.ts index e92ca046..b6bfd2be 100644 --- a/integration/viewer/src/di.config.ts +++ b/integration/viewer/src/di.config.ts @@ -1,5 +1,6 @@ import { createIvyDiagramContainer, + createPerformanceModule, ivyChangeBoundsToolModule, ivyConnectorModule, ivyKeyListenerModule, @@ -31,6 +32,7 @@ export interface IvyDiagramOptions extends IDiagramOptions { select: string | null; zoom: string; theme: ThemeMode; + measurePerformance?: boolean; } export default function createContainer(options: IvyDiagramOptions): Container { @@ -38,6 +40,7 @@ export default function createContainer(options: IvyDiagramOptions): Container { const container = createIvyDiagramContainer( 'sprotty', createDiagramOptionsModule(options), + createPerformanceModule(options.measurePerformance), ivyThemeModule, ivyNavigationModule, ivyStartupDiagramModule, diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 21738c1d..2c51f334 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -41,5 +41,5 @@ export * from './ui-tools/viewport/viewport-bar'; export * from './key-listener/jump-out'; export * from './key-listener/quick-actions'; export * from './start-action/actions'; - +export * from './performance/performance-module'; export * from './ivy-glsp-jsonrpc-client'; diff --git a/packages/editor/src/performance/perf-action-dispatcher.ts b/packages/editor/src/performance/perf-action-dispatcher.ts new file mode 100644 index 00000000..e9ba0658 --- /dev/null +++ b/packages/editor/src/performance/perf-action-dispatcher.ts @@ -0,0 +1,23 @@ +import { Action, GLSPActionDispatcher, RequestAction, ResponseAction } from '@eclipse-glsp/client'; +import { injectable } from 'inversify'; + +@injectable() +export class PerfActionDispatcher extends GLSPActionDispatcher { + protected counter = 0; + + override request(action: RequestAction): Promise { + const counter = ++this.counter; + console.time(`request-${action.kind}-${counter}`); + const result = super.request(action); + console.timeEnd(`request-${action.kind}-${counter}`); + this.counter++; + return result; + } + + override async dispatch(action: Action): Promise { + const counter = ++this.counter; + console.time(`dispatch-${action.kind}-${counter}`); + await super.dispatch(action); + console.timeEnd(`dispatch-${action.kind}-${counter}`); + } +} diff --git a/packages/editor/src/performance/perf-diagram-loader.ts b/packages/editor/src/performance/perf-diagram-loader.ts new file mode 100644 index 00000000..5d944efc --- /dev/null +++ b/packages/editor/src/performance/perf-diagram-loader.ts @@ -0,0 +1,23 @@ +import { DiagramLoader, IDiagramStartup, ResolvedDiagramLoadingOptions } from '@eclipse-glsp/client'; +import { injectable } from 'inversify'; + +@injectable() +export class PerfDiagramLoader extends DiagramLoader { + protected override async invokeStartupHook(hook: keyof Omit): Promise { + console.time('invokeStartupHook-' + hook); + await super.invokeStartupHook(hook); + console.timeEnd('invokeStartupHook-' + hook); + } + + protected override async initialize(options: ResolvedDiagramLoadingOptions): Promise { + console.time('DiagramLoader.initialize'); + await super.initialize(options); + console.timeEnd('DiagramLoader.initialize'); + } + + protected override async requestModel(options: ResolvedDiagramLoadingOptions): Promise { + console.time('DiagramLoader.requestModel'); + await super.requestModel(options); + console.timeEnd('DiagramLoader.requestModel'); + } +} diff --git a/packages/editor/src/performance/perf-viewer.ts b/packages/editor/src/performance/perf-viewer.ts new file mode 100644 index 00000000..a6e6163d --- /dev/null +++ b/packages/editor/src/performance/perf-viewer.ts @@ -0,0 +1,14 @@ +import { Action, GModelRoot, ModelViewer } from '@eclipse-glsp/client'; +import { injectable } from 'inversify'; + +@injectable() +export class PerfModelViewer extends ModelViewer { + protected counter = 0; + + update(model: Readonly, cause?: Action): void { + const counter = ++this.counter; + console.time('Viewer update ' + counter); + super.update(model, cause); + console.timeEnd('Viewer update ' + counter); + } +} diff --git a/packages/editor/src/performance/performance-module.ts b/packages/editor/src/performance/performance-module.ts new file mode 100644 index 00000000..d5eebe0b --- /dev/null +++ b/packages/editor/src/performance/performance-module.ts @@ -0,0 +1,18 @@ +import { DiagramLoader, FeatureModule, GLSPActionDispatcher, TYPES } from '@eclipse-glsp/client'; +import { PerfDiagramLoader } from './perf-diagram-loader'; +import { PerfActionDispatcher } from './perf-action-dispatcher'; +import { PerfModelViewer } from './perf-viewer'; + +export function createPerformanceModule(enabled?: boolean): FeatureModule { + return new FeatureModule( + (bind, unbind, isBound, rebind) => { + if (!enabled) { + return; + } + rebind(DiagramLoader).to(PerfDiagramLoader).inSingletonScope(); + rebind(GLSPActionDispatcher).to(PerfActionDispatcher).inSingletonScope(); + rebind(TYPES.ModelViewer).to(PerfModelViewer).inSingletonScope(); + }, + { featureId: Symbol('performance') } + ); +}