WCartesianChart very slow to redraw

Added by Christophe Delépine over 1 year ago

Hi

I have implemented a simple 2D curve editor widget that derives from WCartesianChart.
The widget listens to mouseDragged events to move a selected marker.

The problem is that it is very slow and very far from being interactive. My curve has only 3 points, so it should be fairly quick.

On the console, i can see messages like this :
127.0.0.1 - - [2010-Sep-03 17:35:27.277246] "POST /hello?wtd=9EWMeGj9rN1KovIO&rand=39823 HTTP/1.1" 200 8695

They seem correlated to the number of times the chart is refreshed.

Any idea of what could cause the slowdown ?

Here is a snapshot of the chart

Regards
Christophe

chart.jpg (7.4 KB)


Replies

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

I am unsure, but you should be able to make up from looking at the log whether the slowdown is at the server or at the client (I suspect the latter). If it is the former it would be great to see what is the actual problem.

In your case it probably makes sense to superimpose two charts or make sure that you only need to redraw the specific things that need to be redrawn (and not repeatedly draw the background) ? I haven't tried but you should be able to do this by superimposing two cartesian charts using absolute positioning, and use one to generate the background + axes and the other one to draw the values ?

You may also want to experiment with the various back-ends. On most browsers (excluding IE) you have the choice between HTML5 canvas and inline SVG. One may be quicker than the other.

Regards
koen

RE: WCartesianChart very slow to redraw - Added by Edward Hill over 1 year ago

Hey, Christophe,
How you done with dropping point after mouseUP event(or just after dragging)?
I know that Wt have setDraggable but l don't know how to hold the object?
If anybody have any idea, please help.

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hi Koen,

I have measured the time elapsed between 2 mouseDragged events (see below).
As you can see, every time i get the "POST 200 22" message from Wt, then a huge delay (> 1s) occurs. Otherwise, the delay is less than 1 ms
In my test, my chart is not updated anymore, i just measure the time for the mouse events.

What is this POST message ??

I have tried the PaintBrush example in the widget gallery example, and it runs very fast. However it is not using a WCartesianChart, just a PaintedWidget.
The PaintBrush example displays lots of "POST 200 410" in the console. What are the meanings for the last 2 numbers ?

Thanks for any insight.
Christophe

Timings between 2 mouseDragged events on a WCartesianChart :
127.0.0.1 - - [2010-Sep-06 10:27:06.397588] "POST /hello?wtd=MPfEYCjAqQFx8I4o&rand=40239 HTTP/1.1" 200 22
elapsed = 1.225565
elapsed = 0.000293
elapsed = 0.000283
elapsed = 0.000282
elapsed = 0.000283
elapsed = 0.000282
elapsed = 0.000281
elapsed = 0.000283
elapsed = 0.000284
elapsed = 0.000286
elapsed = 0.000285
elapsed = 0.000284
elapsed = 0.000287
elapsed = 0.000291
127.0.0.1 - - [2010-Sep-06 10:27:07.625367] "POST /hello?wtd=MPfEYCjAqQFx8I4o&rand=77715 HTTP/1.1" 200 22
elapsed = 1.390741
elapsed = 0.000310
elapsed = 0.000295
elapsed = 0.000294
elapsed = 0.000292
elapsed = 0.000290
elapsed = 0.000289
elapsed = 0.000291
elapsed = 0.000293
elapsed = 0.000294
elapsed = 0.000293
elapsed = 0.000292
elapsed = 0.000294
elapsed = 0.000312
elapsed = 0.000385
elapsed = 0.000300
127.0.0.1 - - [2010-Sep-06 10:27:09.008560] "POST /hello?wtd=MPfEYCjAqQFx8I4o&rand=30648 HTTP/1.1" 200 22
elapsed = 1.389294
elapsed = 0.000314
elapsed = 0.000297
elapsed = 0.000381

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Update :

