LambrechtsWouter / jsplumb

Automatically exported from code.google.com/p/jsplumb
0 stars 0 forks source link

jsPlumb paint performance #258

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Hi there,

I'm having a performance issue when restoring the diagram attached to this 
issue.

I am using the function jsPlumb.setSuspendDrawing(true)
and jsPlumb.setSuspendDrawing(false, true) at the end.

I know the diagram is big.

So far what I have done is make a loop that schedules the drawing of each 
connection separated by 50 ms. This stops the browser from completely blocking.

Original issue reported on code.google.com by mfc...@gmail.com on 22 Jun 2012 at 5:34

Attachments:

GoogleCodeExporter commented 8 years ago
I'm always interested in ways to make the drawing faster.  as it happens i was 
doing some changes to the state machine connector yesterday and it occurred to 
me that the bezier calculations are a whole other area where i could implement 
caching; i think it would save a lot of thrashing around.  so this issue is 
timely.

what would be awesome is if i could somehow recreate this exact setup.  would 
it be possible for you to create a test page of this somehow? you could always 
contact me via email if your stuff needs to be private.

Original comment by simon.po...@gmail.com on 22 Jun 2012 at 10:04

GoogleCodeExporter commented 8 years ago
btw i have a load test page which draws 1520 connections in 2.8 seconds on 
Chrome - significantly more than what your diagram shows. so i will need to get 
a page from you that replicates the issue or i won't be able to debug what's 
going on.

Original comment by simon.po...@gmail.com on 23 Jun 2012 at 8:12

GoogleCodeExporter commented 8 years ago
Hi,

Sure ill extract the code to amke a standalone example. Ill post a link here 
when its ready.

Original comment by mfc...@gmail.com on 23 Jun 2012 at 10:12

GoogleCodeExporter commented 8 years ago
great, thanks.

Original comment by simon.po...@gmail.com on 23 Jun 2012 at 9:37

GoogleCodeExporter commented 8 years ago
Hi again,

So here is my very basic test case: http://jsfiddle.net/XVFwa/. 
The blocking doesn't seem so evident in chrome. Firefox does block for 2-3sec. 
I have included a loading gif to show that the browser actually blocks while 
loading.

Not sure why jsPlumb has decided to ignore my stroke styles in my test.

The JSON has lots of stuff that is not relevant to the test. Ill clean it up 
once i have more free time.

Original comment by mfc...@gmail.com on 25 Jun 2012 at 9:30

GoogleCodeExporter commented 8 years ago
I forgot to include in the issue that closing my editor with the calls: 
jsPlumb.reset(); and container.empty(); is also slow.

If i remove the reset() call it becomes instantaneous. Pretty sure that without 
reset stuff will remain and when i instantiate a new editor im going to have 
problems.

Original comment by mfc...@gmail.com on 25 Jun 2012 at 10:14

GoogleCodeExporter commented 8 years ago
thanks for that page. i have been writing a little load test harness page in 
development; you can see it here:

http://morrisonpitt.com/jsPlumbTest/tests/loadTestHarness.html

click 'Run Test' and it goes pretty quickly.  but click it again and it takes a 
long time, and then you'll see the timing for the reset - for me on Chrome on 
Mac it takes about 13.5 seconds.  

It's a bit of a bummer that ".empty" is slow.  because i was thinking of 
changing jsPlumb.reset to use that (at the moment it loops through all the 
connections).  and at that point we are getting down to the browser level, 
beyond which i can't do anything to make things quicker.  well, at least i 
*think* we're getting down to the browser level.  maybe .empty jumps through a 
lot of hoops that i could avoid by going straight to the DOM.

Original comment by simon.po...@gmail.com on 25 Jun 2012 at 10:26

GoogleCodeExporter commented 8 years ago
I might not have explained correctly. Its reset that is slow, not empty.

Using just empty its fast =).

Original comment by mfc...@gmail.com on 25 Jun 2012 at 10:30

GoogleCodeExporter commented 8 years ago
Interesting ... Removing jsPlumb.setSuspendDrawing(true) has no effect on my 
case.

Yet on your test if I remove setSuspendDrawing it crashes chrome =).

Original comment by mfc...@gmail.com on 25 Jun 2012 at 10:34

