[SOLVED] How to clear/reset results of the Python line profiler?

Issue

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?

Solution

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()

Answered By – Falko

Answer Checked By – Clifford M. (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *