|
|
Home » U++ Library support » U++ Widgets - General questions or Mixed problems » howto best Ctrl Refresh handling w/ MT & very frequent refreshes
howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26758] |
Wed, 26 May 2010 13:15  |
 |
kohait00
Messages: 939 Registered: July 2009 Location: Germany
|
Experienced Contributor |
|
|
hi there people
i am dealing with a performance issue, tackling the borders of Upp (or maybe better: my mind 
got a MT environment wich diversly generates a LOT of frequent refreshes on a LOT of small Ctls.
example:
some 5+ Threads (communication from devices) generate visual data for ~25 Views (with a LOT of Ctrl hierarchy) every 200 ms for each view, each data element causes a refresh of a particular Ctrl (maybe somewhere *deep* in hierarchy).
so the problem is the perfomance is *sh..*, no fluidity
>> How to deal with a lot of frequent updates / refreshes to a lot of Ctrls from several threads (!= main GUI thread)?
i imagine the problem is my design itself, where the threads use GuiLock to do the stuff in the Gui or need to wait for MainThread to finish the work for them and so there is a lot of context switches.. or the Ctrls are pretty deep in hierarchy and refreshing them toggles refreshes on upper ones as well?
is there a possib to disable a view for repainting, have all the update ctrl stuff done and then by enabling trigger a refresh in Main GUI thread for all *dirty* Ctrl (which would be done without context switches)
help apriciated
[Updated on: Wed, 26 May 2010 13:16] Report message to a moderator
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26765 is a reply to message #26758] |
Wed, 26 May 2010 16:45   |
|
Hi kohait,
Just a few ideas:
You can try to update the GUI using PostCallback rather then GuiLock. It sends callback to main thread and gets executed there. I believe it could speed things a bit.
Alternatively, it might (I did not test this) help a little bit to just change the GUI without refresh and then call refresh from main thread periodically.
Best regards,
Honza
|
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26767 is a reply to message #26766] |
Wed, 26 May 2010 17:20   |
Mindtraveller
Messages: 917 Registered: August 2007 Location: Russia, Moscow rgn.
|
Experienced Contributor |

|
|
1. By the way, is GUI MT-safe? If it is so, maybe it is a good idea to have some flag (like GUI_MT) to enable/disable GUI-MT features? This will speed things too.
2. Maybe you could make some descendant class of ParentCtrl which keeps cached image and drws it upon refresh. Actual refresh of child Ctrl is to be made only on explicit request (let's call it ParentCtrlCache). I don't know exactly (didn't test it) but this could give additional speedup by reducing actual GUI updates.
[Updated on: Wed, 26 May 2010 17:25] Report message to a moderator
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26771 is a reply to message #26767] |
Wed, 26 May 2010 18:14   |
|
I propose to decide: How frequently refreshing needed?
Usually I update Ctrl only one times per second, And ignore more frequently updates. But you can decide to refresh more frequently.
It makes no sense to update the widget and spend system resources on it, more often than it is able to notice the eyes.
SergeyNikitin<U++>( linux, wine )
{
under( Ubuntu || Debian || Raspbian );
}
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26772 is a reply to message #26771] |
Wed, 26 May 2010 18:43   |
 |
kohait00
Messages: 939 Registered: July 2009 Location: Germany
|
Experienced Contributor |
|
|
thanks guys for replys.
the app is kind of an audio devices monitoring tool with meterbridges data coming in as push data (i dont have control over time when it comes in). it should display kind of fluidly, 200 ms is alright, but if you imagine 25+ devices firing thir live data, that comes in at random time in different threads, there it's the mess.
Quote: |
It makes no sense to update the widget and spend system resources on it, more often than it is able to notice the eyes.
|
i'd need even 1/20 = 50 ms refreshtime..so 200ms is a compromise already
as far as i know GUI "is" MT safe, as long as you use GuiLock __; scope helper in the other threads to modify the gui.. internally it maps some stuff to Main Thread and waits for it anyway. but not everythin in GUI is MT, like DnD stuff etc.. dig in the CtrlCore win32 code, and you will find some ASSERT(IsMainThread).
Quote: |
ParentCtrl which keeps cached image and drws it upon refresh
|
this would increase memory consumptiion for rather huge ctrl's, but is an option. but what about all the small ctrls already present? it would be a lot of work to adjust them
Quote: |
GuiLock works in similar way like PostCallback?!
|
no, not quite the same. PostCallback gets executen in the same TimerThread, while the GuiLock is only a mutex to aquire GUI use rights for your own different thread (!= main)
Quote: |
little bit to just change the GUI without refresh and then call refresh from main thread periodically.
|
this was my intention, but i dnot know of any means in Ctrl to update a Ctrl (using its API, SetData() etc) without causing an internal Refresh(). setting data to controls always results in an Refresh(), unlike i.e. setting Ctrl properties like maybe font, color, min max etc..this needs a manual Refresh() as far as i know. this all is by design. Ctrls distinguish in their between "parametrising" a Ctrl (setting it up) which does *not* trigger a Refresh() automatically, and "using, providing actual data" to Ctrl, which automatically Triggers a Refresh().
Now I am "using" my Ctrls, so they refresh that frequently..
it would be great to "postpone" the Refresh() of a Ctrl for later.. but donno how to do it, or if the Ctrl API already supports it
|
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26776 is a reply to message #26758] |
Thu, 27 May 2010 09:20   |
|
Hi Kohait,
If you develop some kind of graphics/video/game application where framerate matters, then you should use graphic acceleration as Mindtraveller suggested. But if you just want to show some rapidly changing data in real time, you should be fine with some 5 fps max, user don't react any quicker 
Here is something that might or might not help you:#include <CtrlLib/CtrlLib.h>
using namespace Upp;
template <class T>
class Cached : public T{
Value val;
bool refreshflag;
public:
void operator<<=(Callback action) {T::operator<<=(action);}
void operator<<=(Value data) {refreshflag=true; val=data;}
void SetData(Value data) {refreshflag=true; val=data;}
Value GetData() {return val;}
Value operator~() {return val;}
void Apply() {if(refreshflag) T::SetData(val);}
bool IsChanged() {return refreshflag;}
};
class guitest : public TopWindow {
public:
typedef guitest CLASSNAME;
Cached<EditIntSpin> s;
guitest(){
s.SetRect(0,0,50,24);
Add(s);
s<<=0;
s.Apply();
}
void LeftDown(Point p,dword keyflags){
s<<=int(~s)+1;
}
void RightDown(Point p,dword keyflags){
s.Apply();
}
};
GUI_APP_MAIN{
guitest().Run();
}
It is a simple wrapper template that should work on any Ctrl overloading it's SetData and GetData methods, so they don't trigger Refresh. It will help you only if:- You just change the data, not the Ctrls.
- Your app has some idea about the hierarchy of Ctrl so it can call Apply on all of them when needed.
To update I would use single function called using SetTimeCallback with reasonable interval, let's say 200ms.
Best regards,
Honza
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26787 is a reply to message #26776] |
Thu, 27 May 2010 23:36   |
 |
kohait00
Messages: 939 Registered: July 2009 Location: Germany
|
Experienced Contributor |
|
|
thanx guys, i'll spend some time thinking about it.. maybe there is also an option to use a "globaly accessible" data cache, where to deposit data, that frequently comes in, and then, independantly trigger refresh operations, that take the data and forward it to the controls which would refresh then in one.., thus decoupling the refreshment if visual data itself from the data that comes in.
but anoter general question:
how to best update a whole LOT of controls at once (just once, not frequently, but at once) without causing the GUI to repaint each time in different locations..but at the end maybe to repaint all?
maybe thats the way to go as well..
the OpenGL option is worth thinking about..
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26788 is a reply to message #26776] |
Fri, 28 May 2010 08:12   |
 |
koldo
Messages: 3432 Registered: August 2008
|
Senior Veteran |
|
|
dolik.rce wrote on Thu, 27 May 2010 09:20 | Hi Kohait,
If you develop some kind of graphics/video/game application where framerate matters, then you should use graphic acceleration as Mindtraveller suggested. But if you just want to show some rapidly changing data in real time, you should be fine with some 5 fps max, user don't react any quicker 
Here is something that might or might not help you:#include <CtrlLib/CtrlLib.h>
using namespace Upp;
template <class T>
class Cached : public T{
Value val;
bool refreshflag;
public:
void operator<<=(Callback action) {T::operator<<=(action);}
void operator<<=(Value data) {refreshflag=true; val=data;}
void SetData(Value data) {refreshflag=true; val=data;}
Value GetData() {return val;}
Value operator~() {return val;}
void Apply() {if(refreshflag) T::SetData(val);}
bool IsChanged() {return refreshflag;}
};
class guitest : public TopWindow {
public:
typedef guitest CLASSNAME;
Cached<EditIntSpin> s;
guitest(){
s.SetRect(0,0,50,24);
Add(s);
s<<=0;
s.Apply();
}
void LeftDown(Point p,dword keyflags){
s<<=int(~s)+1;
}
void RightDown(Point p,dword keyflags){
s.Apply();
}
};
GUI_APP_MAIN{
guitest().Run();
}
It is a simple wrapper template that should work on any Ctrl overloading it's SetData and GetData methods, so they don't trigger Refresh. It will help you only if:- You just change the data, not the Ctrls.
- Your app has some idea about the hierarchy of Ctrl so it can call Apply on all of them when needed.
To update I would use single function called using SetTimeCallback with reasonable interval, let's say 200ms.
Best regards,
Honza
|
I like this sample .
And you told you are not a programmer...
Best regards
Iñaki
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26789 is a reply to message #26776] |
Fri, 28 May 2010 12:53   |
Sender Ghost
Messages: 301 Registered: November 2008
|
Senior Member |
|
|
Hello, Jan.
Another sample:
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
template <class T>
class CachedCtrl : public T {
private:
Value value;
bool change;
public:
CachedCtrl() : change(false) { }
Callback operator<<=(Callback action) { return T::operator<<=(action); }
void operator<<=(const Value& data) { change = true; value = data; }
void SetData(const Value& data) { change = true; value = data; }
Value GetData() const { return value; }
Value operator~() const { return value; }
void Apply() { if (change) T::SetData(value); }
bool IsChanged() { return change; }
};
const int NUM_CTRLS = 10,
REFRESH_RATE = 50; // ms
class App : public TopWindow {
private:
bool doing;
public:
typedef App CLASSNAME;
App();
~App();
Thread work;
typedef CachedCtrl<EditInt> CEditInt;
Array<CEditInt> ctrls;
void ChangeData();
void UpdateData();
void LeftDown(Point p, dword keyflags);
void RightDown(Point p, dword keyflags);
};
App::App() : doing(false)
{
Title("CachedCtrl test application");
CenterScreen().Sizeable().MinimizeBox().MaximizeBox();
SetRect(Size(640, 480));
for (int i = 0; i < NUM_CTRLS; ++i)
{
ctrls.Add().HSizePosZ(4, 4).TopPosZ(4 + i*(19 + 4), 19).SetData(i + 1);
ctrls[i].Apply();
Add(ctrls[i]);
}
}
App::~App()
{
Thread::ShutdownThreads();
work.Wait();
}
void App::ChangeData()
{
if (!doing) doing = true;
else return;
const PaintRect curRect = GetBackground();
Background(PaintRect(ColorDisplay(), SColorPaper()));
work.Run(THISBACK(UpdateData));
while (doing)
{
Sleep(1);
GuiLock __;
if (Thread::IsShutdownThreads()) break;
for (int i = 0; i < NUM_CTRLS; ++i)
{
ctrls[i].SetData(int(~ctrls[i]) % (NUM_CTRLS * 100) + 1);
}
}
Background(curRect);
doing = false;
}
void App::UpdateData()
{
while (doing)
{
Sleep(REFRESH_RATE);
GuiLock __;
if (Thread::IsShutdownThreads()) break;
for (int i = 0; i < NUM_CTRLS; ++i)
{
ctrls[i].Apply();
}
}
}
void App::LeftDown(Point p, dword keyflags)
{
doing = !doing;
}
void App::RightDown(Point p, dword keyflags)
{
work.Run(THISBACK(ChangeData));
}
GUI_APP_MAIN
{
Ctrl::GlobalBackPaint();
App app;
app.Run();
}
But may be here needed manual refresh mode for all Ctrls instead of automatic (fullrefresh). No need to store extra data. Also IsChanged() equals IsModified() in last case.
For example, in .Net Framework:
// Stop refreshing
ctrl.BeginUpdate();
// Change data
// ...
// Start refreshing again
ctrl.EndUpdate();
[Updated on: Fri, 28 May 2010 13:29] Report message to a moderator
|
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26945 is a reply to message #26944] |
Fri, 11 June 2010 16:06   |
|
kohait00 wrote on Fri, 11 June 2010 14:11 | the sample from dolik is interesting, it intercepts the data change stuff, nice idea. tnhanks.
the only drawback is, that there are several controls where you dont only have GetData/SetData which triggers the refresh, like Label or Static or sth.. SetText(), SetLabel()...
it'd be great to have kind of a more general way of disabling refresh in entire gui for some time..
|
Hi Kohait,
I admit I didn't think about that. One usually expects Static widgets to be, uhm, kind of static 
Anyway, if you are changing those as well, you can use template specialization. E.g. for label:#include <CtrlLib/CtrlLib.h>
using namespace Upp;
template <class T>
class Cached : public T{
Value val;
bool refreshflag;
public:
void operator<<=(Callback action) {T::operator<<=(action);}
void operator<<=(Value data) {refreshflag=true; val=data;}
void SetData(Value data) {refreshflag=true; val=data;}
Value GetData() {return val;}
Value operator~() {return val;}
void Apply() {if(refreshflag) T::SetData(val);}
bool IsChanged() {return refreshflag;}
};
template <>
class Cached<Label> : public Label{
Value val;
bool refreshflag;
public:
void operator<<=(Value data) {refreshflag=true; val=data;}
void SetData(Value data) {refreshflag=true; val=data;}
Value GetData() {return val;}
Value operator~() {return val;}
void Apply() {if(refreshflag) Label::SetLabel(AsString(val));}
bool IsChanged() {return refreshflag;}
};
class guitest : public TopWindow {
public:
typedef guitest CLASSNAME;
Cached<EditIntSpin> s; Cached<Label> l;
guitest(){
s.SetRect(10,10,50,24); l.SetRect(10,40,100,54);
Add(s); Add(l);
s<<=0; l<<="Nothing yet";
s.Apply(); l.Apply();
}
void LeftDown(Point p,dword keyflags){
s<<=int(~s)+1; l<<=String("Last value: ")+IntStr(s.EditIntSpin::GetData());
}
void RightDown(Point p,dword keyflags){
s.Apply(); l.Apply();
}
};
GUI_APP_MAIN{
guitest().Run();
}
This will unify the interface between usual widgets and Label. Of course you could also make a different template that would keep the SetLabel interface and just added the caching capabilities. That is up to your choice 
BTW: I guess you don't need it, but I quite like the possibility to access the actual value displayed by the control, regardless on what is in cache. So I put it into the example code as a little bonus 
Best regards,
Honza
|
|
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26968 is a reply to message #26964] |
Tue, 15 June 2010 22:18   |
Sender Ghost
Messages: 301 Registered: November 2008
|
Senior Member |
|
|
Hello, Konstantin.
Another possibility is changing Ctrl class.
You can start with Ctrl::RefreshFrame method(s).
void Ctrl::RefreshFrame(const Rect& r) {
GuiLock __;
if (manualRefresh || !IsOpen() || !IsVisible() || r.IsEmpty()) return;
Add switches in private area of Ctrl:
private:
bool manualRefresh;
in public area:
public:
bool IsUpdate() const { return manualRefresh; }
void BeginUpdate() { manualRefresh = true; }
void EndUpdate() { manualRefresh = false; RefreshFrame(); }
Default value in Ctrl constructor:
Ctrl::Ctrl() {
GuiLock __;
manualRefresh = false;
And use in some threading function:
Array<Ctrl *> ctrls;
// Adding needed ctrls to update
// ...
// Begin updating of ctrls
for (int i = 0, n = ctrls.GetCount(); i < n; ++i)
ctrls[i]->BeginUpdate();
// Changing data
// ...
// End updating of ctrls
for (int i = 0, n = ctrls.GetCount(); i < n; ++i)
ctrls[i]->EndUpdate();
[Updated on: Wed, 16 June 2010 00:53] Report message to a moderator
|
|
|
|
|
|
Re: howto best Ctrl Refresh handling w/ MT & very frequent refreshes [message #26975 is a reply to message #26974] |
Wed, 16 June 2010 11:18   |
|
kohait00 wrote on Wed, 16 June 2010 09:56 | how to keep the queue busy so ith wont trigger a refresh each and everytime.
imagine: 50 devices push their live monitoring data (acutally not the problem, 48 bytes only) to the gui, where the data income is linked to Ctrls (SetData, SetText, cusom Ctrls as well) for each device separately. the devices fire unsynchronously, more or less every 200 ms.
==> consequence: Refreshes over and over (even with 4 devices its a problem already), because queue is kept empty..any idea about that?
|
Hi Kohait,
Thanks for better description of the problem. I still think that this is not a problem of how to refresh Ctrls... It is about the app design. You can solve your problems by altering it just a little bit.
What you need is not to feed the incoming data directly into GUI. If I understand correctly, you know very well what is coming from "outside", so it should not be a problem to create some structure representing those 48b of information. Doing this of the screen is very fast. Now all these structures, one for each device, can reside in Vector. If you use one thread per device there should not be no problem with MT.
Then you can just create a function that will iterate through this array and update the Ctrls based on its content. This function can be called using PostCallback. To make it really MT safe you can use some kind of locking (to prevent writing into the structures or to pause receiving new data). If you refresh "only" 10-20 times per second (which is more than enough for human eye, I usually aim for ~5fps), it should not bring any performance problems.
Well, at least that is what I would do 
Best regards,
Honza
|
|
|
Goto Forum:
Current Time: Mon Apr 28 09:51:39 CEST 2025
Total time taken to generate the page: 0.01094 seconds
|
|
|