Hi,
DevNoteHQ wrote:Are Idle task and the GUI individual tasks? Because then kernel -> Idle task -> GUI -> "process that has focus" are 6 task switches in total...
Couldn't I include the GUI in the Idle task? I mean i am planing on calling the Idle task at least every 1ms (at full load i'll call it every 1ms), so there should be sufficient time to update everything... Or is the Idle task usually included in the kernel?
There's 2 ways for a scheduler to handle "there's no work for a CPU to do at all". The first way is to have a special idle state built into the scheduler. The second way is to have an "idle task" that is only ever given CPU time when nothing else can use the CPU (where the existence of an idle task means that the scheduler knows there's always a task to run and avoids the need for the scheduler to deal with a special state).
Note that this is typically tied up with power management (e.g. reducing power consumption when CPU has nothing to do), which gets complex and (if done well) depends on a whole bunch of information that is harder to obtain from an idle task. In general, "idle task" is easier if you're not doing any power management; and "special idle state" is easier if you're doing advanced/complex power management.
Also note that almost all real schedulers have multiple scheduling policies, where each scheduling policy might use a completely different algorithm. For example; "policy 0" might be intended for
real-time tasks and might use an [url=https://en.wikipedia.org/wiki/Earliest_deadline_first_scheduling]"earliest deadline first" algorithm; "policy 1" might be intended for tasks that need very low latency but don't use much CPU time, might have 256 task priorities, and might use a "highest priority task gets the CPU" scheduling algorithm; "policy 2" might be intended for normal tasks and might use a "variable frequency" scheduling algorithm (tasks with higher priority get more time slices); and "policy 3" might be intended for background tasks, might have 256 task priorities, and might use a "variable length time slice round robin" scheduling algorithm (where higher priority tasks are given larger time slices). In this case, if the OS uses an idle task, it can just be a task that uses the lowest priority within a scheduling policy intended for unimportant/background work.
This is because different tasks have different requirements - some tasks might need low latency (e.g. when something happens they need the CPU as soon as possible), some tasks don't care about latency at all but need lots of CPU time (plodding away doing calculations in the background), some tasks need a specific amount of CPU time (e.g. enough to handle 60 frames per second, no more and no less), etc. Different scheduling algorithms are good for some requirements and bad for others; and scheduling policies allows an OS to use different scheduling algorithms for different task requirements.
DevNoteHQ wrote:So you are basically saying the I/O APIC is needed if the BSP is under full load? Because i think i'll prefer the other processors in the... I guess the sheduler manages the load distribution? So i'll have to deal with I/O APIC sometime in the future, but not now since the PIC works fine?
IO APIC (and/or Message Signalled Interrupts/MSI) is needed to balance the overhead of IRQs across available CPUs (possibly in a "dynamic, changing in response to power management and other factors" way); which helps to reduce IRQ latency (IRQ balancing reduces the chance of "CPU can't start IRQ handler immediately because CPU is already executing an IRQ handler" and therefore reduces the time between an IRQ occuring and its IRQ handler being started) and can help to improve cache locality (IRQ handler's code and data still in that CPU's caches).
For now; you're learning and should probably do whatever helps you learn more faster; but this depends on what you're learning (e.g. if you're trying to learn about memory management, then the IO APIC would be a useless distraction).
DevNoteHQ wrote:Do you have any recommendations which algorithm to use for:
I'll also have to do:
Code: Select all
void *kmalloc(uint64_t size, uint16_t align)
And therefore also:
Code: Select all
void* operator new(size_t len, uint16_t align)
Any recommendations on that?
I think "one algorithm" is a bad idea, regardless of which algorithm it is.
Quickly: For something where performance matters (e.g. kernel) you want to be able to control cache locality (e.g. pieces of memory that are used as a set placed close to each other), and the easiest way to do that is to have "memory pools" where each pool has separate allocator (e.g. one pool for "scheduler data" and one pool for "keyboard driver data", so that all of the scheduler's data is in the same area, same set of cache lines, same set of pages, etc, and you don't get more cache misses and more TLB misses because scheduler's data is interspersed with keyboard driver's data). You also want quotas/limits (e.g. so that a memory leak in a keyboard driver can't/won't gobble all the memory and prevent the scheduler from functioning properly), and memory pools works for that too. You also want some hints - one for "lifetime" (for short-lived things allocation time is more important than avoiding fragmentation and wastage, and for long-lived things avoiding fragmentation and wastage is more important than allocation time); one for "performance vs. security" (for the encrypted RAM features modern CPUs have); one for "bandwidth vs. latency" (for various optimisations for things like NUMA, "high bandwidth RAM built into CPU", etc), and maybe a "which NUMA domain" hint (more optimisation). These hints could be associated with a memory pool and (in some cases) could determine which algorithm is used to manage a pool's memory. Finally you want some bug detection and "debug-ability" - a way to detect bugs (e.g. when you free something that is already free), a way to associate a "pointer to name string" (and maybe a "which line of source code in which file") to each pool and each allocated piece of memory within each pool, a generic way to obtain useful statistics (e.g. "Scheduler's pool is 128 MiB, and 12% of RAM within scheduler's pool is allocated for process data objects"), etc.
Cheers,
Brendan