import time import os import threading class ProfileResult: def __init__( self, name: str, start, end, process_id: int = 0, thread_id: int = 0, ) -> None: self.name: str = name self.start = start self.end = end self.process_id = process_id self.thread_id = thread_id class Instrumentor: def __init__(self) -> None: self.file = None self.profile_count: int = 0 def begin_session( self, name: str, file_path: str = 'results.json' ) -> None: self.file = open(file_path, "w") self.write_header() def end_session(self) -> None: self.write_footer() self.file.close() self.session = None self.profile_count = 0 def write_profile( self, result: ProfileResult, ) -> None: if self.profile_count > 0: self.file.write(',') self.profile_count += 1 name: str = result.name name = name.replace('"', "'") self.file.write('{') self.file.write('"cat":"function",') self.file.write(f'"dur":{result.end - result.start},') self.file.write(f'"name":"{name}",') self.file.write('"ph":"X",') self.file.write(f'"pid":{result.process_id},') self.file.write(f'"tid":{result.thread_id},') self.file.write(f'"ts":{result.start}') self.file.write('}') def write_header(self) -> None: self.file.write('{"otherData": {},"traceEvents":[') def write_footer(self) -> None: self.file.write(']}') class InstrumentationTimer: def __init__( self, name: str, process_id = None, thread_id = None, ) -> None: self.name = name self.process_id = os.getpid() if process_id is not None: self.process_id = process_id self.thread_id = threading.get_native_id() if thread_id is not None: self.thread_id = thread_id self.stopped: bool = False self.start = time.time_ns() / 1000 def __del__(self) -> None: if not self.stopped: self.stop() def stop(self) -> None: end = time.time_ns() / 1000 instance.write_profile(ProfileResult(self.name, self.start, end, self.process_id, self.thread_id)) self.stopped = True instance = Instrumentor() def configure_profiling( save_location: str, file_name: str = 'results', ) -> None: instance.begin_session(os.path.join(save_location, file_name + '.json')) def profile_decorator(func, pid = None, tid = None): def wrapper(*args, **kwargs): timer = InstrumentationTimer(func.__name__, pid, tid) ret = func(*args, **kwargs) timer.stop() return ret return wrapper def end_profiling() -> None: instance.end_session()