Thanks so much for you help David. I have cracked it. This is what I did.
>>>>>>>>>>>>>>
# do_profiling.pyx
# cython: linetrace=False
# cython: language_level=3
import os
from sys import stderr
from time import perf_counter
from cpython.pystate cimport PyFrameObject, Py_tracefunc
from cpython cimport PyObject
cdef extern from "frameobject.h":
pass
cdef extern from *:
void PyEval_SetTrace(Py_tracefunc, o)
class TRACEX:
def __init__(self, Fn = None, Line = -1, Func = None):
self.Stack = (Fn, Line, Func)
def set(self, Fn, Line, Funct):
self.Stack = (Fn, Line, Funct)
def get(self):
return self.Stack
cdef int tracefunc(PyObject* o, PyFrameObject* frame, int what, PyObject* arg):
from inspect import getframeinfo
Fi = getframeinfo(<object>frame)
TraceX.set(os.path.basename(Fi.filename), Fi.lineno, Fi.function)
def TRCX(*args, **kwargs):
Fn, L, Func = TraceX.get()
print(f"{perf_counter():0.6f}:{Fn}:{L}:{Func}:", *args, file=stderr, flush=True, **kwargs)
PyEval_SetTrace(tracefunc, None) # None)
TraceX = TRACEX()
<<<<<<<<<<<
>>>>>>>>>>>>>>
# is_profiled.pyx
# cython: linetrace=True
# distutils: define_macros=CYTHON_TRACE=1
from sys import stderr
from do_profiling import TRCX
def func(n):
sum1 = 0
TRCX("got here")
for i in range(n):
dummy_fn1(sum1)
if i%2:
sum1 += 1
TRCX(f"plus sum: {sum1}")
else:
sum1 *= 2
TRCX(f"mult sum: {sum1}")
def dummy_fn1(sum1):
abc = sum1
TRCX("got here 1")
dummy_fn2()
def dummy_fn2():
dasdef = 234234
TRCX("got here 2")
<<<<<<<<<<<<<
>>>>>>>>>>
# tracethis.py
from do_profiling import TRCX
from is_profiled import func
i = 5
for z in range(10):
TRCX(f"i = {i}")
i += z
func(15)
<<<<<<<<<<
>>>>>>>>>> Output
0.167374:tracethis.py:11:<module>: i = 5
0.167751:tracethis.py:11:<module>: i = 5
0.168106:tracethis.py:11:<module>: i = 6
0.168460:tracethis.py:11:<module>: i = 8
0.168811:tracethis.py:11:<module>: i = 11
0.169163:tracethis.py:11:<module>: i = 15
0.169515:tracethis.py:11:<module>: i = 20
0.169865:tracethis.py:11:<module>: i = 26
0.170217:tracethis.py:11:<module>: i = 33
0.170567:tracethis.py:11:<module>: i = 41
0.171515:is_profiled.pyx:15:func: got here
0.172437:is_profiled.pyx:27:dummy_fn1: got here 1
0.173067:is_profiled.pyx:32:dummy_fn2: got here 2
0.173851:is_profiled.pyx:23:func: mult sum: 0
0.174637:is_profiled.pyx:27:dummy_fn1: got here 1
0.175263:is_profiled.pyx:32:dummy_fn2: got here 2
0.176043:is_profiled.pyx:20:func: plus sum: 1
0.176822:is_profiled.pyx:27:dummy_fn1: got here 1
0.177448:is_profiled.pyx:32:dummy_fn2: got here 2
0.178226:is_profiled.pyx:23:func: mult sum: 2
0.179003:is_profiled.pyx:27:dummy_fn1: got here 1
0.179627:is_profiled.pyx:32:dummy_fn2: got here 2
0.180406:is_profiled.pyx:20:func: plus sum: 3
0.181183:is_profiled.pyx:27:dummy_fn1: got here 1
0.181808:is_profiled.pyx:32:dummy_fn2: got here 2
0.183051:is_profiled.pyx:23:func: mult sum: 6
0.184307:is_profiled.pyx:27:dummy_fn1: got here 1
0.184966:is_profiled.pyx:32:dummy_fn2: got here 2
0.185760:is_profiled.pyx:20:func: plus sum: 7
This approach works in both interpreted and compiled code. Just import do_profiling into which ever file *.py or *.pyx.
Hope this helps others out there.