简体   繁体   中英

Line profiling with cython in jupyter notebook

I'm trying to use liner_profiler library in jupyter notebook with cython function. It is working only halfway. The result I get only consist of first row of the function and no profiling results.

%%cython -a
# cython: linetrace=True
# cython: binding=True
# distutils: define_macros=CYTHON_TRACE_NOGIL=1
import numpy as np
cimport numpy as np
from datetime import datetime
import math


cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):
    cdef np.ndarray months=np.array([31,28,31,30,31,30,31,31,30,31,30,31])
    if month==2:
        if (year%4==0 and year%100!=0) or (year%400==0):
            return 29
    return months[month-1]

For the profiling result int onlt shows one line of code

    Timer unit: 1e-07 s

Total time: 0.0015096 s
File: .ipython\cython\_cython_magic_0154a9feed9bbd6e4f23e57d73acf50f.pyx
Function: get_days at line 15

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    15                                           cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):

This can be seen as a bug in the line_profiler (if it is supposed to support Cython). To get the code of the profiled function, line_profiler reads the pyx -file and tries to extract the code with help of inspect.getblock :

...
# read pyx-file
all_lines = linecache.getlines(filename)
# try to extract body of the function strarting at start_lineno:
sublines = inspect.getblock(all_lines[start_lineno-1:])
...

However, getblock knows nothing about cpdef -function, as python has only def -functions and thus yields wrong function-body (ie only the signature).

Workaround:

A simple work around would be to introduce a dummy def -function, which would be a sentinel for the cpdef -function in such a way, that inspect.getblock would yield the whole body of the cpdef-function + body of the the sentinel function, ie:

%%cython
...
cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):
    ...

def get_days_sentinel():
    pass

and now the report %lprun -f get_days get_days(2019,3) looks as follows:

Timer unit: 1e-06 s

Total time: 1.7e-05 s
File: XXXX.pyx
Function: get_days at line 10

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    10                                           cpdef np.int64_t get_days(np.int64_t year, np.int64_t month):
    11         1         14.0     14.0     82.4      cdef np.ndarray months=np.array([31,28,31,30,31,30,31,31,30,31,30,31])
    12         1          1.0      1.0      5.9      if month==2:
    13                                                   if (year%4==0 and year%100!=0) or (year%400==0):
    14                                                       return 29
    15         1          2.0      2.0     11.8      return months[month-1]
    16                                           
    17                                           def get_days_sentinel():
    18                                               pass

There are still somewhat ugly trailing lines from the sentinel, but it is probably better as not seeing anything at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM