Skip to content

Instantly share code, notes, and snippets.

@rocky
Created November 30, 2024 23:41
Show Gist options
  • Save rocky/96b8f6b1c2f41bce0fada6b108004ba2 to your computer and use it in GitHub Desktop.
Save rocky/96b8f6b1c2f41bce0fada6b108004ba2 to your computer and use it in GitHub Desktop.
For Michal

Examples of running run-program-with-counts.py

$ python run-python-program-with-counts.py ../test/example/fib.py
fib(2)= 2, fib(3) = 3, fib(4) = 5

Event "call" seen 25 times.
Event "line" seen 70 times.
Event "opcode" seen 358 times.
Event "return" seen 24 times.
$ python run-python-program-with-counts.py ../test/example/gcd.py 3 5
The GCD of 3 and 5 is 1
Event "call" seen 12 times.
Event "line" seen 65 times.
Event "opcode" seen 314 times.
Event "return" seen 11 times.
$

The programs fib.py and gcd.py` can be found in https://github.com/Trepan-Debuggers/python3-trepan/tree/master/test/example

#!/usr/bin/env python3
"""
A simple program to run a Python program and dump statistics of how many
sys_trace events ("call", "return", "line", "opcode") it runs.
Run like this:
python3 run-python-program-with-count.py *your-python-program* *args*
"""
import atexit
import os.path as osp
import sys
import types
from collections import defaultdict
from typing import Callable, Optional
_globals = globals().copy()
class TraceEvents:
"""
A simple sys.settrace event handler for counting sys_trace() events.
"""
def __init__(self):
self.event_counts = defaultdict(int)
def event_handler(self, call_frame: types.FrameType, event: str, _) -> Optional[Callable]:
self.event_counts[event] += 1
# If you don't want to count opcode you can comment this out.
# Actually, it probably only needs to be set once (per frame
# call?, per trace session?)
call_frame.f_trace_opcodes = True
# print(f"event: {event} {call_frame.f_code.co_filename}:{call_frame.f_lineno}")
# We need to return our method to make sure tracing keeps calling us.
return self.event_handler
def stop_trace_and_dump(self):
sys.settrace(None)
for event, count in self.event_counts.items():
print(f'Event "{event}" seen {count} times.')
def run_and_trace_program(python_path: str):
"""
Compile `python_path` and evaluate it in a way to keep track
of the instruction events it runs.
"""
if not osp.exists(python_path):
print(f"Python file {python_path} does not exist")
compiled = compile(open(python_path, "r").read(), filename=python_path, mode='exec')
tracer = TraceEvents()
atexit.register(tracer.stop_trace_and_dump)
sys.argv.pop(0)
sys.settrace(tracer.event_handler)
exec(compiled, _globals)
if __name__ == "__main__":
traced_program = sys.argv[1]
run_and_trace_program(traced_program)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment