Re: Doubts about GPeriodic



On Thu, 2010-10-21 at 08:17 -0400, Havoc Pennington wrote:
> Hi,
> 
> 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
  spinner!

* 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
  sync calls:

   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
  thread-safe.

  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.

- Owen




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]