Линейное профилирование с помощью Cython в блокноте Jupyter

Я пытаюсь использовать библиотеку liner_profiler в ноутбуке Jupyter с функцией Cython. Это работает только на полпути. Результат, который я получаю, состоит только из первой строки функции и без результатов профилирования.

%%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]

Для результата профилирования int onlt показывает одну строку кода

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

1 ответ

Решение

Это можно рассматривать как ошибку в line_profiler (если предполагается поддержка Cython). Чтобы получить код профилированной функции, line_profiler читает pyx -файл и пытается извлечь код с помощью 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:])
...

Тем не мение, getblock ничего не знает о cpdef -функция, так как питон имеет только def -функции и, следовательно, дает неправильное тело функции (т.е. только подпись).

Временное решение:

Простой обходной путь - ввести пустышку def -функция, которая была бы часовым для cpdef -функция таким образом, что inspect.getblock выдаст все тело функции cpdef + тело функции часового, то есть:

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

def get_days_sentinel():
    pass

а теперь отчет %lprun -f get_days get_days(2019,3) выглядит следующим образом:

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

От стража все еще есть несколько отвратительные следы, но, вероятно, лучше вообще ничего не видеть.

Другие вопросы по тегам