I'm trying to start and stop the line profiling of a Python function multiple times during runtime. Therefore I'd like to reset the already collected stats when starting a new profiling. Is there a way to do that?
In lack of an obvious solution I also tried replacing the line profiler lp
with a fresh instance:
#!/usr/bin/env python3
from line_profiler import LineProfiler
lp = LineProfiler()
@lp
def count():
return sum(range(1_000_000))
count()
lp.print_stats()
# reset line profiler
new_lp = LineProfiler()
for f in lp.functions:
new_lp(f)
lp = new_lp
count()
lp.print_stats()
But somehow the new stats are empty, possibly because the function count()
can't be wrapped twice?
CodePudding user response:
I came up with the following solution based of a new profiler class. Every time a profiling is started, it creates a new instance of LineProfiler
. The key is to store wrapped functions next to the originals, so that they can be reset when stopping the profiler.
from typing import Optional
from line_profiler import LineProfiler
from functools import wraps
class MyLineProfiler:
def __init__(self):
self.functions: list[list] = []
self.line_profiler: Optional[LineProfiler] = None
def __call__(self, func):
index = len(self.functions)
@wraps(func)
def wrap(*args, **kw):
return self.functions[index][1](*args, **kw)
self.functions.append([func, func])
return wrap
def start(self):
self.line_profiler = LineProfiler()
for f in self.functions:
f[1] = self.line_profiler(f[0])
def stop(self, *, print: bool = True):
for f in self.functions:
f[1] = f[0]
if self.line_profiler and print:
self.line_profiler.print_stats()
def reset(self):
self.stop(print=False)
self.start()
The wrapped functions call whatever is currently stored at functions[index][1]
, either the original func
(when no profiling is stopped) or the decorated one (when start()
was called).
It can be used as follows:
profile = MyLineProfiler()
@profile
def count():
return sum(range(1_000_000))
count()
profile.start()
count()
count()
profile.stop()
profile.start()
count()
profile.stop()