4 Performance 4.2 Scaling Simics
Intel® Simics® Simulator User’s Guide  /  4 Performance  / 

4.1 Simulation Performance

This chapter covers various topics related to Simics performance and what can be done to measure and improve it. It discusses the general performance features provided by Simics. For ways to scale the simulation even further see chapter 4.2.

Simics is a fast simulator utilizing various techniques such as run-time code generation to optimize performance. In some cases Simics can execute code faster than the target system being simulated, while it can also be considerably slower in other cases.

There are four major execution modes Simics uses to execute target instructions: hypersimulation, VMP, JIT and interpreted mode.

Hypersimulation means that Simics detects repetitive work performed by the target code and performs the effects of the code without actually having to run the code. In the most simple case this is a simple idle loop, but it can also be applied to more complex examples such as spin-locks and device polling. This is the fastest execution mode.

VMP, which is a part of Simics’s x86 models, utilizes the virtualization capabilities of modern processors to run target instructions directly. This typically results in high simulation performance, but the host and target need to have the same instruction set, and you have to do special set up to enable it. VMP is currently only supported on x86 hosts.

JIT mode uses run-time code generation to translate blocks of the target instructions into blocks of host instructions. JIT mode is when Simics runs such translated blocks. This mode is supported by most target processor models in Simics.

Interpreted mode interprets the target instructions one by one. This mode is the slowest, but it is always available.

There are basically two ways to measure Simics performance:

In most cases the user is mostly interested in the first. Simics should execute instructions as fast as possible to finish the workload in shortest possible time. However, since Simics is a full system simulator, it is also important that the virtual time on the simulated machine advances quickly. That is important in cases where a program or operating system is waiting on a timer to expire or an interrupt from a device in order to proceed with the workload.

If we divide the wall-clock time on the host that Simics executes on, with the elapsed virtual time on the target machine, we get a slowdown number.

slowdown = Timehost/Timevirtual

A slowdown number of 2.3 means that Simics performance is 2.3 times slower than the system it simulates. A slowdown value of less than 1.0 means that Simics manages to execute the corresponding code faster than the system it simulates. The slowdown depends on various factors:

The default time model in Simics is that each target instruction takes one target cycle to execute. That is the default, Instructions Per Cycle (IPC) is 1.0. This is a simplification (but in many cases an adequate approximation) compared to the actual time it takes on the real hardware to execute instructions. It is possible to change the IPC number using the <cpu>.set-step-rate command. For example:

simics> board.mb.cpu0.core[0][0].set-step-rate ipc = 1.5
Setting step rate to 3/2 steps/cycle
simics> board.mb.cpu0.core[0][0].set-step-rate ipc = 0.5
Setting step rate to 1/2 steps/cycle

In the first example, IPC of 1.5 means that Simics needs to execute 3 instructions for 2 cycles to elapse. In the second example, for each instruction executed two cycles elapse. Thus, with a lower IPC value, virtual time will progress faster and simulation slowdown will decrease.

Note that there is nothing wrong in changing the default IPC when it comes to the accuracy of the simulation. In many cases, the IPC observed for a given benchmark is much lower than the 1.0 that Simics assumes, and matching it will both make the simulation closer to the real hardware and improve the simulation speed, at least in virtual time. Simulations that profit most from this change are simulations involving devices and long memory latencies.

4.1.1 Measuring Performance

The new-system-perfmeter command can be used to understand the performance you get out of Simics. It is sample based, which means that you can see the performance during the workload execution, and how it varies, not only the end result when a workload is finished.

new-system-perfmeter is built on the general Probes framework, and replaces the older, now deprecated, system-perfmeter singleton command. The Probes framework and the full new-system-perfmeter command reference, including all available probes and switches, is described in chapter 2.7. This chapter instead focuses on some practical scenarios, see 4.1.1.1.

The easiest way to try it out is simply to issue the new-system-perfmeter command without any additional arguments:

simics> new-system-perfmeter

This creates a new object, by default named sp0, which samples a number of default probes every 1.0 real (wallclock) seconds, and prints a summary when the simulation stops. The output can look like this:

