Howto keep the processor idle?
-
- Member
- Posts: 32
- Joined: Tue Jan 06, 2015 5:15 pm
Howto keep the processor idle?
Hi there
I have a multitasking kernel. I implemented an idle task to be run whenever there is no other runnable task. The idle task simply goes into an infinite loop and does nothing. The problem is that this vicious cycle of JMP's keeps the processor busy 100% of the time. I tried using the pause instruction in place of the infinite loop, but the result is the same. I can't disable interrupts as I am checking the presence of runnable tasks in the timer interrupt handler. How can I make the processor truly idle?
Thanks in advance
I have a multitasking kernel. I implemented an idle task to be run whenever there is no other runnable task. The idle task simply goes into an infinite loop and does nothing. The problem is that this vicious cycle of JMP's keeps the processor busy 100% of the time. I tried using the pause instruction in place of the infinite loop, but the result is the same. I can't disable interrupts as I am checking the presence of runnable tasks in the timer interrupt handler. How can I make the processor truly idle?
Thanks in advance
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: Howto keep the processor idle?
You're supposed to be able to use hlt to halt the processor until the next interrupt occurs. If that's still using all (or nearly all) of your CPU then I assume that you're doing something wrong in your task scheduler (for example, you might be getting timer interrupts too frequently and thus keeping the CPU busy even when it's supposed to be idle).
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 32
- Joined: Tue Jan 06, 2015 5:15 pm
Re: Howto keep the processor idle?
okay. I will try putting HLT instead of my current idle loop and see the result.
thanks!
thanks!
Re: Howto keep the processor idle?
Use something like this:
That way if an interrupt handler wakes up a task, your idle task will be replaced with this task.
Code: Select all
while(true){hlt(); yield();}
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: Howto keep the processor idle?
Except that if his scheduler is pre-emptive then he just needs to hlt every time there are no active tasks. It would be easier to do this:Boris wrote:Use something like this:That way if an interrupt handler wakes up a task, your idle task will be replaced with this task.Code: Select all
while(true){hlt(); yield();}
Code: Select all
void switch_to_next_task()
{
if (task_waiting())
{
switch_to_waiting_task();
}
else
{
cleanup_and_hlt();
}
}
If an interrupt other than the timer interrupt wakes a task (such as a keypress, disk I/O, etc.) the interrupt will start the CPU and your interrupt handler can then schedule the task and call switch_to_next_task, which will switch to the task that has been woken.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 32
- Joined: Tue Jan 06, 2015 5:15 pm
Re: Howto keep the processor idle?
I updated my idle task as such:
It looks like the CPU is still being busy. I think my timer handler is the culprit and it needs to be more lightweight. Here is the handler:
Any suggestions?
Cheers
Code: Select all
void idle_task_func()
{
loop:
__asm__ __volatile__("sti\nhlt":::);
goto loop;
}
Code: Select all
void _timer_handler(regs_t r)
{
__asm__ __volatile__("cli":::);
_ticks++;
/* we are using 100Hz frequency, so update seconds every 100 ticks */
if((_ticks%100) == 0) { _secs++; }
task_t *current = get_current_task();
/* called before tasking is init-ed */
if(!current) goto finish;
if(current == idle_task && get_next_runnable() == idle_task) goto finish;
/* current task is sleeping or blocked? Schedule */
if(current->state != TASK_RUNNING) { scheduler(&r); goto finish; }
if(current->time_left) current->time_left--;
else { scheduler(&r); goto finish; }
finish:
pic_send_eoi(0);
}
Cheers
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: Howto keep the processor idle?
I believe modulus to be a somewhat slow operation and you could replace instance where _secs is used with a call to get_secs(), which returns _ticks / 100.mohammedisam wrote:Code: Select all
if((_ticks%100) == 0) { _secs++; }
mohammedisam wrote:Code: Select all
get_current_task();
How complex are these functions? Bear in mind that the former especially is being called on every timer tick.mohammedisam wrote:Code: Select all
get_next_runnable()
If I'm understanding your code correctly, that line is to prevent a crash if your scheduler isn't initialised yet. In that case, remove the line and only enable the timer once your scheduler has been initialised, otherwise you're adding an extra conditional test on every timer tick.mohammedisam wrote:Code: Select all
if(!current) goto finish;
This line can only mean that you're scheduling each task for more than one tick. What is current->time_left initialised to? Because that's how many ticks you're going to process before another task gets scheduled, and if that's too high for your idle task then your idle task isn't going to keep the CPU very idle.mohammedisam wrote:Sorry but I don't understand this line. Is this supposed to call the idle task when there's nothing to schedule? (Because it doesn't.)Code: Select all
if(current == idle_task && get_next_runnable() == idle_task) goto finish;
mohammedisam wrote:Code: Select all
if(current->time_left) current->time_left--;
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Re: Howto keep the processor idle?
How do you know that it's busy?mohammedisam wrote:It looks like the CPU is still being busy
If a trainstation is where trains stop, what is a workstation ?
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: Howto keep the processor idle?
To be honest I've been wondering that all along. Oh, and bear in mind that if you're focussing on CPU clock speed or something you'll probably have to perform some ACPI initialisation/configuration before CPU speed throttling will take effect.gerryg400 wrote:How do you know that it's busy?mohammedisam wrote:It looks like the CPU is still being busy
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 32
- Joined: Tue Jan 06, 2015 5:15 pm
Re: Howto keep the processor idle?
It's worth a try.onlyonemac wrote: I believe modulus to be a somewhat slow operation and you could replace instance where _secs is used with a call to get_secs(), which returns _ticks / 100.
The code for get_current_task() is one line, returning a pointer to the current task's struct:
Code: Select all
task_t *get_current_task()
{
return _task;
}
Code: Select all
task_t *get_next_runnable()
{
task_t *next = ready_queue;
/* Running queue is empty? run idle task */
if(!next) next = idle_task;
return next;
}
Hmmm. Sounds quite reasonable. I guess I actually don't need the timer before tasking is init'ed.onlyonemac wrote:If I'm understanding your code correctly, that line is to prevent a crash if your scheduler isn't initialised yet. In that case, remove the line and only enable the timer once your scheduler has been initialised.Code: Select all
if(!current) goto finish;
Code: Select all
if(current == idle_task && get_next_runnable() == idle_task) goto finish;
Here is how I initialize timeslices for new processes (in order of timer ticks):onlyonemac wrote: What is current->time_left initialised to? Because that's how many ticks you're going to process before another task gets scheduled, and if that's too high for your idle task then your idle task isn't going to keep the CPU very idle.
Code: Select all
void reset_task_timeslice(task_t *task)
{
switch(task->priority)
{
case PRIO_NORMAL: task->time_left = 20; break;
case PRIO_LO: task->time_left = 10; break;
case PRIO_HI: task->time_left = 50; break;
case PRIO_IDLE: task->time_left = 1; break;
case PRIO_ZOMBIE: task->time_left = 0; break;
default: task->time_left = 20; break;
}
}
-
- Member
- Posts: 32
- Joined: Tue Jan 06, 2015 5:15 pm
Re: Howto keep the processor idle?
I am testing my kernel using Bochs under Fedora Linux. The GNOME System Monitor shows that at any given time (when my kernel is active) one of my quad processors is running at 100%. When I pause Bochs, the activity returns to its baseline (3-4%). If it runs for a while, all my other programs would considerably slow down, so I have to test my kernel after I close other windows.gerryg400 wrote:How do you know that it's busy?mohammedisam wrote:It looks like the CPU is still being busy
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: Howto keep the processor idle?
Most emulators, especially Bochs, will use all available CPU power even when the emulated CPU is supposed to be idle. I'm afraid I can't suggest a better way of measuring CPU usage as I'm not too familiar with it myself.mohammedisam wrote:I am testing my kernel using Bochs under Fedora Linux. The GNOME System Monitor shows that at any given time (when my kernel is active) one of my quad processors is running at 100%.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: Howto keep the processor idle?
You should probably make those functions inline (instead of declaring "task_t *get_next_runnable()", declare "inline task_t *get_next_runnable()"). You might even want to think about removing the first one (although keeping it as a separate function does make the code easier to understand).mohammedisam wrote:The code for get_current_task() is one line, returning a pointer to the current task's struct:It is merely a convenience function. The code for get_next_runnable() is:Code: Select all
task_t *get_current_task() { return _task; }
where read_queue is a linked list containing the ready-to-run processes.Code: Select all
task_t *get_next_runnable() { task_t *next = ready_queue; /* Running queue is empty? run idle task */ if(!next) next = idle_task; return next; }
You probably want to keep that timeslice as short as possible, otherwise the idle task will keep running even when something else is ready to run. However, you're still getting timer interrupts 100 times every second no matter which way you're looking at it. When I first commented on that line, I didn't realise that your scheduler had priorities, sorry.mohammedisam wrote:The timeslice for the idle process is only 1, this shouldn't keep the processor busy, right?. But on the other hand, this means the scheduler will be called on each and every timer tick (if the idle task is the running task). This will add to the overhead of the timer handler and compound my problem further, right?
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Re: Howto keep the processor idle?
Sleeping ~10ms is pretty much. Declaring stuff as inline etc is premature optimization in my opinion, the code is just a few calls here and there. Did you enable realtime sync in bochs?
-
- Member
- Posts: 32
- Joined: Tue Jan 06, 2015 5:15 pm
Re: Howto keep the processor idle?
Looks like I will have to live with it. I cannot risk testing it on physical device yet.onlyonemac wrote:Most emulators, especially Bochs, will use all available CPU power even when the emulated CPU is supposed to be idle.