Bug 444101 - Remove (or reduce the number of) the adapters installed by DLineSpec, DCellSpec, DTargetColumnSpec
Summary: Remove (or reduce the number of) the adapters installed by DLineSpec, DCellSp...
Status: CLOSED FIXED
Alias: None
Product: Sirius
Classification: Modeling
Component: Table (show other bugs)
Version: 1.0.0   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 3.0.0M7   Edit
Assignee: Laurent Redor CLA
QA Contact: Belqassim Djafer CLA
URL:
Whiteboard:
Keywords: performance, triaged
Depends on:
Blocks:
 
Reported: 2014-09-15 08:20 EDT by Pierre-Charles David CLA
Modified: 2015-06-24 11:14 EDT (History)
5 users (show)

See Also:


Attachments
Incremental refresh by using the xRef (first test) (77.92 KB, image/png)
2015-02-17 05:22 EST, Florian Barbin CLA
no flags Details
Incremental refresh by using the xRef (second test) (73.49 KB, image/png)
2015-02-17 05:22 EST, Florian Barbin CLA
no flags Details
Incremental refresh without using the xRef (first test) (101.16 KB, image/png)
2015-02-17 05:23 EST, Florian Barbin CLA
no flags Details
Incremental refresh without using the xRef (second test) (75.47 KB, image/png)
2015-02-17 05:23 EST, Florian Barbin CLA
no flags Details
Test case (based on ecore tool) (4.91 MB, application/zip)
2015-02-17 05:24 EST, Florian Barbin CLA
no flags Details
sampleProject.zip: Used to test the manual refresh (4.54 KB, application/zip)
2015-03-20 05:43 EDT, Laurent Redor CLA
no flags Details
444101.zip (replace old sampleProject.zip): Used to test the manual refresh (4.58 KB, application/zip)
2015-05-26 08:40 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-15 08:20:15 EDT
See https://bugs.eclipse.org/bugs/show_bug.cgi?id=442862#c4

I found some suspect code in DLineSpec, DCellSpec and DTargetColumnSpec. The getOrCreateListener() methods, which is called on activate() seems to install adapters on all semantic elements (target and associated elements) referenced by the table, which on every change on any of these will check the value of the AUTO_REFRESH setting directly from the preference store! 

This looks so bad at first glance that I am surprised we never found this in the profiles we took (granted, there are larger performance issues in tables that could explain that accesses to the preference store would not show up as hot spots). Anyway, I'm putting it here to remember to look further into this.

There is also another problem (again, this needs further investigation to confirm): the activate() and deactivate() methods both refer to the getSemanticElements() reference to install (resp. uninstall the adapters). But the value of that reference is computed from a user-supplied expression, and is updated on each refresh. This means that:
1) if new semantic elements become associated to the table element after its creation, the adapter will not be installed on them.
2) if semantic elements disappear from the reference, deactivate() will not remove the adapter from them. The adapter is an instance of a anonymous internal class, which keeps a reference to the DTable/DLine/DCell/etc., and through is to all the representation, the session model, etc. The adapter also captures the DTableElementSynchronizer, which may retain other elements.

If these issues are confirmed, we should create a separate ticket, this is quite different from the origin scope of "avoid accessing the preference store too often".

In the Tree dialect, the same mechanism is present (see DTreeSpec and DTreeITemSpec)

On the diagram side, this is done with listeners (precommit) and not adapters, see org.eclipse.sirius.diagram.ui.edit.api.part.AbstractBorderedDiagramElementEditPart.activate() and 
org.eclipse.sirius.diagram.ui.edit.internal.part.DiagramElementEditPartOperation.createEAdpaterSemanticElements(IDiagramElementEditPart)
Comment 1 Cedric Brun CLA 2014-09-15 08:43:06 EDT
We should indeed re-consider the way these "updates" are handled.
* the memory cost is not null in managing so many "bindings" as tables tend to ΓΉ easily grow in number of lines/cells.
* in a table at least, many DCells/Dline are actually listening to the same element. 
* such a granularity (the model elements) tend to make optimisation of "what we do when something changes" hard to plan.

I am wondering if an approach where :
1- the change is inspected, the DTable model is browsed for .target elements
2- an element targeted by a .target reference has changed => we might need to re-compute the semantic elements references, we do so
3- we browse the dtable model to detect DLine/DColumns/DCells which will need a "local refresh" based on change and the .target and .semanticElements references