GoogleCodeExporter commented 8 years ago
re comment 8: ok cool. that's good.  so i will probably not actually use 
.empty; i'll use straight up DOM removes.  but it's good to know that that will 
be quick enough.

re comment 9: do you mean that in the code that generates the diagram above, 
setSuspendDrawing makes no appreciable difference to the speed at which the UI 
is drawn?  It's slow either way?

my test page is designed to do an excessive amount of drawing; i intend to use 
it to tune up jsPlumb's performance to the point where hundreds of connections 
are possible.  within browser constraints, of course.  are you on Windows?

Original comment by simon.po...@gmail.com on 25 Jun 2012 at 10:42

GoogleCodeExporter commented 8 years ago
I'm on OSX. The problem is also present on Windows 7.

I'm running the profiler trying to figure out what I'm doing that might cause 
the problem.

Suspects so far: 

 - The code in "jsPlumb.Overlays.Label.setLabel" doesn't seem to check if it should repaint or not. Might be present on another function.
 - The calls to jquery ui draggables seem to take up a bit of time. Guessing there is no way around this.
 - jsPlumb.CurrentLibrary.getSize gets called in a few places. I might try to cache its values for loading the initial connections.

The quest continues =).

Original comment by mfc...@gmail.com on 25 Jun 2012 at 11:13

GoogleCodeExporter commented 8 years ago
interesting about the setLabel thing - i will take a look at that in dev.  it 
would explain why setSuspendDrawing has no effect for you.

the calls to .draggable, yeah, might be unavoidable.  well, nothing's 
unavoidable, of course, but maybe the payoff for re-engineering that would be 
low.

i'm not sure that the getSize calls would be slowing things down a great deal.  
i think the label issue you identified would have much more of an effect.

Original comment by simon.po...@gmail.com on 25 Jun 2012 at 11:21

GoogleCodeExporter commented 8 years ago
Last observations for today:

 - Removing the label does provide a slight speed bump.
 - When using self referencing connections there is a lost empty div that should contain the endpoint (an svg in chrome). This div contains "ui-draggable". Maybe it is being processed by jquery ui when in fact it serves no point when its empty.

I will keep on looking for a way to make it smoother to load =).

Original comment by mfc...@gmail.com on 25 Jun 2012 at 11:41

GoogleCodeExporter commented 8 years ago
i just made some updates in dev (not on the test site yet) - adding a check to 
the setLabel function to not paint if drawing is suspended does have quite a 
good effect. i was getting 700ms to do the full paint with no setLabel call, 
and 4500ms with a setLabel call on each connection.  adding the code to honour 
'suspendDrawing' took that number down to 2700ms with a setLabel call.  

it's still not fast enough though. i'll keep looking.

Original comment by simon.po...@gmail.com on 26 Jun 2012 at 12:54

GoogleCodeExporter commented 8 years ago
i have a similar problem but i think the repaintEverything after painting has 
been unsuspended is a bit slow. i have 110 endpoints and 71 connections and 
repaint takes around 4 seconds to repaint everything. in chrome timeline it is 
doing lots of relayout events (~252) that take ~18ms each. it looks like i get 
one for each endpoint and 2 for each connection (one for label and one for 
connection itself i think). i suspect it might be possible to improve this if 
the calculation of all the positions is done in one step and then changing all 
the styles is done in another step. 

i also have problem prior to repaintEverything because of 
labels/droppable/draggable.

i have a fiddle which shows the general problem:

http://jsfiddle.net/kvWBG/

the performance of the layout ends up being quadratic to the number of elements 
:(

http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/

Original comment by benmmur...@gmail.com on 4 Jul 2012 at 10:11

GoogleCodeExporter commented 8 years ago
i have found the reason for the reset being slow.  on a branch in dev this is 
fixed - 40 seconds for one particular reset became 34 milliseconds.

Original comment by simon.po...@gmail.com on 8 Jul 2012 at 7:04

GoogleCodeExporter commented 8 years ago
Cool ty. Ill give it a try ASAP =).

Original comment by mfc...@gmail.com on 9 Jul 2012 at 2:53

GoogleCodeExporter commented 8 years ago
i havent checked this in yet.  will let you know once i have.

Original comment by simon.po...@gmail.com on 10 Jul 2012 at 12:33

GoogleCodeExporter commented 8 years ago
this is checked in now.