I have replaced my WCartesianChart class by the PaintBrush class that runs fast in the widget gallery example and i get the same problem.
So the problem is not related to the use of WCartesianChart instead of a WPaintedWidget.

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

I suspect something unrelated to your graphics is causing the slow redraw. If you replace the painted widget with a container widget, does it still work slowly?
What other widgets are you using? Layout managers? Tree- or table views? Some of these widgets can potentially slow down every update to the page.

The log output is requests, it is a typical access_log format such as used by Apache or other web servers. The first number is the response code (200 == OK), the second number is the content length.

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hi Koen,

Your suspicion is right : if my GUI contains only one widget (the PaintedWidget inside a container) then it runs ok.

My GUI is not very complex. It contains a TreeView on the left and several WText+WSlider+WLineEdit+WCartesianChart inside layouts (Grid+HBox+VBox) on the right (see snapshot)
My PC is a high-end workstation and everything runs locally.

Is there a specific widget/layout that slows down everything or is it the accumulation ?
Can't the PaintedWidget be redrawn locally without having to update the whole page ?

Obviously this is very bad news...i may reconsider the choice of Wt if i can't get things run decently fast.

Regards
Christophe

gui.jpg (100 KB)

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

Although we are aware of the potential problem, so far, nobody seemed to be affected by it.

The performance problem is caused by layout managers recomputing their layout at every update because every update potentially can affect it. The solution is to only do this when the layout manager may be affected, and the library could detect this by itself.

I have created a bug issue for it: http://redmine.emweb.be/issues/495

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Koen

In fact the main bottleneck seems to come from GridLayouts. I have tried to replace one of them by a BoxLayout, and now the curve editor runs much quicker.

I am still very interested by your optimization though because my GUI is not complete yet and i am afraid that when everything is there, performance will become worse and worse.

Thanks very much for your help!

Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

I am curious as to how your code looks for instantiating the grid layout versus box layout, they share the same implementation and thus I would like to understand how they result in a different performance.

The latest public git contains a batch of optimizations for the layout managers. In fact it turns out that this was a much needed improvement since also the widget gallery and most other applications feel alot snappier !

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Sounds great!
I need to revert to the previous gui code to see if it works faster.

I 'll let you know.

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hi,

Repainting the chart is not slowed down anymore by the layouts.

However, i have another performance problem which seems again related to use of layouts. In my gui, i have a tree widget on the left. When the user selects one item, a widget container is shown on the right. The widget container depends on the item that was selected. It takes about 1-2 s for the container to appear. If the container is very simple, the redisplay is fast.

To display/undisplay the container, i use WHboxLayout::insertWidget and WHboxLayout::removeWidget

Is there anything i can do to have better performance ?

Note that all the widgets are created and ready to be used. There is no dynamic creation of widgets. I just change the view by adding/removing one widget from one layout.

The snapshot attached illustrates the described use case (the selected item is 'glow' and the widget container is everything on the right of the tree panel)

Regards
Christophe

gui.jpg (133.9 KB)

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

You are right about your suspicion about the layouts. They are currently not optimized related to insertion and removal of items: they will rerender their entire contents.

Does the container correspond to the entire right side? If that is the case, you should consider the WStackedWidget in a WVBoxLayout to which you (add and/or) select the container when an item is clicked.

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

That's a very good idea.
It feels much more responsive now.

Thanks !

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hello Koen,

Looks like the WStackedWidget is giving me problems :

I have a strange wt behavior when using a WStackedWidget with one child "complex" container.
The behavior i am observing is that everything is slowed down. The gui is displayed but it is almost unusable : if i try to click on a tree node to expand it, nothing happens, if i place the cursor over the expand '+' then the cursor changes its shape after 3 seconds !

If i replace the WStackedWidget by a more classic WBoxLayout and use insert/remove to manage widget visibility then i never get the problem.

I have also noticed that the problem is random but fail rate is higher than success

This is with the latest git.

Could the WStackedWidget correct behavior depend on its child complexity ?

