Bug 443518 - Investigate (and optimize) the suspiciously high number of EditPart.refresh() calls on Sirius diagrams
Summary: Investigate (and optimize) the suspiciously high number of EditPart.refresh()...
Status: NEW
Alias: None
Product: Sirius
Classification: Modeling
Component: Diagram (show other bugs)
Version: 1.0.0   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance, triaged
Depends on:
Blocks:
 
Reported: 2014-09-08 11:41 EDT by Pierre-Charles David CLA
Modified: 2021-03-11 08:38 EST (History)
3 users (show)

See Also:


Attachments
Test case (7.13 KB, application/zip)
2015-03-06 04:31 EST, Esteban DUGUEPEROUX CLA
no flags Details
TestProject.zip: Sample to verify changes in manual refresh (4.71 KB, application/zip)
2015-03-30 05:08 EDT, Laurent Redor CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Pierre-Charles David CLA 2014-09-08 11:41:24 EDT
While profiling the scenario for bug 441770, it became obvious that even for basic operations, we trigger too many EditPart.refresh() calls.

For example, by instrumenting AbstractDDiagramEditPart.refresh() and AbstractDiagramElementContainerEditPart.refresh(), when creating a empty container on an otherwise empty diagram, I count:
* 2 calls to DDiagramEditPart.refresh() on the same DDiagramEditPart instance.
* 17 calls to AbstractDiagramElementContainerEditPart.refresh() on the same DNodeContainerEditPart instance.

They appear in this order:
DDiagramEditPart[7082f813].refresh()
DNodeContainerEditPart[5c550cd3].refresh() (13 times)
DDiagramEditPart[7082f813].refresh()
DNodeContainerEditPart[5c550cd3].refresh() (4 times)

When dropping a list container with 112 list items (from the sample model available on bug 441770), the numbers are even worse:

DDiagramEditPart[7082f813].refresh()
DNodeListEditPartWithAlpha[4aff8c01].refresh()
DDiagramEditPart[7082f813].refresh()
DNodeListEditPartWithAlpha[4aff8c01].refresh() (238 times)
DDiagramEditPart[7082f813].refresh()
DNodeListEditPartWithAlpha[4aff8c01].refresh() (4 times)

