Share via


Over-updating...

Raymond writes an interesting post about how some programs run faster if you hold down the mouse.

This is a classic situation to get yourself into - I've probably seen it 5 times, and hit it again recently.

When we're burning a DVD, the burn engine calls back into the UI layer so that we can update the progress bar. To give the user a single monotonically-increasing progress bar, we (well, Dean, actually) have to play some games with our progress tracking, which means that sometimes we get progress callbacks once a second, and sometimes we get them 100 times a second.

The progress dialog looks fine, but if you look a profile of the burn, you'll find that a fair amount of time is being spent in the UI code updating. In this case, it's not a big deal, but I've seen cases where programs are spending 90% of their time updating the UI. That takes a 10 second operation and makes it take 100 seconds, which is pretty bad.

The fix? Well, there are two good ones.

The simplest one is to simply update every <N> calls. I traditionally start with N=10, which is guaranteed to same 90% of the overhead, and usually works fine.

If your callbacks are sporadic - as they are in the DVD Maker case - it works better to timebox the updates. Whenever you update the UI, record the time, and then don't update it again until a specific time has gone by. I usually find 1/4 second to work well.

Comments

  • Anonymous
    February 24, 2006
    Is there an "advanced" option to see the actual status of the underlying dependency chain rather than the single monotonically increasing progress bar?
  • Anonymous
    February 24, 2006
    No, there is no advanced option. I don't think there is a lot of utility in it - DVD burning will take hours with typical content.
  • Anonymous
    February 26, 2006
    I think you missed the point of Raymond's post -- or perhaps I'm misinterpreting what you're saying.

    The "worker" code should never call into UI code.  Ever.

    At most it could post a message to the UI thread, but preferably any interaction should be the other way around, with the UI code either polling for new status information (if updates are frequent) or sleeping on an event object that the worker signals (if updates are infrequent).

    The simplest way to do this is to do all your progress updates from within a window timer callback (System.Windows.Forms.Timer, for managed code), in which you query the worker objects for info on how far they've gotten.
  • Anonymous
    February 26, 2006
    Oh, and regarding the "advanced view" -- that's exactly why you should be able to get more detail, so that you can see whether it's still encoding video or whether it's made it through to constructing the IFO tables (or whatever).  And if it's encoding video, which source file it's currently working on.

    People like to know details about what's actually going on, especially for long-running processes.  Otherwise there's the tendency to think it just locked up.
  • Anonymous
    February 27, 2006
    Miral,

    I was a bit imprecise here. It is true that you can't update UI from a non-UI thread, but in this case the callback calls a UI method which uses a PostMessage, so there's no issue.

    On the "more detail" topic, it's something we could do, but I'd rank it pretty low down the feature list.
  • Anonymous
    March 07, 2006
    Eric Gunnerson (of C# designer fame) writes about over-updating.