I use a non multi-threaded build of wt

Is there anything i can do to investigate the problem ?

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

I do not have an idea. The stacked widget is a really simple widget, and we never saw a problem with it. It is also well tested, for example in the widget gallery everything is displayed in a container widget.

Do you have many children in the stacked widget? Perhaps time is wasted somehow resizing invisible widgets, but I cannot imagine that a browser does not consider this correctly (and it always seems to do this).

What browser do you use to test this ?

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hi Koen,

The stacked widget has 2 children : one empty WContainerWidget and a non empty one that is quite complex
The empty container is the default activated child when the gui is launched. Even with the empty container, the application is completely unusable.

The stacked widget is inside a WHBoxLayout.

I use Firefox 3.5.7

Any suggestion ?

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

I have no idea how in such a way a WStackedWidget could slow down your application.

There are three options:
- have a debug-JavaScript build of your application and use FireBug to generate a profile (that requires some more explanation on how to build and run your app from our side)
- make a reproducible test case.
- put your app available (partly) online so I can try to figure out what is slowing the app down.

I prefer a reproducible test case, if possible.

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hi Koen,

I have installed Firebug.

Firebug breaks and complains that j53 is undefined (see snapshot)

Does it give you a clue ?
I have attached the source code for the script

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

The firebug + js helps. It seems that the JavaScript statement involving j53 is completely out of place, and looking at the code this is very very weird. It almost looks like a nasty corner case in a core utility class of Wt. But then I would expect that it is not entirely reproducible with multiple sessions in one application. Is that the case ?

Are you using WViewWidget by any chance ?

Can you also copy/paste the actual ajax response from the Console in Firebug ?

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hi !

Yes the problem is really random :
I tried to open 2 sessions : firebug complained for the 1st one but not the 2nd one.

I tried again and firebug complained only at the 4th session.

No I don't use WViewWidget.

Attached is the javascript & console output for the new session (my wt code has changed a little bit since my previous try so i prefered to send you again the javascript)

I have a WTimer that fires every 100 ms as soon as the session is started. This explains why there are lots of POST messages at the beginning of the console output
Then i clicked on a "start" button in the gui, and it is at this point that the main gui (with the WStackedWidget) is activated.
This is where firebug breaks.
I suppose the last console POST only shows the AJAX answer just before i clicked on the start button ?

I could not send you the entire content of the last POST message : Firebug prompts me to click to see the entire answer in another firefox tab, but when i click nothing happens..

Hope that helps
Let me know if you need something else

Regards
Christophe

javascript.js (311.7 KB)

console_firebug.txt (105.4 KB)

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

Perhaps the many updates by the timer is causing havoc. Can you disable the timer and see if that has an influence ?

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Koen,
Your suspicion is right : removing the timer does have an influence. Firebug does not break anymore.

I don't quite understand why using a WStackedWidget reveals this problem (which never occured even with the timer activated without the WStackedWidget).

The only reason i need the timer is because my other application threads need to send messages to the web server thread. In the timer callback, the web server thread reads and processes those messages.

I cannot increase the timer period too much because the application thread that sends the message needs to wait for the completion of the processing by the web server before continuing.

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

That helps me to make sense of the error -- I think I know what direction to look in.

With respect to the timer: have you considered server-push (WApplication::enableUpdates() ?) as in the serverpush feature example ?

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

That's great if you can find out what is going on.

Regardings the timer, i don't even need to update the widget tree in the timer callback. The callback is just used to read and process messages coming from other threads.
Indeed, during an event (in a slot), the web server thread needs to read access some objects which may be deleted at any time by another application's thread. So to avoid a crash, the thread that wants to delete an object needs to inform (send a message) to the web server thread and wait for the message to be processed.
By doing that, i am sure that the web server thread can safely read access the objects during an event.

Besides, i currently use a non multithreaded build of Wt and i believe WApplication::enableUpdates() does not work in this configuration ?

