dhylands / rshell

Remote Shell for MicroPython
MIT License
956 stars 137 forks source link

On Windows (and Linux?) rshell is significantly slower when `-p` is specified #202

Open arbego opened 2 years ago

arbego commented 2 years ago

In PowerShell:

Without -p option: 0.76elapsed

time rshell --quiet 'exit'

0.00user 0.00system 0:00.76elapsed 0%CPU (0avgtext+0avgdata 5140maxresident)k
0inputs+0outputs (1338major+0minor)pagefaults 0swaps

With -p option: 1.77elapsed

time rshell --quiet -p COM6 'exit'

0.00user 0.00system 0:01.77elapsed 0%CPU (0avgtext+0avgdata 5128maxresident)k
0inputs+0outputs (1336major+0minor)pagefaults 0swaps
heeplr commented 1 year ago

can confirm this on linux:

$ time rshell --debug --port /dev/ttyACM0 cp -r ./src/* "/pyboard"
Debug = True
Port = /dev/ttyACM0
Baud = 115200
User = micro
Password = python
Wait = 0
List = 0
nocolor = 0
ascii = 0
Timing = 0
Quiet = 0
BUFFER_SIZE = 512
Cmd = [cp, -r, ./src/main.py, /pyboard]
Using buffer-size of 32
Connecting to /dev/ttyACM0 (buffer-size 32)...
Trying to connect to REPL  connected
Retrieving sysname ... ----- About to send 205 bytes of code to the pyboard -----
def sysname():
    try:
        import os
        return repr(os.uname().sysname)
    except:
        return repr('unknown')
output = sysname()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"'rp2'\r\n"
-----
rp2
Testing if ubinascii.unhexlify exists ... ----- About to send 224 bytes of code to the pyboard -----
def test_unhexlify():
    import ubinascii
    try:
        _ = ubinascii.unhexlify
        return True
    except:
        return False
output = test_unhexlify()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'True\r\n'
-----
Y
Retrieving root directories ... ----- About to send 150 bytes of code to the pyboard -----
def listdir(dirname):
    import os
    return os.listdir(dirname)
output = listdir('/')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"['config.json', 'main.py']\r\n"
-----
/config.json/ /main.py/
Setting time ... ----- About to send 1250 bytes of code to the pyboard -----
def set_time(rtc_time):
    rtc = None
    try:
        import pyb
        rtc = pyb.RTC()
        rtc.datetime(rtc_time)
    except:
        try:
            import pycom
            rtc_time2 = (rtc_time[0], rtc_time[1], rtc_time[2], rtc_time[4], rtc_time[5], rtc_time[6])
            import machine
            rtc = machine.RTC()
            rtc.init(rtc_time2)
        except:
            try:
                import machine
                rtc = machine.RTC()
                try:
                    rtc.datetime(rtc_time)
                except:
                    rtc.init(rtc_time)
            except:
                try:
                    import os
                    if os.uname().sysname == 'rp2':
                        setup_0 = rtc_time[0] << 12 | rtc_time[1] << 8 | rtc_time[2]
                        setup_1 = (rtc_time[3] % 7) << 24 | rtc_time[4] << 16 | rtc_time[5] << 8 | rtc_time[6]
                        machine.mem32[0x4005c004] = setup_0
                        machine.mem32[0x4005c008] = setup_1
                        machine.mem32[0x4005c00c] |= 0x10
                except:
                    pass
output = set_time((2023, 1, 11, 3, 12, 10, 9, 0))
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'None\r\n'
-----
Jan 11, 2023 12:10:09
Evaluating board_name ... ----- About to send 479 bytes of code to the pyboard -----
def board_name(default):
    try:
        import board
        try:
            name = board.name
        except AttributeError:
            name = default
    except ImportError:
        name = default
    except BaseException as err:
        print('Error encountered executing board.py')
        import sys
        sys.print_exception(err)
        name = default
    return repr(name)
output = board_name('pyboard')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"'pyboard'\r\n"
-----
pyboard
Retrieving time epoch ... ----- About to send 215 bytes of code to the pyboard -----
def get_time_epoch():
    import time
    try:
      return time.gmtime(0)
    except:
      return (2000, 1, 1, 0, 0, 0, 0, 0)
output = get_time_epoch()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'(1970, 1, 1, 0, 0, 0, 3, 1)\r\n'
-----
Jan 01, 1970
Executing "cp -r ./src/main.py /pyboard"
----- About to send 204 bytes of code to the pyboard -----
def get_mode(filename):
    import os
    try:
        return os.stat(filename)[0]
    except OSError:
        return 0
output = get_mode('/')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'16384\r\n'
-----
----- About to send 666 bytes of code to the pyboard -----
def is_visible(filename):
    return filename[0] != '.' and filename[-1] != '~'

def stat(filename):
    import os
    rstat = os.stat(filename)
    return rstat[:7] + tuple(tim + 0 for tim in rstat[7:])

def listdir_stat(dirname, show_hidden=True):
    import os
    try:
        files = os.listdir(dirname)
    except OSError:
        return None
    if dirname == '/':
        return list((file, stat('/' + file)) for file in files if is_visible(file) or show_hidden)
    return list((file, stat(dirname + '/' + file)) for file in files if is_visible(file) or show_hidden)
output = listdir_stat('/')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"[('config.json', (32768, 0, 0, 0, 0, 0, 16, 1673438561, 1673438561, 1673438561)), ('main.py', (32768, 0, 0, 0, 0, 0, 1018, 1673438986, 1673438986, 1673438986))]\r\n"
-----
Copying '/home/daniel/code/embedded/pico/bike-alarm/fw/src/main.py' to '/pyboard/main.py' ...
----- About to send 1747 bytes of code to the pyboard -----
def recv_file_from_host(src_file, dst_filename, filesize, dst_mode='wb'):
    import sys
    import ubinascii
    import os
    if False:
        try:
            import micropython
            micropython.kbd_intr(-1)
        except:
            pass
    try:
        import time
        with open(dst_filename, dst_mode) as dst_file:
            bytes_remaining = filesize
            if not False:
                bytes_remaining *= 2
            buf_size = 32
            write_buf = bytearray(buf_size)
            read_buf = bytearray(buf_size)
            while bytes_remaining > 0:
                sys.stdout.write('\x06')
                read_size = min(bytes_remaining, buf_size)
                buf_remaining = read_size
                buf_index = 0
                while buf_remaining > 0:
                    if False:
                        bytes_read = sys.stdin.buffer.readinto(read_buf, read_size)
                    else:
                        bytes_read = sys.stdin.readinto(read_buf, read_size)
                    time.sleep_ms(20)
                    if bytes_read > 0:
                        write_buf[buf_index:bytes_read] = read_buf[0:bytes_read]
                        buf_index += bytes_read
                        buf_remaining -= bytes_read
                if False:
                    dst_file.write(write_buf[0:read_size])
                else:
                    dst_file.write(ubinascii.unhexlify(write_buf[0:read_size]))
                if hasattr(os, 'sync'):
                    os.sync()
                bytes_remaining -= read_size
        return True
    except:
        return False
output = recv_file_from_host(None, '/main.py', 1018)
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'True\r\n'
-----
rshell --debug --port /dev/ttyACM0 cp -r ./src/* "/pyboard"  0,24s user 0,03s system 4% cpu 5,997 total

A long delay happens right after "Using buffer-size of 32". No delay without "--port" argument.

$ time rshell --debug cp -r ./src/* "/pyboard" 
Debug = True
Port = None
Baud = 115200
User = micro
Password = python
Wait = 0
List = 0
nocolor = 0
ascii = 0
Timing = 0
Quiet = 0
BUFFER_SIZE = 512
Cmd = [cp, -r, ./src/main.py, /pyboard]
Connecting to /dev/ttyACM0 (buffer-size 512)...
Trying to connect to REPL  connected
Retrieving sysname ... ----- About to send 205 bytes of code to the pyboard -----
def sysname():
    try:
        import os
        return repr(os.uname().sysname)
    except:
        return repr('unknown')
output = sysname()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"'rp2'\r\n"
-----
rp2
Testing if sys.stdin.buffer exists ... ----- About to send 209 bytes of code to the pyboard -----
def test_buffer():
    import sys
    try:
        _ = sys.stdin.buffer
        return True
    except:
        return False
output = test_buffer()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'True\r\n'
-----
Y
Retrieving root directories ... ----- About to send 150 bytes of code to the pyboard -----
def listdir(dirname):
    import os
    return os.listdir(dirname)
output = listdir('/')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"['config.json', 'main.py']\r\n"
-----
/config.json/ /main.py/
Setting time ... ----- About to send 1251 bytes of code to the pyboard -----
def set_time(rtc_time):
    rtc = None
    try:
        import pyb
        rtc = pyb.RTC()
        rtc.datetime(rtc_time)
    except:
        try:
            import pycom
            rtc_time2 = (rtc_time[0], rtc_time[1], rtc_time[2], rtc_time[4], rtc_time[5], rtc_time[6])
            import machine
            rtc = machine.RTC()
            rtc.init(rtc_time2)
        except:
            try:
                import machine
                rtc = machine.RTC()
                try:
                    rtc.datetime(rtc_time)
                except:
                    rtc.init(rtc_time)
            except:
                try:
                    import os
                    if os.uname().sysname == 'rp2':
                        setup_0 = rtc_time[0] << 12 | rtc_time[1] << 8 | rtc_time[2]
                        setup_1 = (rtc_time[3] % 7) << 24 | rtc_time[4] << 16 | rtc_time[5] << 8 | rtc_time[6]
                        machine.mem32[0x4005c004] = setup_0
                        machine.mem32[0x4005c008] = setup_1
                        machine.mem32[0x4005c00c] |= 0x10
                except:
                    pass
output = set_time((2023, 1, 11, 3, 12, 11, 34, 0))
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'None\r\n'
-----
Jan 11, 2023 12:11:34
Evaluating board_name ... ----- About to send 479 bytes of code to the pyboard -----
def board_name(default):
    try:
        import board
        try:
            name = board.name
        except AttributeError:
            name = default
    except ImportError:
        name = default
    except BaseException as err:
        print('Error encountered executing board.py')
        import sys
        sys.print_exception(err)
        name = default
    return repr(name)
output = board_name('pyboard')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"'pyboard'\r\n"
-----
pyboard
Retrieving time epoch ... ----- About to send 215 bytes of code to the pyboard -----
def get_time_epoch():
    import time
    try:
      return time.gmtime(0)
    except:
      return (2000, 1, 1, 0, 0, 0, 0, 0)
output = get_time_epoch()
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'(1970, 1, 1, 0, 0, 0, 3, 1)\r\n'
-----
Jan 01, 1970
Executing "cp -r ./src/main.py /pyboard"
----- About to send 204 bytes of code to the pyboard -----
def get_mode(filename):
    import os
    try:
        return os.stat(filename)[0]
    except OSError:
        return 0
output = get_mode('/')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'16384\r\n'
-----
----- About to send 666 bytes of code to the pyboard -----
def is_visible(filename):
    return filename[0] != '.' and filename[-1] != '~'

def stat(filename):
    import os
    rstat = os.stat(filename)
    return rstat[:7] + tuple(tim + 0 for tim in rstat[7:])

def listdir_stat(dirname, show_hidden=True):
    import os
    try:
        files = os.listdir(dirname)
    except OSError:
        return None
    if dirname == '/':
        return list((file, stat('/' + file)) for file in files if is_visible(file) or show_hidden)
    return list((file, stat(dirname + '/' + file)) for file in files if is_visible(file) or show_hidden)
output = listdir_stat('/')
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b"[('config.json', (32768, 0, 0, 0, 0, 0, 16, 1673438561, 1673438561, 1673438561)), ('main.py', (32768, 0, 0, 0, 0, 0, 1018, 1673439011, 1673439011, 1673439011))]\r\n"
-----
Copying '/home/daniel/code/embedded/pico/bike-alarm/fw/src/main.py' to '/pyboard/main.py' ...
----- About to send 1744 bytes of code to the pyboard -----
def recv_file_from_host(src_file, dst_filename, filesize, dst_mode='wb'):
    import sys
    import ubinascii
    import os
    if True:
        try:
            import micropython
            micropython.kbd_intr(-1)
        except:
            pass
    try:
        import time
        with open(dst_filename, dst_mode) as dst_file:
            bytes_remaining = filesize
            if not True:
                bytes_remaining *= 2
            buf_size = 512
            write_buf = bytearray(buf_size)
            read_buf = bytearray(buf_size)
            while bytes_remaining > 0:
                sys.stdout.write('\x06')
                read_size = min(bytes_remaining, buf_size)
                buf_remaining = read_size
                buf_index = 0
                while buf_remaining > 0:
                    if True:
                        bytes_read = sys.stdin.buffer.readinto(read_buf, read_size)
                    else:
                        bytes_read = sys.stdin.readinto(read_buf, read_size)
                    time.sleep_ms(20)
                    if bytes_read > 0:
                        write_buf[buf_index:bytes_read] = read_buf[0:bytes_read]
                        buf_index += bytes_read
                        buf_remaining -= bytes_read
                if True:
                    dst_file.write(write_buf[0:read_size])
                else:
                    dst_file.write(ubinascii.unhexlify(write_buf[0:read_size]))
                if hasattr(os, 'sync'):
                    os.sync()
                bytes_remaining -= read_size
        return True
    except:
        return False
output = recv_file_from_host(None, '/main.py', 1018)
if output is None:
    print("None")
else:
    print(output)

-----
-----Response-----
b'True\r\n'
-----
rshell --debug cp -r ./src/* "/pyboard"  0,21s user 0,03s system 30% cpu 0,775 total
github0null commented 3 months ago

Hello,

I have also found this problem,

This line will not work on Windows when '-p COMx' is specified

https://github.com/dhylands/rshell/blob/56f75cf846b2fd89f9a89c08a9dabd8015c30931/rshell/main.py#L1422

I have post a PR to fix it.

https://github.com/dhylands/rshell/pull/233