In the default model, the execution of a step takes no time by itself, and steps are run in program order. This is called the Simics in-order model. It implements the basic instruction set abstraction that instructions execute discretely and sequentially. This minimalistic approach makes simulation fast but does not attempt to model execution timing in any way.
Normally one step is executed every cycle, so that the step and cycle counts are the same. See the section Changing the Step Rate for how to change this.
The in-order model can be extended by adding timing models to control the timing of memory operations, typically using the memory hierarchy interface. When timing models are introduced, steps are no longer atomic operations taking no time. A step performing a memory operation (whether an instruction fetch or a data transaction) can stall for a number of cycles. Cycle events are performed during the stalling period as time goes forward. Step events are performed just before the step execution, as in the default model. Simics executes one step at a time, but with varying timing for each step, so the simulation is still performing an in-order execution of the instruction flow. The basic step rate can also be changed; see the section Changing the Step Rate below.
Choosing an execution mode is matter of trade-off between performance and accuracy. The stalling mode is notably slower than in-order, but allows for memory timing models to operate correctly and, as a consequence, also allows for inspection of all memory transactions. By using checkpoints, it is possible to switch between the two modes, since a checkpoint created in the in-order mode can be loaded in stall mode. The simple in-order mode can thus be used to reach interesting parts of the simulation quickly, and the stall mode is used to simulate those parts.
The step rate is the number of steps executed each cycle, disregarding any stalling. It is expressed as the quotient q/p. By default, p=q=1; this schedules one step to run in each cycle. This can be changed by using the <processor>.set-step-rate command. For example,
simics> cpu0.set-step-rate "3/4"
will set the step rate of cpu0 to 3/4; that is, three steps every four cycles.
If q<p, then some cycles will execute no step at all; if q>p, then some cycles will execute more than one step. The step rate parameters are currently limited to 1 ≤ p ≤ 128 with p=2k for some integer k, and 1 ≤ q ≤ 128.
Setting a non-unity step rate can be used to better approximate the timing of a target machine averaging more or less than one instruction per cycle. It can also be used to compensate for Simics running instructions slower than actual hardware when it is desirable to have the simulated time match real time; specifying a lower step rate will cause simulated time go faster. Finally, a lower step rate may improve simulator performance by reducing the number of instructions executed between consecutive simulated timer interrupts. This is, however, to a high degree depending on the workload in question. Some workloads even benefit from a larger number of steps between timer interrupts.
The step rate is sometimes called IPC (instructions per cycle), and its inverse, the cycle rate, may be called CPI (cycles per instruction). The actual rates will depend on how many extra cycles are added by stalling.
Let us look at an example using the QSP-x86 platform. We will first run 1 million steps with the default settings:
simics> c 1_000_000
simics> print-time
┌──────────────────────┬─────────┬─────────┬────────┐
│ Processor │ Steps │ Cycles │Time (s)│
├──────────────────────┼─────────┼─────────┼────────┤
│qsp.mb.cpu0.core[0][0]│1_000_000│1_400_000│ 0.001│
└──────────────────────┴─────────┴─────────┴────────┘
The processor has run 1 million steps, taking 1.4 million cycles to execute them. (The larger number is because QSP is configured so that certain operations will stall the core for 20,000 cycles, see Stalling above, as well as the output from the qsp.mb.cpu0.core[0][0].info command.) Let us now set the cycle rate to the value mentioned above, 3 steps for every 4 cycles:
simics> qsp.mb.cpu0.core[0][0].set-step-rate "3/4"
Setting step rate to 3/4 steps/cycle
simics> bp.cycle.break 1_200_000
Breakpoint 2: qsp.mb.cpu0.core[0][0] will break at cycle 2600000
simics> c
[bp.cycle] Breakpoint 2: qsp.mb.cpu0.core[0][0] reached cycle 2600000
simics> print-time
┌──────────────────────┬─────────┬─────────┬────────┐
│ Processor │ Steps │ Cycles │Time (s)│
├──────────────────────┼─────────┼─────────┼────────┤
│qsp.mb.cpu0.core[0][0]│1_900_000│2_600_000│ 0.001│
└──────────────────────┴─────────┴─────────┴────────┘
When running the next 1.2 million cycles, the processor executes only 900000 steps, which corresponds to the 3/4 rate that we configured.
It is possible to set the step rate to infinity, or equivalently, to suspend simulated time while executing steps. This is done by setting the step_per_cycle_mode processor attribute to one of the following values:
"constant"step_rate attribute"infinite"While time is suspended, the cycle counter does not advance, nor are any time events run. To the simulated machine this appears as if all instructions are run infinitely fast. Using the same example as above, we set the step per cycle mode to "infinite" to prevent the simulated time from advancing:
simics> qsp.mb.cpu0.core[0][0]->step_per_cycle_mode = "infinite"
simics> c 1_000_000
simics> print-time
┌──────────────────────┬─────────┬──────┬────────┐
│ Processor │ Steps │Cycles│Time (s)│
├──────────────────────┼─────────┼──────┼────────┤
│qsp.mb.cpu0.core[0][0]│1_000_000│ 0│ 0.000│
└──────────────────────┴─────────┴──────┴────────┘
The processor has executed 1 million steps but the simulated time has not advanced. Note that setting this mode would probably prevent many machines from booting since many hardware events (like interrupts) are time-based.
Conversely, it is possible set the step rate to zero, thus suspending execution while letting simulated time pass. This can be done by stalling the processor for a finite time (see Stalling above) or by disabling the processor for an indefinite time. Disabling and re-enabling processors is done with the commands <processor>.enable and <processor>.disable.