Friday, November 15, 2013

process idling in Xinu

While experimenting with Xinu inside a virtual machine, I soon found that my laptop was getting quite warm, and the fan was running constantly. Examining my Mac's Activity Monitor, I saw that one of my CPUs was being used at 100% any time the Xinu VM was running. I decided to investigate the cause of the high CPU utilization.

The culprit wasn't hard to find. In initialize.c, after creating and "resuming" a shell process, the nulluser function goes on to enter a while (1) idle loop. The code comment at the top of the function indicated that this process remained in existence in order to provide the scheduler with a lowest-priority item suitable for scheduling on the CPU when no other process was "ready" to execute.  Extended Internet research discovered that many modern OSes provide a low priority process that is always 'ready' to execute in order to simplify the code for the scheduler, avoiding the necessity of a special case for when no processes are ready to execute. However, of course, most OSes do not actually consume the full time and power of the CPU during these busy-waiting loops.

I began to wonder if it would be possible to make the necessary changes to Xinu to provide a low-power/efficient busy-wait loop for when no processes were scheduled. Especially for an OS that is otherwise well suited for applications with low resource (memory, CPU, etc.) availability, it would seem to make sense to provide the benefit of low power consumption when no processes are ready to execute.

According to Wikipedia, modern architectures use the HLT (halt) instruction to allow an interrupt-driven CPU to enter a low power state while waiting for a timer or I/O-based interrupt to reactivate another process. Examining the code in intr.S, I found an existing assembler function "pause" that first enables interrupts with the sti instruction, and then issues the hlt instruction. By doing so, pause ensures first of all that any incoming interrupts will be able to wake the processor for handling, and then puts the processor into the low-power idle state to wait for such interrupts.

I initially attempted to have the while(1) loop in the nulluser() method in initialize.c simply execute a hlt instruction, since the nulluser() method had already enabled interrupts, but I found that I was causing boot hangups on occasion. By calling the pause() routine, I immediately realized a 85% reduction in CPU usage, without impacting any OS functionality. But I found myself wondering if there was anything to be done about the remaining 15% CPU usage, which was apparently happening even when no processes other than the shell were running on the Xinu system.

No comments:

Post a Comment