From ce80ee2018064403bb0123624031a731ab92b20e Mon Sep 17 00:00:00 2001 From: Lennard <27106448+SirWalross@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:01:43 +0200 Subject: [PATCH] Add measure.py --- .gitignore | 4 +- measure.py | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 measure.py diff --git a/.gitignore b/.gitignore index 59bdc3b..67c91ae 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ out/* CHANGELOG.md data/data -logs/log \ No newline at end of file +logs/log +profiling.log +profiling_trace.json \ No newline at end of file diff --git a/measure.py b/measure.py new file mode 100644 index 0000000..08820f5 --- /dev/null +++ b/measure.py @@ -0,0 +1,133 @@ +# +# Example of how to profile a Python app with multiple processes +# by logging events and opening the resulting trace file in chrome://tracing. +# + +# pip install multiprocessing_logging + +from functools import wraps +import json +import logging +from multiprocessing import Pool +import os +import random +import time +import threading +import serial +import datetime + +from multiprocessing_logging import install_mp_handler + +# we want to be able to log from multiple processes +logging.basicConfig(level=logging.DEBUG) +logger = logging.getLogger() +install_mp_handler() + +# separate logger that only stores events into a file +prof_logger = logging.getLogger("profiling") +# not not propagate to root logger, we want to store this separately +prof_logger.propagate = False +handler = logging.FileHandler("profiling.log", "w+") +handler.setFormatter(logging.Formatter("%(message)s")) +prof_logger.addHandler(handler) +install_mp_handler(prof_logger) + + +def log_profile(category: str = None): + def decorator(f): + @wraps(f) + def wrapper(*args, **kwargs): + # format compatible with chrome://tracing + # info: https://www.gamasutra.com/view/news/176420/Indepth_Using_Chrometracing_to_view_your_inline_profiling_data.php + base_info = { + "name": f.__name__, + "pid": os.getpid(), + "tid": threading.current_thread().ident, + "cat": category, + } + + def log_event(**kwargs): + prof_logger.debug(json.dumps(kwargs)) + + def time_usec(): + return int(round(1e6 * time.time())) + + start_time = time_usec() + log_event(ph="B", ts=start_time, **base_info) + + result = f(*args, **kwargs) + + end_time = time_usec() + duration = end_time - start_time + # TODO: duration could possibly be computed afterwards (if we can pair the events correctly) + log_event(ph="E", ts=end_time, duration=duration, **base_info) + + return result + + return wrapper + + return decorator + + +def convert_log_to_trace(log_file, trace_file): + with open(trace_file, "wt") as output, open(log_file, "rt") as input: + events = [json.loads(line) for line in input] + json.dump({"traceEvents": events}, output) + + +@log_profile("compute") +def read(connection: serial.Serial): + for _ in range(4): + recv1 = connection.readline() + float(convert(recv1)) + + +@log_profile("write") +def write(connection: serial.Serial): + connection.write(1) + + +@log_profile("offset") +def offset(connection: serial.Serial): + return 0 if int(convert(connection.readline())) == 1.0 else 4 + + +@log_profile("write_data") +def write_data(): + print("writing data") + time.sleep(10e-3) + + +def convert(data) -> str: + return str(data).replace("b'", "").replace("'", "").replace("\\r\\n", "") + + +@log_profile("get_data") +def get_data(con1: serial.Serial, con2: serial.Serial): + try: + for connection in [con1, con2]: + write(connection) + offset(connection) + read(connection) + + except (TypeError, ValueError): + # may occur if no data was read over serial + print("Didn't receive data from arduino") + + +@log_profile("loop") +def loop(con1: serial.Serial, con2: serial.Serial): + last_write = time.time() + delta_time = 30 + while time.time() - last_write < delta_time: + get_data(con1, con2) + write_data() + + +def main() -> None: + with serial.Serial("/dev/ttyACM0", 9600, timeout=3) as con1, serial.Serial("/dev/ttyACM1", 9600, timeout=3) as con2: + for _ in range(100): + loop(con1, con2) + + +convert_log_to_trace("profiling.log", "profiling_trace.json") -- GitLab