Original comment by simon.po...@gmail.com on 17 Jul 2012 at 8:53

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
Ok i have included all the files like in the tests and i get: "undefined is not 
a function" 49 times at line 4289 in jsPlumb-1.4.0-RC1.js

Not sure if im missing something.

Original comment by mfc...@gmail.com on 17 Jul 2012 at 9:58

GoogleCodeExporter commented 8 years ago
Ok Got it. Was missing the state-machine.js

Unfortunately the performance didn't change much. 

It is a little better. With my hack to delay connection rendering neither 
firefox nor chrome block the browser anymore.

Original comment by mfc...@gmail.com on 17 Jul 2012 at 10:11

GoogleCodeExporter commented 8 years ago
the performance of reset now is significantly faster than it was before.  what 
are you referring to when you say the performance didn't change much?  

Original comment by simon.po...@gmail.com on 17 Jul 2012 at 10:16

GoogleCodeExporter commented 8 years ago
Its the performance of loading the connections on startup. 

I realize that there are some other factors that seem make it worst in my case. 
In the fiddle (http://jsfiddle.net/XVFwa/) the loading only blocks for a split 
second. In my app it blocks for 3-5 sec atm.

I will keep looking for the guilty code =). If you want you can close the 
ticket. 

The reset is indeed faster.

Original comment by mfc...@gmail.com on 17 Jul 2012 at 10:30

GoogleCodeExporter commented 8 years ago
Maybe closing is not the best solution. 

There is another person that is reporting a similar problem (Comment 15 by 
benmmur).

Original comment by mfc...@gmail.com on 17 Jul 2012 at 10:33

GoogleCodeExporter commented 8 years ago
yeah it's reset i was talking about.  this issue has morphed into two separate 
issues. 

you mentioned a hack you have written to delay connection rendering.  how are 
you doing that?

Original comment by simon.po...@gmail.com on 17 Jul 2012 at 10:46

GoogleCodeExporter commented 8 years ago
oh is that the loop thing you talked about in your first comment.

Original comment by simon.po...@gmail.com on 17 Jul 2012 at 11:05

GoogleCodeExporter commented 8 years ago
I run through my connections and schedule the creation with jquery timers:

$(self).oneTime((k * 20), function() {
// create the connection
});

This spreads the creation into 20ms intervals and avoids browser blocking. 
Firefox still chockes a little.

With this hack jsPlumb.setSuspendDrawing(true); becomes irrelevant. 

The downside is that the user sees the graph being drawn. It is actually funny 
to see it draw live =).

Original comment by mfc...@gmail.com on 17 Jul 2012 at 11:09

GoogleCodeExporter commented 8 years ago
yeah i quite like the idea of seeing it drawn live actually ;)

i just updated the test site, so this is the load test page with what is 
currently in dev:

http://morrisonpitt.com/jsPlumbTest/tests/loadTestHarness.html

i saw the other guy's comment about repainting.  strangely, though, i don't see 
that many layout events when i watch the load test page in chrome timeline.  

Original comment by simon.po...@gmail.com on 17 Jul 2012 at 11:12

GoogleCodeExporter commented 8 years ago
Another test i have done is use jsPlumb.setSuspendDrawing(true) and 
jsPlumb.setSuspendDrawing(false, true) in the last connection. It takes 20ms x 
connections to create but renders instantly.

This does point to the problem not being the actual render but maybe the math 
for creating the connections with the labels?

Original comment by mfc...@gmail.com on 17 Jul 2012 at 11:15

GoogleCodeExporter commented 8 years ago
have you looked at the load test page?  you can try various combinations and 
you will see that labels do indeed slow things down.

Original comment by simon.po...@gmail.com on 17 Jul 2012 at 11:17

GoogleCodeExporter commented 8 years ago
Yeah the behavior im seeing is similar to the one in the test. My browser 
blocks for 2-3secs in the test.

I see the reset has really improve congrats =).

Original comment by mfc...@gmail.com on 17 Jul 2012 at 11:18

GoogleCodeExporter commented 8 years ago
ah, well, good to know that we have a solid test case for what someone is 
experiencing out there in the real world...improving the performance of this 
page should, in theory, improve performance for everyone.

