mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-25 08:58:14 +00:00
07797158db
When the tests are run using multiple cores, there will be one .coverage file for each core. So that the one file is not being overwritten many times, using unique filename for each core. [no changelog]
135 lines
3.8 KiB
Python
135 lines
3.8 KiB
Python
import sys
|
|
|
|
from uio import open
|
|
from uos import getenv
|
|
import micropython
|
|
|
|
# We need to insert "" to sys.path so that the frozen build can import main from the
|
|
# frozen modules, and regular build can import it from current directory.
|
|
sys.path.insert(0, "")
|
|
|
|
PATH_PREFIX = (getenv("TREZOR_SRC") or ".") + "/"
|
|
|
|
|
|
class Coverage:
|
|
def __init__(self):
|
|
self.__files = {}
|
|
|
|
def line_tick(self, filename, lineno):
|
|
if not filename in self.__files:
|
|
self.__files[filename] = set()
|
|
self.__files[filename].add(lineno)
|
|
|
|
def lines_execution(self):
|
|
lines_execution = {"lines": {}}
|
|
lines = lines_execution["lines"]
|
|
this_file = globals()["__file__"]
|
|
for filename in self.__files:
|
|
if not filename == this_file:
|
|
lines[PATH_PREFIX + filename] = list(self.__files[filename])
|
|
|
|
return lines_execution
|
|
|
|
|
|
class _Prof:
|
|
trace_count = 0
|
|
display_flags = 0
|
|
__coverage = Coverage()
|
|
|
|
def trace_tick(self, frame, event, arg):
|
|
self.trace_count += 1
|
|
|
|
# if frame.f_code.co_filename.endswith('/loop.py'):
|
|
# print(event, frame.f_code.co_filename, frame.f_lineno)
|
|
|
|
if event == "line":
|
|
self.__coverage.line_tick(frame.f_code.co_filename, frame.f_lineno)
|
|
|
|
def coverage_data(self):
|
|
return self.__coverage.lines_execution()
|
|
|
|
def write_data(self):
|
|
print("Total traces executed: ", __prof__.trace_count)
|
|
# In case of multithreaded tests, we might be called multiple times.
|
|
# Making sure the threads do not overwrite each other's data.
|
|
worker_id = getenv("PYTEST_XDIST_WORKER")
|
|
if worker_id:
|
|
file_name = f".coverage.{worker_id}"
|
|
else:
|
|
file_name = ".coverage"
|
|
with open(file_name, "w") as f:
|
|
# wtf so private much beautiful wow
|
|
f.write("!coverage.py: This is a private format, don't read it directly!")
|
|
# poormans json
|
|
f.write(str(__prof__.coverage_data()).replace("'", '"'))
|
|
|
|
|
|
class AllocCounter:
|
|
def __init__(self):
|
|
self.last_alloc_count = 0
|
|
self.data = {}
|
|
self.last_line = None
|
|
|
|
def count_last_line(self, allocs):
|
|
if self.last_line is None:
|
|
return
|
|
|
|
entry = self.data.setdefault(
|
|
self.last_line,
|
|
{
|
|
"total_allocs": 0,
|
|
"calls": 0,
|
|
},
|
|
)
|
|
entry["total_allocs"] += allocs
|
|
entry["calls"] += 1
|
|
|
|
def trace_tick(self, frame, event, arg):
|
|
allocs_now = micropython.alloc_count()
|
|
|
|
if event != "line":
|
|
return
|
|
|
|
allocs_per_last_line = allocs_now - self.last_alloc_count
|
|
self.count_last_line(allocs_per_last_line)
|
|
self.last_line = f"{frame.f_code.co_filename}:{frame.f_lineno}"
|
|
self.last_alloc_count = micropython.alloc_count()
|
|
|
|
def dump_data(self, filename):
|
|
allocs_now = micropython.alloc_count()
|
|
allocs_per_last_line = allocs_now - self.last_alloc_count
|
|
self.count_last_line(allocs_per_last_line)
|
|
with open(filename, "w") as f:
|
|
for key, val in self.data.items():
|
|
f.write("{} {total_allocs} {calls}\n".format(key, **val))
|
|
|
|
def write_data(self):
|
|
self.dump_data("alloc_data.txt")
|
|
|
|
|
|
def trace_handler(frame, event, arg):
|
|
__prof__.trace_tick(frame, event, arg)
|
|
return trace_handler
|
|
|
|
|
|
def atexit():
|
|
print("\n------------------ script exited ------------------")
|
|
__prof__.write_data()
|
|
|
|
|
|
sys.atexit(atexit)
|
|
|
|
global __prof__
|
|
if not "__prof__" in globals():
|
|
if getenv("TREZOR_MEMPERF") == "1":
|
|
__prof__ = AllocCounter()
|
|
else:
|
|
__prof__ = _Prof()
|
|
|
|
sys.settrace(trace_handler)
|
|
|
|
if isinstance(__prof__, AllocCounter):
|
|
__prof__.last_alloc_count = micropython.alloc_count()
|
|
|
|
import main
|