[Rpcemu] Improving CPU usage when idle

Theo Markettos rpcemu at markettos.org.uk
Tue Apr 7 13:58:15 EDT 2009

On Mon, Apr 06, 2009 at 09:54:34PM +0100, Jake Waskett wrote:
> I'm just trying to make sense of the IOMD timer code at the moment,
> and wonder if perhaps someone can help bring me up to speed.  The code
> is somewhat confusing - a brief overview of how the current mechanisms
> work would save a lot of time in trying to work it out!

While I know my way around the IOMD hardware, it's been a long time since I
looked at the code in RPCEmu.  Anyone fresher than me?

> I'm not sure that we can safely jump forwards in time (as it were)
> when delivering simulated events.  I think that we need to try to
> replicate the same intervals between each event.  

You wouldn't necessarily move in jumps, but make the clock faster and slower
as appropriate to synchronise.

> If I remember correctly (it has been a decade, so forgive me if I'm
> totally wrong here!), RISC OS uses a 10 millisecond timer to coordinate
> the timing needs of the system.  This is more than fast enough for both
> mouse and keyboard events, so I anticipated adding something like the
> following pseudocode:

That's true.

> /* countdown to next event */
> if (event_queue_head != NULL && event_queue_head->ticks > 0)
>     event_queue_head->ticks--;
> /* and simulate all pending events */
> while (event_queue_head != NULL && event_queue_head->ticks == 0)
> {
>    /* do what's necessary to simulate event */
>    /* ... */
>    /* and remove it from the event queue */
>    delete_event_queue_head();
> }
> /* now simulate timer interrupt */

[disclaimer: I'm rusty on the RPCEmu specifics]

I'm probably missing something, but IIRC keys etc aren't run on timer
interrupts.  The key itself generates an interrupt, and sometime later the
interrupt service routine (ISR) reads the current time.  I can't remember
what RISC OS does.  If it reads it on the centisecond timer (and I think it
might) that's probably OK because the OS won't update the centisecond timer
without an interrupt.  If it reads it on the 2MHz timer then we have the
problem of the time moving forward (potentially by a lot, because the timer
might get updated asynchronously to the CPU thread) before the ISR gets
around to reading the register.

And if the timers don't, on a sub-second average, match realtime, you get
problems with games suddenly becoming too fast or too slow.

> I'm not sure if I fully understand the problem.  I think the above
> code would handle that, provided that it was called from the context
> of the CPU thread.

Yes, I think.  (I'm perhaps muddying the waters more than is necessary here
with my comments on asynchrony between threads.  Asynchrony with realtime is
the one we're trying to solve!)

> I'm making the assumption that Allegro has a background thread that
> does an XNextEvent, GetMessage, or whatever it is under MacOS, and
> then calls the callback routines.  I think this must be the case,
> because otherwise we'd have to poll periodically, and that doesn't
> seem to be necessary.  A small amount of thread synchronisation code
> will be needed to protect the integrity of the queue data structure,
> and I think this will have to depend on this thread.  This is a bit
> ugly as an implementation detail, and I don't particularly like that
> little bit of non-portable code (it'll have to be #ifdef'd), but I
> don't see any alternative.

Anyone who knows more about the emulator internals than me want to comment?

> I think it's best to leave that kind of decision to the host kernel.
> Managing the hardware for optimum power usage is its responsibility,
> not ours.  All we need to do to help it is to try to be asleep as
> often and for as long as possible.


> >That's true.  Probably a Wimp filter would return you that information...
> >(Pity we can't access the Wimp's idle loop directly)
> I know nothing whatsoever about Wimp filters. :-)

Don't worry, they're quite simple.  And it sounds like Portable_Speed means
such a trick is unnecessary.

> I don't think that's going to be a problem.  It seems extremely
> responsive.  I'm seeing as many as five calls to Portable_Speed per
> second.


> Right, that should work then.  It seems sensible, though, to get the
> event queueing working first.

Yup.  Find an appropriate place to sleep() before worrying about how to
trigger the mechanism.

> No such luck, I'm afraid.  It wouldn't be *too* hard to write a little
> library to abstract the differences.

There's libacpi for Linux:
which looks so simple that writing a version for Windows/Mac/etc probably
wouldn't be hard.

(I found what claims to be a crossplatform power library called power-utils
on savannah, but it doesn't seem to have any code)


More information about the Rpcemu mailing list