if you look at the breakdown of timings on that page you see that the 'repaint' 
time (all the drawing) is always a bit more than the 'create' time (all the 
maths...but includes the addition of elements to the DOM).  in FF with 10 
elements I get a create time of 1010ms and a repaint time of 2082ms.  the 
average create time is ~ 2.3ms. changing the number of elements has a small 
effect on the average create time but it is repaint that starts to blow out.  
so it is there that i will concentrate first.

reset is indeed a lot better now. i am considering actually releasing 1.3.11 
instead of 1.4.0, with the reset fix in it (plus a couple of other things), 
because i know a few people are waiting for it.

Original comment by simon.po...@gmail.com on 17 Jul 2012 at 11:29

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
redo from start

Original comment by simon.po...@gmail.com on 25 Jul 2012 at 10:11

GoogleCodeExporter commented 8 years ago
i have split out two issues from this:

issue 267 - setLabel ignores suspendDrawing flag

issue 268 - deleteEveryEndpoint should suspend drawing

this issue is now a general issue about how people would like jsPlumb to draw 
faster.

Original comment by simon.po...@gmail.com on 25 Jul 2012 at 10:37

GoogleCodeExporter commented 8 years ago

Original comment by simon.po...@gmail.com on 26 Jul 2012 at 12:02

GoogleCodeExporter commented 8 years ago
i just pushed a change to 1.3.12 dev that provides a further performance 
enhancement when using labels - jsPlumb now caches the dimensions of a label 
once it has been calculated. Prior to this change, it was going off to 
calculate the dimensions each time a paint was performed (it needs to do this 
in order to be able to create a parent container large enough to hold the 
label).

so as i said, as of 1.3.12 the label's dimensions are cached. the cache is 
cleared if you change the label's text, of course, and there is another method 
that forces a cache clear (in case you made a change via CSS, for example).

For the default case in the load test page, result comparison is:

Before
-----

Total time: 2156
Create time:    526
Average create time:    1.2944444444444445
Repaint time:   1630

After
----

Total time: 1540
Create time:    531
Average create time:    1.3555555555555556
Repaint time:   1009

...so it's now about 30% faster (this is with labels of course.  without labels 
the performance is unchanged). 

Original comment by simon.po...@gmail.com on 12 Aug 2012 at 3:38

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
Just pushed a change into 1.3.13 development which sees a further performance 
gain.  

1.3.12
-----

Total time: 1581
Create time:    601
Average create time:    1.4777777777777779
Repaint time:   980

1.3.13
------

Total time: 1121
Create time:    164
Average create time:    0.33055555555555555
Repaint time:   957

this change affects all connections - those with labels and those without.  it 
involved reducing the number of calls to get the offset/size of elements during 
the time that drawing is suspended (you can see this reflected in the fact that 
'create' time is much quicker but repaint time is pretty much unchanged).

Original comment by simon.po...@gmail.com on 27 Aug 2012 at 1:18

GoogleCodeExporter commented 8 years ago

Original comment by simon.po...@gmail.com on 27 Aug 2012 at 1:18

GoogleCodeExporter commented 8 years ago
Hi there,

I have tested 1.3.13 and the performance is amazing =). Congratz !!

Just trying to decide if i leave the loading part for the cool effect =P. 
Loading is now 1s or less =). Amazing job =).

Original comment by mfc...@gmail.com on 5 Sep 2012 at 1:31

GoogleCodeExporter commented 8 years ago
awesome! 

thanks for the update - i appreciate the feedback.

Original comment by simon.po...@gmail.com on 5 Sep 2012 at 9:57

GoogleCodeExporter commented 8 years ago
closing.

Original comment by simon.po...@gmail.com on 30 Apr 2013 at 11:33

GoogleCodeExporter commented 8 years ago
how was this solved exactly? cuz i just ran into the same problem and i have 
around 150 connections only :S...but the operation is taking >50s !!!

Please help :( i know its fixed but i need to know..kinda got confused with all 
the posts

Original comment by Mero.R...@gmail.com on 3 May 2013 at 2:39

GoogleCodeExporter commented 8 years ago
Hi,

I am facing the same issue. For 386 connectors its taking 15.107 sec and for 
445 connections its taking 24.961 sec.
The setSuspendDrawing method has no affect on execution time. I am using 
version 1.3.13. Its flowchart based and endpoints are dots.
Please help.  

Original comment by jayant...@gmail.com on 18 Sep 2013 at 4:45