simics> run-seconds 20
┌──────────┬──────────┬─────────┬─────────┬────────┬────┬────┐
│ Session  │ Session  │Virtual- │Wallclock│Slowdown│Host│Sim │
│ Virtual- │Wallclock │Time (s) │   (s)   │        │CPU%│Load│
│   Time   │(hh:mm:ss)│         │         │        │    │ %  │
│(hh:mm:ss)│          │         │         │        │    │    │
├──────────┼──────────┼─────────┼─────────┼────────┼────┼────┤
│  00:00:00│  00:00:00│479.60 ms│215.28 ms│    0.45│118%│ 22%│
│  00:00:02│  00:00:01│  1.91 s │  1.00 s │    0.52│ 57%│  3%│
│  00:00:19│  00:00:02│ 16.47 s │999.54 ms│    0.06│114%│  0%│

The Slowdown column shows how fast virtual time elapses compared to wallclock time; a value below one means Simics executes faster than the simulated system. The Host CPU% column shows how much of the host CPU that Simics has used, allowing you to notice if there is another process consuming the host CPU resources, or if Simics itself is running in real-time mode where Simics sleeps so that virtual time does not race ahead of host time.

Additional probes can be added with convenience switches, for example -cpu-exec-modes adds, per processor, the percentage of instructions executed in hypersim, VMP, JIT and interpreter mode (see chapter 4.1.4.1 for more on hypersimulation):

simics> new-system-perfmeter -summary -cpu-exec-modes

Other convenience switches include -mips/-cpu-mips for instructions per second, -cpu-load for per-processor load, -module-profile for live profiling of the main Simics thread, and -io for instructions per I/O operation. Since new-system-perfmeter is a regular creatable object (not a singleton), several instances can run at the same time, each measuring a different set of probes. See chapter 2.7 for the full list of switches, as well as the more general-purpose add-probe command which allows any probe in the system to be monitored.

You can use the help command to read more about the tool’s different command arguments.

simics> help new-system-perfmeter

4.1.1.1 Useful Performance Scenarios

This section describes some common ways of using new-system-perfmeter when investigating Simics performance.

Adding and removing individual probes

Besides the convenience switches shown above, any probe in the system can be monitored with <obj>.add-probe, using either the probe-kind argument (adds the probe on every object that has it, for example all processors) or the probe argument (a specific object’s probe). Each probe is added with a mode: delta (the default, change since the last sample), session (accumulated since the probe was added), or current (the raw value, useful for probes that are not monotonically increasing). Probes can later be removed again with <obj>.remove-probe. See chapter 2.7 for the full explanation of these modes and the probe-kind/probe matching rules, including how a common prefix can be used to add or remove several related probes at once.

Object-specific probes are grouped under their own table sub-heading. Below is an example where we add cpu.load_percent probes, alongside the default sim.load_percent probe, to show the per-processor values behind the global value.

simics> new-system-perfmeter
simics> sp0.add-probe probe-kind = cpu.load_percent
Added 2 probes to sp0
simics> c
┌────────────────────────────────────────────────────────────┬────┬────┐
│                                                            │cpu0│cpu1│
├──────────┬──────────┬─────────┬─────────┬────────┬────┬────┼────┼────┤
│ Session  │ Session  │Virtual- │Wallclock│Slowdown│Host│Sim │Sim │Sim │
│ Virtual- │Wallclock │Time (s) │   (s)   │        │CPU%│Load│Load│Load│
│   Time   │(hh:mm:ss)│         │         │        │    │ %  │ %  │ %  │
│(hh:mm:ss)│          │         │         │        │    │    │    │    │
├──────────┼──────────┼─────────┼─────────┼────────┼────┼────┼────┼────┤
│  00:00:01│  00:00:01│515.00 ms│788.34 ms│    1.53│ 43%│ 36%│ 73%│  0%│
│  00:00:08│  00:00:02│  7.39 s │999.68 ms│    0.14│ 76%│  1%│  2%│  0%│
│  00:00:13│  00:00:03│  5.02 s │999.72 ms│    0.20│109%│  6%│ 13%│  0%│

It is also possible to add a probe for one specific object, instead of adding the probe to every matching object:

simics> new-system-perfmeter
simics> sp0.add-probe probe = "cpu0:cpu.load_percent"
Added 1 probes to sp0
simics> c
┌────────────────────────────────────────────────────────────┬────┐
│                                                            │cpu0│
├──────────┬──────────┬─────────┬─────────┬────────┬────┬────┼────┤
│ Session  │ Session  │Virtual- │Wallclock│Slowdown│Host│Sim │Sim │
│ Virtual- │Wallclock │Time (s) │   (s)   │        │CPU%│Load│Load│
│   Time   │(hh:mm:ss)│         │         │        │    │ %  │ %  │
│(hh:mm:ss)│          │         │         │        │    │    │    │
├──────────┼──────────┼─────────┼─────────┼────────┼────┼────┼────┤
│  00:00:01│  00:00:01│  1.21 s │  1.32 s │    1.10│ 44%│ 20%│ 39%│
│  00:00:12│  00:00:02│ 11.15 s │997.73 ms│    0.09│116%│  2%│  3%│
│  00:00:14│  00:00:03│  1.33 s │999.44 ms│    0.75│109%│ 37%│ 75%│

Exploring potential bottlenecks

Rather than adding probes one by one, a named probe-collection can be used to add a larger, curated set of probes in one go. The explore collection adds a broad selection of probes useful for finding performance bottlenecks, including CPU counters, execution modes, VMP information, and host resource usage:

simics> new-system-perfmeter -summary probe-collection = explore

A probe-collection can add more probes than would be practical to print in the live sample table. Probes can be marked hidden in the collection, meaning they are still sampled and included in the summary, the exported JSON, and the HTML report, but are not printed for each sample. This is how the explore collection can add a large number of probes without making the live output unreadable. A probe can also be marked no_sampling, in which case only its final value is collected (no per-sample history), which keeps the exported JSON smaller for probes where the history is not interesting, such as histograms. Use <obj>.list-probe-collection to see which probes, and with which flags, a given collection adds, without having to open the JSON file defining it; the <obj>.add-probe command’s -hidden and -no-sampling switches give the same behavior when adding probes individually.

Generating an HTML report

Once a new-system-perfmeter (or new-probe-monitor) session has recorded data, the html-report command can turn it into an interactive report with graphs, making it much easier to spot trends or anomalies than reading the raw sample table:

simics> new-system-perfmeter -summary probe-collection = explore
simics> run-seconds 60
simics> sp0.html-report -open-browser

The -open-browser switch automatically opens the generated report in the default web browser once it has been created. Use -one-page to consolidate the report into a single HTML file instead of one file per category (such as per-CPU or per-cell graphs), which can be convenient for sharing the report as a single artifact. See help <probe_system_perfmeter>.html-report for the full list of switches, including how to supply a custom graph specification.

Every report includes an “Analysis” section, generated by a set of rules that inspect the collected probe data and flag anything that looks like a potential concern, without requiring any AI support. Adding the -ai switch extends this with an AI-generated narrative on top of those same findings; see Performance Tweaks for its prerequisites.

Comparing two runs with an HTML diff report

To see how performance has changed, for example between two versions of a model or two different workloads, the collected probe data can be exported to JSON with export-json and compared with the html-diff-report command. To compare the active run with a previously saved baseline, export the active session before diffing it against that baseline file:

simics> new-system-perfmeter -summary probe-collection = explore
simics> run-seconds 60
simics> sp0.export-json filename = comparison.json
simics> sp0.html-diff-report baseline-json-file = baseline.json comparison-json-file = comparison.json -open-browser

The generated report shows diff badges indicating how many values changed between the two runs.

4.1.2 Multithreaded Simulation Profiling and Tuning

With Simics Accelerator, simulation performance can be increased by utilizing host system parallelism. Simics exploits available target system parallelism and spreads the load over available host cores, in order to increase performance.

Simics Accelerator has two different mechanisms that can operate alone or work together to improve performance. The first is Simics® Multimachine Accelerator which is based upon the cell concept. The other mechanism is Multicore Accelerator which can parallelize simulation even within cells.

A cell ideally contains tightly coupled parts of the target system (typically one or more CPUs and associated devices). Different cells can be simulated in parallel with Multimachine Accelerator (which is default on), but unless Multicore Accelerator is enabled (default off), a single cell will be simulated in a single-threaded fashion (see chapter 4.2 for more details).

4.1.2.1 Simics® Multimachine Accelerator

The Multithreaded Simulation Profiler tool (mtprof) can be used to analyze some performance aspects of multithreaded simulation. Mtprof is primarily useful to

The Multithreaded Simulation Profiler helps in understanding threading behavior at the Multimachine Accelerator level. There is no explicit tool support for optimizing specific Multicore Accelerator issues.

