Skip to content

Commit

Permalink
Improve performance tracking
Browse files Browse the repository at this point in the history
Measure actions when they are actually handled instead of on dispatch
(avoids inconsistencies due to action queue blocking)
Add in depth logging for set-model-command and model update
  • Loading branch information
tortmayr committed Nov 26, 2024
1 parent 28042a9 commit 3714743
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 20 deletions.
21 changes: 21 additions & 0 deletions packages/editor/src/performance/per-set-model-command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { CommandExecutionContext, GModelRoot, SetModelCommand } from '@eclipse-glsp/client';
import { injectable } from 'inversify';

@injectable()
export class PerfSetModelCommand extends SetModelCommand {
protected counter = 0;

execute(context: CommandExecutionContext): GModelRoot {
const counter = ++this.counter;
console.time(`execute SetModelCommand (sc) ${counter}`);
console.time(`sc-createOldRoot (${counter})`);
this.oldRoot = context.modelFactory.createRoot(context.root);
console.timeEnd(`sc-createOldRoot (${counter})`);
console.time(`sc-createNewRoot (${counter})`);
this.newRoot = context.modelFactory.createRoot(this.action.newRoot);
console.timeEnd(`sc-createNewRoot (${counter})`);
console.timeEnd(`execute SetModelCommand (sc) ${counter}`);

return this.newRoot;
}
}
10 changes: 6 additions & 4 deletions packages/editor/src/performance/perf-action-dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ export class PerfActionDispatcher extends GLSPActionDispatcher {
return result;
}

override async dispatch(action: Action): Promise<void> {
protected override async handleAction(action: Action): Promise<void> {
const counter = ++this.counter;
console.time(`dispatch-${action.kind}-${counter}`);
await super.dispatch(action);
console.timeEnd(`dispatch-${action.kind}-${counter}`);
console.time(`handleAction-${action.kind}-${counter}`);
console.log(`handleAction-${action.kind}-${counter}`, action);
const result = await super.handleAction(action);
console.timeEnd(`handleAction-${action.kind}-${counter}`);
return result;
}
}
35 changes: 34 additions & 1 deletion packages/editor/src/performance/perf-diagram-loader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { DiagramLoader, IDiagramStartup, ResolvedDiagramLoadingOptions } from '@eclipse-glsp/client';
import {
ApplicationIdProvider,
DiagramLoader,
DiagramLoadingOptions,
GLSPClient,
IDiagramStartup,
Ranked,
ResolvedDiagramLoadingOptions
} from '@eclipse-glsp/client';
import { injectable } from 'inversify';

@injectable()
Expand All @@ -20,4 +28,29 @@ export class PerfDiagramLoader extends DiagramLoader {
await super.requestModel(options);
console.timeEnd('DiagramLoader.requestModel');
}

override async load(options: DiagramLoadingOptions = {}): Promise<void> {
this.diagramStartups.sort(Ranked.sort);
await this.invokeStartupHook('preLoadDiagram');
const resolvedOptions: ResolvedDiagramLoadingOptions = {
requestModelOptions: {
sourceUri: this.options.sourceUri ?? '',
diagramType: this.options.diagramType,
...options.requestModelOptions
},
initializeParameters: {
applicationId: ApplicationIdProvider.get(),
protocolVersion: GLSPClient.protocolVersion,
...options.initializeParameters
},
enableNotifications: options.enableNotifications ?? true
};
await this.actionDispatcher.initialize();
await this.invokeStartupHook('preInitialize');
await this.initialize(resolvedOptions);
await this.invokeStartupHook('preRequestModel');
await this.requestModel(resolvedOptions);
await this.invokeStartupHook('postRequestModel');
this.modelInitializationConstraint.onInitialized(() => this.invokeStartupHook('postModelInitialization'));
}
}
14 changes: 0 additions & 14 deletions packages/editor/src/performance/perf-viewer.ts

This file was deleted.

