Why are priorities always from a fixed set of integers? In operating systems priorities are integers typically between 1..MAX. But what is the reason that this is the case, when it would obviously be easier to place a new task between priority 2 and 3 with priority 2.5 instead? The way it is now, my scheduling can run out of priorities if my operating system has priorities between 1 and 10 and I need to schedule more than 10 different priorities or must re-arrange for a new task that should be between two subsequently scheduled tasks.
-
$\begingroup$ The same goes for floating point. there is a finite number of floating point numbers, and hence you will see the same problem there. Also, computation with floating point is just slower, so we prefer integers when we can $\endgroup$– nir shaharCommented Jun 17, 2021 at 21:06
-
1$\begingroup$ Floating point arithmetic is slower than integer arithmetic, and floating point numbers typically take up more space. Sometimes they is needed. In the case of priorities, you can easily do without them. Do you really need more than 256 many priorities? $\endgroup$– Yuval FilmusCommented Jun 17, 2021 at 21:07
-
$\begingroup$ @YuvalFilmus No i don't need that many but it's still difficult to know from the start which priority to assign when several new tasks can need to be either more or less prioritized, which lead me to re-assign priorities by trial-and-error. In my case I had priorities between 1 and 10, if I remember, with the RTOS MicroC from Micrium, and it was rather difficult to understand how to set the priorities for even a rather small number (about 5) of tasks $\endgroup$– Niklas RosencrantzCommented Jun 17, 2021 at 21:12
1 Answer
Historically, floating point has been slower than integer arithmetic, though this has not been the case for about 20 years on most non-embedded architectures.
The more compelling reason is to optimise FPU context switching.
When an operating system switches between two threads (not to mention the fact that the operating system itself is software that uses CPU registers), the contents of the CPU registers needs to be saved and restored. A typical modern CPU might have 16 or so general-purpose 64-bit registers, so that's 128 bytes.
Modern FPUs, however, have wide SIMD registers, and thus carry much more state; on modern Intel-esque CPUs, for example, you need 512 bytes.
You could save and restore these on every context switch, but that would incur a nontrivial cost. Instead, most system services, device drivers, and system programs (not to mention the OS itself) are written so they don't use the FPU. Not only does merely invoking a system call not require saving and restoring the FPU, neither does context switching to a system service and back again.
To support this, you need a few things:
- The compiler needs a mode where it will never generate any instructions which involve the FPU. This ensures that the kernel and other system software never changes the FPU state implicitly.
- The CPU needs a mode or flag where it traps to the operating system when a FPU instruction is executed. This flag is set whenever the CPU context switches to a thread for which the FPU state is "stale", and the FPU state is switched if the trap happens.
Note that while this optimisation "works", it has been the source of a Spectre-like security vulnerability on recent Intel CPUs, where it can leak information when the FPU operation is executed speculatively. But even without the full lazy FPU switch optimisation, this still allows saving and restoring FPU context only when a context switch actually occurs, rather than on every system call.