Note that the DNodeListEditPartWithAlpha which is refresh()-ed 243 times is the list container itself, not the items (I did not instrument the items' refresh(), but fro what I saw in https://bugs.eclipse.org/bugs/show_bug.cgi?id=441770#c8, it would be 10s or 100s of thousands of calls).

We should understand better why so many calls are triggered, and strive to reduce them to the minimum.
Comment 1 Pierre-Charles David CLA 2014-12-30 10:26:28 EST
Cleanups that will be done in the context of bug #453902 could make it easier to understand what happens and why. Conversely, do not hesitate to simplify/refactor the code (referencing #453902 for this work) when working on this particular ticket if it makes it easier to analyze (and fix) the issues.
Comment 2 Eclipse Genie CLA 2015-03-04 10:07:36 EST
New Gerrit change created: https://git.eclipse.org/r/43165
Comment 3 Esteban DUGUEPEROUX CLA 2015-03-06 04:31:33 EST
Created attachment 251351 [details]
Test case
Comment 4 Eclipse Genie CLA 2015-03-06 09:57:01 EST
New Gerrit change created: https://git.eclipse.org/r/43318
Comment 5 Esteban DUGUEPEROUX CLA 2015-03-06 11:50:46 EST
Non exhaustive list of things to rework/remove to limit the number of EditPart.refresh() :

-  Replace SemanticChangedCommand by a precommit in manual
refresh : https://git.eclipse.org/r/#/c/43165/
- Analyse if on Mapping's StyleDescription change NotificationListener of DiagramElementEditPartOperation.createEApdaterDiagramElement() is useful. And if useful have a better mechanism like GMF View corresponding to the IStyleEditPart recreated to have IStyleEditPart recreated, for example SquareEditPart -> DotEditPart.
- Have AbstractDiagramNodeEditPart.refreshVisuals() don't call DiagramNodeEditPartOperation.refreshVisuals(this); and have draw2d bounds updated only through GMF Bounds and not from DNode.width and not using AbstractDiagramNodeEditPartRefreshVisualsOperation.refreshSize()
- EditStatusUpdater should be a postcommit
- AbstractDiagramNodeEditPart.refresh() should not refresh its children, that don't seems usefull, children of a DNodeXEditPart are AbstractDiagramNameEditPart or others DNodeXEditParts which are refreshed on their GMF View changes
- Code in AbstractDDiagramEditPart.handleNotificationEvent() seems do EditPart.refresh() about layer/filter changes while layer/filter changes impact only visibility of GMF View then only EditPart.refreshVisibility() should be called and automatically by GMF.
- Too more listeners are registered in DiagramElementEditPartOperation.activate() and this could be 
- AbstractDiagramElementContainerEditPart.handleNotificationEvent() in some case can refresh its IStyleEditPart which seems useless and also 2 refresh of itself which following notification launch a refresh in super.handleNotificationEvent().

More cleanup works :
- Have changes about color, i.e. RGBValues, in viewpoint model propagated in GMF model to avoid code like DiagramNodeEditPartOperation/DiagramElementEditPartOperation/DiagramEdgeEditPartOperation/DiagramContainerEditPartOperation.refreshForegroundColor()/refreshBackgroundColor()/refreshFont() as this can be managed directly by GMF.
Comment 6 Laurent Redor CLA 2015-03-16 04:19:22 EDT
To complete comment 5, I see a suspicious code in org.eclipse.sirius.diagram.ui.business.api.image.ImageSelectorService: when a basicLabelStyle is updated with a new image path, through method updateStyle(BasicLabelStyle, String), all the edit parts of the diagram is refreshed  --> WorkspaceImageFigureRefresher.refreshAllEditPart
Comment 7 Eclipse Genie CLA 2015-03-20 12:09:38 EDT
New Gerrit change created: https://git.eclipse.org/r/44263
Comment 8 Eclipse Genie CLA 2015-03-20 12:09:41 EDT
New Gerrit change created: https://git.eclipse.org/r/44264
Comment 9 Eclipse Genie CLA 2015-03-26 07:01:19 EDT
New Gerrit change created: https://git.eclipse.org/r/44674
Comment 10 Eclipse Genie CLA 2015-03-27 12:28:15 EDT
New Gerrit change created: https://git.eclipse.org/r/44765
Comment 14 Laurent Redor CLA 2015-03-30 04:38:48 EDT
The initial review proposed by Esteban: https://git.eclipse.org/r/#/c/43165/ has been reworked and pushed with commits of comment 11 and comment 12.
Comment 15 Laurent Redor CLA 2015-03-30 05:08:43 EDT
Created attachment 251981 [details]
TestProject.zip: Sample to verify changes in manual refresh

This scenario is here to verify that the refresh is always done after the modifications of comment 11

Steps to reproduce:
* Import the project 443518 from TestProject.zip
* Open "root package entities" and "new Diagram" diagrams
* Split the editors part to see both editor simultaneously
* Check that you are in manual refresh mode (preference "Sirius/Automatic refresh" unchecked)
* Rename p1 in p3 in "root package entities" diagram
* --> Classes "p1-C1" and "p1-C2" are renamed in "new Diagram" diagram
* Rename p3 in p5 in "root package entities" diagram
* --> Classes "p3-C1" and "p3-C2" are renamed in "new Diagram" diagram, the background color of these classes have been changed and the icons too.
Comment 16 Eclipse Genie CLA 2015-03-30 05:12:22 EDT
New Gerrit change created: https://git.eclipse.org/r/44821
Comment 18 Laurent Redor CLA 2015-04-02 13:01:16 EDT
Assessment of the work done so far: No real gain on the number of refresh calls

For the scenario of bug 441770 comment 3, there is no gain with what is done with commit of comment 11. There are 247 calls to DNodeListEditPartWithAlpha.refresh and 
30537 calls to GraphicalEditPart.refresh().

With scenario of comment 15, there is also no gain on the number of refresh. But there is a gain on the number of adapters and on the number of transactionAboutToCommit.
With the fix of comment 11, all the calls to org.eclipse.sirius.diagram.ui.edit.internal.part.DiagramElementEditPartOperation$1.transactionAboutToCommit(Notification) are removed.
Comment 19 Esteban DUGUEPEROUX CLA 2015-04-22 05:17:41 EDT
About gerrit https://git.eclipse.org/r/#/c/43318/ which remove refreshVisuals() call in AbstractDiagramNodeEditPart.refresh(), we have test failures whose test LabelAlignmentRefreshTest.testLabelAlignmentRefresh() at diagram editor opening because the label is not displayed for DNodeEditPart Nodes2.

Indeed when DNodeEditPart.refresh() is called, refreshChildren() is called after refreshVisuals() and its last through "DiagramNodeEditPartOperation.refreshVisuals(this);" refresh the child editpart figure, the SquareEditPart$SquareFigure in this case.

To summarize the general issue is that parent EditPart manage draw2d figure refresh of its children EditParts while it should not, it is responsibility of each EditPart to refresh its draw2d figure.
Comment 20 Pierre-Charles David CLA 2015-06-23 10:32:56 EDT
Moving to 4.0, as the actual performance benefits are not yet measured (only the number of refresh() invocation).
Comment 21 Pierre-Charles David CLA 2015-12-15 04:11:13 EST
Moving out of the 4.0 scope for now, along with all the other issues which were there "by default". This does not mean some of these will not be re-integrated at some point, but for now these issues are not part of the roadmap for 4.0.

If you feel strongly about this removal from 4.0 and/or are ready to sponsor the corresponding work, feel free to comment.
Comment 23 Eclipse Genie CLA 2017-03-06 11:17:55 EST
New Gerrit change created: https://git.eclipse.org/r/92390
Comment 25 Laurent Redor CLA 2021-03-11 08:38:51 EST
The steps to reproduce of bug 571872 comment 1 is an interesting scenario for this kind of issue: only one modification (causing 5 notifications) and refresh doing the same thing called several times. In this issue, there is a text file [1] identifying the "stack" of each calls to DBorderItemLocator.setConstraint (called 18 times).
In this scenario, as a part of comment 5, there are:
* edit parts that react several times to the same notification
* and edit parts that react, in the same way, to different notifications

[1] https://bugs.eclipse.org/bugs/attachment.cgi?id=285800