would have better scalability characteristics or not.
Comment 2 Florian Barbin CLA 2015-02-13 04:35:38 EST
A gerrit review is available: https://git.eclipse.org/r/#/c/41298/

The approach consist in update the DTableElements in pre-commit instead of install adapters on each semantic targets.
Comment 3 Eclipse Genie CLA 2015-02-17 04:25:14 EST
New Gerrit change created: https://git.eclipse.org/r/42015
Comment 4 Florian Barbin CLA 2015-02-17 05:22:24 EST
Created attachment 250858 [details]
Incremental refresh by using the xRef (first test)
Comment 5 Florian Barbin CLA 2015-02-17 05:22:51 EST
Created attachment 250859 [details]
Incremental refresh by using the xRef (second test)
Comment 6 Florian Barbin CLA 2015-02-17 05:23:28 EST
Created attachment 250860 [details]
Incremental refresh without using the xRef (first test)
Comment 7 Florian Barbin CLA 2015-02-17 05:23:45 EST
Created attachment 250861 [details]
Incremental refresh without using the xRef (second test)
Comment 8 Florian Barbin CLA 2015-02-17 05:24:16 EST
Created attachment 250862 [details]
Test case (based on ecore tool)
Comment 9 Florian Barbin CLA 2015-02-17 05:31:16 EST
Results of the poc by using the InverseCrossReferencer to retrieve impacted DTableElements:

During the first test the interpreter is being initialized. the incremental refresh took 84ms
During the second test the interpreter was initialized. the incremental refresh took 4ms

Results of the poc without using the InverseCrossReferencer but by iterating on each Dline:

During the first test the interpreter is being initialized. the incremental refresh took 168ms
During the second test the interpreter was initialized. the incremental refresh took 28ms

All tests have been done with the "full-sirius-code class table"
Comment 10 Florian Barbin CLA 2015-02-17 05:34:17 EST
The profiling is based on this path set for the test without Xref: https://git.eclipse.org/r/#/c/42015/2

and this patch set for test using the XRef: https://git.eclipse.org/r/#/c/41298/6
Comment 11 Cedric Brun CLA 2015-02-24 09:03:17 EST
I gave it a shot by improving the implementation of both codes to avoid iterating 20K times over the list of changes adapting the "non-xref" implementation to correctly search into cells. I kept both code running at the same time calling the two methods in the same environment to have a more precise comparison.

I also extended the test data to have "more .aird stuffs", to do so I did a few copies of the tables to see if we have a noticeable change of scalability when the .aird grow (as the xRef based implementation will be sensitive to that)

I made sure to be on manual refresh and triggered Yourkit in tracing mode with "adaptive=false" (or as we are measuring very small times yourkit tends to "truncate" some of the calls)

10 subsequents invocations by changing an EClass name through the property view with two tables being opened, veryfing the tables are getting properly updated :

total time spent in search for impacted DTableElements :
- with Xref :  3ms (10 calls)
- without Xref :  1300ms (10 calls)

The difference is more important than I would have expected. When not using the xRef the time is spent in AbstractEList.EIterator (mostly constructor and hasNext())  and in HashSet.contains() 

All in all we should go for the xRef based one even if it might get slower and slower once the .aird grow, the overhead of browsing through the table is too significant to be ignored.
Comment 12 Eclipse Genie CLA 2015-03-17 12:18:50 EDT
New Gerrit change created: https://git.eclipse.org/r/44025
Comment 13 Eclipse Genie CLA 2015-03-18 04:19:12 EDT
New Gerrit change created: https://git.eclipse.org/r/44064
Comment 14 Eclipse Genie CLA 2015-03-18 04:19:16 EDT
New Gerrit change created: https://git.eclipse.org/r/44063
Comment 18 Laurent Redor CLA 2015-03-18 13:29:52 EDT
Fixed with the commits of the 3 last comments.

The method used is not directly added in DialectServices but in non API DialectServices2 as it can change sooner when applying this mechanism to tree dialect and to diagram dialect (part of bug 443518 for diagram).
Comment 19 Laurent Redor CLA 2015-03-20 05:43:22 EDT
Created attachment 251779 [details]
sampleProject.zip: Used to test the manual refresh

The sampleProject allows to check that the refresh manual is always OK with the new implementation of this feature.

