.. _time-framework: Time framework ============== Time and performance units -------------------------- Time inside the emulation is referred to as *virtual time* (as opposed to *host time* or *real time*) and is expressed in *virtual seconds*. Currently, the resolution of *virtual time*, i.e., the minimum expressable time quant, is 10^-6 *virtual second* or 1 *virtual microsecond*. Performance of the CPU is expressed in *MIPS* units (*millions of instructions per second*) and is an integer value. This means that setting the minimum time quant allows the CPU with performance of 1 *MIPS* to execute exactly one instruction. .. note:: For CPU with performance higher than 1 *MIPS*, it is possible to execute instruction-by-instruction using a special *stepping* mode. Performance of the CPU can be configured with the following command (in this case, set to 120 *MIPS*):: cpu PerformanceInMips 120 The default value of the performance setting is 100 *MIPS*. Time sources and sinks ---------------------- Objects controlling flow of *virtual time* are called *time sources*. By default, there is one *time source*, called *master time source*, assosiated with the emulation. Currently, there is no API to create other *master time sources*, but the framework itself is capable of handling multiple *time domains* (with each *master time source* being a root of the domain). Objects that are aware of the time flow are called *time sinks*. Each *sink* is connected to exactly one *source* (at any time, although it can change *sources*) and awaits information about how much *virtual time* has passed so far. There are objects that play both roles: *sink* and *source* - they are called *slave time sources*. The reason for having a *slave time source* is explained in the following section. .. _time-framework_synchronization: Synchronization --------------- Virtual time flows in the form of *quants* generated by *master time sources* and granted to *sinks*. The value of a *quant* is expressed in *virtual seconds* (or a fraction thereof) and is configurable by the user. Once a *quant* is granted to the *sinks*, the *source* waits for them to finish execution. Once all slaves have reported back, it is time for the *synchronization phase*. As it is guaranteed that no nodes work during this phase, it is safe to process all inter-node communication during this. Only when the *synchronization phase* is finished, can a new *quant* be granted to all *sinks*. It is possible to introduce *slave time sources* in the *domain* that divides the quantum into smaller fragments and allows for tighter synchronization of selected nodes. Time domain ----------- A configuration of *time sources* and *time slaves* connected together is called a *time domain*. All members of a *time domain* observe the flow of the same *virtual time* and are synchronized together. In case of having multiple *time domains* the time values are not comparable between them - in other words, there is no synchronization across different *time domains*. There is one *time domain* by default in the emulation. The *master time source* is associated with the emulation itself, every machine provides its own *slave time source* that drives the CPU(s) being a *sink*. Configuration and monitoring ---------------------------- There are several properties provided by a *time source* that can be used to tune the *virtual time* flow: *Quantum* The amount of *virtual time* between two *synchronization phases*. It is guraranteed that the difference of *virtual time* perceived of two *slaves* is never higher than a *quantum* of its closest common *source*. The value of *quantum* can be changed between *synchronization phases*, but the new value won't be used until the next grant. The *slave time source* can have a different *quantum* than its *master time source*. If the slave's quantum is smaller than master's, the slave will split the quantum into smaller pieces and report back to master only when all the pieces are used up. If the slave's quantum is bigger than master's, the slave will report immediately (not executing any CPU instructions) and accumulate the granted interval until it reaches the required quantum. It is illegal to set *quantum* to *zero* as it would not allow the *virtual time* to pass at all. *Performance* Floating-point value describing the ratio of *virtual* to *real* time flow. Value of *1.0* means that the *virtual time* should in average pass in the same pace as a *real* one - the user feels like using real hardware; software that sleeps for 1 second should sleep for 1 real-world second. Value higher than *1.0* means that the *virtual time* should pass faster than the *real* one - it can be used to speed up long emulations (e.g., test what happens in the emulated system after 24 hours of uptime). Value lower than *1.0* means that the *virtual time* should pass slower than the *real* one - it can be used to slow down emulation when a lot of events is happening in a short period. The performance of the host machine puts a natural limit on an effective values of this parameter (see ``CurrentLoad``). It is possible to temporarily overwrite this setting by using ``AdvanceImmediately`` property. *AdvanceImmediately* Boolean value that can be used to overwrite the current value of ``Performance`` and force the emulation to execute as fast as possible. There are also some read-only properties that can be used to monitor the current state of the *source*: *CurrentLoad* Floating-point value indicating the stress the emulation puts on a host CPU. Value of *1.0* (the maximal possible) means that the host uses all its CPU resources to run the current emulation and it is not possible to execute it faster. In other words, increasing *Performance* will not have any effect. Value of *0.5* means that the host is loaded only in 50% so it is possible to speed up the emulation by a factor of 2. This value is calculated as an avarage of *10* samples. *CummulativeLoad* The same as ``Load`` but calculated as an average over all samples since the beginning of the emulation. *ElapsedVirtualTime* The amount of *virtual time* that passed since the *source* has been started. *NearestSyncPoint* The time stamp of the nearest *synchronization phase*. *NumberOfSyncPoints* The number of *synchronization phases* executed so far. CPU pausing vs. halting ----------------------- When any of the members of *time domain* pauses its execution, it will effectively block *virtual time* from passing. As a result, all other members will execute to the nearest *synchronization phase* and wait for the paused member to continue. Sometimes it is convinient to have a member in the *domain* that is disabled, but does not block others - e.g., a CPU that is not clocked in multi-CPU architectures. The *CPU* class provides the ``IsHalted`` property that allows to achieve this goal.