Description
import pyb
class WithTest:
def __init__(self):
pass
def __enter__(self):
pass
def __exit__(self, *exc):
pass
x1 = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.OUT_PP)
# CYCLICALLY INCREASING INTERVALS
wt = WithTest()
while True:
with wt as wtx:
x1.value(not x1.value())
#OK: CONSTANT INTERVALS
while True:
with WithTest() as wt:
x1.value(not x1.value())
The first loop in this test program produces a cyclically increasing square wave. I tested on a PyBoard v1.1 with v1.94 and the also the latest build pybv11-20200208-v1.12-154-gce40abcf2.dfu
The period of the waveform increases from about 38 microseconds to about 240 microseconds. Then there's a gap (gc?) and it starts over.
If you comment out the first loop and use the second (which constructs the with
object over and over), it runs at a constant 180 microseconds or so.
The fact that it's a with
statement is important; The as
is not necessary. We first discovered this while doing I2C transactions in CircuitPython which were taking too long. It took a while to figure out that it was not an I2C issue, but was solely due to the with
.
I don't see why the with
should inherently cause this behavior, so I think there's something going on in the VM that's slowing things down on each iteration, probably allocating storage which finally gets gc'd. But why should we see an increasing interval? It's like something is walking down an increasingly longer list.
This is easiest to see on an oscilloscope:
https://youtu.be/tGB2uVwig_4 (unlisted; use the link)
Screen shots from Saleae:
first loop (taken at gap: starts fast after a gap and slows down):
second loop (constant before and after gap):
Also filed as adafruit#2602.