Skip to content

Commit 204ea68

Browse files
committed
default exec timeout=None, mount: removed auto-repl/monitor, added bench comparison
1 parent 987792d commit 204ea68

5 files changed

Lines changed: 29 additions & 80 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ For reporting bugs, please include `-ddd` output in the issue.
497497

498498
## Performance
499499

500-
`mpytool` uses optimized chunked transfer with automatic compression, which allows copying files very quickly. See [README_BENCH.md](README_BENCH.md) for detailed benchmarks.
500+
`mpytool` uses optimized chunked transfer with automatic compression, which allows copying files very quickly. See [README_bench.md](README_bench.md) for detailed benchmarks.
501501

502502
### Summary
503503

README_BENCH.md renamed to README_bench.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,25 @@ Higher speed achieved by automatic compression of text-based files during transf
6666
- **Skip unchanged: 1.5x - 2.9x faster** than mpremote
6767

6868
Many more test scenarios could be designed (different file types, sizes, mixed workloads), but in most cases mpytool would be **at least 2x faster** than mpremote.
69+
70+
## Mount VFS Benchmark
71+
72+
Reading files from mounted VFS (PC filesystem accessible on device).
73+
74+
### RP2040 - USB-CDC - MacOS
75+
76+
| Test | mpytool | mpremote | Speedup |
77+
|------|---------|----------|---------|
78+
| Read 50 x 2KB files | **1.5s** | 3.9s | **2.5x** |
79+
| Read 1 x 100KB file | **1.0s** | 1.1s | **1.1x** |
80+
81+
### ESP32-C6 - USB-CDC - MacOS
82+
83+
| Test | mpytool | mpremote | Speedup |
84+
|------|---------|----------|---------|
85+
| Read 50 x 2KB files | **0.6s** | 3.2s | **5.6x** |
86+
| Read 1 x 100KB file | **0.3s** | 0.5s | **1.8x** |
87+
88+
### Summary
89+
90+
Batch LISTDIR (1 RTT) vs iterative ilistdir (N+1 RTT) makes significant difference when opening many files. The speedup is more pronounced on faster CPUs (ESP32-C6 160MHz vs RP2040 133MHz).

mpytool/mpy_comm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,12 @@ def reset_state(self):
182182
self._repl_mode = None
183183
self._raw_paste_supported = None
184184