By the way, could you tell me how to avoid all the POST messages in my console due to the timer ? Is it possible to redirect them to a file or to the void ?
Also, have you found the time to improve the look of sliders (a while ago, i suggested to make them look as extjs sliders)?

Thanks for your great support.
Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

I think I have found the problem and committed a fix to public git. Can you verify ?

Why do the other threads not just grab the application's update lock and update the application state so that it is always consistent and knowledgeable about what objects are real and which ones were deleted ?

It's true you need a multi-threaded Wt build for enableUpdates(), but since you are using threads already there is no penalty with having a multi-threaded Wt build ?

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Congratulations, the problem cannot be reproduced anymore !

Yes, i could do what you suggest.
However having a multi-threaded Wt build does have problems :

Non multithreaded Wt :
- only one thread is created and the thread is created by my code so i can initialize processor affinity and priority and use my own Thread class

Multithreaded Wt:
- 2 threads are created, one for the event loop (WRun) and another one that executes the signal code
- the thread that executes the signal code is created by Wt library, so i cannot use my Thread class to send messages or synchronize with other threads.

My application usually runs on a 4-6 cpus PC and is using very high priority threads for rendering 3D graphics. If wt thread runs on one of these cpus, it will not run at all or very very slowly. I have had the case where the POST messages are displayed one character per second in the console if wt thread runs on the wrong cpu.
Therefore it is important for me to control the thread creation from the beginning.
There is an opened issue about that (see http://redmine.emweb.be/issues/491)
I just hope that wt will offer new mechanisms in the future to ease integration with application frameworks

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Koen,

Actually, i still get random problems even with your recent fix. It does not really crash but when it occurs, the app is really crawling. The top right "loading" is shown almost constantly.
i can see that the last number in the POST messages has become very big, whereas normally it is around 60 (see below)
I have increased the timer period to 200 ms

The problem is much less frequent however

Regards
Christophe

127.0.0.1 - - [2010-Oct-15 17:25:05.383027] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=67528 HTTP/1.1" 200 60
127.0.0.1 - - [2010-Oct-15 17:25:05.633022] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=97431 HTTP/1.1" 200 60
127.0.0.1 - - [2010-Oct-15 17:25:05.883017] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=47703 HTTP/1.1" 200 60
127.0.0.1 - - [2010-Oct-15 17:25:06.133012] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=21675 HTTP/1.1" 200 60
127.0.0.1 - - [2010-Oct-15 17:25:08.664214] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=54385 HTTP/1.1" 200 140877
127.0.0.1 - - [2010-Oct-15 17:25:08.711088] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=9045 HTTP/1.1" 200 154420
127.0.0.1 - - [2010-Oct-15 17:25:09.257952] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=6030 HTTP/1.1" 200 154422
127.0.0.1 - - [2010-Oct-15 17:25:09.476698] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=99715 HTTP/1.1" 200 154424
127.0.0.1 - - [2010-Oct-15 17:25:09.726693] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=34880 HTTP/1.1" 200 154466
127.0.0.1 - - [2010-Oct-15 17:25:10.023562] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=65190 HTTP/1.1" 200 154507
127.0.0.1 - - [2010-Oct-15 17:25:10.336056] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=57979 HTTP/1.1" 200 154548
127.0.0.1 - - [2010-Oct-15 17:25:10.695425] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=67782 HTTP/1.1" 200 154589
127.0.0.1 - - [2010-Oct-15 17:25:11.070417] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=23211 HTTP/1.1" 200 154630
127.0.0.1 - - [2010-Oct-15 17:25:11.476660] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=19305 HTTP/1.1" 200 154671
127.0.0.1 - - [2010-Oct-15 17:25:11.914151] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=20448 HTTP/1.1" 200 154712
127.0.0.1 - - [2010-Oct-15 17:25:12.398517] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=473 HTTP/1.1" 200 154753
127.0.0.1 - - [2010-Oct-15 17:25:12.601638] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=69493 HTTP/1.1" 200 154794
127.0.0.1 - - [2010-Oct-15 17:25:13.789115] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=83027 HTTP/1.1" 200 154835
127.0.0.1 - - [2010-Oct-15 17:25:14.460977] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=13430 HTTP/1.1" 200 154876
127.0.0.1 - - [2010-Oct-15 17:25:15.132839] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=96397 HTTP/1.1" 200 154917
127.0.0.1 - - [2010-Oct-15 17:25:15.835951] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=14319 HTTP/1.1" 200 154958
127.0.0.1 - - [2010-Oct-15 17:25:16.570312] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=25287 HTTP/1.1" 200 154999
127.0.0.1 - - [2010-Oct-15 17:25:17.351547] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=94111 HTTP/1.1" 200 155040
127.0.0.1 - - [2010-Oct-15 17:25:18.164031] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=22174 HTTP/1.1" 200 155081
127.0.0.1 - - [2010-Oct-15 17:25:19.039014] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=8765 HTTP/1.1" 200 155122
127.0.0.1 - - [2010-Oct-15 17:25:19.913998] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=85488 HTTP/1.1" 200 155163
127.0.0.1 - - [2010-Oct-15 17:25:20.851480] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=29787 HTTP/1.1" 200 155204
127.0.0.1 - - [2010-Oct-15 17:25:21.851460] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=39147 HTTP/1.1" 200 155245
127.0.0.1 - - [2010-Oct-15 17:25:22.851441] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=21932 HTTP/1.1" 200 155286
127.0.0.1 - - [2010-Oct-15 17:25:23.179560] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=58823 HTTP/1.1" 200 155327
127.0.0.1 - - [2010-Oct-15 17:25:25.023274] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=6160 HTTP/1.1" 200 155368
127.0.0.1 - - [2010-Oct-15 17:25:26.070129] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=14425 HTTP/1.1" 200 155409
127.0.0.1 - - [2010-Oct-15 17:25:28.304461] "POST /hello?wtd=DzTOSalKyjhgDjum&rand=35930 HTTP/1.1" 200 155450

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Koen,

The problem is definitely related with the timer.
To get around the bug, i now start the timer after the main gui is created.

It would be nice however if you can provide a fix

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

I think I have fixed this. Can you try with latest git ?

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Koen,

I still managed to get a crash (see snapshot)

Regards
Christophe

P.S. the popup menu does not show any pre-selected item anymore which is a good thing. However, it still jumps.

crash.jpg (12.1 KB)

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

And that crash has now replaced the big POSTs ? I guess I'll need to be able reproduce the problem here: any chance you can narrow it down to a test case ?

W.r.t. the popup menu: I adapted the treeview-dragdrop example, so that it also recycles the same popup menu. I don't see it shift position, could you verify that this behaves well for you too and see what you do differently ?

Regards,
koen

RE: WCartesianChart very slow to redraw - Added by Christophe Delépine over 1 year ago

Hi Koen,

popup :

the treeview-dragdrop example works fine indeed.
my code is quite similar except that i use a WTree instead of a WTreeView.
I have noticed that the menu does not jump if the tree node is already selected. But if i bring up the popup menu (with a right-mouse click) on a non-selected tree node, then the menu jumps.
Could you please have a look at my code (attached) ? I am clueless..

The popup is created in the constructor of my class (variable popup_). PopupAction is the method called when an item is triggered.
The popup is shown on a mouseWentUp event on specific tree nodes of the WTree.

crash :

it would take some time to make a test case because i would have to get rid of lots of application code for you to be able to compile the project.
i'll see if i can reproduce the problem in the widget gallery example by activating a timer first.

Regards
Christophe

RE: WCartesianChart very slow to redraw - Added by Koen Deforche over 1 year ago

Hey Christophe,

Can you try with the latest git, I think I might have solved both issues.

Regards,
koen