The Multithreaded Simulation Profiler is started with the following command:

simics> enable-mtprof

When mtprof is enabled, Simics keeps track of how much CPU time is spent simulating each cell in the system. Once Simics has been running for a while, it is possible to ask mtprof for an overview:

simics> mtprof.cellstat
============================================================
  cellname                    rt   %elapsed  %cputime
------------------------------------------------------------
  ebony3.cell3             77.0s     93.6%    80.0% 
  ebony1.cell1              8.9s     10.9%     9.3% 
  ebony2.cell2              8.2s     10.0%     8.5% 
  ebony0.cell0              2.1s      2.5%     2.1% 
------------------------------------------------------------
  elapsed_realtime         82.2s    100.0%    85.5%
============================================================

From the above output, we can conclude that cell3 is a limiting factor: the other cells frequently have to wait upon this cell in order to keep the virtual time in sync. Investigating why cell3 is so expensive to simulate is the next natural step: there might be an expensive poll loop or the idle optimization might not function properly, for instance. Other potential ways to address the load imbalance include

The mtprof tool can also be used to estimate how fast the simulation would run on a machine with enough host cores to allow Simics to assign a dedicated host core to each cell:

simics> mtprof.modelstat
============================================================
  latency      rt_model  realtime/rt_model
------------------------------------------------------------
    10 ms        81.9s       100.4%
    40 ms        81.2s       101.2%
   160 ms        80.3s       102.4%
   640 ms        78.6s       104.6%
============================================================

The latency column corresponds to various values for set-min-latency. In this case, the simulation was executed with a 10 ms latency, which means that the model predicts that the simulation would take 81.9 s to run (which is pretty close to the measured value of 82.2 s above).

It is important to note that the performance model does not take modified target behavior, due to different latency settings, into account (which can be a huge factor if the cells interact). With substantial inter-cell interaction, only the row corresponding to the current latency setting should be trusted.

Below is an example from a more evenly loaded system run with a min-latency of 1 ms:

simics> mtprof.modelstat
============================================================
  latency      rt_model  realtime/rt_model
------------------------------------------------------------
     1 ms        35.3s       107.4%
     4 ms        29.5s       128.8%
    16 ms        25.9s       146.3%
    64 ms        24.2s       156.5%
============================================================

In this case, we see that increasing the latency setting to about 16 ms would improve simulation performance substantially (once again, without taking changed target behavior into account).

Quite often, the target behavior is not static but varies with simulated time. In that case, it is often useful to export the collected data and plot it using an external tool:

simics> mtprof.save-data output.txt

The exported data is essentially the information provided by mtprof.cellstat and/or mtprof.modelstat, but expressed as a function of virtual time (exported in a plot friendly way). The mtprof.save-data command takes multiple flags which can be used to customize the output. One useful flag is -oplot:

simics> mtprof.save-data mtprof-plot.m -oplot

which outputs the data in the form of an Octave file together with commands which plots the data.

The mtprof tool currently does not support Multicore Accelerator.

4.1.2.2 Multicore Accelerator

Whether to use Multicore Accelerator or not depends heavily on the workload of the system that is being modeled. Multicore Accelerator performs best for systems with CPU intensive tasks, with little communication, and a low I/O rate. The print-device-access-stats and new-system-perfmeter (with the -io switch) commands can be used to measure the frequency of I/O operations in the system. (I/O operations are expensive in Multicore Accelerator mode.)

Note that some systems perform well even if the number of target instructions per I/O operation is as low as 300 while others perform poorly even though this number is considerably higher. Different target systems behave differently, and in the end, one has to benchmark each system by itself to get highest possible performance. As a guideline, if a target system executes less than 10,000 instructions per I/O operation on average, one might have to consider switching off Multicore Accelerator, or tune the system software in order to achieve good performance.

The enable-multicore-accelerator command provides some tuning and settings for Multicore Accelerator. For more information, see the documentation for the enable-multicore-accelerator command.

It is probably best practice to try to optimize the cell partitioning as described in section 4.1.2.1 to find the most resource demanding cells first, and then switching on Multicore Accelerator for those cells (if available host cores still exist). Currently, it is not possible to restrict a number of host cores for particular target CPUs. Simics will instead automatically balance the system as efficient as possible.

4.1.3 Platform Effects

