-
-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug] using f'format strings in tight loop blocks and triggers watchdog timer #1668
Comments
Good find! When not connected, it is supposed to ignore printed output but that clearly isn't happening. |
Did you try this on any other hub? |
Up to now only the Spike and Inventor. Will "do" others. |
More minimal program and method below. Run this on SPIKE Prime and press the disconnect button in Pybricks Code. No need to restart anything. while True:
print(f'hello - hello - hello - hello - hello - hello - hello')
print(f'hello - hello - hello - hello - hello - hello - hello') The hub doesn't quite crash all the way, but the animation still visibly stutters. Just for less than it needs for the watchdog timer to trigger. |
Yet this is OK. So I guess we'll have to have a look at the format-string source code: while True:
print('hello - hello - hello - hello - hello - hello - hello')
print('hello - hello - hello - hello - hello - hello - hello') |
This one stutters: while True:
print(f'{"hello":>10} -{"hello":>10} {"hello":>10} {"hello":>10} {"hello":>10}')
print(f'{"hello":>10} -{"hello":>10} {"hello":>10} {"hello":>10} {"hello":>10}')
print(f'{"hello":>10} -{"hello":>10} {"hello":>10} {"hello":>10} {"hello":>10}')
print(f'{"hello":>10} -{"hello":>10} {"hello":>10} {"hello":>10} {"hello":>10}') |
Yes, any long |
How to "see" the stutter the other hubs? |
Thanks for having a look! Since it seems to be specifically related to these format strings, I think it's OK to stick to just the primehub for now to keep it simple. Thanks for bringing it to our attention. I haven't used these f-strings much in Pybricks for some reason. |
I like the f-strings more and more. Just getting to know the formatting characters. BTW this was the issue I found while testing the BT-on/off change in build 3380. |
You know me, I keep fiddling 😄 Idea was does the f-string pose the problem or the print doing the formatting. This snippet: formatted1 = f'{"hello" * 3:>20} - {"wow"[:2]:>10} {"hello":>10} {"hello":>10} {"hello":>10}'
print(type(formatted1))
formatted2 = f'{formatted1[:10]:>20}'
while True:
formatted2 = f'{formatted1[:10]:>20}'
print(type(formatted1), formatted1)
print(formatted2)
print(type(formatted1), formatted1) with an f-string in the loop makes the animation stutter. The same program but the formatting commented out within the loop does not stutter: formatted1 = f'{"hello" * 3:>20} - {"wow"[:2]:>10} {"hello":>10} {"hello":>10} {"hello":>10}'
print(type(formatted1))
formatted2 = f'{formatted1[:10]:>20}'
while True:
# formatted2 = f'{formatted1[:10]:>20}'
print(type(formatted1), formatted1)
print(formatted2)
print(type(formatted1), formatted1) The watchdog is not triggered. The 3 print commands are needed to see the stutter. [EDIT] The boolean SLICE determines which loop runs: f-strings with or without slices# SLICE = False # normal animation
SLICE = True # animation skips frames; my term: it stutters
if SLICE:
while True: # loop with only f-string formatting and slices
formatted1 = f'{"hello?"[:-1] * 3:>20} - {"wow"[:2]:>10} {"hello"[:4]:>10} {"hello":>10} {"hello":>10}'
formatted2 = f'{formatted1[6:]:<20}'
else:
while True: # loop with only f-string formatting and NO slices
formatted1 = f'{"hello" * 3:>20} - {"wow":>10} {"hello":>10} {"hello":>10} {"hello":>10}'
formatted2 = f'{formatted1:<20}' Movies:SLICE_False_connected.mp4SLICE_False_not_connected.mp4SLICE_True_connected.mp4SLICE_True_not_connected.mp4 |
Related: https://github.com/orgs/pybricks/discussions/1855 f-strings don't seem to work on REPL. Update: This can be enabled with |
The crash / reboot has been fixed as linked above. Thanks for reporting! |
But the "stutter" is still there on build 3569. |
This one no longer stutters for me. while True:
print(f'hello - hello - hello - hello - hello - hello - hello')
print(f'hello - hello - hello - hello - hello - hello - hello') Can you share a program that still stutters? It's possible that there are other places where it still blocks. |
I see that your program under the expander still stutters but in a different way. Unlike the others, this one also stutters while still connected, and it is not related to printing. We can further reduce yours to just the following: # This is the whole program, nothing else needed.
while True:
a = f'{("hello?"[:-1] * 3)}' And also without the f-string, even if this is probably equivalent as David indicated: while True:
a = "{0}".format("hello?"[:-1] * 3) |
And further simplified: while True:
a = "{}".format("h"[0] * 2) |
Adding a single |
You guys are fast. In my words: This program: while True:
a = "{}".format("h"[0] * 2) [EDIT] The slice in the format is the culprit, I think. Further simplified it does not stutter: while True:
# a = "{}".format("h"[0] * 2)
a = "{}".format("h" * 2) |
This sounds like a GC issue. str.format() has to allocate memory as does slicing, so no stutter until memory starts getting full, then stutter until memory is full, the GC is triggered and starts over again. So maybe Could test this by setting the GC threshold |
gc seems partly implemented:
|
A 'try / except' around the format shows a smooth display animation. This one also goes smooth: (edit program was wrong! no slice was enabled) import gc
help(gc)
gc.disable()
gc.collect()
print("PRE ", gc.mem_alloc(), " ", gc.mem_free())
while True:
try:
a = "{}".format("h"[0] * 2)
# a = "{}".format("h" * 2)
except:
print("POST", gc.mem_alloc(), " ", gc.mem_free())
gc.collect() |
I made pybricks/pybricks-micropython#267 to enable it for experimentation. |
Will test. |
Changing #define MICROPY_GC_HOOK_LOOP(i) do { \
if ((i & 0xf) == 0) { \
MICROPY_VM_HOOK_LOOP \
} \
} while (0) From I suppose this exists to keep the calls down, but maybe we could use an actual counter to keep it every |
Technically, So Or maybe we need |
Not sure if this still helps, but here it is anyway 😄 import gc
print("PRE ", gc.mem_alloc(), " ", gc.mem_free())
print("pre enable", gc.threshold())
# flip-flopping stutter and normal animation up to here
# gc.threshold(500) # smooth animation prints 496
# gc.threshold(5000) # smooth animation prints 4992
# gc.threshold(25000) # smooth animation prints 24992
gc.threshold(27500) # smooth animation prints 27488
# gc.threshold(30000) # slight stutter
# gc.threshold(40000) # slight stutter
# gc.threshold(50000) # slight stutter
# gc.threshold(75000) # a bit more stutter
# gc.threshold(100000) # stutter
# gc.threshold(150000) # stutter and normal animation (huh?)
# gc.threshold(200000) # stutter and normal animation (huh?)
# gc.threshold(1000000) # stutter
gc.enable()
print("AFT enable", gc.threshold())
while True:
a = "{}".format("h"[0] * 2) |
Oops, I misread -- yes, any multiple of 16 so including 0.
This seems to apply to one place where it is called but not all?
I suppose we could time the gc for the case where we always call EDIT: This test case also gets fixed by keeping the GC hook to run every 16 calls, but having one I see now this is what you probably meant above, to modify |
Here is a version you can try to break @BertLindeman 😄 https://github.com/pybricks/pybricks-micropython/actions/runs/11140023735 |
Nice, Laurens. Ran all my issue1668 tests and all OK now. Ran on technic hubs (build 3656 as happend to be next to me and his build 3571) I see no difference between them, but also nothing out of the ordinary. I like it. Thank you both, Bert Anything else to do for this issue, like merge to master? |
Possibly David's approval, he knows more about the garbage collector ♻️ . |
Hmm... I should have put that in the commit message. Likely I used the pystones test for this.
Yes, that is the idea. 😉 |
Describe the bug
Program is a tight loop printing f-strings. Within seconds the hub does a shutdown (somehow)
The display animation is no longer smooth but has large hickups.
Might this be related to #436 ?
To reproduce
Steps to reproduce the behavior:
Aditional info
Connected the hub before the test to USB to keep the power on.
After the crash connect to the hub and go to the REPL.
Showed:
Expected behavior
You'd expect the program to just keep running and not to power-off.
Screenshots
There is a saying that a picture is worth a 1000 words. Screenshots really help to identify and solve problems.
test program for this issue
The text was updated successfully, but these errors were encountered: