micropython/aioprof: Add a simple profiler for asyncio applications.

pull/650/head
Andrew Leech 2023-04-27 11:37:21 +10:00
rodzic c113611765
commit 8bc1e40feb
3 zmienionych plików z 119 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,86 @@
import json as jsonlib
from time import ticks_ms, ticks_diff
import uasyncio as asyncio
## Public API
def enable():
"""
Once enabled, all new asyncio tasks will be tracked.
Existing tasks will not be tracked.
"""
asyncio.Task = Task
asyncio.core.Task = Task
def reset():
"""
Reset all the accumlated task data
"""
global timing
timing = {}
def report():
"""
Print a report to repl of task run count and timing.
"""
details = [
(name, str(value[0]), str(value[1]))
for name, value in reversed(sorted(timing.items(), key=lambda i: i[1][1]))
]
nlen = max([len(n) for n, i, t in details])
ilen = max((len("count"), max([len(i) for n, i, t in details])))
tlen = max([len(t) for n, i, t in details])
print("┌─" + "" * nlen + "─┬─" + "" * ilen + "─┬─" + "" * tlen + "─┐")
print(f"│ function name {' '*(nlen-14)} │ count{' '*(ilen-5)} │ ms {' '*(tlen-2)}")
print("├─" + "" * nlen + "─┼─" + "" * ilen + "─┼─" + "" * tlen + "─┤")
for name, i, t in details:
npad = " " * (nlen - len(name))
ipad = " " * (ilen - len(i))
tpad = " " * (tlen - len(t))
print(f"{name}{npad}{i}{ipad}{t}{tpad}")
print("└─" + "" * nlen + "─┴─" + "" * ilen + "─┴─" + "" * tlen + "─┘")
def json():
"""
Directly dump the task [run-count,timing] details as json.
"""
return jsonlib.dumps(timing)
## Internal functionality
__task = asyncio.Task
timing = {}
class Coro:
def __init__(self, c) -> None:
self.name = str(c)
self.c = c
def send(self, *args, **kwargs):
t_name = self.name
t_start = ticks_ms()
try:
ret = self.c.send(*args, **kwargs)
finally:
if t_name not in timing:
timing[t_name] = [0, 0]
t = timing[t_name]
t[0] += 1
t[1] += ticks_diff(ticks_ms(), t_start)
return ret
def __getattr__(self, name: str):
return getattr(self.c, name)
def Task(coro, glob):
return __task(Coro(coro), glob)

Wyświetl plik

@ -0,0 +1,30 @@
import time
import uasyncio as asyncio
import aioprof
aioprof.enable()
async def quicker():
while True:
time.sleep_ms(1) # blocking sleep, shouldn't do this in asyncio.
await asyncio.sleep_ms(20)
async def slow():
while True:
time.sleep_ms(80) # long blocking sleep, _really_ shouldn't do this in asyncio!
await asyncio.sleep_ms(20)
async def main():
asyncio.create_task(slow())
asyncio.create_task(quicker())
await asyncio.sleep_ms(500)
# print(aioprof.json())
aioprof.report()
asyncio.run(main())

Wyświetl plik

@ -0,0 +1,3 @@
metadata(description="Tool for basic profiling of asyncio applications.", version="1.0.0")
module("aioprof.py")