-
Notifications
You must be signed in to change notification settings - Fork 1
TimeVirtualization
Minha is based on a simple event-driven simulation kernel. Each event is specified by subclassing from Event and implementing run(). This method runs to completion at some given simulation time and manipulates model state. This straighforward simulation kernel is then enhanced with two features:
-
Simulated threads avoid inversion of control and allow simulation code to be written as sequential programs. This code is however scheduled non-preemptively: it has to relinquish the CPU for simulation time to advance.
-
Timing of code allows real-time spent in a simulation thread to be used when advancing simulation time, whenever the a simulation thread relinquishes control of the CPU.
Together with BytecodeInstrumentation, that translates blocking primitives to simulation primitives, this allows real code to be run as a simulation.
The following diagram shows in detail how time advances when a simulated host handles some upcall from simulation(e.g., a network packet arriving):
Consider that time flows from left to right and that the two horizontal lines depict the kernel thread (T), that runs simulation events, and the simulated thread (ST) that runs actual code:
-
The simulated thread starts blocked in pause().
-
An event is run. This event calls wakeup() on the thread, allowing it to run. This blocks the kernel thread (i.e., simulation time is stopped).
-
ST is thus running simulation code, being able to directly modify model state. Eventually, ST enters real code and calls startTime(). This queues the thread for acquiring a simulated CPU and pauses.
-
T wakes up and returns from event.run(). This allows simulation time to advance, possibly executing other events. ST is still blocked.
-
When the simulated CPU is available, an event is run. This calls wakeup() and allows ST to run again, being timed.
-
When the simulated CPU encounters some blocking code, it calls stopTime(). This measures the amount of real time spent, that updates the simulated CPU usage.
-
An event is then queued, waiting for simulated time to catch up to the real time spent executing the code. When this happens, an event is run, waking up ST now back to simulation code.
-
Eventually, ST will block explicitly by calling pause() again.