forked from DB3D/Plugin-Profiler
-
Notifications
You must be signed in to change notification settings - Fork 2
/
exectracker.py
141 lines (106 loc) · 4.92 KB
/
exectracker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import bpy
import os
import sys
import time
import types
import datetime
from . utils import RunningOperator
from . utils import list_have_common_elements
def tracker(frame: types.FrameType, event: str, arg):
"""tracker to be registered in sys.setprofile
https://docs.python.org/3/library/sys.html#sys.setprofile"""
prefs = bpy.context.preferences.addons["Plugin-Profiler"].preferences
#initiate a static variable
_f = tracker
if (not hasattr(_f,"callstack")):
_f.callstack = {}
#trace a function
if (event=="call"):
func_source = os.path.abspath(frame.f_code.co_filename)
func_name = frame.f_code.co_name
func_key = f"{func_source}:{func_name}"
#Default Filters:
#filter out all builtin python function
if func_source.startswith(sys.prefix):
return tracker
#ignore list comp
if ( prefs.exectracker_ignore_listcomp):
if ("<listcomp>" in func_name):
return tracker
#Preference Filters:
#listen only to specific modules ?
if ( prefs.exectracker_module_path!="" and not func_source.startswith(prefs.exectracker_module_path) ):
return tracker
#ignore some sub-modules?
if (len(prefs.exectracker_modules_ignore)):
l1 = [e.name for e in prefs.exectracker_modules_ignore]
l2 = [e if (".py" not in e) else e.replace(".py","") for e in os.path.normpath(func_source).split(os.sep)]
if (list_have_common_elements(l1,l2)):
return tracker
#only listen to x sub-modules?
if (len(prefs.exectracker_modules_only)):
l1 = [e.name for e in prefs.exectracker_modules_only]
l2 = [e if (".py" not in e) else e.replace(".py","") for e in os.path.normpath(func_source).split(os.sep)]
if (not list_have_common_elements(l1,l2)):
return tracker
#ignore some functions
if (len(prefs.exectracker_functions_ignore)):
if prefs.exectracker_functions_ignore_proxy:
for e in [e.name for e in prefs.exectracker_functions_ignore]:
if (e in func_name):
return tracker
else:
if (func_name in prefs.exectracker_functions_ignore):
return tracker
#only listen to x functions?
if (len(prefs.exectracker_functions_only)):
if prefs.exectracker_functions_only_proxy:
for e in [e.name for e in prefs.exectracker_functions_only]:
if (e not in func_name):
return tracker
else:
if (func_name not in prefs.exectracker_functions_only):
return tracker
#save the time at the moment of a call
_f.callstack[func_key] = {"datetime":datetime.datetime.now()}
return tracker
#function exiting
elif (event=="return"):
func_source = os.path.abspath(frame.f_code.co_filename)
func_name = frame.f_code.co_name
func_key = f"{func_source}:{func_name}"
if (func_key in _f.callstack):
printer = "Executed "
#generate print string
if prefs.exectracker_print_funcname:
if prefs.exectracker_print_funcdepth:
fct_path = os.path.normpath(func_source).split(os.sep)
for i in range(prefs.exectracker_print_funcdepth):
modidx = i-prefs.exectracker_print_funcdepth
modname = fct_path[modidx]
if (".py" in modname):
modname = modname.replace(".py","")
printer+=f"{modname}\\"
printer+=f"{func_name}() "
if prefs.exectracker_print_sourcepath:
printer+=f"from '{func_source}' "
if prefs.exectracker_print_datetime:
start_time = _f.callstack[func_key]["datetime"]
printer+="at '%sh%sm%ss' " % (start_time.hour, start_time.minute, start_time.second)
if prefs.exectracker_print_functime:
start_time = _f.callstack[func_key]["datetime"]
elapsed = (datetime.datetime.now() - start_time).total_seconds()
printer+=f"during '{elapsed:4f}s' "
print(printer)
del _f.callstack[func_key]
return tracker
return tracker
class PLUGINPROFILER_OT_exectracker(RunningOperator):
"""https://stackoverflow.com/questions/73620822/how-to-track-functions-executions-in-real-time/73654195#73654195"""
bl_idname = "pluginprofiler.exectracker"
def start(self):
sys.setprofile(tracker)
return None
def end(self):
sys.setprofile(None)
return None