59 changes: 59 additions & 0 deletions packages/editor/src/performance/perf-viewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/** @jsx html */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Action, GModelRoot, ModelViewer, copyClassesFromElement, copyClassesFromVNode, html, setClass } from '@eclipse-glsp/client';
import { injectable } from 'inversify';

@injectable()
export class PerfModelViewer extends ModelViewer {
protected counter = 0;
update(model: Readonly<GModelRoot>, cause?: Action): void {
const counter = ++this.counter;
console.time(`Viewer update (vu) (${counter})`);
this.logger.log(this, 'rendering', model);
console.time(`vu- renderElement (${counter})`);
const newVDOM = <div id={this.options.baseDiv}>{this.renderer.renderElement(model)}</div>;
console.timeEnd(`vu- renderElement (${counter})`);
if (this.lastVDOM !== undefined) {
const hadFocus = this.hasFocus();
console.time(`vu- copyClassesFromVNode (${counter})`);
copyClassesFromVNode(this.lastVDOM, newVDOM);
console.timeEnd(`vu- copyClassesFromVNode (${counter})`);
console.time(`vu- patch vdom (${counter})`);
this.lastVDOM = this.patcher.call(this, this.lastVDOM, newVDOM);
console.timeEnd(`vu- patch vdom (${counter})`);
console.time(`vu- restoreFocus (${counter})`);
this.restoreFocus(hadFocus);
console.timeEnd(`vu- restoreFocus (${counter})`);
} else if (typeof document !== 'undefined') {
let placeholder = null;
if (this.options.shadowRoot) {
const shadowRoot = document.getElementById(this.options.shadowRoot)?.shadowRoot;
if (shadowRoot) {
placeholder = shadowRoot.getElementById(this.options.baseDiv);
}
} else {
placeholder = document.getElementById(this.options.baseDiv);
}
if (placeholder !== null) {
if (typeof window !== 'undefined') {
window.addEventListener('resize', () => {
this.onWindowResize(newVDOM);
});
}
console.time(`vu- copyClassesFromElement (${counter})`);
copyClassesFromElement(placeholder, newVDOM);
setClass(newVDOM, this.options.baseClass, true);
console.timeEnd(`vu- copyClassesFromElement (${counter})`);
console.time(`vu- patch vdom (${counter})`);
this.lastVDOM = this.patcher.call(this, placeholder, newVDOM);
console.timeEnd(`vu- patch vdom (${counter})`);
} else {
this.logger.error(this, 'element not in DOM:', this.options.baseDiv);
}
}
console.time(`vu- postUpdate (${counter})`);
this.renderer.postUpdate(cause);
console.timeEnd(`vu- postUpdate (${counter})`);
console.timeEnd(`Viewer update (vu) (${counter})`);
}
}
4 changes: 3 additions & 1 deletion packages/editor/src/performance/performance-module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { DiagramLoader, FeatureModule, GLSPActionDispatcher, TYPES } from '@eclipse-glsp/client';
import { DiagramLoader, FeatureModule, GLSPActionDispatcher, SetModelCommand, TYPES } from '@eclipse-glsp/client';
import { PerfDiagramLoader } from './perf-diagram-loader';
import { PerfActionDispatcher } from './perf-action-dispatcher';
import { PerfModelViewer } from './perf-viewer';
import { PerfSetModelCommand } from './per-set-model-command';

export function createPerformanceModule(enabled?: boolean): FeatureModule {
return new FeatureModule(
Expand All @@ -12,6 +13,7 @@ export function createPerformanceModule(enabled?: boolean): FeatureModule {
rebind(DiagramLoader).to(PerfDiagramLoader).inSingletonScope();
rebind(GLSPActionDispatcher).to(PerfActionDispatcher).inSingletonScope();
rebind(TYPES.ModelViewer).to(PerfModelViewer).inSingletonScope();
rebind(SetModelCommand).to(PerfSetModelCommand);
},
{ featureId: Symbol('performance') }
);
Expand Down

0 comments on commit 3714743

Please sign in to comment.