Re: Doubts about GPeriodic
- From: Owen Taylor <otaylor redhat com>
- To: Havoc Pennington <hp pobox com>
- Cc: Ryan Lortie <desrt desrt ca>, gtk-devel-list gnome org
- Subject: Re: Doubts about GPeriodic
- Date: Thu, 21 Oct 2010 14:28:21 -0400
On Thu, 2010-10-21 at 08:17 -0400, Havoc Pennington wrote:
> On Thu, Oct 21, 2010 at 5:46 AM, Ryan Lortie <desrt desrt ca> wrote:
> > What about non-input events, though? Like, if some download is
> > happening and packets are coming in and causing dispatches from the
> > mainloop that we do not have control over.
> I brought this up a bit in the earlier thread.
> My takeaway is that for I/O type stuff you usually want what we ended
> up with at litl, which is to limit it to some length of time per
> frame. Unfortunately GMainLoop has no native way to do that. I
> described our solution a bit in the old paint clock thread.
> There's a danger both of some random download starving animation and
> of your download spinner starving the download.
I think to start off we have to realize that a GTK+ application is
significantly different from a compositor like Mutter or the litl shell
in a number of ways:
* GTK+ is quite efficient when just a small amount of stuff is
changing. Even if the entire toplevel takes a long time to paint,
a cheesy animation somewhere in the frame isn't going to cause
all the time to be spent painting.
* GTK+ is not going to be using a blocking glSwapBuffers(); GTK+ will
be timing frames either based on a straight-up timer, or by getting
frame-complete signals back from the compositor.
* It's not the compositor - if painting blocks, it's not the end
of the world.
Once we move beyond that, then I'm skeptical about lumping everything
that's not events/animation/relayout/repaint into the same bucket.
"Everything else" includes a number of different things:
* UI updates being done in response to asynchronous IO finishing
In this case, I think usually you just want to do the updates
immediately; for most UI updates the real expense is the relayout/
repaint, so there's no advantage to trickling them in... if you
get such a bunch of updates that you block for a couple hundred
ms, then you just accept a small stutter.
If that might be a couple of seconds, then I think it's up to
the app author to figure out how to fix the situation - if updates
can be batched and batching reduces the work that needs to be done,
then an easy to use "before relayout" API is handy.
* Computations being done in idle chunks because "threads are evil".
If the computations don't affect the GUI, then in my mind they
should just happen in whatever time isn't needed to draw whatever
is going on. We have no way of knowing whether whatever is going
on is a spinner or is a video playing.
In other words, progress displays need to be self-limiting to eat
only a small amount of CPU. After all, it's pretty bad if my
computation is going on at *half*-speed because of the progress
* Servicing incoming IPC calls
Assuming incoming calls queue up, I think it's fine to just handle
them at higher priority than the repaint.
The pathological case here is that Totem is playing a movie which
is maxing out the frame rate, and somebody in another process does
for (movie in allMovies)
movie.length = totemProxy.getPlayingTime(movie.id);
And Totem handles one call, then paints a frame, then handles another
call and the whole thing takes forever. This is clearly bad, but I
don't think the solution is for totem to reserve 5ms for ever
frame of every movie just because someone might start using the
D-Bus API it exports. Solutions here are general solutions:
- Don't put "service" API's in the GUI thread of GUI applications
- Use async calls - if the above was done by making a bunch of
async calls in parallel, it would be completed in one frame.
* Expensive GUI work done incrementally (adding thousands of items
to a GtkTreeView, say) Threads not useful because GTK+ isn't
This one is slightly harder because each update can actually trigger
a relayout/repaint, which might be expensive. So if this is being
done at idle priority, you may be in the situation of do one chunk,
which takes 0.1ms, repaint for 20ms, do another chunk, and so forth.
This is the case where something like your proposal of reserving
time per frame starts making sense to me. But rather than just doing
a blanket reservation of 5ms per frame, it seems better to actually
let the master clock know what's going on. To have an API where you
add a function and the master clock balances calling it with relayout.
That a) avoids wasting time waiting for nothing to happen
b) allows better handling of the case where the relayout takes 100ms
not 20ms so you don't work for 5ms, relayout for 100ms, repeat.
] [Thread Prev