Starting with the most important, consider these factors when choosing a platform to run Simics on:

CPU Speed

Simulation is a very compute intensive application. As a general rule, a machine with higher compute performance will outperform a lower compute performance machine unless the simulation is starved for memory. The SPECint2006 benchmark suite (www.spec.org) is a good indicator of compute performance and can be used to compare systems with different processors. Both processor architecture and clock frequency affects the performance. Within an architecture performance scales almost linearly with clock frequency.

Other CPU features such as the size of the caches does affect performance, but less so than the architecture and the clock frequency.

Memory Size

The simulator can operate with less memory than the simulated memory size. It does that by allocating pages only when used and swapping out pages to disk when running low on memory. The memory size needs to be large enough so that the paging of memory to disk does not hurt performance too much.

Number of Cores

Simics Accelerator will utilize multiple host threads to simulate in parallel. If all simulated processors require equal amounts of time to simulate, then the simulator can theoretically utilize as many host cores as there are simulated processors. In practice, the workload is always skewed, meaning that fewer host cores can be effectively utilized. It is more efficient to use multiple cores or processors on a single machine compared to distributing the simulation across multiple host machines.

File System

Running from local disk is faster than running over a network file system. When running low on memory, make sure that the swap directory used by the memory limit feature is located on local disk. Also, solid state disks (SSDs) are highly preferred over traditional rotating disks.

4.1.4 Workload Characteristics

The performance of Simics sometimes depends on the kind of software that runs inside the target machine being simulated. Thus, the slowdown can vary a lot depending on what the target software is currently executing. Here are some general tips for understanding what decreases simulation speed.

Floating-point intense workloads
If the target software runs floating-point arithmetic instructions frequently, the performance is likely lower compared to running integer based workloads. The same is usually true for workloads with frequent use of SIMD-style media instructions.
Supervisor code
If a workload runs much of the code in supervisor mode such as frequently causing exceptions, this type of code normally runs slower than regular user-level code.
I/O workloads
If the code does frequent accesses to devices, compared to accessing RAM, Simics needs to do more work to simulate this, which slows down simulation. Note that this type of workload is an excellent candidate for a lower IPC setting.
Memory usage
If the target software is using more memory than available on the host. This is typically a problem when the simulated machine has equal or more memory than the host it executes on and the software also uses it. This will cause Simics to swap out pages on disk, which decreases performance.
Event usage
Simics modules which frequently post events with short time quanta. For example, if a device posts an event every 10th cycle, to keep a counter register updated, this will severely affect performance.

Typically, target code which runs with low performance on real hardware due to bad cache behavior, bad memory locality etc. will also cause Simics to run with poor performance.

4.1.4.1 Idle Loops and Performance

When an operating system does not have any processes to schedule, it typically runs some tight loop waiting for an interrupt to occur. This is referred to as the idle loop. The way the idle loop is implemented varies between operating systems and the capabilities in the underlying hardware.

For example, the most simple idle loop would be a “branch to itself” instruction. When the processor reaches this instruction, nothing but an interrupt will cause the execution to proceed somewhere else. Another example is when the operating system uses some kind of power-down mode on the processor, causing the processor to stop executing any more instructions (and consequently consume less power). Some processors also have dedicated instructions causing the processor to stop until something interesting happens, such as the x86 HLT instruction. Processor idling in Simics is defined by what the simulator can detect and usually includes architectural states such as halt or power-down, but can also be loops normally executed by the processor.

A fast simulation of the idle loop, is very important in some cases. For example, when simulating multiple processors, we want to use as much of the host CPU cycles as possible for simulating the processor that actually performs useful tasks. Rather than wasting cycles on the idle loop.

Even when simulating a single CPU, fast idle loops can be important, since all of the active processes might be stalling on disk or some other peripheral. Execution of the processes will not continue unless, for example, a disk issues an interrupt.

Simics processor models can sometimes detect idle conditions. When the processor model detects a branch to itself, there is no point in simulating the instruction, if it branches to itself repeatedly.

Instead, Simics is capable of fast-forwarding time until an event that can generate an interrupt is about to be executed. Hence, this model is equivalent to running the branch millions of times, but is much faster.

In some cases, the idle loop in the operating system is more than a single instruction, e.g., it might be a loop checking a variable in memory for the next process to schedule. These more difficult cases can be handled with hypersimulation (see chapter 4.1.5).

