Skip to content

Commit 55b04c4

Browse files
committed
Add license headers. Add pre-commit config.
1 parent dec9e08 commit 55b04c4

File tree

9 files changed

+215
-33
lines changed

9 files changed

+215
-33
lines changed

.pre-commit-config.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
repos:
2+
- repo: https://github.com/charliermarsh/ruff-pre-commit
3+
rev: v0.1.3
4+
hooks:
5+
- id: ruff
6+
- id: ruff-format
7+
- repo: https://github.com/codespell-project/codespell
8+
rev: v2.2.6
9+
hooks:
10+
- id: codespell
11+
name: Spellcheck for changed files (codespell)
12+
additional_dependencies:
13+
- tomli

examples/example1.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# MIT license; Copyright (c) 2024, Planet Innovation
2+
# SPDX-License-Identifier: MIT
3+
# 436 Elgar Road, Box Hill, 3128, VIC, Australia
4+
# Phone: +61 3 9945 7510
5+
6+
# Create an async program with a number of tasks:
7+
#
8+
# 1) allocate large blocks
9+
# 2) de-allocate blocks, call gc.collect
10+
# 3) profile
11+
12+
import asyncio
13+
import time
14+
import logging
15+
import gc
16+
17+
import mem_dump
18+
19+
logging.basicConfig(level=logging.INFO)
20+
log = logging.getLogger("MemTest")
21+
22+
_MEMORY = []
23+
24+
25+
class SimpleTimer:
26+
"""A simple class that, when called, will return True if the time since
27+
it's creation has expired."""
28+
29+
def __init__(self, seconds):
30+
self.start = int(time.time())
31+
self.seconds = seconds
32+
33+
def __call__(self) -> bool:
34+
return (int(time.time()) - self.start) > self.seconds
35+
36+
37+
async def allocate_task(finished, size_alloc=5_000, interval_ms=100):
38+
while not finished():
39+
log.info(f"Allocating {size_alloc} bytes")
40+
_MEMORY.append(bytearray(size_alloc))
41+
await asyncio.sleep_ms(interval_ms)
42+
43+
44+
async def release_task(finished, interval_ms=2_000):
45+
while not finished():
46+
log.info("Freeing half of the allocated bytearrays")
47+
48+
del _MEMORY[: len(_MEMORY) // 2]
49+
gc.collect()
50+
51+
await asyncio.sleep_ms(interval_ms)
52+
53+
54+
async def main():
55+
# Start the mem_dump async task
56+
await mem_dump.start_async()
57+
58+
log.info("Begin Example 1")
59+
log.info(
60+
"Periodically, allocate bytearray blocks and store them in a list. "
61+
"At a slower interval, delete half of the list recover the memory."
62+
)
63+
64+
# Run the example for ten seconds
65+
timer = SimpleTimer(10)
66+
67+
# Start allocating and deleting memory
68+
await asyncio.gather(allocate_task(timer), release_task(timer))
69+
70+
log.info("End Example 1")
71+
72+
73+
asyncio.run(main())

mem_dump.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
# MIT license; Copyright (c) 2024, Planet Innovation
2+
# SPDX-License-Identifier: MIT
3+
# 436 Elgar Road, Box Hill, 3128, VIC, Australia
4+
# Phone: +61 3 9945 7510
5+
16
import time
27
import micropython
38

49
_MEM_DUMP_PERIOD_MS = 350
510
_FIRST = True
611

12+
713
def mem_dump(_):
814
global _FIRST
915
if _FIRST:
@@ -19,6 +25,7 @@ def mem_dump(_):
1925

2026
def start_timer(period_ms=_MEM_DUMP_PERIOD_MS):
2127
from machine import Timer
28+
2229
# Start a timer to periodically dump the heap.
2330
Timer(period=period_ms, callback=mem_dump)
2431

rendering_tools/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# rendering_tools

rendering_tools/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# MIT license; Copyright (c) 2024, Planet Innovation
2+
# SPDX-License-Identifier: MIT
3+
# 436 Elgar Road, Box Hill, 3128, VIC, Australia
4+
# Phone: +61 3 9945 7510
5+
#
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
from .frame_parser import Capture, LogFrame, DummyFrame, HeapFrame
1+
# MIT license; Copyright (c) 2024, Planet Innovation
2+
# SPDX-License-Identifier: MIT
3+
# 436 Elgar Road, Box Hill, 3128, VIC, Australia
4+
# Phone: +61 3 9945 7510
5+
#

rendering_tools/mem_usage_parser/frame_parser.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
1+
# MIT license; Copyright (c) 2024, Planet Innovation
2+
# SPDX-License-Identifier: MIT
3+
# 436 Elgar Road, Box Hill, 3128, VIC, Australia
4+
# Phone: +61 3 9945 7510
5+
#
26

37
import re
48

9+
510
class Capture:
611
def __init__(self):
712
self.title = ""
@@ -43,14 +48,13 @@ def __init__(self, timestamp_ms, heap):
4348
# convert body to something prettier
4449

4550
def gen(heap: list[str]):
46-
4751
for entry in heap:
4852
if entry.find("lines all free") != -1:
4953
m = re.search(r"\((\d+) lines all free", entry)
5054
for _ in range(int(m.group(1))):
5155
yield "." * 64
5256
else:
53-
yield entry[10:] # The contents of the memory representation
57+
yield entry[10:] # The contents of the memory representation
5458

5559
while True:
5660
yield ""

rendering_tools/mem_usage_render.py

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
1+
# MIT license; Copyright (c) 2024, Planet Innovation
2+
# SPDX-License-Identifier: MIT
3+
# 436 Elgar Road, Box Hill, 3128, VIC, Australia
4+
# Phone: +61 3 9945 7510
5+
#
6+
17
"""
28
Convert a device log containing periodic micropython.mem_info(1) into a set of
39
images suitable to make a video.
4-
5-
A capture should be made first by running mem_usage_main.py on the device. For
6-
example:
7-
8-
$ pyboard.py mem_usage_main.py | tee > mem_usage.log
9-
10-
Then run this script to convert the log to a sequence of PNG images:
11-
12-
$ python mem_usage_render.py mem_usage.log
13-
14-
Video can then be made with (replace -s size with actual size of images):
15-
16-
ffmpeg -r 10 -f image2 -s 2100x1252 -i image_%04d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p mem_usage.mp4
1710
"""
1811

1912
import re
@@ -27,6 +20,7 @@
2720
COLOUR_TEXT_PLAIN = (0, 0, 0)
2821
COLOUR_TEXT_CHANGED = (1, 0, 0)
2922

23+
3024
def parse_capture(filename):
3125
capture = Capture()
3226
rtc_offset = None
@@ -40,7 +34,7 @@ def parse_capture(filename):
4034
if line.startswith("@@@ v"):
4135
# Title line
4236
capture.title = line[4:]
43-
#print("title:", capture.title)
37+
# print("title:", capture.title)
4438
elif line.startswith("@@@ ") and line.find(" (") != -1:
4539
# Timestamp *and* datetime line
4640
_, timestamp_ms, datetime = line.split(None, 2)
@@ -51,7 +45,6 @@ def parse_capture(filename):
5145
rtc_offset = (
5246
((hr * 60 + mn) * 60 + sc) * 1000 + us // 1000 - timestamp_ms
5347
)
54-
#print("timestamp_ms:", timestamp_ms, "rtc_offset:", rtc_offset)
5548
elif line.startswith("@@@ "):
5649
# Line with (only) a timestamp. The *frame*, which includes
5750
# the memory and heap information, follows this line and
@@ -67,15 +60,10 @@ def parse_capture(filename):
6760
heap.append(line)
6861
if rtc_offset is None:
6962
rtc_offset = capture.frames[-1].timestamp_ms - timestamp_ms + 200
70-
#print(heap[:5])
71-
#print(heap[6:])
7263
frame = HeapFrame(rtc_offset + timestamp_ms, heap)
7364
else:
7465
# LogFrame, use the timestamp if it's available
75-
#print("match timestamp")
76-
#print(line)
7766
m = re.match(r"20\d\d-\d\d-\d\d (\d\d):(\d\d):(\d\d),(\d\d\d) ", line)
78-
print('log')
7967
timestamp_ms = None
8068
if m:
8169
hr = int(m.group(1))
@@ -84,18 +72,15 @@ def parse_capture(filename):
8472
ms = int(m.group(4))
8573
timestamp_ms = ((hr * 60 + mn) * 60 + sc) * 1000 + ms
8674
elif len(capture.frames) > 0:
87-
print(len(capture.frames))
8875
timestamp_ms = capture.frames[-1].timestamp_ms + 10
8976
if timestamp_ms:
9077
frame = LogFrame(timestamp_ms, line)
9178
else:
9279
# We can't create LogFrames before recording a
9380
# timestamp. So drop any log text until the first
9481
# HeapFrame is found.
95-
print(f"drop: {line}")
9682
frame = None
9783
if frame:
98-
print("add capture")
9984
capture.add_frame(frame, rtc_offset)
10085
return capture
10186

rendering_tools/tests/frame_parser_test.py

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
21
from mem_usage_parser.frame_parser import HeapFrame
32

3+
44
class TestHeapFrame:
55
def test_unix(self):
66
heap = [
@@ -16,10 +16,9 @@ def test_unix(self):
1616

1717
def test_device(self):
1818
heap = [
19-
"stack: 668 out of 15360"
20-
"GC: total: 152512, used: 1264, free: 151248",
19+
"stack: 668 out of 15360" "GC: total: 152512, used: 1264, free: 151248",
2120
" No. of 1-blocks: 24, 2-blocks: 3, max blk sz: 18, max free sz: 9440",
22-
"GC memory layout; from 20006c30:"
21+
"GC memory layout; from 20006c30:",
2322
]
2423
frame = HeapFrame(4321, heap)
2524
print("test device")
@@ -29,5 +28,96 @@ def test_device(self):
2928
# Other tests
3029

3130
# - Ensure blank lines are stripped
32-
# - Ensure LogFrames are generated for inital lines (preceeding @@@ lines)
33-
# - Check each of the frame types
31+
# - Ensure LogFrames are generated for initial lines (preceding @@@ lines)
32+
# - Check each of the frame types
33+
34+
35+
two_frames = """
36+
Installing logging (latest) from https://micropython.org/pi/v2 to /root/.micropython/lib
37+
Copying: /root/.micropython/lib/logging.mpy
38+
Done
39+
INFO:MemTest:Begin Example 1
40+
INFO:MemTest:Periodically, allocate bytearray blocks and store them in a list. At a slower interval, delete half of the list recover the memory.
41+
@@@ 45828774 (2024, 9, 10, 12, 5, 42, 1, 254)
42+
@@@ 45828774
43+
mem: total=77932, current=44073, peak=44073
44+
stack: 7328 out of 80000
45+
GC: total: 296448, used: 49920, free: 246528
46+
No. of 1-blocks: 695, 2-blocks: 83, max blk sz: 91, max free sz: 7704
47+
GC memory layout; from 7f2951dbdde0:
48+
00000000: MDhh=hhLhhSh===h========hhhBMDhBShThSBBMDh==BShBDBDBBBhBhBBBBh==
49+
00000800: =h===T==B==BBBTB=BBBT=B=h=h========MDShhSh========hhShMhShh==hhS
50+
00001000: SDSh=BMDBShhhh==ShDhShLhh=LLhShSh=LhT=AhDhh=====================
51+
00001800: ================================================================
52+
00002000: =====h=============TSSSh=hhLhShShShShhSSLhShShSh=SSLhShSh=Shh=SS
53+
00002800: LhShShShhShSLhShShShh=SSLhShSh=ShhSSSLhShShhSSLhShShShhSSLLhShSh
54+
00003000: Shh=SSLhShShh====hShShhShhShSh==hSh=ShShhhSSSh=hhThh=hSSTDBMDhDS
55+
00003800: h=hhALhShShShLhShShLhT=AhDhh====================================
56+
00004000: ======================================================h=========
57+
00004800: ====TSSSh=hhLhShShShShhSSLhShShSh=SSLhShSh=Shh=SSLhShShShhShSLhS
58+
00005000: hShShh=SSLhShSh=Shh=SSLhShShhSSLhShShShhShSSLhShShhSSLhShShh====
59+
00005800: hh=h==SShT==hShSShhThShhShSShhThShhSh===hhhBTT=Dh=BDBDhTh===BDhT
60+
00006000: h===hhhTB=BBBBBhh=hh==h===DSShhh===h===BBBBBBBBhhh===BTh=B=BhBDB
61+
00006800: BBBBhhh=h====TB=BBhhh=hDDBBBBh===h====hhh===============Bh===Sh=
62+
00007000: h=====h==============hSShDTh======hh====h===========h===h===h===
63+
00007800: ===h===h==hh===h============================h=Sh====hhh=========
64+
00008000: ==============h=========h==hhh=h=hhhhhhhhhhhh=hh=hhhh=hhh=hh=hhh
65+
00008800: hh=hh=hhhh=hh==hhh==h===h=hhhhhhhh===hhhhhhhhhhhh===hhhhhhh=hhhh
66+
00009000: hhhhhhhhhhhh=hhhh====hhh==DBDBBh=DBTB=BBBBDh===BBBBBBBBBT==hBTh=
67+
00009800: ==h===B=hTBBh==h===DhBTB=hh=hTh===BDBTB=BBBh==h===DBTB=BBBBBBBBD
68+
0000a000: hB=BBh===TB=h========B==hhhh===hBBTTh==================hhhB=BDBB
69+
0000a800: Lh=h====hLhLhhhh=LhhhTh=hh=Th=hTh=h=hhh===Th===h===h=h========h=
70+
0000b000: ==hh=Thhh=h==h=hh=hh=h======h==h=hMFhDBFFFDShh===h==hSFFFDh=====
71+
0000b800: =========h==Sh====h====ShTBBTh=DhTDhBhh=h===h===h=h=============
72+
0000c000: =====hhBh=BLhh=h=T==hT==........................................
73+
(119 lines all free)
74+
00048000: ................................................
75+
@@@
76+
INFO:MemTest:Allocating 5000 bytes
77+
INFO:MemTest:Freeing half of the allocated bytearrays
78+
INFO:MemTest:Allocating 5000 bytes
79+
INFO:MemTest:Allocating 5000 bytes
80+
INFO:MemTest:Allocating 5000 bytes
81+
@@@ 45829127
82+
mem: total=102737, current=66214, peak=66358
83+
stack: 7328 out of 80000
84+
GC: total: 296448, used: 46112, free: 250336
85+
No. of 1-blocks: 324, 2-blocks: 56, max blk sz: 157, max free sz: 7209
86+
GC memory layout; from 7f2951dbdde0:
87+
00000000: MDhh=hhLhhSh===h========hhhBMDhFShShhBBMDShAFShFDBDBBBhBhBBBBh==
88+
00000800: =h===FDSB==BBBSB=BBBh=B=h=h========MDh=hFh========hhSSMhShAFh==F
89+
00001000: ShSAFBMDFShhhDh==SDSShLhh=Lh====================================
90+
00001800: ================================================================
91+
00002000: ========================================================h=h=h...
92+
00002800: ..FFFDh==Sh=h=S.................................................
93+
00003000: .........................hShS...h.......................TDBMDh..
94+
00003800: ..h......................D......................................
95+
00004000: ................................................................
96+
00004800: ....................Sh.......Sh.......Sh...Sh......Sh..Sh......S
97+
00005000: h..Sh......Sh...Sh......Sh.......Sh..Sh..h....Sh.......Sh..h====
98+
00005800: ...h==.........................................Dh=.D.Dh.h===.Dh.
99+
00006000: h===hhh.B=BBB.Bh..hh==h===DSShh....h===BBBBBBBBhhh===B.h=B=Bh.DB
100+
00006800: BBBBhhh=h====.B=BBhhh=hDDBBBBh===h====..h===============.h===Sh=
101+
00007000: h=====h==============.SShD.h======hh====h===========h===h===h===
102+
00007800: ===h===h==hh===h============================h=S.................
103+
00008000: ........................h==......h.h.h.h.h.....h=.h.h=.....h=.h.
104+
00008800: ....h=.h.h=.h==.........h=.h.h.h.h===.h.h.h.h.h.h===.h.h..h=.h.h
105+
00009000: .h.h.h.h.h.h=.h.h====..h==D.D.Bh=DB.B=BBB.Dh===BBBBBBBBB...hB.h=
106+
00009800: ==h===B=h..Bh==h===DhB.B=hh=h.h===.DB.B=B.Bh==h===DB.B=BBBBBBBBD
107+
0000a000: hB=BBh===.B=h========B==hhhh===..B..h==================...B=.DBB
108+
0000a800: .h=h====hLhLhh.h=Lhhh.h=hh=.h=hTh=h=h.h===Th===h===h=h========..
109+
0000b000: ..h..Thh..h==h=hh=hh=h======h==h=hM.hD.......h===...............
110+
0000b800: ........................h.B..h=DhTDhBhh=h===h===h=h=============
111+
0000c000: =====hhBh=.Lhh=h=............A.hF...............h===============
112+
0000c800: ================================================================
113+
0000d000: ================================================================
114+
0000d800: =============h==================================================
115+
0000e000: ================================================================
116+
0000e800: ==========================================h=====================
117+
0000f000: ================================================================
118+
0000f800: ================================================================
119+
00010000: =======.........................................................
120+
(111 lines all free)
121+
00048000: ................................................
122+
@@@
123+
"""

0 commit comments

Comments
 (0)