24.22.4.1. gem5 event queue AtomicSimpleCPU syscall emulation freestanding example analysis
Let’s now analyze every single event on a minimal gem5 syscall emulation mode in the simplest CPU that we have:
./run \ --arch aarch64 \ --emulator gem5 \ --userland userland/arch/aarch64/freestanding/linux/hello.S \ --trace Event,ExecAll,FmtFlag \ --trace-stdout \ ;
which gives:
0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 scheduled @ 0 **** REAL SIMULATION **** 0: Event: Event_70: generic 70 scheduled @ 0 info: Entering event queue @ 0. Starting simulation... 0: Event: Event_70: generic 70 rescheduled @ 18446744073709551615 0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 0 0: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue : movz x0, #1, #0 : IntAlu : D=0x0000000000000001 flags=(IsInteger) 0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 500 500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 500 500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+4 : adr x1, #28 : IntAlu : D=0x0000000000400098 flags=(IsInteger) 500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 1000 1000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 1000 1000: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+8 : ldr w2, #4194464 : MemRead : D=0x0000000000000006 A=0x4000a0 flags=(IsInteger|IsMemRef|IsLoad) 1000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 1500 1500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 1500 1500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+12 : movz x8, #64, #0 : IntAlu : D=0x0000000000000040 flags=(IsInteger) 1500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 2000 2000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 2000 2000: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+16 : svc #0x0 : IntAlu : flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall) hello 2000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 2500 2500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 2500 2500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+20 : movz x0, #0, #0 : IntAlu : D=0x0000000000000000 flags=(IsInteger) 2500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 3000 3000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 3000 3000: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+24 : movz x8, #93, #0 : IntAlu : D=0x000000000000005d flags=(IsInteger) 3000: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 3500 3500: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 3500 3500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+28 : svc #0x0 : IntAlu : flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall) 3500: Event: Event_71: generic 71 scheduled @ 3500 3500: Event: Event_71: generic 71 executed @ 3500
On the event trace, we can first see:
0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 scheduled @ 0
This schedules a tick event for time 0
, and leads to the first clock tick.
Then:
0: Event: Event_70: generic 70 scheduled @ 0 0: Event: Event_70: generic 70 rescheduled @ 18446744073709551615
schedules the end of time event for time 0
, which is later rescheduled to the actual end of time.
At:
0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 executed @ 0 0: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue : movz x0, #1, #0 : IntAlu : D=0x0000000000000001 flags=(IsInteger) 0: Event: AtomicSimpleCPU tick.wrapped_function_event: EventFunctionWrapped 39 rescheduled @ 500
the tick event happens, the instruction runs, and then the instruction is rescheduled in 500
time units. This is done at the end of AtomicSimpleCPU::tick()
:
if (_status != Idle) reschedule(tickEvent, curTick() + latency, true);
At:
3500: ExecEnable: system.cpu: A0 T0 : @asm_main_after_prologue+28 : svc #0x0 : IntAlu : flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall) 3500: Event: Event_71: generic 71 scheduled @ 3500 3500: Event: Event_71: generic 71 executed @ 3500
the exit system call is called, and then it schedules an exit evit, which gets executed and the simulation ends.
We guess then that Event_71
comes from the SE implementation of the exit syscall, so let’s just confirm, the trace contains:
exitSimLoop() at sim_events.cc:97 0x5555594746e0 exitImpl() at syscall_emul.cc:215 0x55555948c046 exitFunc() at syscall_emul.cc:225 0x55555948c147 SyscallDesc::doSyscall() at syscall_desc.cc:72 0x5555594949b6 Process::syscall() at process.cc:401 0x555559484717 SimpleThread::syscall() at 0x555559558059 ArmISA::SupervisorCall::invoke() at faults.cc:856 0x5555572950d7 BaseSimpleCPU::advancePC() at base.cc:681 0x555559083133 AtomicSimpleCPU::tick() at atomic.cc:757 0x55555907834c
and exitSimLoop()
does:
new GlobalSimLoopExitEvent(when + simQuantum, message, exit_code, repeat);
Tested in gem5 12c917de54145d2d50260035ba7fa614e25317a3.