Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how profiling class method using IPython %lprun magic function

How can I profile a method of an object called inside a function? I am using the %lprun magic in a jupyter notebook. Please see the following ex.py example file:

class foo():
    def __init__(self, a=0, n=1):
                self.a=a
                self.n=n

    def compute(self):
        result = 0
        for i in range(self.n):
            result += self.a
        return result 

def my_func():
    a = 1
    n = 1000
    my_foo = foo(a, n)
    result = my_foo.compute()
    print(result)

Then, from my jupyter notebook, i can profile my_func:

 from ex import my_func

 %lprun -f my_func my_func()

but I cannot profile my compute method:

from ex import my_func

%lprun -f my_foo.compute my_func()

Is what I want even possible? How would I have to fill the class method in the -f argument for it to work?

According to the documentation, "cProfile only times explicit function calls, not special methods called because of syntax", ... so it should work.

A (maybe) related question that I found is here.

like image 442
Youcef Avatar asked Mar 06 '18 17:03

Youcef


People also ask

How do you use %% Timeit in Jupyter?

The “%timeit” is a line magic command in which the code consists of a single line or should be written in the same line for measuring the execution time. In the “%timeit” command, the particular code is specified after the “%timeit” is separated by a space.

What does %% mean in Jupyter notebook?

Save this question. Show activity on this post. Both ! and % allow you to run shell commands from a Jupyter notebook. % is provided by the IPython kernel and allows you to run "magic commands", many of which include well-known shell commands. ! , provided by Jupyter, allows shell commands to be run within cells.

What is the magic command in Jupyter notebook to time how long a cell takes to run?

Here using -r and -n we precise that we want 20 runs executing the statement 100 times each. What's more, %timeit can also be used as a magic cell. It will then measure the time execution of the whole cell instead of a single statement.


1 Answers

TL;DR: Use foo in %lprun -f foo.compute my_func(), not my_foo as in your example.


Given the current example, you can profile your class and method as such:

  1. %load_ext line_profiler

  2. Profile your function in which you call your class: %lprun -f my_func my_func(), which returns:


Timer unit: 1e-06 s

Total time: 0.000363 s
File: <ipython-input-111-dedac733c95b>
Function: my_func at line 12

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    12                                           def my_func():
    13         1          2.0      2.0      0.6      a = 1
    14         1          1.0      1.0      0.3      n = 1000
    15         1          4.0      4.0      1.1      my_foo = foo(a, n)
    16         1        278.0    278.0     76.6      result = my_foo.compute()
    17         1         78.0     78.0     21.5      print(result)

  1. Then, upon inspection you see that most of the time is being spent within your method my_foo.compute(). my_foo is an instance of the the foo class, so you make a further and more specific profiler call %lprun -f foo.compute my_func(), which returns:

Timer unit: 1e-06 s

Total time: 0.001566 s
File: <ipython-input-12-e96be9cf3108>
Function: compute at line 6

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     6                                               def compute(self):
     7         1          3.0      3.0      0.2          result = 0
     8      1001        765.0      0.8     48.9          for i in range(self.n):
     9      1000        797.0      0.8     50.9              result += self.a
    10         1          1.0      1.0      0.1          return result

like image 137
S.A. Avatar answered Oct 13 '22 18:10

S.A.