Search code examples
pythonlinuxsystem-callscpu-architecturegem5

Gem5 not working when executing a python script



I'm trying to execute a simple python script and pass command line parameters to just do simple addition of numbers in gem5 Command:

sudo ./build/X86/gem5.opt configs/example/se.py --cmd /usr/bin/python3 --options "sum.py 3 4"

sum.py source code:

import sys
x=int(sys.argv[1])
y=int(sys.argv[2])
sum=x+y
print("The addition is :",sum)

Error I got:

osboxes@osboxes:~/gem5$ sudo ./build/X86/gem5.opt configs/example/se.py --cmd /usr/bin/python3 --options "sum.py 3 4"
gem5 Simulator System.  http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.

gem5 version 21.0.0.0
gem5 compiled Aug  5 2021 21:03:24
gem5 started Aug 11 2021 20:44:15
gem5 executing on osboxes, pid 4072
command line: ./build/X86/gem5.opt configs/example/se.py --cmd /usr/bin/python3 --options 'sum.py 3 4'

warn: membus.slave is deprecated. `slave` is now called `cpu_side_ports`
warn: membus.slave is deprecated. `slave` is now called `cpu_side_ports`
warn: membus.slave is deprecated. `slave` is now called `cpu_side_ports`
warn: membus.slave is deprecated. `slave` is now called `cpu_side_ports`
warn: membus.slave is deprecated. `slave` is now called `cpu_side_ports`
warn: membus.master is deprecated. `master` is now called `mem_side_ports`
warn: membus.master is deprecated. `master` is now called `mem_side_ports`
warn: membus.slave is deprecated. `slave` is now called `cpu_side_ports`
Global frequency set at 1000000000000 ticks per second
warn: DRAM device capacity (8192 Mbytes) does not match the address range assigned (512 Mbytes)
warn: Not reserving swap space. May cause SIGSEGV on actual usage
0: system.remote_gdb: listening for remote gdb on port 7000
** REAL SIMULATION **
info: Entering event queue @ 0.  Starting simulation...
warn: ignoring syscall access(...)
warn: ignoring syscall access(...)
warn: ignoring syscall access(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall access(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall access(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall access(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall access(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall access(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall access(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall mprotect(...)
warn: ignoring syscall set_robust_list(...)
warn: ignoring syscall rt_sigaction(...)
      (further warnings will be suppressed)
warn: ignoring syscall rt_sigprocmask(...)
      (further warnings will be suppressed)
fatal: Syscall 318 out of range
Memory Usage: 705664 KBytes

Can anyone let me know where I'm going wrong in executing the python script. Any help would be appreciated.

Thanks


Solution

  • System call #318 is __NR_getrandom for x86-64 Linux (see asm/unistd_64.h). See the getrandom(2) man page for the system call. CPython uses it if available instead of open("/dev/urandom"), as part of the implementation for os.getrandom. (It may not be practical or even possible to avoid calling that by just changing the .py you run the interpreter on.)

    It's pretty new, e.g. getrandom syscall in C not found mentions that many GNU/Linux distros in 2017 hadn't yet updated to a glibc that contained a wrapper function for it (to make calling from C easy). So I'm not surprised that gem5's single-process mode (not system mode) doesn't have a handler for it.

    https://bugs.python.org/issue27955 indicates that Python's os.getrandom will attempt to use it, only falling back to open("/dev/urandom") if it doesn't exist (i.e. returns -ENOSYS). That issue was a NAS kernel returning -EPERM instead, fixed by having CPython also treat that as not available.

    Your case is similar: instead of returning -ENOSYS for system calls it doesn't know about (which would trigger graceful fallback in this case), GEM5 treats it as a fatal error. That means there's no way for CPython to stay safe except for never attempting to use that system call in the first place. An old version of python3 would probably be safe, or a custom build that comments out the optimistic attempt.

    If there's a way to change that GEM5 behaviour, that would also do it. e.g. find the code that prints that error, and change it to instead return -ENOSYS for unsupported call numbers, like a real Linux kernel. (If there isn't a GEM5 option to do that already.)

    TL:DR: your options are one of:

    • Find a GEM5 option to handle unknown system calls differently if there is one.
    • or: Change the GEM5 source code to return -ENOSYS instead of aborting with that fatal error and build GEM5 from that source.
    • or: Rebuild CPython from source after changing its os.getrandom implementation in C.
    • or: Use an old python3 binary from before it tried to use Linux getrandom(2).

    The CPython interpreter is not a simple little program; it's written in C and it's large.

    Remember that you're profiling /usr/bin/python3 with your .py as input data to that compiled binary executable. That's what you're profiling; remember that CPython is purely an interpreter.

    At no point is your "simple addition" ever directly running as native machine code, except that the interpreter will end up dispatching to a handler for the addition operator, which will check whether the inputs are both "simple" (fitting in one chunk of Python's extended precision integer data structure) or not, and if so doing the special case which probably involves a C + operation which probably compiles to an x86 add or lea instruction, but much more code just to get to that point. Massive interpreter overhead vs. a compiled C program.