Pull to refresh

Comments 14

Только подумал, щаз конкретика попрёт, даже IDLE открыл, а статья кончилась. Жду продолжения.
Да, пора бы узнать об инструментах, а то кроме print и ручного профилирования больше ничего и не пробовал
Инструментов очень много разных, тут Python вне конкуренции.
Рекомендую попробовать начать использовать logging вместо print. Вот пост небольшой был.
да, согласен, логи можно потом не удалять, в отличие от print'ов, да и в продакшене можно оставить, дебажные, надо взять за правило
Программисты по дебаггингу делятся на print и не print.
В следующий раз обязательно добавлю в статью секцию «tl;dr» ;)

Если совсем уж не терпится, то список инструментов можно посмотреть в презентации по самой первой ссылке в статье. Например, вот событийные профайлеры: speakerdeck.com/moscowdjango/profilirovaniie-i-otladka-django?slide=38
тысячи их...

А есть хоть один качественный визуальный? Наколбасить декораторов и консольных тулов на базе profile/cProfile каждый горазд, а до ума довести? А законченный продукт сделать?
Тут тоже интересуются. RunSnakeRun — это… хм, как-то не очень. :)
В PTVS, например, есть кое-что.
Нужно, чтобы был удобный, наглядный и мощный инструмент. И ещё, чтобы красивые отчёты делать умел. :)
Вот JetBrains давно просят-просят, а они внимания не обращают.

Хочется, чтобы выглядело вот как-то так примерно (это Matlab):



В моей практике самые удобные результаты профилирования и отчёты были у NYTProf (профайлер для Perl, авторы из New York Times).
В питоне всё не так удобно и красиво, конечно (к слову картинка профайлера из Matlab меня ужаснула =), но это не мешает профилировать программы и оптимизировать их.

Всегда хочется чего-то лучшего. Комментарий совершенно справедлив, и если этот вопрос действительно интересен, есть предложение пообщаться более плотно в личке.
к слову картинка профайлера из Matlab меня ужаснула =)

Да, может показаться страшненьким, но зато он довольно логичный и удобный. Тормозит, конечно, как и все подобные профайлеры, но понять где узкое место позволяет.

Вот контр-пример с cProfile. Например, есть у меня модуль с некой математической функцией.

Например, с такой вот:
def bspline_deboor(px, py, weights=None, degree=3, knots=None, t=100):
    def _bspline_deboor_interval(u, k):
        idx = (u >= k) & (u < np.hstack((k[1:], 2*k[-1])))
        row, col = np.nonzero(idx)
        sidx = np.argsort(row)

        return col[sidx]

    len_p = len(px)
    d = degree
    d1 = degree + 1

    if weights is None:
        weights = np.ones(len_p)

    if knots is None:
        knots = np.hstack((
            np.zeros(d),
            np.linspace(0, 1, len_p-d1+2),
            np.ones(d),
        ))

    if isinstance(t, int):
        t = np.linspace(knots[d], knots[-d1], t)

    px = px * weights
    py = py * weights

    len_knots = len(knots)
    len_t = len(t)

    m = 3
    tt = np.array(t, ndmin=2).T

    s = np.sum(util.fuzzy_equal(knots, tt), axis=1)
    ii = _bspline_deboor_interval(tt, knots)

    p = np.vstack((px, py, weights))
    pk = np.zeros((d1, m, len_p))
    c = np.zeros((m, len_t))

    for i in xrange(len_t):
        ti = t[i]
        si = s[i]
        ix = ii[i]

        r = slice(ix-d, ix-si+1)
        pk[0, :, r] = p[:, r]

        h = d - si

        if h > 0:
            # de Boor recursion formula
            for r in xrange(h):
                r1 = r + 1
                q = ix - 1

                for j in xrange(q-d+r1, q-si+1):
                    j1 = j + 1

                    a = (ti - knots[j1]) / (knots[j1+d-r] - knots[j1])
                    pk[r1, :, j1] = (1 - a) * pk[r, :, j] + a * pk[r, :, j1]

            val = pk[d-si, :, ix-si]

        elif ix == (len_knots-1):
            val = p[:, -1]
        else:
            val = p[:, ix-d]

        c[:, i] = val

    # Normalize and remove weights from computed points
    c = c[:-1, :] / c[-1, :]

    sx = np.array(c[0, :])
    sy = np.array(c[1, :])

    return sx, sy



Которая работает, скажем ~0.016-0.017 сек. в некоторых условиях. Скажем, померил я это через time.clock()/timeit. Теперь хочу посмотреть профайлером более подробно:

p = cProfile.Profile()
p.enable()
sx, sy = splines.bspline_deboor(px, py, degree=3, t=100)
p.disable()
p.print_stats()


И что я вижу:
93 function calls in 0.016 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 _methods.py:16(_sum)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:1172(nonzero)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:1422(sum)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:599(argsort)
        2    0.000    0.000    0.000    0.000 function_base.py:6(linspace)
        2    0.000    0.000    0.000    0.000 numeric.py:120(ones)
        8    0.000    0.000    0.000    0.000 numeric.py:322(asanyarray)
        1    0.000    0.000    0.000    0.000 shape_base.py:177(vstack)
        2    0.000    0.000    0.000    0.000 shape_base.py:228(hstack)
        3    0.000    0.000    0.000    0.000 shape_base.py:58(atleast_2d)
        5    0.000    0.000    0.000    0.000 shape_base.py:6(atleast_1d)
        1    0.015    0.015    0.016    0.016 splines.py:14(bspline_deboor)
        1    0.000    0.000    0.000    0.000 splines.py:73(_bspline_deboor_interval)
        1    0.000    0.000    0.000    0.000 util.py:136(fuzzy_equal)
        2    0.000    0.000    0.000    0.000 {isinstance}
       22    0.000    0.000    0.000    0.000 {len}
        3    0.000    0.000    0.000    0.000 {map}
        8    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'argsort' of 'numpy.ndarray' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {method 'nonzero' of 'numpy.ndarray' objects}
        1    0.000    0.000    0.000    0.000 {method 'reduce' of 'numpy.ufunc' objects}
        1    0.000    0.000    0.000    0.000 {method 'reshape' of 'numpy.ndarray' objects}
        2    0.000    0.000    0.000    0.000 {numpy.core.multiarray.arange}
       11    0.000    0.000    0.000    0.000 {numpy.core.multiarray.array}
        3    0.000    0.000    0.000    0.000 {numpy.core.multiarray.concatenate}
        2    0.000    0.000    0.000    0.000 {numpy.core.multiarray.copyto}
        2    0.000    0.000    0.000    0.000 {numpy.core.multiarray.empty}
        3    0.000    0.000    0.000    0.000 {numpy.core.multiarray.zeros}



Я ничего не понял из этого отчёта, правда. Я так и не знаю где же узкое место в моей функции. :)
Я просто запустил профайлер с настройками по умолчанию и не получил ничего вразумительного на первый взгляд, да и на второй тоже. Я считаю, что это не очень здорово. :)
Как уже отметили выше, лучше использовать другой профайлер — который выдает информацию по каждой строчке: pythonhosted.org/line_profiler/
Кстати, если в профайлере PTVS вам чего-то не хватает — напишите, пожалуйста.

(из вышеприведенных картинок с Matlab несколько неочевидно — вроде бы есть все то же самое, кроме построчной выборки)
Sign up to leave a comment.