custom-profiler 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- custom_profiler/__init__.py +11 -0
- custom_profiler/collecteur.py +140 -0
- custom_profiler/custum_logger.py +63 -0
- custom_profiler/custum_profiler.py +95 -0
- custom_profiler/human_readable_time.py +49 -0
- custom_profiler/line_by_line.py +75 -0
- custom_profiler-0.1.0.dist-info/METADATA +11 -0
- custom_profiler-0.1.0.dist-info/RECORD +10 -0
- custom_profiler-0.1.0.dist-info/WHEEL +5 -0
- custom_profiler-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
from . import custum_profiler
|
|
3
|
+
from . import collecteur
|
|
4
|
+
|
|
5
|
+
from functools import partial
|
|
6
|
+
|
|
7
|
+
profiler = partial(custum_profiler.profiler, linePerline=False)
|
|
8
|
+
profiler_lbl = partial(custum_profiler.profiler, linePerline=True)
|
|
9
|
+
magic_profiler = custum_profiler.magic_profiler
|
|
10
|
+
profiler_collecteur = collecteur.profiler_collecteur
|
|
11
|
+
INTERACTIVITY_OPT_ENUM = collecteur.INTERACTIVITY_OPT_ENUM
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import sys
|
|
3
|
+
if sys.platform == 'linux':
|
|
4
|
+
import resource
|
|
5
|
+
import logging
|
|
6
|
+
from collections import OrderedDict
|
|
7
|
+
|
|
8
|
+
import psutil
|
|
9
|
+
from psutil._common import bytes2human
|
|
10
|
+
process = psutil.Process()
|
|
11
|
+
|
|
12
|
+
from custom_profiler.custum_logger import add_logging_level
|
|
13
|
+
from custom_profiler.human_readable_time import human_time_duration as htd
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class INTERACTIVITY_OPT_ENUM :
|
|
17
|
+
ENABLE = "ENABLE" # thread (for memory peak follow) and interactive print
|
|
18
|
+
MF_NO_INTERAC = "MF_NO_INTERAC" # memory peak follow (with thread), no interacrtif print
|
|
19
|
+
DISABLE = "DISABLE" # no thread, no memory peak follow, no interacrtif print
|
|
20
|
+
AUTO = "AUTO" # if console is redirect in file (sys.stdout.isatty() == false) AUTO is equivalente to MF_NO_INTERAC else is equivalente to ENABLE
|
|
21
|
+
|
|
22
|
+
def get_ENUM_list(ENUM):
|
|
23
|
+
return [key for key in ENUM.__dict__ if key not in ["__main__", "__module__", "__doc__", '__dict__', '__weakref__']]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class profiler_collecteur(object):
|
|
27
|
+
_instance = None
|
|
28
|
+
|
|
29
|
+
def __new__(self):
|
|
30
|
+
if self._instance is None:
|
|
31
|
+
self._instance = super(profiler_collecteur, self).__new__(self)
|
|
32
|
+
self.profData = OrderedDict()
|
|
33
|
+
self.profThread = OrderedDict()
|
|
34
|
+
self.interractivity = INTERACTIVITY_OPT_ENUM.ENABLE
|
|
35
|
+
self.logger = None
|
|
36
|
+
self.start_time = time.perf_counter()
|
|
37
|
+
return self._instance
|
|
38
|
+
|
|
39
|
+
def options(self, interractivity = INTERACTIVITY_OPT_ENUM.ENABLE
|
|
40
|
+
, useLogger=False
|
|
41
|
+
, loggername = " ⚡"
|
|
42
|
+
, addCustumLvl= True
|
|
43
|
+
, profilerlvl = 25):
|
|
44
|
+
|
|
45
|
+
assert interractivity in get_ENUM_list(INTERACTIVITY_OPT_ENUM), f'interractivity {interractivity} must be in INTERACTIVITY_OPT_ENUM : {getEnumList(INTERACTIVITY_OPT_ENUM)}'
|
|
46
|
+
|
|
47
|
+
if interractivity == INTERACTIVITY_OPT_ENUM.AUTO :
|
|
48
|
+
if sys.stdout.isatty():
|
|
49
|
+
self.interractivity = INTERACTIVITY_OPT_ENUM.ENABLE
|
|
50
|
+
else :
|
|
51
|
+
self.interractivity = INTERACTIVITY_OPT_ENUM.MF_NO_INTERAC
|
|
52
|
+
|
|
53
|
+
if useLogger:
|
|
54
|
+
if self.interractivity == INTERACTIVITY_OPT_ENUM.ENABLE :
|
|
55
|
+
self.interractivity = INTERACTIVITY_OPT_ENUM.MF_NO_INTERAC
|
|
56
|
+
if addCustumLvl :
|
|
57
|
+
add_logging_level('PROFILER', profilerlvl)
|
|
58
|
+
logging.getLogger().setLevel("PROFILER")
|
|
59
|
+
self.logger = logging.getLogger(loggername).profiler
|
|
60
|
+
else :
|
|
61
|
+
logging.getLogger().setLevel("INFO")
|
|
62
|
+
self.logger = logging.getLogger(loggername).info
|
|
63
|
+
else :
|
|
64
|
+
self.logger = None
|
|
65
|
+
|
|
66
|
+
def save(self, fname, deltaTime, deltaMem, long_fname=None):
|
|
67
|
+
if fname in self.profData.keys():
|
|
68
|
+
self.profData[fname]["dt"] += deltaTime
|
|
69
|
+
self.profData[fname]["dm"] += deltaMem
|
|
70
|
+
self.profData[fname]["dm_list"].append(deltaMem)
|
|
71
|
+
self.profData[fname]["nbCall"] += 1
|
|
72
|
+
else :
|
|
73
|
+
self.profData[fname] = {"dt": deltaTime ,"dm": deltaMem, "dm_list": [deltaMem], "nbCall": 1}
|
|
74
|
+
|
|
75
|
+
t_str = htd(deltaTime)
|
|
76
|
+
value = f"{t_str}"
|
|
77
|
+
strmen = bytes2human(deltaMem)
|
|
78
|
+
if long_fname == None :
|
|
79
|
+
long_fname = fname
|
|
80
|
+
self.print_line(long_fname, value, strmen)
|
|
81
|
+
|
|
82
|
+
def thread_view(self, fname, deltaMem):
|
|
83
|
+
if fname in self.profThread.keys():
|
|
84
|
+
if deltaMem > self.profThread[fname]:
|
|
85
|
+
self.profThread[fname] = deltaMem
|
|
86
|
+
else :
|
|
87
|
+
self.profThread[fname] = deltaMem
|
|
88
|
+
|
|
89
|
+
def get_global_info(self):
|
|
90
|
+
run_time = htd(time.perf_counter() - self.start_time)
|
|
91
|
+
if sys.platform == 'win32':
|
|
92
|
+
mem_peack = bytes2human(process.memory_info().peak_wset)
|
|
93
|
+
else :
|
|
94
|
+
mem_peack = bytes2human(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 0.0009765625) # in bytes
|
|
95
|
+
return run_time, mem_peack
|
|
96
|
+
|
|
97
|
+
def _print(self, toprint, end='\n'):
|
|
98
|
+
if self.logger:
|
|
99
|
+
self.logger(toprint)
|
|
100
|
+
else:
|
|
101
|
+
print(toprint, end=end)
|
|
102
|
+
|
|
103
|
+
def print_line(self, fname, delta_time, delta_mem, end='\n', color=""):
|
|
104
|
+
delta_mem = " Δ " + f"{delta_mem:>7}"
|
|
105
|
+
if fname in self.profThread.keys():
|
|
106
|
+
mmax = 0.
|
|
107
|
+
if fname in self.profData.keys():
|
|
108
|
+
mmax = max(self.profData[fname]["dm_list"])
|
|
109
|
+
if mmax < self.profThread[fname] :
|
|
110
|
+
mmax = self.profThread[fname]
|
|
111
|
+
delta_mem += " / peak " + f"{bytes2human(mmax):>7}"
|
|
112
|
+
toprint = f"{color} ⚡ {fname: ^21} took : {delta_time:<10} consumes : {delta_mem} \033[0m"
|
|
113
|
+
self._print(toprint, end)
|
|
114
|
+
|
|
115
|
+
def __str__(self):
|
|
116
|
+
run_time, mem_peack = self.get_global_info()
|
|
117
|
+
str = ("\n " + "⚡" * 6 + f" customProfiler log : global timer {run_time} / max memory use {mem_peack:^10}"+ "⚡" * 6)
|
|
118
|
+
str += "\n " + "⚡" * 50
|
|
119
|
+
str += "\n ⚡ {:^31} | {:8} | {:<29} | {:^17} ⚡".format("fct name"
|
|
120
|
+
, "Nb call"
|
|
121
|
+
, " time : mean / global"
|
|
122
|
+
, "mem : mean / max")
|
|
123
|
+
str += "\n ⚡ "+ "="*95 + "⚡"
|
|
124
|
+
for key, val in self.profData.items():
|
|
125
|
+
t_str = htd(val["dt"])
|
|
126
|
+
t_p_call_str = htd(val["dt"]/val['nbCall'])
|
|
127
|
+
str += f"\n ⚡ {key: ^31.31} | {val['nbCall']:^8} "
|
|
128
|
+
str += f"| {t_p_call_str} / {t_str} "
|
|
129
|
+
strmen = bytes2human(self.profData[key]["dm"]/val['nbCall'])
|
|
130
|
+
mmax = max(self.profData[key]["dm_list"])
|
|
131
|
+
if key in self.profThread.keys():
|
|
132
|
+
if mmax < self.profThread[key] :
|
|
133
|
+
mmax = self.profThread[key]
|
|
134
|
+
strmaxmem = bytes2human(mmax)
|
|
135
|
+
str += f"| {strmen:>7} / {strmaxmem:>7} ⚡"
|
|
136
|
+
str += "\n " + "⚡" * 50
|
|
137
|
+
return str
|
|
138
|
+
|
|
139
|
+
def __del__(self):
|
|
140
|
+
print(self)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
#https://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility/35804945#35804945
|
|
4
|
+
def add_logging_level(levelName, levelNum, methodName=None):
|
|
5
|
+
"""
|
|
6
|
+
Comprehensively adds a new logging level to the `logging` module and the
|
|
7
|
+
currently configured logging class.
|
|
8
|
+
|
|
9
|
+
`levelName` becomes an attribute of the `logging` module with the value
|
|
10
|
+
`levelNum`. `methodName` becomes a convenience method for both `logging`
|
|
11
|
+
itself and the class returned by `logging.getLoggerClass()` (usually just
|
|
12
|
+
`logging.Logger`). If `methodName` is not specified, `levelName.lower()` is
|
|
13
|
+
used.
|
|
14
|
+
|
|
15
|
+
To avoid accidental clobberings of existing attributes, this method will
|
|
16
|
+
raise an `AttributeError` if the level name is already an attribute of the
|
|
17
|
+
`logging` module or if the method name is already present
|
|
18
|
+
|
|
19
|
+
Example
|
|
20
|
+
-------
|
|
21
|
+
>>> addLoggingLevel('TRACE', logging.DEBUG - 5)
|
|
22
|
+
>>> logging.getLogger(__name__).setLevel("TRACE")
|
|
23
|
+
>>> logging.getLogger(__name__).trace('that worked')
|
|
24
|
+
>>> logging.trace('so did this')
|
|
25
|
+
>>> logging.TRACE
|
|
26
|
+
5
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
if not methodName:
|
|
30
|
+
methodName = levelName.lower()
|
|
31
|
+
|
|
32
|
+
if hasattr(logging, levelName):
|
|
33
|
+
raise AttributeError('{} already defined in logging module'.format(levelName))
|
|
34
|
+
if hasattr(logging, methodName):
|
|
35
|
+
raise AttributeError('{} already defined in logging module'.format(methodName))
|
|
36
|
+
if hasattr(logging.getLoggerClass(), methodName):
|
|
37
|
+
raise AttributeError('{} already defined in logger class'.format(methodName))
|
|
38
|
+
|
|
39
|
+
# This method was inspired by the answers to Stack Overflow post
|
|
40
|
+
# http://stackoverflow.com/q/2183233/2988730, especially
|
|
41
|
+
# http://stackoverflow.com/a/13638084/2988730
|
|
42
|
+
def logForLevel(self, message, *args, **kwargs):
|
|
43
|
+
if self.isEnabledFor(levelNum):
|
|
44
|
+
self._log(levelNum, message, args, **kwargs)
|
|
45
|
+
def logToRoot(message, *args, **kwargs):
|
|
46
|
+
logging.log(levelNum, message, *args, **kwargs)
|
|
47
|
+
|
|
48
|
+
logging.addLevelName(levelNum, levelName)
|
|
49
|
+
setattr(logging, levelName, levelNum)
|
|
50
|
+
setattr(logging.getLoggerClass(), methodName, logForLevel)
|
|
51
|
+
setattr(logging, methodName, logToRoot)
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
|
|
55
|
+
add_logging_level('PROFILER', 25)
|
|
56
|
+
logging.getLogger().setLevel("PROFILER")
|
|
57
|
+
logger = logging.getLogger("⚡")
|
|
58
|
+
|
|
59
|
+
ch = logging.StreamHandler()
|
|
60
|
+
logger.addHandler(ch)
|
|
61
|
+
|
|
62
|
+
logger.profiler("test print")
|
|
63
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
from functools import wraps
|
|
5
|
+
|
|
6
|
+
import threading
|
|
7
|
+
from threading import Thread
|
|
8
|
+
from threading import Event
|
|
9
|
+
|
|
10
|
+
import psutil
|
|
11
|
+
from psutil._common import bytes2human
|
|
12
|
+
process = psutil.Process()
|
|
13
|
+
|
|
14
|
+
from custom_profiler.line_by_line import trace_calls
|
|
15
|
+
from custom_profiler.collecteur import profiler_collecteur, INTERACTIVITY_OPT_ENUM
|
|
16
|
+
from custom_profiler.human_readable_time import human_time_duration as htd
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
profC = profiler_collecteur()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def task(event, fname, start_time, start_mem):
|
|
23
|
+
i = 0
|
|
24
|
+
while True :
|
|
25
|
+
time.sleep(0.01)
|
|
26
|
+
if i % 100 == True :
|
|
27
|
+
t_str = htd(time.perf_counter() - start_time)
|
|
28
|
+
dm = process.memory_info().rss - start_mem
|
|
29
|
+
profC.thread_view(fname, dm) #sauvegarde delta mem max
|
|
30
|
+
strmen = bytes2human(dm)
|
|
31
|
+
if profC.interractivity == INTERACTIVITY_OPT_ENUM.ENABLE :
|
|
32
|
+
if threading.active_count() < 3:
|
|
33
|
+
profC.print_line(fname, t_str, strmen, end="\r", color="\033[93m")
|
|
34
|
+
|
|
35
|
+
i += 1
|
|
36
|
+
if event.is_set():
|
|
37
|
+
break
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class thread_mananger:
|
|
41
|
+
def __init__(self, fname, start_time, start_mem):
|
|
42
|
+
self.event = Event()
|
|
43
|
+
self.t = Thread(target=task, args=(self.event, fname, start_time, start_mem))
|
|
44
|
+
self.t.daemon = True
|
|
45
|
+
self.t.start()
|
|
46
|
+
|
|
47
|
+
def end(self):
|
|
48
|
+
self.event.set()
|
|
49
|
+
self.t.join()
|
|
50
|
+
|
|
51
|
+
#https://stackoverflow.com/questions/5929107/decorators-with-parameters
|
|
52
|
+
def profiler(func, linePerline):
|
|
53
|
+
@wraps(func)
|
|
54
|
+
def wrapper(*args, **kwargs):
|
|
55
|
+
if profC.interractivity != INTERACTIVITY_OPT_ENUM.DISABLE and linePerline == False:
|
|
56
|
+
tm = thread_mananger(func.__name__, time.perf_counter(), process.memory_info().rss)
|
|
57
|
+
|
|
58
|
+
start_mem = process.memory_info().rss
|
|
59
|
+
start_time = time.perf_counter()
|
|
60
|
+
|
|
61
|
+
if linePerline :
|
|
62
|
+
sys.settrace(trace_calls)
|
|
63
|
+
result = func(*args, **kwargs)
|
|
64
|
+
if linePerline :
|
|
65
|
+
sys.settrace(None)
|
|
66
|
+
|
|
67
|
+
end_time = time.perf_counter()
|
|
68
|
+
end_mem = process.memory_info().rss
|
|
69
|
+
|
|
70
|
+
if profC.interractivity != INTERACTIVITY_OPT_ENUM.DISABLE and linePerline == False :
|
|
71
|
+
tm.end()
|
|
72
|
+
|
|
73
|
+
profC.save(func.__name__, end_time - start_time, end_mem - start_mem)
|
|
74
|
+
|
|
75
|
+
return result
|
|
76
|
+
return wrapper
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class magic_profiler():
|
|
80
|
+
|
|
81
|
+
def __init__(self, func_name):
|
|
82
|
+
self.func_name = func_name
|
|
83
|
+
|
|
84
|
+
def __enter__(self):
|
|
85
|
+
if profC.interractivity != INTERACTIVITY_OPT_ENUM.DISABLE :
|
|
86
|
+
self.tm = thread_mananger(self.func_name, time.perf_counter(), process.memory_info().rss)
|
|
87
|
+
self.start_mem = process.memory_info().rss
|
|
88
|
+
self.start_time = time.perf_counter()
|
|
89
|
+
|
|
90
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
91
|
+
end_time = time.perf_counter()
|
|
92
|
+
end_mem = process.memory_info().rss
|
|
93
|
+
if profC.interractivity != INTERACTIVITY_OPT_ENUM.DISABLE :
|
|
94
|
+
self.tm.end()
|
|
95
|
+
profC.save(self.func_name, end_time - self.start_time, end_mem - self.start_mem)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
TIME_UTS_DURATION_UNITS = (
|
|
6
|
+
('d', 60*60*24),
|
|
7
|
+
('h', 60*60),
|
|
8
|
+
('min', 60),
|
|
9
|
+
('s', 1),
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
TIME_LTS_DURATION_UNITS = (
|
|
14
|
+
('s ', 1),
|
|
15
|
+
('ms', 1e-3),
|
|
16
|
+
('µs', 1e-6),
|
|
17
|
+
('ns', 1e-9),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def human_time_duration(seconds):
|
|
22
|
+
assert type(seconds) in [float, int], f'seconds ({type(seconds)}) must be a float or int'
|
|
23
|
+
if seconds == 0:
|
|
24
|
+
return 0
|
|
25
|
+
if seconds <= 60 :
|
|
26
|
+
for unit, div in TIME_LTS_DURATION_UNITS:
|
|
27
|
+
if seconds >= div :
|
|
28
|
+
return f"{seconds/div:11.2f}{unit}"
|
|
29
|
+
return f"{Decimal(seconds):11.2E}s "
|
|
30
|
+
else :
|
|
31
|
+
if seconds < 3600 :
|
|
32
|
+
return f"{seconds//60:6.0f}min{seconds%60:2.0f}s"
|
|
33
|
+
else :
|
|
34
|
+
h = seconds // 3600
|
|
35
|
+
m = (seconds - h * 3600) // 60
|
|
36
|
+
s = seconds - (h * 3600) - (m * 60)
|
|
37
|
+
return f"{h:3}h{m:2}min{s:2}s"
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
|
|
41
|
+
for i in range(0, 11):
|
|
42
|
+
print(f"{10**-i:8}", human_time_duration(10**-i) \
|
|
43
|
+
, human_time_duration(2*10**-i)
|
|
44
|
+
, human_time_duration(10**-i - 10**(-i-3))
|
|
45
|
+
, human_time_duration(1/3*10**-i))
|
|
46
|
+
|
|
47
|
+
for i in [1, 2, 59, 60, 61, 144, 3599, 3600, 3601, 3660, 3661, 3600*120]:
|
|
48
|
+
print(f"{i:8}",human_time_duration(i))
|
|
49
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import time
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import psutil
|
|
6
|
+
from psutil._common import bytes2human
|
|
7
|
+
process = psutil.Process()
|
|
8
|
+
|
|
9
|
+
from custom_profiler.collecteur import profiler_collecteur
|
|
10
|
+
from custom_profiler.human_readable_time import human_time_duration as htd
|
|
11
|
+
|
|
12
|
+
profC = profiler_collecteur()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def trace_lines(frame, event, arg):
|
|
16
|
+
|
|
17
|
+
code_source, lineStart = inspect.getsourcelines(frame.f_code)
|
|
18
|
+
co_name = frame.f_code.co_name
|
|
19
|
+
|
|
20
|
+
if event != "line":
|
|
21
|
+
fname = f"l {frame.f_lineno:<3} {profC.__src[-1]:40}"
|
|
22
|
+
fnameSave = f"{co_name} l {frame.f_lineno:<3}"
|
|
23
|
+
t = time.perf_counter() - profC.__tic
|
|
24
|
+
men = process.memory_info().rss - profC.__tic_mem
|
|
25
|
+
profC.save(fnameSave, t, men, fname)
|
|
26
|
+
profC._print( " " + "⚡"*20 + f" line per line : end")
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
profC.__src.append(code_source[frame.f_lineno - lineStart].split('\n')[0])
|
|
30
|
+
|
|
31
|
+
if len(profC.__src) == 1 :
|
|
32
|
+
head = code_source[1].split('\n')[0]
|
|
33
|
+
profC._print( " " + "⚡"*20 + f" line per line : {head.split()[1].split('(')[0]} from {frame.f_code.co_filename}")
|
|
34
|
+
else :
|
|
35
|
+
fname = f"l {frame.f_lineno-1:<3} {profC.__src[-2]:40}"
|
|
36
|
+
fnameSave = f"{co_name} l {frame.f_lineno-1:<3}"
|
|
37
|
+
t = time.perf_counter() - profC.__tic
|
|
38
|
+
men = process.memory_info().rss - profC.__tic_mem
|
|
39
|
+
profC.save(fnameSave, t, men, fname)
|
|
40
|
+
|
|
41
|
+
profC.__tic = time.perf_counter()
|
|
42
|
+
profC.__tic_mem = process.memory_info().rss
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def trace_calls(frame, event, arg):
|
|
46
|
+
profC.__tic = 0.
|
|
47
|
+
profC.__tic_mem = 0.
|
|
48
|
+
profC.__src = []
|
|
49
|
+
|
|
50
|
+
if event != "call":
|
|
51
|
+
return
|
|
52
|
+
return trace_lines
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def lpl(fonction):
|
|
56
|
+
def wrapper(*args, **kwargs):
|
|
57
|
+
sys.settrace(trace_calls)
|
|
58
|
+
resultat = fonction(*args, **kwargs)
|
|
59
|
+
sys.settrace(None)
|
|
60
|
+
return resultat
|
|
61
|
+
return wrapper
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
|
|
66
|
+
@lpl
|
|
67
|
+
def my_func():
|
|
68
|
+
a = [1] * (10 ** 6)
|
|
69
|
+
b = [2] * (2 * 10 ** 7)
|
|
70
|
+
time.sleep(1)
|
|
71
|
+
del b
|
|
72
|
+
# time.sleep(5)
|
|
73
|
+
return a
|
|
74
|
+
|
|
75
|
+
my_func()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
custom_profiler/__init__.py,sha256=uZ_u96uNulrFnkRWXzk8kLYC1QMU3U_Zn1nC6eOA2c8,378
|
|
2
|
+
custom_profiler/collecteur.py,sha256=LhwCfbIA7rP7izCQN1Ry4JISvzHRQj-CXuXtOfMho8o,5967
|
|
3
|
+
custom_profiler/custum_logger.py,sha256=x6AV6PI3XNFszhPdJ08BynRhF5R5tJFaWvB09PvM-Dw,2450
|
|
4
|
+
custom_profiler/custum_profiler.py,sha256=nCDIATRqKm2-AzqeAeY0yhJwYfbVmLYqOsBzzgkpqpM,3103
|
|
5
|
+
custom_profiler/human_readable_time.py,sha256=xtYYVqfdbhag8L1ajhCjv8tq1YDxZEoq9a9ck_voVqM,1291
|
|
6
|
+
custom_profiler/line_by_line.py,sha256=MOSBGhrvStWm0PC-ByNbxKfkR9OwW6QVaC-c_wlNX64,2043
|
|
7
|
+
custom_profiler-0.1.0.dist-info/METADATA,sha256=CnpVw6SFKVoXdtaLlFBiJFkCG90UFzxXP2Kh25veJuI,237
|
|
8
|
+
custom_profiler-0.1.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
|
9
|
+
custom_profiler-0.1.0.dist-info/top_level.txt,sha256=ublWGGbVR2ckXpSymkDluEn2-sP8i6LVpql4DZOs1YY,16
|
|
10
|
+
custom_profiler-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
custom_profiler
|