185-
def exec(self, command, timeout=5):
185+
def exec(self, command, timeout=None):
186186
"""Execute command
187187
188188
Arguments:
189189
command: command to execute
190-
timeout: maximum waiting time for result,
190+
timeout: maximum waiting time for result (None = wait forever),
191191
0 = submit only (send code, don't wait for output)
192192
193193
Returns:

mpytool/mpytool.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import fnmatch as _fnmatch
55
import importlib.metadata as _metadata
66
import os as _os
7+
import sys as _sys
78
import time as _time
89

910
import mpytool as _mpytool
@@ -410,6 +411,9 @@ def cmd_repl(self):
410411
if not _terminal.AVAILABLE:
411412
self._log.error("REPL not available on this platform")
412413
return
414+
if not _sys.stdin.isatty():
415+
self._log.error("REPL requires interactive terminal")
416+
return
413417
self.verbose("REPL (Ctrl+] to exit)", 1)
414418
terminal = _terminal.Terminal(self.conn, self._log)
415419
terminal.run()
@@ -1316,26 +1320,6 @@ def _parse_chunk_size(value):
13161320
return num
13171321

13181322

1319-
def _mount_auto_repl(command_groups):
1320-
"""Append repl to command groups if mount is used without terminal command.
1321-
1322-
mount requires mpytool to stay alive (PC handles FS requests).
1323-
If the last command after mount is not repl or monitor, auto-append repl.
1324-
"""
1325-
# mount with args = real mount (needs repl to stay alive)
1326-
# mount without args = listing only (no repl needed)
1327-
has_mount = any(
1328-
group[0] == 'mount' and len(group) > 1
1329-
for group in command_groups if group)
1330-
if not has_mount:
1331-
return
1332-
# Check first item (command name) of last group
1333-
last_group = command_groups[-1] if command_groups else []
1334-
last_cmd = last_group[0] if last_group else None
1335-
if last_cmd not in ('repl', 'monitor'):
1336-
command_groups.append(['repl'])
1337-
1338-
13391323
def _build_main_parser():
13401324
"""Build the main argument parser."""
13411325
_description = _about["Summary"] if _about else None
@@ -1402,8 +1386,6 @@ def main():
14021386
force=args.force, compress=compress, chunk_size=args.chunk_size,
14031387
port=args.port, address=args.address, baudrate=args.baud)
14041388
command_groups = _utils.split_commands(args.commands)
1405-
# Auto-REPL for mount: if mount is used and last command is not repl/monitor
1406-
_mount_auto_repl(command_groups)
14071389
try:
14081390
with_progress = args.verbose >= 1
14091391
_run_commands(mpy_tool, command_groups, with_progress=with_progress)

tests/test_mount.py

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -713,61 +713,6 @@ def test_reboot_split_across_reads(self):
713713
self.assertTrue(intercept._needs_remount)
714714

715715

716-
class TestMountAutoRepl(unittest.TestCase):
717-
"""Tests for auto-REPL logic with mount command"""
718-
719-
def test_mount_only(self):
720-
"""mount without repl/monitor appends repl"""
721-
from mpytool.mpytool import _mount_auto_repl
722-
groups = [['mount', './src']]
723-
_mount_auto_repl(groups)
724-
self.assertEqual(len(groups), 2)
725-
self.assertEqual(groups[1], ['repl'])
726-
727-
def test_mount_with_repl(self):
728-
"""mount -- repl does not append extra repl"""
729-
from mpytool.mpytool import _mount_auto_repl
730-
groups = [['mount', './src'], ['repl']]
731-
_mount_auto_repl(groups)
732-
self.assertEqual(len(groups), 2)
733-
734-
def test_mount_with_monitor(self):
735-
"""mount -- monitor does not append repl"""
736-
from mpytool.mpytool import _mount_auto_repl
737-
groups = [['mount', './src'], ['monitor']]
738-
_mount_auto_repl(groups)
739-
self.assertEqual(len(groups), 2)
740-
741-
def test_mount_with_exec(self):
742-
"""mount -- exec "..." appends repl"""
743-
from mpytool.mpytool import _mount_auto_repl
744-
groups = [['mount', './src'], ['exec', 'import app']]
745-
_mount_auto_repl(groups)
746-
self.assertEqual(len(groups), 3)
747-
self.assertEqual(groups[2], ['repl'])
748-
749-
def test_mount_exec_monitor(self):
750-
"""mount -- exec -- monitor does not append repl"""
751-
from mpytool.mpytool import _mount_auto_repl
752-
groups = [['mount', './src'], ['exec', 'import app'], ['monitor']]
753-
_mount_auto_repl(groups)
754-
self.assertEqual(len(groups), 3)
755-
756-
def test_no_mount(self):
757-
"""Without mount, no auto-repl"""
758-
from mpytool.mpytool import _mount_auto_repl
759-
groups = [['exec', 'print(1)']]
760-
_mount_auto_repl(groups)
761-
self.assertEqual(len(groups), 1)
762-
763-
def test_mount_list_no_auto_repl(self):
764-
"""mount without args (listing) does not append repl"""
765-
from mpytool.mpytool import _mount_auto_repl
766-
groups = [['mount']]
767-
_mount_auto_repl(groups)
768-
self.assertEqual(len(groups), 1)
769-
770-
771716
class TestMountDispatch(unittest.TestCase):
772717
"""Tests for mount command dispatch"""
773718

0 commit comments

Comments
 (0)