sim β Simulation Engine
The discrete-event simulation core that drives gem5's timing model, managing object lifecycles, event scheduling, and system-level coordination.
The sim module is like the engine of a car. While other modules (CPU, memory, caches) are the wheels, seats, and body, the sim module provides the crankshaft (EventQueue), the chassis (SimObject hierarchy), and the control computer (System) that makes everything run together in lockstep.
Architecture Overview
The sim module forms the foundation of gem5's discrete-event simulation framework. It provides three pillars: SimObject β the universal base class for all simulated components, EventQueue β the priority-driven scheduling engine, and System β the top-level container binding CPUs, memory, and workloads together.
graph TB
SimObject["SimObject\n(base class)"]
ClockedObject["ClockedObject\n(clock domain aware)"]
System["System\n(top-level container)"]
Process["Process\n(SE mode)"]
EventQueue["EventQueue\n(scheduling)"]
Event["Event\n(scheduled action)"]
Workload["Workload\n(FS/SE)"]
PowerState["PowerState"]
VoltageDomain["VoltageDomain"]
SimObject --> ClockedObject
SimObject --> Workload
SimObject --> Process
ClockedObject --> System
Workload --> KernelWorkload["KernelWorkload"]
Workload --> SEWorkload["SEWorkload"]
EventQueue --> Event
System --> VoltageDomain
ClockedObject --> PowerState
SimObject Hierarchy
Every component in gem5 β CPUs, caches, buses, memories β inherits from SimObject. This base class provides a uniform interface for construction (via Python-generated Params), initialization, serialization (checkpointing), and statistics registration.
SimObject Lifecycle
SimObjects follow a strict initialization protocol:
- Construction β Python creates Params structs, C++ constructors receive them
init()β Post-construction setup, resolve cross-object referencesregStats()β Register statistics countersregProbePoints()β Register probe points for instrumentationstartup()β Schedule initial events, final setup
class SimObject : public EventManager, public Serializable, public Drainable, public statistics::Group
{
public:
typedef SimObjectParams Params;
const Params ¶ms() const;
SimObject(const Params &p);
virtual ~SimObject();
virtual void init();
virtual void startup();
virtual void regStats();
virtual void regProbePoints();
virtual void regProbeListeners();
// Serialization for checkpointing
void serializeSection(CheckpointOut &cp, const char *name) const;
void unserializeSection(CheckpointIn &cp, const char *name);
// Find SimObject by name
static SimObject *find(const char *name);
};
ClockedObject
ClockedObject extends SimObject with clock domain awareness. It associates each object with a ClockDomain, enabling cycle-accurate timing. Components use clockEdge() to align operations to clock boundaries and cyclesToTicks() for time conversion.
class ClockedObject : public SimObject
{
ClockDomain &clockDomain;
Tick tick;
Cycles cycle;
public:
Tick clockEdge(Cycles cycles = Cycles(0)) const;
Tick cyclesToTicks(Cycles c) const;
Tick clockPeriod() const;
double voltage() const;
Cycles ticksToCycles(Tick t) const;
PowerState *powerState;
};
Event System
gem5 uses a discrete-event simulation model where the EventQueue maintains a time-ordered queue of Event objects. The simulation loop repeatedly dequeues the earliest event, advances simulation time, and invokes the event's process() method.
sequenceDiagram
participant Main as simulate()
participant EQ as EventQueue
participant Ev as Event
participant Obj as SimObject
Main->>EQ: serviceOne()
EQ->>EQ: dequeue head event
EQ->>Ev: process()
Ev->>Obj: execute action
Obj->>EQ: schedule(newEvent, when)
EQ->>EQ: insert sorted by time+priority
Main->>EQ: serviceOne() [next iteration]
Event Priorities
Events at the same tick are ordered by priority. gem5 defines several standard priorities to ensure correct execution order within a single simulation tick:
| Priority | Value | Description |
|---|---|---|
| Minimum_Pri | -128 | Earliest possible within a tick |
| Debug_Enable_Pri | -101 | Debug flag enable/disable |
| Debug_Break_Pri | -100 | Debugger breakpoints |
| CPU_Tick_Pri | 0 | Default CPU tick events |
| DVFS_Update_Pri | 31 | DVFS transitions |
| Serialize_Pri | 32 | Checkpoint serialization |
| CPU_Exit_Pri | 64 | CPU exit events |
| Stat_Event_Pri | 90 | Pipeline β gem5 Wiki" class="xref">Statistics dumping |
| Sim_Exit_Pri | 100 | Simulation exit |
| Maximum_Pri | 127 | Latest possible within a tick |
Event Class
class Event : public Serializable
{
public:
typedef int8_t Priority;
Event(Priority p = Default_Pri, Flags f = AutoDelete);
virtual ~Event();
virtual void process() = 0; // Override to define action
virtual const char *description() const;
bool scheduled() const;
Tick when() const;
Priority priority() const;
void squash() { flags.set(Squashed); }
bool squashed() const { return flags.isSet(Squashed); }
};
System and Workloads
The System class is the top-level container that binds all components together. It manages the physical memory address map, tracks all CPUs, provides access to the workload, and coordinates full-system vs. syscall-emulation modes.
System Class
class System : public SimObject
{
public:
std::vector<BaseRemoteGDB *> remoteGDB;
std::vector<ThreadContext *> threads;
Workload *workload;
PhysicalMemory physmem;
Enums::MemoryMode memoryMode;
AddrRangeList shadowRomRanges;
// Memory access
bool isMemAddr(Addr addr) const;
PortProxy &getPhysMem();
Addr memSize() const;
// Thread context management
void registerThreadContext(ThreadContext *tc);
int numContexts() const;
ThreadContext *threads[int id];
};
Workload Hierarchy
The workload abstraction decouples the simulated system from the software being run:
- Workload β Abstract base managing object files, symbol tables, entry points
- KernelWorkload β Loads kernel images for full-system simulation, handles kernel symbols and command lines
- SEWorkload β Manages syscall-emulation processes, maps system calls to host OS
Process & Syscall Emulation
The Process class models a user-space process in syscall emulation (SE) mode. It provides virtual memory (MemState), file descriptor tracking (FDArray), and system call dispatching without requiring a full OS kernel.
class Process : public SimObject
{
public:
System *system;
std::shared_ptr<MemState> memState;
std::shared_ptr<FDArray> fds;
Addr brk_point; // Current brk() address
Addr stack_base; // Stack base address
Addr mmap_end; // mmap region boundary
ObjectFile *objFile; // Loaded binary
SymbolTable *symtab; // Symbol table
virtual void initState();
virtual void syscall(ThreadContext *tc);
// VMA management
void allocateMem(Addr vaddr, int64_t size, bool clobber = false);
bool mmapGrowsDown() const;
};
Simulation Control
The simulate() function is the main simulation loop entry point. It processes events from the EventQueue until a simulation exit event fires or the maximum tick count is reached.
// Core simulation entry β returns when exit event is triggered
GlobalSimLoopExitEvent *simulate(Tick num_cycles = MaxTick);
// Exit events for terminating simulation
class GlobalSimLoopExitEvent : public GlobalEvent
{
std::string cause;
int code;
public:
const std::string getCause() const { return cause; }
int getCode() const { return code; }
};
π Narrated Walkthrough: Simulation Startup & Event Cycle
- Python Configuration β User writes a Python script instantiating SimObjects (CPU, Cache Hierarchy | gem5 Wiki" href="../mem_doc/cache/index.html">cache, memory, bus). The Python layer generates
Paramsstructs for each. - C++ Construction β
m5.instantiate()creates all C++ SimObjects from their Params. Each constructor registers with the global SimObject list. - Initialization Phase β
init()called on all objects (resolve ports, connect wires). ThenregStats()registers statistics counters. - Startup Phase β
startup()called on all objects. CPUs schedule their first tick events. Memory controllers initialize their state machines. - Event Loop β
simulate()enters the main loop. Each iteration callseventq->serviceOne(), which dequeues the earliest event and callsprocess(). - Event Cascade β A CPU tick event might generate a cache access event, which generates a memory request event, creating a chain of events across the simulated timeline.
- Exit β When a
SimLoopExitEventfires (e.g., max instructions reached), control returns to Python with the exit cause string.
Key Components Reference
| Component | Header | Purpose | Category |
|---|---|---|---|
SimObject | sim_object.hh | Universal base class for all simulated components | Core |
EventQueue | eventq.hh | Time-ordered priority queue for discrete events | Core |
Event | eventq.hh | Schedulable action with time and priority | Core |
System | system.hh | Top-level container binding all components | Core |
ClockedObject | clocked_object.hh | SimObject with clock domain support | Core |
Process | process.hh | User-space process for SE mode | Core |
Workload | workload.hh | Abstract workload base class | Config |
KernelWorkload | kernel_workload.hh | Full-system kernel image loading | Config |
SEWorkload | se_workload.hh | Syscall-emulation workload manager | Config |
VoltageDomain | voltage_domain.hh | Voltage domain for DVFS | Power |
DVFSHandler | dvfs_handler.hh | Dynamic voltage/frequency scaling controller | Power |
PowerDomain | power_domain.hh | Hierarchical power domain management | Power |
TickedObject | ticked_object.hh | SimObject with periodic tick events | Util |
GlobalEvent | global_event.hh | Events synchronized across all event queues | Core |
FaultBase | faults.hh | Base class for architectural faults/exceptions | Core |
Sub-Modules
β‘ power
Power state modeling, thermal simulation, DVFS control, and energy estimation for simulated components.
5 classes㪠probe
Non-intrusive instrumentation framework using ProbePoints and ProbeListeners for runtime monitoring.
4 classesCross-Module Connections
graph LR
sim["sim\n(SimObject, EventQueue)"]
base["base\n(types, stats, debug)"]
cpu["cpu\n(BaseCPU)"]
mem["mem\n(MemObject)"]
arch["arch\n(ISA)"]
dev["dev\n(devices)"]
base -->|"Tick, Addr types"| sim
sim -->|"SimObject base"| cpu
sim -->|"SimObject base"| mem
sim -->|"SimObject base"| dev
sim -->|"System, Workload"| arch
Glossary
| Term | Definition |
|---|---|
| Tick | The fundamental time unit in gem5 (typically 1 ps = 10-12 s) |
| SE Mode | Syscall Emulation β runs user binaries by trapping syscalls to the host OS |
| FS Mode | Full System β boots a real OS kernel on simulated hardware |
| Drain | Mechanism to quiesce all components before checkpointing or switching CPU models |
| Checkpoint | Serialized snapshot of entire simulation state for resume |
| DVFS | Dynamic Voltage and Frequency Scaling β runtime power management |
| Probe Point | Named instrumentation hook for non-intrusive monitoring |