Steps to reproduce for edition table:
* Check that the preference "Sirius/Automatic Refresh" is false
* Open session 444101.aird
* Open table "new editionTable"
* Open diagram "root package entities"
* Split the edit view to see both editors
* In the diagram, rename NewEClass2 into NewEClass3
--> The line of NewEClass1 with prefix "listen-" is automatically updated.
--> The cell of column "Listen-Name" of the line "NewEClass1 -> NewEClass2" should be updated. This is a bug (already here before this issue). Another bugzilla will be created for it.

Steps to reproduce for cross table:
* Check that the preference "Sirius/Automatic Refresh" is false
* Open session 444101.aird
* Open table "new crossTable"
* Open diagram "root package entities"
* Split the edit view to see both editors
* In the diagram, rename NewEClass2 into NewEClass3
--> The line and column "NewEClass1 extends ..." are automatically updated.

The same modifications will be done shortly for tree dialect.

Steps to reproduce for tree:
* Check that the preference "Sirius/Automatic Refresh" is false
* Open session 444101.aird
* Open table "new Tree"
* Open diagram "root package entities"
* Split the edit view to see both editors
* In the diagram, rename NewEClass2 into NewEClass3
--> For NewEClass1, the line with prefix "listen-" is automatically updated.
Comment 20 Eclipse Genie CLA 2015-03-20 05:58:03 EDT
New Gerrit change created: https://git.eclipse.org/r/44231
Comment 21 Eclipse Genie CLA 2015-03-20 12:09:36 EDT
New Gerrit change created: https://git.eclipse.org/r/44262
Comment 25 Laurent Redor CLA 2015-03-23 02:50:35 EDT
Tha last 3 commits handle the case for Tree dialect (and some bugs on Table dialect discovered during Tree implementation).
Comment 26 Esteban DUGUEPEROUX CLA 2015-03-25 05:28:58 EDT
Reopened with remarks on https://git.eclipse.org/r/#/c/41298 Gerrit :
- TableDialectServices.getTableElementsToRefresh() : using a Set instead of a ArrayList could avoid having potential duplicate. And instead of having 2 loops, we could do all work in a single one.
- TableDialectServices.getTableElementsFromInverseReferences() : we could use EObjectQuery.getInverseReferences(EReference) instead of writting this specific code. Have EObjectQuery.getInverseReferences(Set<EReference>) could be more usefull for our use case.
- Instead of DialectServices2.refreshImpactedElements(), a better interface could be DialectServices2.getImpactedDRepresentationElements():Collection<DRepresentationElement>
with a second method DialectServices2.refreshDRepresentationElements(Collection<DRepresentationElement>)
- RefreshEditorsPrecommitListener.isImpactingNotification() do  !notification.isTouch() test while touch notification are already filtered by SessionEventBroker
- IProgressMonitor parameter is not used in TableDialectServices.refreshImpactedElements()
Comment 28 Eclipse Genie CLA 2015-03-27 12:28:13 EDT
New Gerrit change created: https://git.eclipse.org/r/44764
Comment 29 Laurent Redor CLA 2015-03-27 12:46:08 EDT
Remarks of comment 26 and comment 27 are handled with reviews [1] and [2]

Except for 
"Instead of DialectServices2.refreshImpactedElements(), a better interface could be DialectServices2.getImpactedDRepresentationElements():Collection<DRepresentationElement>
with a second method DialectServices2.refreshDRepresentationElements(Collection<DRepresentationElement>)"
that is out of scope.

[1] https://git.eclipse.org/r/#/c/44764
[2] https://git.eclipse.org/r/#/c/44765
Comment 31 Laurent Redor CLA 2015-03-30 04:03:25 EDT
Remarks of comment 26 are done (see comment 29)
Comment 32 Laurent Redor CLA 2015-03-30 04:05:44 EDT
Eclipse Genie missed this commit (it has been added for bug 443518):

Gerrit change https://git.eclipse.org/r/44765 was merged to [master].
Commit: http://git.eclipse.org/c/sirius/org.eclipse.sirius.git/commit/?id=42e7a7967977f1e7b8467747a7fccb4a81b4c89d
Comment 33 Laurent Redor CLA 2015-05-26 08:40:15 EDT
Created attachment 253769 [details]
444101.zip (replace old sampleProject.zip): Used to test the manual refresh
Comment 34 Belqassim Djafer CLA 2015-05-26 09:31:40 EDT
Verified with Sirius 3.0.0 RC1
Comment 35 Pierre-Charles David CLA 2015-06-24 11:14:06 EDT
Available in Sirius 3.0.0. See https://wiki.eclipse.org/Sirius/3.0.0.