[PATCH] EXA: Defragment offscreen memory.
Michel Dänzer
michel at daenzer.net
Thu Mar 5 08:28:51 PST 2009
On Wed, 2009-03-04 at 11:06 -0500, Adam Jackson wrote:
> On Tue, 2009-02-24 at 10:41 +0100, Michel Dänzer wrote:
>
> > That said, I would have expected it to get called every 100ms when the server
> > is idle, but that isn't the case, so maybe I'm missing something and was just
> > lucky it didn't blow up for me. I'd like to get confirmation from Adam that the
> > BlockHandler/WakeupHandler/Timer idea makes sense.
>
> I think it's just bugs:
>
> > +static CARD32 ExaDefragTimerCallback(OsTimerPtr pTimer, CARD32 time,
> > + pointer arg)
> > +{
> > + /* Try and keep the offscreen memory area tidy every now and then when the
> > + * server has been idle for at least 100ms.
> > + */
> > + ExaOffscreenDefragment(arg);
> > +
> > + return 0;
> > +}
>
> The return value from the timer callback is the interval (in millis)
> until it fires again. Since you return 0 here, you effectively make
> this a one-shot;
Yes, that's the intention.
> it'll fire once at 100ms of idle, and then never again (until the next
> loop through Wakeup/Block).
I'm trying to re-arm the timer from BlockHandler, but now I think this
doesn't work because WaitForSomething() calculates the select timeout
before calling BlockHandler(). Is this a bug that should be fixed, or is
TimerSet in the BlockHandler just no-no?
> > +static void
> > +ExaWakeupHandler(int screenNum, pointer wakeupData, unsigned long result,
> > + pointer pReadmask)
> > +{
> > + ScreenPtr pScreen = screenInfo.screens[screenNum];
> > + ExaScreenPriv(pScreen);
> > +
> > + /* Prevent the timer callback from being called if Select() didn't time out.
> > + */
> > + if (result != 0)
> > + TimerCancel(pExaScr->defragTimer);
>
> You don't need to do this, I don't think. DoTimer() will skip you if
> your timer hasn't fired yet; and the TimerSet in BlockHandler will reset
> the expiry to another 100ms in the future.
The idea was to prevent the callback from getting called if the server
was busy for 100ms. Can that never happen?
> > +_X_HIDDEN ExaOffscreenArea*
> > +ExaOffscreenDefragment (ScreenPtr pScreen)
> > +{
> > + ExaScreenPriv (pScreen);
> > + ExaOffscreenArea *area, *largest_available = NULL;
> > + int largest_size = 0;
> > + PixmapPtr pDstPix;
> > + ExaPixmapPrivPtr pExaDstPix;
> > + CARD32 now = GetTimeInMillis();
> > +
> > + /* Don't defragment more than once per second, to avoid adding more overhead
> > + * than we're trying to prevent
> > + */
> > + if (abs((INT32) (now - pExaScr->lastDefragment)) < 1000)
> > + return NULL;
>
> This is sort of unpleasant. We'll wake up 10 times a second because the
> timer will fire, but we'll only do work once a second, so that's wasting
> power.
FWIW the test above is also to prevent exaOffscreenAlloc() from
triggering more than one defragmentation pass per second.
> But defrag as you've got it is fairly expensive, since it's a full
> walk through the whole arena. Might be better to split this into
> ExaOffscreenDefragmentIncremental to move just one pixmap, call that
> from the timer, and leave the full-force version for when allocation
> would otherwise fail.
The partial defragment would still need to walk (almost) everything in
the worst case. It shouldn't be that expensive anyway.
> Only other comment is that you don't have any way of marking the screen
> as completely defragmented, which means you'll _always_ wake up 10 times
> a second. Or, you would, if you didn't return 0 from the timer
> callback. Should probably record whether defrag did work, and avoid
> arming the timer when you're defragged. (You'll also need to catch
> pixmap destruction when defragged, and use that to re-arm the timer.)
Good point, I'll add something for that.
--
Earthling Michel Dänzer | http://www.vmware.com
Libre software enthusiast | Debian, X and DRI developer
More information about the xorg-devel
mailing list