4.1.5 Hypersimulation

The term hypersimulation refers to a simulator feature which can detect, analyze and understand, frequently executed target instructions and fast-forward the simulation of these, thus providing the corresponding results more rapidly.

Being able to detect the idle loop (see chapter 4.1.4.1) is one example of when this technique is applicable. A much more extreme hypersimulation task would be to understand a complete program and simply provide the corresponding result without actually starting the program. Naturally, this is hardly ever applicable, and impossible in general. Busy-wait loops and spin-locks are more realistic examples of cases where it is easy to optimize away the execution with hypersimulation.

Hypersimulation can be achieved in several ways:

The following instructions are handled with CPU handled instruction hypersimulation:

TargetInstructionComment
ARMmcrEnabling “Wait for Interrupt”
m68kstop
MIPSwait
PowerPCmtmsrSetting MSR[POW].
PowerPCb 0Branch to itself
PowerPCwait
x86hlt
x86mwait

Hypersimulation should be as non-intrusive as possible, the only difference that should be noticeable as a Simics user is the increased performance. Registers, timing, memory contents, exceptions, interrupts etc. should be identical.

Hypersimulation using the hypersim-pattern-matcher may have some intrusions regarding Simics features:

Hypersimulation using the hypersim-pattern-matcher is activated by default, and can be activated/deactivated with enable-hypersim/disable-hypersim.

The hypersim-status command gives some details on what hypersim features that are currently active.

Hypersim patterns are typically fragile, since they depend on an exact instruction pattern. Simply changing the compiler revision or an optimizing flag to the compiler can break the pattern from being recognized.

4.1.6 VMP

The VMP add-on for Simics makes use of hardware virtualization support to provide vastly improved performance when simulating x86-based systems. It is an optional part of the x86-based models.

The VMP feature requires that the host machine running Simics has the Intel® Virtualization Technology (Intel® VT) for IA-32, Intel® 64 and Intel® Architecture (Intel® VT-x) enabled in the host machine firmware (the BIOS).

Almost all Intel® processors since the original Core™ architecture, including Xeon® server processors, support the Intel® VT-x feature set. See the Intel® ARK at ark.intel.com for information on specific products.

The Intel® VT-x virtualization feature and the NX execute protection feature must also be enabled in the host machine firmware to run VMP. Look for options under either Security or Virtualization to find where to enable Intel® VT and NX in your firmware. If Intel® Trusted Execution Technology (TXT) is enabled in the firmware, it can also happen that the Intel® VT-x virtualization feature is restricted to trusted applications only; there is usually a special firmware setting controlling this behavior. VMP requires Intel® VT-x to be generally available.

All major features of Simics, including full inspectability of simulated state, and ability to model heterogeneous systems, are fully supported when running with VMP.

4.1.6.1 Installing the VMP Kernel Module

4.1.6.1.1 Linux

Installing and managing VMP kernel modules requires sudo privileges. Installing will compile the kernel module and therefore also requires an environment to build kernel modules. Which packages you need for building kernel modules depend on the distribution of Linux that you are using, but at least for certain Red Hat based distributions you would need gcc-c++, kernel-headers, and kernel-devel. Change directory to the user project and run:

[project]$ bin/vmp-kernel-install

The script will build and then load the VMP kernel module. It will not install it permanently however, but it will tell you how to do that.

Disable VMP temporarily by running the bin/vmp-kernel-unload script, and enable VMP with the bin/vmp-kernel-load script. Permanently uninstall VMP from your host by running the bin/vmp-kernel-uninstall script.

If the installation is read-only, or if you for some other reason want to have the built VMP artifacts outside of the installation, you can give a directory to the relevant VMP scripts, for example:

[project]$ bin/vmp-kernel-install /somewhere/directory

4.1.6.1.2 Windows

The kernel module can be loaded and unloaded by running the bin\vmp-kernel-load.bat respective bin\vmp-kernel-unload.bat scripts as administrator. To do that, open a command shell as administrator and run:

[project]> bin\vmp-kernel-load.bat

Another way to perform the same action would be to right-click on vmp-kernel-load.bat and select run as administrator.

The /AUTO and /DEMAND options select the start option for the VMP service. With /AUTO (default), the service will be available after restart whereas with /DEMAND makes the service available just until shutdown or reboot, and then VMP has to be loaded again when needed.

