Crate simd_personality
source ·Expand description
Management of two kernel personalities, one for SIMD-enabled code, and one for regular code.
This crate is responsible for creating and managing multiple CrateNamespace
s so that Theseus
can run two instances of code side-by-side, like library OS-style personalities.
This crate itself is part of the regular non-SIMD world, not the SIMD world.
There are two considerations here to ensure correctness by saving/restoring SIMD registers: how to deal with it for context switching, and also for interrupt handling. Both of these policies are determined per-core as follows:
Context Switching
- If there is one or zero SIMD-enabled
Task
s running on a given core, then allTask
s running on that core can use the standard, non-SIMD-enabled context switching routine. This is because there is no need to save and restore SIMD registers (e.g., xmm), as only a singleTask
will ever use them. - If there are multiple SIMD-enabled
Task
s running on a given core, then all of the SIMDTask
s on that core must use the SIMD-enabled context switching routine, which is found in thecontext_switch_sse
crate.
Note that there is no danger in forcing all SIMD Tasks to always use the SIMD-enabled context switching routine,
it will always be correct to do so.
Each Task can have its own Context and context_switch routine, based on whether or not it uses SIMD instructions,
and that can be determined statically and independently for each task, without considering which other tasks are running.
We don’t really need personalities for that, since the context_switch
routines are self-contained.
However, that static policy misses out on the performance optimization of
not having to save/restore SIMD registers when only a single SIMD Task is running on a given core.
Interrupt Handling
-
If interrupt handlers are only ever compiled for the regular world, i.e., no interrupt handlers exist that are compiled to use SIMD instructions, then we do not have to save/restore SIMD registers on an interrupt because we’re guaranteed that no interrupt handling code can ever use (overwrite) SIMD registers. Thus, even if there are some SIMD enabled tasks running on a given core, an interrupt handler need not save those SIMD registers if it cannot possibly ever touch them.
-
If interrupt handlers are compiled for the SIMD world and use SIMD instructions in the handler (or any function accessible from the interrupt handler), then they must (and obviously will) save SIMD registers. In fact, I don’t believe it’s possible to compile an interrupt handler that uses SIMD instructions but doesn’t save SIMD registers (at least while we’re stil using the special x86 interrupt calling convention to have LLVM do it for us).
Thus, the best option is just to require that any SIMD-enabled interrupt handlers must save all SIMD registers, which is a rule determined completely independently of which tasks are running on that core. In general, this is a good rule, because it’s poor design to have an interrupt handler do a lot of work, such as processing data in a way that would need SIMD instructions. Instead, those processing stages should be moved out of the interrupt handler and into a separate Task elsewhere, i.e., a classic bottom-half/top-half design.