On µ-Kernel Construction
Liedtke (1995)
What kind of paper is this?
- Refute conventional wisdom.
- Big idea (µ-kernels are fast enough).
The Story
- µ-Kernels have gotten a bad rap
- They are considered inefficient and inflexible
- The problem is not the µKernel idea but the implementation
- µ-Kernel should *not* be portable
- If you build a µ-Kernel correctly, then you get good performance
AND flexibility
- So, what should you do?
- Reason about µ-Kernel concepts
- Only put in the kernel that which, if moved outside the kernel, would
prehibit functionality
- Assumptions
- Require security
- Require page-based VM
- Requirements
- Subsystems must be able to be isolated from one another
- Must be able to communicate between 2 subsystems without interference from a 3rd
- Components
- Address spaces
- Threads and IPC
- Unique IDs (not much more to say here, but you need to be able to identify
address spaces, threads, and message).
Address Spaces
- All through inheritance
- One master address space (physical memory)
- All others are selections from this space
- Interface
- Grant: move a page from your address space to a new one.
- Map: share a page with another address space
- Flush: remove a page from someone's address space
- These three operations are the only functionality required by the
microkernel.
- All other functionality (e.g., paging, general memory management,
controlling IO device rights, and IO drivers)
are done outside the kernel.
Threads
- Threads execute in an address space.
- Included in µ-kernel because a thread is associated with a
particular
address space (although the association may change over time);
changes to address state must be managed by kernel.
- Thread state includes registers (minimally defined) and address
space.
- Communication among threads (IPC) must also be a µ-kernel
feature.
- IPC represents an agreement: sender sends and receiver agrees to
receive (e.g., in a grant, the receiver of the page must agree to take
the page).
- Interrupts are IPC messages with no payload; only purpose is to
supply the sender ID so that the interrupt can be associated with a
particular hardware device (each of which has a unique id that is
used as the sender).
- Kernel must turn real hardware interrupts into thread events, but the
rest of the kernel need never be aware of interrupts as they are truly
manifested.
So, what is a microkernel
- Minimal interface to address space construction (grant, map, flush).
- Threads
- IPC
- Unique identifiers
Implementing user-level services on a µ-kernel
- Memory manager/Pager
- Grant, map, flush are the basic mechanisms.
- Policies for how and when you issue these calls can be
made in a user-level manager.
- Each address space can have its own manager.
- Can have application-specific managers (e.g.,
multimedia resource allocator) that must, itself,
coordinate with other managers to make appropriate
guarantees.
- Device Drivers
- Can live outside the kernel, because they don't access
hardware directly; they send/receive messages from the
thread that represents the hardware.
- Cache and TLB handling
- User pagers to implement whatever policies you like.
- In practice, 1st level TLB handling still needs to be in the
kernel for performance.
- Unix server
- Simply a user-level server that creates and manages its
own Unix address spaces.
Performance
Refute the question of why results in the literature suggest that
microkernels are inherently slower.
- Context switches (e.g., system calls) shouldn't be that
expensive.
- Conventional systems pay almost 90% of their context
switch time in "overhead."
- L3 does not.
- Why? What is being ignored?
- Parameter checking?
- Parameter passing?
- Saving kernel state?
- What else?
- Similarly, switching between address spaces shouldn't be so
expensive.
- Include thread and address space switching in the
discussion (because that's what people measure).
- If caches are physical, these don't affect context switch
time.
- If TLBs are untagged, an address space switch requires
a flush of the TLB (and subsequent TLB faults to establish new
entries).
- Use PowerPC hacks to get rid of TLB reload problem, by
use of segment registers.
- Tailor context switch code to the HW and figure out how
to get it fast.
- Basic approach suggested is actually placing all processes in a large
(e.g., 52 bit address space, so that by changing a segment register, you
essentially fake a tagged TLB). Essentially this is reminescent of Multics --
you are (sort of) mapping things like device drivers and small servers
into every address space (with appropriate permissions).
- Thread switches and IPC
- Empirically show that L3 has fast IPC.
- Memory Effects
- Chen and Bershad "showed" that microkernels had
signficantly worse memory behavior.
- Liedtke shows that the difference is entirely in the cache
miss behavior.
- What kinds of misses are these (capacity or conflict)?
- What would each imply?
- conflict: might imply structure
- capacity: code is just too big
- Chen and Bershad show that self-interference causes
more misses than user/kernel.
- Ratio of conflict to capacity is much lower in Mach.
- Liedtke concludes that the problem is simply too much
code, and that most of that code is in Mach.
Conclusion is that the slowness of microkernels is really just
problems of implementation.
Portability
- µ-kernels should not be portable; they are the hardware
compatibility layer.
- Example: implementation decision between 486 and Pentium is
different if you are going for high performance. This difference
suggests significant rewriting to port.
- Think of µ-kernel as microcode.