The Synthesis Kernel
Pu, Massalin, Ioanidis (1988)
What kind of paper is this?
- Big idea
- This may be the first OS/code synthesis paper
- This is the proof of concept to justify building out the whole system.
- May be even a bit premature to call it a proof of concept.
The Story
- Once upon a time all operating systems were forced trade off
high level, powerful interfaces and performance.
High level powerful interfaces made it easier to write applications,
but these applications than ran slowly.
Lower level, performant interfaces made writing applications hard.
By synthesizing efficient code, the authors were able to produce an
operating system for which it was easy to write applications while
retaining high performance.
As such, everyone lived happily ever after.
Two big ideas
- Code synthesis: very specific code to accomplish the specific operation
a kernel is doing, e.g., read this specific file. (Their description makes
it feel like a specific implementation of caching.)
- Writing to a synthetic machine -- this is like a paravirtualized hypervisor
- The particular synthetic machine used here is a logical (virtual)
multi-processor with its own address space: CPUs, memory, and IO units.
- Both ideas are critical to this working.
Synthesis Approaches
- Invariant Factoring
- Generalization of currying
- Currying creates "specialized" functions that bind one (or more)
parameters to specific values.
- In the file system example, if read takes 3 arguments: file, offset, len,
a curried (specialized) read could take 2 arguments
read-of-this-file(offset,len).
- Further, read actually works with all sorts of devices -- this means
that the actual code path navigates through many levels of indirection
to get to code that handles this specific read for this specific device.
Synthesizing the specialized code gets rid of all that.
- Collapsing Layers
- This is kind of like inlining, only at a much grander scale
- Executable Data Structures
- The idea is self-traversing
- Their example: executing stop-job on an element of the runqueue
automatically invokes start-job on the next element.
- Maybe there is an analogy to path traversal? If I invoke
lookup on a directory with a path, perhaps it automatically
invokes lookup on one of its children with the truncated path?
- This feels similar to layer collapsing.
Technical Challenges and Solutions
- All this specialization could lead to a HUGE kernel, so
synthesize directly into a synthetic machine (kind of like a JIT?)
- Where is the supervisor boundary? Whenever you go into synthesized
code, it's a trap (but a simplified one, ideally). Synthesized code for
each program goes in its address space, but is accessible only to
supervisor code.
Synthetic Machines
- Each synthetic machine is a protection domain (address space)
- Machines contain: CPUs, memory, and IO
- Each CPU is a thread.
- Each memory element (SMEM) is a memory segment
- SMEM can be shared among machines.
- Powerful enough to build a hypervisor (by a different name)
Synthetic Machine Interface
- Creating a machine generates code for the terminate, query, and
reconfigure "methods" of that machine.
- Creating kernels produces read/write routines.
- Basically, you can create 4 kinds of things: machines, cpus, memory,
and IO.
- Each of those (may) supports create, terminate, reconfigure, read, write.
- Recursively you create the entire system this way!
Implementation
- Kind of (leidtke) microkernel like: has to be rewritten from scratch
for every piece of hardware.
- Different synthesis techniques are used for different parts of the kernel.
Evaluation
- Things we wanted answered:
- How much shorter is the synthesized code path than a full one?
- How long does the synthesis take?
- What they measured: We're faster on a read than SunOS, HP, etc.
Feature Analysis
- Features that are common practice
- Hypervisor/virtual/synthetic machine.
- Features that are not used and should stay that way
- Features that are not used but should be reconsidered
- The orthogonality of interfaces
- Features for which the jury is out
- (Dynamically) Synthesizing OS code