If the script fails, see the Windows event log for more information. The most common reason is that Intel® VT-x technology or the NX feature is not enabled in the UEFI/BIOS. The kernel module will also fail to load if the Hyper-V feature is enabled.

4.1.6.1.3 Hyper-V Interaction

Windows 8 and later can be run with Hyper-V enabled. Hyper-V is a feature where the operating system is run as a guest under the control of a hypervisor. VMP cannot be used in conjunction with Hyper-V: loading the VMP kernel module will fail.

There are various ways to disable the Hyper-V feature. Below are instructions for adding an additional boot configuration database entry to make it easy to boot with Hyper-V disabled:

4.1.6.2 Running with the VMP Add-on

With the VMP kernel modules installed, VMP will be enabled by default for each processor. You can disable VMP by running the disable-vmp command.

Due to details about how the Intel® VT feature that VMP is based on works, the acceleration may not kick in. Use new-system-perfmeter -cpu-exec-modes to find out if a processor actually uses the VMP execution mode. To find out why VMP is not used, either raise the log level of the CPU in question or use the info command on the CPU.

4.1.6.3 Current Limitations of the VMP Add-on

The VMP packages are currently available and supported for Linux and Windows.

Due to bugs in the performance counters on many Intel CPU types, precise instruction counting cannot be achieved with VMP. The only CPU types that we are aware of that do not have this bug are Intel® Core™ Duo/Solo, and Pentium® 4 processors. As a result, slight differences in timing between runs will appear and cannot be avoided due to the bug in the underlying hardware.

Software using hardware virtualization frequently have problems co-existing on a machine. If you are running other software using hardware virtualization such as VMware, VirtualBox, KVM, or Intel® Hardware Accelerated Execution Manager (Intel® HAXM), you may need to unload the driver corresponding to that software before using VMP.

Note that virtualizers such as VMware or Xen in most versions do not expose the Intel® VT feature. Even virtualizers that do expose the Intel® VT feature are likely to either lack support for the performance counters needed to run with VMP, or will have very different performance characteristics compared to native solutions. To summarize, it is highly recommended that VMP is run in a non-virtualized environment.

4.1.6.4 Differences Between VMP and non-VMP

VMP is designed to be a transparent performance enhancement. The implementation with Intel® VT-x makes that impossible in some areas, and in some other areas we have taken the chance to utilize the VMP mode to tweak performance further. Enabling features that cannot be emulated using Intel® VT-x will automatically disable VMP.

VMP is optimized for software development, and the default timing parameters used in VMP reflect that. The timing settings can be viewed with the info command on the CPU object. As default, VMP timing will stall the PAUSE instruction, the RDTSC instruction, and each port-mapped I/O access for 10 milliseconds. These stalls are added to allow loops containing these operations to consume more virtual time per iteration and therefore speed up simulation if the loop is terminated after a set virtual time. This is controlled by attributes in the CPU object and can be changed if somewhat more realistic timing is more important than maximum simulation speed.

The hardware performance counters are used to figure out the number of executed instructions when running in VMP mode. Since those counters count string instructions as one regardless of the number of iterations, this is the instruction count model that must be used to enable VMP. This is controlled by the one_step_per_string_instruction attribute, and setting that to classic counting will disable VMP.

The TLB model is bypassed in VMP mode. To simulate a particular configuration of the TLB, or listen to the haps that the TLB model generates, VMP has to be manually disabled.

4.1.7 Performance Tweaks

Before tweaking any parameters, it is a good idea to first generate a new-system-perfmeter HTML report (see Useful Performance Scenarios), using the explore probe-collection. The report’s “Analysis” section automatically scores the collected probe data against a set of rules and flags anything that looks like a potential concern, which can save time compared to guessing which of the tweaks below might be relevant. This works without any AI support; adding the -ai switch to html-report additionally asks an AI agent to write a narrative summary on top of the same findings.

The -ai switch relies on the general ai-mode feature in Simics, which currently requires a working gh copilot setup (a GitHub Copilot license and the GitHub CLI with the Copilot extension, authenticated). Make sure ai-mode itself works before trying -ai; see help ai-mode for prerequisites and setup instructions.

There are a number of parameters in Simics which can be tweaked which might lead to increased performance.

4 Performance 4.2 Scaling Simics