Bagaimana Anda bisa membuat profil skrip Python?

1283

Project Euler dan kontes pengkodean lainnya sering kali memiliki waktu maksimum untuk dijalankan atau orang-orang membanggakan seberapa cepat solusi khusus mereka berjalan. Dengan Python, terkadang pendekatannya agak kludgey - yaitu menambahkan kode waktu ke __main__.

Apa cara yang baik untuk membuat profil berapa lama program Python perlu dijalankan?

Chris Lawlor
sumber
113
Program euler proyek tidak perlu dibuat profil. Entah Anda memiliki algoritme yang berfungsi kurang dari satu menit, atau Anda memiliki algoritme yang sepenuhnya salah. "Tuning" jarang tepat. Anda biasanya harus mengambil pendekatan baru.
S.Lott
105
S.Lott: Membuat profil sering kali merupakan cara yang bermanfaat untuk menentukan subrutin mana yang lambat. Subrutin yang memakan waktu lama adalah kandidat yang bagus untuk peningkatan algoritmik.
stalepretzel

Jawaban:

1370

Python menyertakan profiler yang disebut cProfile . Ini tidak hanya memberikan total waktu berjalan, tetapi juga kali setiap fungsi secara terpisah, dan memberi tahu Anda berapa kali setiap fungsi dipanggil, sehingga memudahkan untuk menentukan di mana Anda harus melakukan optimasi.

Anda dapat memanggilnya dari dalam kode Anda, atau dari penerjemah, seperti ini:

import cProfile
cProfile.run('foo()')

Yang lebih bermanfaat lagi, Anda dapat menjalankan cProfile saat menjalankan skrip:

python -m cProfile myscript.py

Untuk membuatnya lebih mudah, saya membuat file batch kecil yang disebut 'profile.bat':

python -m cProfile %1

Jadi yang harus saya lakukan adalah menjalankan:

profile euler048.py

Dan saya mendapatkan ini:

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

EDIT: Tautan yang diperbarui ke sumber video yang bagus dari PyCon 2013 berjudul Python Profiling
Juga melalui YouTube .

Chris Lawlor
sumber
251
Juga berguna untuk mengurutkan hasil, yang dapat dilakukan dengan -s switch, contoh: '-s time'. Anda dapat menggunakan opsi penyortiran kumulatif / nama / waktu / file.
Jiri
19
Perlu dicatat juga bahwa Anda dapat menggunakan modul cProfile dari ipython menggunakan fungsi sulap% prun (profil run). Impor modul Anda terlebih dahulu, lalu panggil fungsi utama dengan% prun: import euler048; % prun euler048.main ()
RussellStewart
53
Untuk memvisualisasikan dump cProfile (dibuat oleh python -m cProfile -o <out.profile> <script>), RunSnakeRun , dipanggil sebagai runsnake <out.profile>sangat berharga.
Lily Chung
13
@NeilG bahkan untuk python 3, cprofilemasih dianjurkan lebih profile.
trichoplax
17
Untuk memvisualisasikan dump cProfile, RunSnakeRun belum diperbarui sejak 2011 dan tidak mendukung python3. Anda harus menggunakan snakeviz bukan
Giacomo Tecya Pigani
424

Beberapa waktu lalu saya membuat pycallgraphyang menghasilkan visualisasi dari kode Python Anda. Sunting: Saya telah memperbarui contoh untuk bekerja dengan 3.3, rilis terbaru pada tulisan ini.

Setelah a pip install pycallgraphdan menginstal GraphViz Anda dapat menjalankannya dari baris perintah:

pycallgraph graphviz -- ./mypythonscript.py

Atau, Anda dapat membuat profil bagian tertentu dari kode Anda:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

Salah satu dari ini akan menghasilkan pycallgraph.pngfile yang mirip dengan gambar di bawah ini:

masukkan deskripsi gambar di sini

gak
sumber
43
Apakah Anda mewarnai berdasarkan jumlah panggilan? Jika demikian, Anda harus memberi warna berdasarkan waktu karena fungsi dengan panggilan terbanyak tidak selalu menjadi yang paling banyak memakan waktu.
merah
21
@Red Anda dapat menyesuaikan warna sesuka Anda, dan bahkan secara independen untuk setiap pengukuran. Misalnya merah untuk panggilan, biru untuk waktu, hijau untuk penggunaan memori.
gak
2
mendapatkan kesalahan iniTraceback (most recent call last): /pycallgraph.py", line 90, in generate output.done() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 94, in done source = self.generate() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 143, in generate indent_join.join(self.generate_attributes()), File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 169, in generate_attributes section, self.attrs_from_dict(attrs), ValueError: zero length field name in format
Ciasto piekarz
3
Saya memperbarui ini untuk menyebutkan bahwa Anda perlu menginstal GraphViz untuk hal-hal yang berfungsi seperti yang dijelaskan. Di Ubuntu ini adil sudo apt-get install graphviz.
mlissner
2
Ini membutuhkan sedikit usaha untuk menginstal di sini adalah 3 langkah untuk membantu. 1. Instal via pip, 2. Instal GraphViz via exe 3. Atur variabel path ke direktori GraphViz 4. Cari tahu cara memperbaiki semua kesalahan lainnya. 5. Cari tahu di mana ia menyimpan file png?
marsh
199

Perlu ditunjukkan bahwa menggunakan profiler hanya berfungsi (secara default) pada utas utama, dan Anda tidak akan mendapatkan informasi dari utas lain jika Anda menggunakannya. Ini bisa menjadi semacam gotcha karena sepenuhnya tidak disebutkan dalam dokumentasi profiler .

Jika Anda juga ingin membuat utas profil, Anda akan ingin melihat threading.setprofile()fungsi di dokumen.

Anda juga dapat membuat threading.Threadsubclass sendiri untuk melakukannya:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

dan gunakan ProfiledThreadkelas itu alih-alih yang standar. Mungkin memberi Anda lebih banyak fleksibilitas, tapi saya tidak yakin itu layak, terutama jika Anda menggunakan kode pihak ketiga yang tidak akan menggunakan kelas Anda.

Joe Shaw
sumber
1
Saya juga tidak melihat referensi untuk runcall dalam dokumentasi. Melihat cProfile.py, saya tidak yakin mengapa Anda menggunakan fungsi threading.Thread.run atau self sebagai argumen. Saya berharap untuk melihat referensi ke metode menjalankan thread lain di sini.
PypeBros
Itu tidak ada dalam dokumentasi, tetapi ada di modul. Lihat hg.python.org/cpython/file/6bf07db23445/Lib/cProfile.py#l140 . Itu memungkinkan Anda untuk membuat profil panggilan fungsi tertentu, dan dalam kasus kami, kami ingin membuat profil fungsi Thread target, yang dilakukan oleh threading.Thread.run()panggilan tersebut. Tapi seperti yang saya katakan di jawaban, mungkin tidak layak untuk subkelas Thread, karena kode pihak ketiga mana pun tidak akan menggunakannya, dan sebagai gantinya digunakan threading.setprofile().
Joe Shaw
9
membungkus kode dengan profiler.enable () dan profiler.disable () tampaknya bekerja dengan baik juga. Pada dasarnya itulah yang dilakukan runcall dan tidak memaksakan sejumlah argumen atau hal serupa.
PypeBros
1
Saya menggabungkan stackoverflow.com/questions/10748118/… saya sendiri dengan ddaa.net/blog/python/lsprof-calltree dan itu berfungsi
;!
1
Joe, apakah Anda tahu bagaimana profiler bermain dengan asyncio di Python 3.4?
Nick Chammas
149

Wiki python adalah halaman yang bagus untuk profil sumber daya: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

seperti halnya python docs: http://docs.python.org/library/profile.html

seperti yang ditunjukkan oleh Chris Lawlor cProfile adalah alat yang hebat dan dapat dengan mudah digunakan untuk mencetak ke layar:

python -m cProfile -s time mine.py <args>

atau ke file:

python -m cProfile -o output.file mine.py <args>

PS> Jika Anda menggunakan Ubuntu, pastikan untuk menginstal profil python

apt-get install python-profiler 

Jika Anda menghasilkan file Anda bisa mendapatkan visualisasi yang bagus menggunakan alat berikut

PyCallGraph: alat untuk membuat gambar panggilan grafik
menginstal:

 pip install pycallgraph

Lari:

 pycallgraph mine.py args

melihat:

 gimp pycallgraph.png

Anda dapat menggunakan apa pun yang Anda suka untuk melihat file png, saya menggunakan gimp
Sayangnya saya sering mendapatkannya

dot: grafik terlalu besar untuk bitmap cairo-renderer. Penskalaan 0,257079 agar sesuai

yang membuat gambar saya luar biasa kecil. Jadi saya biasanya membuat file svg:

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS> pastikan untuk menginstal graphviz (yang menyediakan program dot):

pip install graphviz

Grafik Alternatif menggunakan gprof2dot melalui @maxy / @quodlibetor:

pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
brent.payne
sumber
12
gprof2dot dapat melakukan grafik itu juga. Saya pikir outputnya sedikit lebih bagus ( contoh ).
maksimal
2
graphviz juga diperlukan jika Anda menggunakan OSX
Vaibhav Mishra
134

@ Maxy mengomentari jawaban ini cukup membantu saya sehingga saya pikir itu layak jawaban sendiri: Saya sudah punya file .pstats yang dihasilkan cProfile dan saya tidak ingin menjalankan kembali hal-hal dengan pycallgraph, jadi saya menggunakan gprof2dot , dan mendapatkan cukup svgs:

$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg

dan BLAM!

Ia menggunakan dot (hal yang sama yang digunakan pycallgraph) sehingga output terlihat serupa. Saya mendapat kesan bahwa gprof2dot kehilangan lebih sedikit informasi:

contoh keluaran gprof2dot

quodlibetor
sumber
1
Pendekatan yang baik, berfungsi dengan sangat baik karena Anda dapat melihat SVG di Chrome dll dan meningkatkannya. Baris ketiga memiliki kesalahan ketik, seharusnya: ln -s pwd/gprof2dot/gprof2dot.py $ HOME / bin (atau gunakan ln -s $ PWD / gprof2dot / gprof2dot.py ~ / bin di sebagian besar shell - aksen kubur diambil sebagai pemformatan terlebih dahulu saat memformat terlebih dahulu Versi: kapan).
RichVel
2
Ah, poin bagus. Saya mendapatkan ln's argumen-urutan yang salah hampir setiap waktu.
quodlibetor
7
triknya adalah untuk mengingat bahwa ln dan cp memiliki urutan argumen yang sama - anggap sebagai 'menyalin file1 ke file2 atau dir2, tetapi membuat tautan'
RichVel
Itu masuk akal, saya pikir penggunaan "TARGET" di halaman manual melempar saya.
quodlibetor
Tolong, bagaimana Anda mendapatkan sudut membulat? Saya merasa itu meningkatkan keterbacaan. Saya hanya mendapatkan sudut-sudut tajam jelek yang tidak keren di hadapan banyak tepi di sekitar kotak.
Hibou57
78

Saya berlari ke alat yang berguna yang disebut SnakeViz ketika meneliti topik ini. SnakeViz adalah alat visualisasi profiling berbasis web. Sangat mudah untuk menginstal dan menggunakan. Cara biasa saya menggunakannya adalah untuk menghasilkan file stat dengan %prundan kemudian melakukan analisis di SnakeViz.

Teknik utama yaitu yang digunakan adalah grafik Sunburst seperti yang ditunjukkan di bawah ini, di mana hirarki panggilan fungsi diatur sebagai lapisan busur dan info waktu dikodekan dalam lebar sudutnya.

Yang terbaik adalah Anda bisa berinteraksi dengan bagan. Sebagai contoh, untuk memperbesar satu dapat mengklik pada busur, dan busur dan turunannya akan diperbesar sebagai sunburst baru untuk menampilkan rincian lebih lanjut.

masukkan deskripsi gambar di sini

zaxliu
sumber
1
Jawaban CodeCabbie mencakup instruksi instalasi (pendek), dan menunjukkan cara (mudah) menggunakan SnakeViz.
Oren Milman
Di sini saya telah membaca panduan IMHO baik cara menggunakan profil untuk Python di jupyter notebook: towardsdatascience.com/speed-up-jupyter-notebooks-20716cbe2025
Alexei Martianov
73

Cara termudah dan tercepat untuk menemukan ke mana perginya waktu.

1. pip install snakeviz

2. python -m cProfile -o temp.dat <PROGRAM>.py

3. snakeviz temp.dat

Menggambar diagram lingkaran di browser. Bagian terbesar adalah fungsi masalah. Sangat sederhana.

CodeCabbie
sumber
1
Ini sangat membantu. Terima kasih.
jippyjoe4
55

Saya pikir itu cProfilebagus untuk profil, sementara kcachegrindbagus untuk memvisualisasikan hasil. Di pyprof2calltreeantara menangani konversi file.

python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree

Untuk menginstal alat yang diperlukan (setidaknya di Ubuntu):

apt-get install kcachegrind
pip install pyprof2calltree

Hasil:

Tangkapan layar hasilnya

Federico
sumber
9
Pengguna Mac memasang brew install qcachegrinddan masing kcachegrind - masing dengan qcachegrind dalam keterangan untuk berhasil membuat profil.
Kevin Katzke
Saya harus melakukan ini untuk membuatnya bekerja:export QT_X11_NO_MITSHM=1
Yonatan Simson
41

Juga layak disebutkan adalah penampil dump GUI cProfile RunSnakeRun . Ini memungkinkan Anda untuk mengurutkan dan memilih, sehingga memperbesar bagian yang relevan dari program. Ukuran persegi panjang dalam gambar sebanding dengan waktu yang dibutuhkan. Jika Anda mengarahkan mouse di atas persegi panjang itu menyoroti panggilan itu di dalam tabel dan di mana-mana di peta. Ketika Anda mengklik dua kali pada persegi panjang itu memperbesar bagian itu. Ini akan menunjukkan kepada Anda siapa yang memanggil bagian itu dan apa yang bagian itu panggilan.

Informasi deskriptif sangat membantu. Ini menunjukkan kepada Anda kode untuk bit yang dapat membantu ketika Anda berurusan dengan panggilan perpustakaan built-in. Ini memberi tahu Anda file apa dan baris apa untuk menemukan kode.

Juga ingin menunjukkan bahwa OP mengatakan 'profiling' tetapi sepertinya dia maksudkan 'timing'. Perlu diingat program akan berjalan lebih lambat saat diprofilkan.

masukkan deskripsi gambar di sini

Pete
sumber
34

Modul profil yang bagus adalah line_profiler (dipanggil menggunakan skrip kernprof.py). Itu bisa diunduh di sini .

Pemahaman saya adalah bahwa cProfile hanya memberikan informasi tentang total waktu yang dihabiskan di setiap fungsi. Jadi setiap baris kode tidak diberi batas waktu. Ini adalah masalah dalam komputasi ilmiah karena seringkali satu baris tunggal dapat mengambil banyak waktu. Juga, seingat saya, cProfile tidak mengetahui waktu yang saya habiskan di katakanlah numpy.dot.

Ian Langmore
sumber
34

Baru-baru ini saya membuat tuna untuk memvisualisasikan runtime Python dan mengimpor profil; ini mungkin membantu di sini.

masukkan deskripsi gambar di sini

Instal dengan

pip install tuna

Buat profil runtime

python3 -m cProfile -o program.prof yourfile.py

atau profil impor (diperlukan Python 3.7+)

python3 -X importprofile yourfile.py 2> import.log

Kemudian jalankan tuna pada file

tuna program.prof
Nico Schlömer
sumber
33

profil

line_profiler(sudah disajikan di sini) juga terinspirasi pprofile, yang digambarkan sebagai:

Garis-granularitas, deterministik thread-aware dan statistik murni-python profiler

Ini memberikan garis-granularitas sebagai line_profiler, adalah Python murni, dapat digunakan sebagai perintah mandiri atau modul, dan bahkan dapat menghasilkan file format callgrind yang dapat dengan mudah dianalisis [k|q]cachegrind.

vprof

Ada juga vprof , paket Python yang dideskripsikan sebagai:

[...] menyediakan visualisasi yang kaya dan interaktif untuk berbagai karakteristik program Python seperti waktu berjalan dan penggunaan memori.

peta panas

BenC
sumber
14

Ada banyak jawaban bagus tetapi mereka menggunakan baris perintah atau program eksternal untuk membuat profil dan / atau mengurutkan hasilnya.

Saya benar-benar merindukan cara yang bisa saya gunakan dalam IDE saya (eclipse-PyDev) tanpa menyentuh baris perintah atau menginstal apa pun. Jadi begini.

Pembuatan profil tanpa baris perintah

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __name__ == '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

Lihat dokumen atau jawaban lain untuk info lebih lanjut.

David Mašek
sumber
misalnya, profil mencetak {peta} atau {xxx}. bagaimana saya tahu metode {xxx} dipanggil dari file mana? profil saya mencetak {metode 'kompres' pada objek 'zlib.Compress'} mengambil sebagian besar waktu, tetapi saya tidak menggunakan zlib apa pun, jadi saya kira beberapa fungsi panggilan numpy dapat menggunakannya. Bagaimana saya tahu file dan jalur mana tepatnya yang membutuhkan banyak waktu?
machen
12

Mengikuti jawaban Joe Shaw tentang kode multi-utas untuk tidak berfungsi seperti yang diharapkan, saya menduga bahwa runcallmetode di cProfile hanya melakukan self.enable()dan self.disable()memanggil sekitar panggilan fungsi yang diprofilkan, sehingga Anda dapat melakukannya sendiri dan memiliki kode apa pun yang Anda inginkan di antaranya. gangguan minimal dengan kode yang ada.

PypeBros
sumber
3
Tip luar biasa! Sebuah mengintip cepat di cprofile.py's kode sumber mengungkapkan itu persis apa yang runcall()dilakukannya. Menjadi lebih spesifik, setelah membuat instance Profil dengan prof = cprofile.Profile(), segera panggil prof.disable(), lalu tambahkan prof.enable()dan prof.disable()panggil di sekitar bagian kode yang ingin Anda profil.
martineau
Ini sangat membantu, tetapi tampaknya kode yang benar-benar antara aktif dan nonaktif tidak diprofilkan - hanya fungsi yang dipanggil. Apakah saya punya hak ini? Saya harus membungkus kode itu dalam panggilan fungsi untuk menghitung ke salah satu angka di print_stats ().
Bob Stein
10

Dalam sumber Virtaal ada kelas dan dekorator yang sangat berguna yang dapat membuat profil (bahkan untuk metode / fungsi tertentu) sangat mudah. Outputnya kemudian dapat dilihat dengan sangat nyaman di KCacheGrind.

Walter
sumber
1
Terima kasih untuk permata ini. FYI: Ini dapat digunakan sebagai modul mandiri dengan kode apa pun, basis kode Virtaal tidak diperlukan. Cukup simpan file ke profiling.py dan impor profile_func (). Gunakan @profile_func () sebagai dekorator untuk fungsi apa pun yang Anda perlukan untuk profil dan biola. :)
Amjith
9

cProfile sangat bagus untuk profil cepat tetapi sebagian besar waktu itu berakhir untuk saya dengan kesalahan. Fungsi runctx memecahkan masalah ini dengan menginisialisasi dengan benar lingkungan dan variabel, semoga bermanfaat bagi seseorang:

import cProfile
cProfile.runctx('foo()', None, locals())
Datageek
sumber
7

Jika Anda ingin membuat profiler kumulatif, artinya menjalankan fungsi beberapa kali berturut-turut dan menonton jumlah hasilnya.

Anda dapat menggunakan cumulative_profilerdekorator ini :

itu python> = 3,6 spesifik, tetapi Anda dapat menghapusnya nonlocalagar berfungsi pada versi yang lebih lama.

import cProfile, pstats

class _ProfileFunc:
    def __init__(self, func, sort_stats_by):
        self.func =  func
        self.profile_runs = []
        self.sort_stats_by = sort_stats_by

    def __call__(self, *args, **kwargs):
        pr = cProfile.Profile()
        pr.enable()  # this is the profiling section
        retval = self.func(*args, **kwargs)
        pr.disable()

        self.profile_runs.append(pr)
        ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
        return retval, ps

def cumulative_profiler(amount_of_times, sort_stats_by='time'):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            nonlocal function, amount_of_times, sort_stats_by  # for python 2.x remove this row

            profiled_func = _ProfileFunc(function, sort_stats_by)
            for i in range(amount_of_times):
                retval, ps = profiled_func(*args, **kwargs)
            ps.print_stats()
            return retval  # returns the results of the function
        return wrapper

    if callable(amount_of_times):  # incase you don't want to specify the amount of times
        func = amount_of_times  # amount_of_times is the function in here
        amount_of_times = 5  # the default amount
        return real_decorator(func)
    return real_decorator

Contoh

membuat profil fungsi baz

import time

@cumulative_profiler
def baz():
    time.sleep(1)
    time.sleep(2)
    return 1

baz()

baz berlari 5 kali dan mencetak ini:

         20 function calls in 15.003 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10   15.003    1.500   15.003    1.500 {built-in method time.sleep}
        5    0.000    0.000   15.003    3.001 <ipython-input-9-c89afe010372>:3(baz)
        5    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

menentukan jumlah kali

@cumulative_profiler(3)
def baz():
    ...
moshevi
sumber
7

Solusi terminal saja (dan paling sederhana), jika semua UI mewah gagal untuk menginstal atau menjalankan:
abaikan cProfilesepenuhnya dan ganti dengan pyinstrument, yang akan mengumpulkan dan menampilkan pohon panggilan segera setelah eksekusi.

Install:

$ pip install pyinstrument

Profil dan hasil tampilan:

$ python -m pyinstrument ./prog.py

Bekerja dengan python2 dan 3.

[EDIT] Dokumentasi API, untuk profil hanya sebagian dari kode, dapat ditemukan di sini .

Francois
sumber
6

Cara saya adalah menggunakan yappi ( https://github.com/sumerc/yappi ). Ini sangat berguna dikombinasikan dengan server RPC di mana (bahkan hanya untuk debugging) Anda mendaftar metode untuk memulai, menghentikan dan mencetak informasi profil, misalnya dengan cara ini:

@staticmethod
def startProfiler():
    yappi.start()

@staticmethod
def stopProfiler():
    yappi.stop()

@staticmethod
def printProfiler():
    stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
    statPrint = '\n'
    namesArr = [len(str(stat[0])) for stat in stats.func_stats]
    log.debug("namesArr %s", str(namesArr))
    maxNameLen = max(namesArr)
    log.debug("maxNameLen: %s", maxNameLen)

    for stat in stats.func_stats:
        nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
        log.debug('nameAppendSpaces: %s', nameAppendSpaces)
        blankSpace = ''
        for space in nameAppendSpaces:
            blankSpace += space

        log.debug("adding spaces: %s", len(nameAppendSpaces))
        statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
            round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"

    log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
    log.log(1000, statPrint)

Kemudian ketika program Anda bekerja, Anda dapat memulai profiler kapan saja dengan memanggil startProfilermetode RPC dan membuang informasi profil ke file log dengan memanggil printProfiler(atau memodifikasi metode rpc untuk mengembalikannya ke pemanggil) dan mendapatkan output seperti:

2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
name                                                                                                                                      ncall     ttot    tsub
2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243     4         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4         0.0     0.0
<string>.__new__:8                                                                                                                        220       0.0     0.0
C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0
C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0
<string>.__new__:8                                                                                                                        4         0.0     0.0
C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0
C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0
C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0
C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\__init__.py.cpu_times:1066               4         0.0     0.0 

Ini mungkin tidak terlalu berguna untuk skrip pendek tetapi membantu untuk mengoptimalkan proses tipe server terutama mengingat printProfilermetode ini dapat dipanggil beberapa kali dari waktu ke waktu untuk profil dan membandingkan misalnya skenario penggunaan program yang berbeda.

Dalam versi yappi yang lebih baru, kode berikut akan berfungsi:

@staticmethod
def printProfile():
    yappi.get_func_stats().print_all()
Tn. Girgitt
sumber
Bukankah itu harus dinamai Yappi yang Luar Biasa?
Therealstubot
Sayangnya kode di atas hanya berfungsi dengan versi 0.62 yang tidak tersedia di pypy. Modul perlu dikompilasi dari 0,62 sumber yang tersedia di sini: github.com/nirs/yappi/releases atau gunakan build yang saya buat untuk windows di repo yang bercabang untuk tujuan itu github.com/Girgitt/yappi/releases
Mr. Girgitt
kompatibilitas dengan versi 1.0 dapat dengan mudah disediakan - setidaknya untuk hasil cetak - dengan memodifikasi fungsi printProfiler: def printProfiler(): if not yappi_available: return stats = yappi.get_func_stats() stats.print_all(columns={0:("name",90), 1:("ncall", 5), 2:("tsub", 8), 3:("ttot", 8), 4:("tavg",8)}) (OK setelah mencoba beberapa kali untuk menyisipkan blok kode ke dalam komentar yang saya berikan. Ini sangat sulit untuk situs tanya jawab yang berorientasi pemrograman. )
Tn. Girgitt
4

Alat baru untuk menangani profil dengan Python adalah PyVmMonitor: http://www.pyvmmonitor.com/

Ini memiliki beberapa fitur unik seperti

  • Lampirkan profiler ke program (CPython) yang sedang berjalan
  • On profil permintaan dengan integrasi Yappi
  • Profil pada mesin yang berbeda
  • Dukungan banyak proses (multiprocessing, django ...)
  • Pengambilan sampel langsung / tampilan CPU (dengan pemilihan rentang waktu)
  • Profil deterministik melalui integrasi profil / cProfile
  • Analisis hasil PStats yang ada
  • Buka file DOT
  • Akses API terprogram
  • Kelompokkan sampel dengan metode atau garis
  • Integrasi PyDev
  • Integrasi PyCharm

Catatan: ini komersial, tetapi gratis untuk sumber terbuka.

Fabio Zadrozny
sumber
4

gprof2dot_magic

Fungsi ajaib untuk gprof2dotmemrofilkan pernyataan Python sebagai grafik DOT di JupyterLab atau Jupyter Notebook.

masukkan deskripsi gambar di sini

Repo GitHub: https://github.com/mattijn/gprof2dot_magic

instalasi

Pastikan Anda memiliki paket Python gprof2dot_magic.

pip install gprof2dot_magic

Ketergantungannya gprof2dotdan graphvizakan diinstal juga

pemakaian

Untuk mengaktifkan fungsi sulap, muat gprof2dot_magicmodul terlebih dahulu

%load_ext gprof2dot_magic

dan kemudian profil setiap pernyataan garis sebagai grafik DOT seperti itu:

%gprof2dot print('hello world')

masukkan deskripsi gambar di sini

Mattijn
sumber
3

Pernah ingin tahu apa yang dilakukan skrip python? Masukkan Shell Inspeksi. Inspect Shell memungkinkan Anda mencetak / mengubah global dan menjalankan fungsi tanpa mengganggu skrip yang sedang berjalan. Sekarang dengan lengkapi-otomatis dan riwayat perintah (hanya di linux).

Inspect Shell bukan debugger gaya pdb.

https://github.com/amoffat/Inspect-Shell

Anda bisa menggunakannya (dan jam tangan Anda).

Kolonel Panic
sumber
3

Itu akan tergantung pada apa yang ingin Anda lihat dari profil. Metrik waktu sederhana dapat diberikan oleh (bash).

time python python_prog.py

Bahkan '/ usr / bin / time' dapat menampilkan metrik terperinci dengan menggunakan flag '--verbose'.

Untuk memeriksa metrik waktu yang diberikan oleh masing-masing fungsi dan untuk lebih memahami berapa banyak waktu yang dihabiskan untuk fungsi, Anda bisa menggunakan cProfile inbuilt dengan python.

Memasuki metrik yang lebih rinci seperti kinerja, waktu bukanlah satu-satunya metrik. Anda dapat khawatir tentang memori, utas dll.
Opsi pembuatan profil:
1. line_profiler adalah profiler lain yang biasa digunakan untuk mengetahui metrik pewaktu baris demi baris.
2. memory_profiler adalah alat untuk profil penggunaan memori.
3. heapy (from project Guppy) Profil bagaimana objek di heap digunakan.

Ini adalah beberapa yang umum saya cenderung gunakan. Tetapi jika Anda ingin mencari tahu lebih banyak, cobalah membaca buku ini. Ini adalah buku yang cukup bagus untuk memulai dengan mempertimbangkan kinerja. Anda dapat beralih ke topik lanjutan tentang menggunakan python yang dikompilasi Cython dan JIT (Just-in-time).

VishalMishra
sumber
2

Dengan profiler statistik seperti austin , tidak diperlukan instrumentasi, artinya Anda bisa mendapatkan data profiling dari aplikasi Python hanya dengan

austin python3 my_script.py

Output mentah tidak terlalu berguna, tetapi Anda dapat menyalurkannya ke flamegraph.pl untuk mendapatkan representasi grafik nyala dari data yang memberi Anda rincian tempat waktu (diukur dalam mikrodetik waktu nyata) dihabiskan.

austin python3 my_script.py | flamegraph.pl > my_script_profile.svg
Phoenix87
sumber
2

Untuk mendapatkan statistik profil cepat pada notebook IPython. Seseorang bisa menanamkan line_profiler dan memory_profiler langsung ke notebook mereka.

Paket bermanfaat lainnya adalah Pympler . Ini adalah paket profil yang kuat yang mampu melacak kelas, objek, fungsi, kebocoran memori, dll. Contoh di bawah ini, Documents terlampir.

Mendapatkan!

!pip install line_profiler
!pip install memory_profiler
!pip install pympler

Muat itu!

%load_ext line_profiler
%load_ext memory_profiler

Gunakan!


%waktu

%time print('Outputs CPU time,Wall Clock time') 
#CPU times: user 2 µs, sys: 0 ns, total: 2 µs Wall time: 5.96 µs

Memberi:

  • Waktu CPU: Waktu pelaksanaan tingkat CPU
  • sys times: waktu eksekusi level sistem
  • total: waktu CPU + waktu sistem
  • Waktu dinding: Waktu Jam Dinding

% timeit

%timeit -r 7 -n 1000 print('Outputs execution time of the snippet') 
#1000 loops, best of 7: 7.46 ns per loop
  • Memberikan waktu terbaik dari jumlah run (r) tertentu dalam putaran (n) kali.
  • Detail keluaran tentang caching sistem:
    • Ketika cuplikan kode dieksekusi beberapa kali, sistem membuat cache beberapa operasi dan tidak mengeksekusinya lagi yang dapat menghambat akurasi laporan profil.

% prun

%prun -s cumulative 'Code to profile' 

Memberi:

  • jumlah panggilan fungsi (panggilan)
  • memiliki entri per panggilan fungsi (berbeda)
  • waktu yang diambil per panggilan (percall)
  • waktu berlalu hingga pemanggilan fungsi (cumtime)
  • nama func / modul yang disebut dll ...

Profil kumulatif


% memit

%memit 'Code to profile'
#peak memory: 199.45 MiB, increment: 0.00 MiB

Memberi:

  • Penggunaan memori

% lprun

#Example function
def fun():
  for i in range(10):
    print(i)

#Usage: %lprun <name_of_the_function> function
%lprun -f fun fun()

Memberi:

  • Statistik garis bijaksana

LineProfile


sys.getsizeof

sys.getsizeof('code to profile')
# 64 bytes

Mengembalikan ukuran objek dalam byte.


asizeof () dari pympler

from pympler import asizeof
obj = [1,2,("hey","ha"),3]
print(asizeof.asizeof(obj,stats=4))

pympler.asizeof dapat digunakan untuk menyelidiki berapa banyak memori yang dikonsumsi objek Python tertentu. Berbeda dengan sys.getsizeof, ukuran objek asizeof rekursif

pympler.asizeof


pelacak dari pympler

from pympler import tracker
tr = tracker.SummaryTracker()
def fun():
  li = [1,2,3]
  di = {"ha":"haha","duh":"Umm"}
fun()
tr.print_diff()

Melacak masa pakai suatu fungsi.

output pelacak

Paket Pympler terdiri dari sejumlah besar fungsi utilitas tinggi untuk kode profil. Semuanya tidak dapat dibahas di sini. Lihat dokumentasi terlampir untuk implementasi profil verbose.

Dok Pympler

Aditya Patnaik
sumber
1

Ada juga profiler statistik yang disebut statprof. Ini adalah profiler pengambilan sampel, sehingga menambahkan overhead minimal ke kode Anda dan memberikan pengaturan waktu berbasis garis (bukan hanya berdasarkan fungsi). Ini lebih cocok untuk aplikasi real-time lunak seperti game, tetapi mungkin memiliki presisi kurang dari cProfile.

The Versi di pypi agak tua, sehingga dapat menginstalnya dengan pipdengan menentukan repositori git :

pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01

Anda dapat menjalankannya seperti ini:

import statprof

with statprof.profile():
    my_questionable_function()

Lihat juga https://stackoverflow.com/a/10333592/320036

z0r
sumber
1

Saya baru saja mengembangkan profiler saya sendiri yang terinspirasi dari pypref_time:

https://github.com/modaresimr/auto_profiler

Dengan menambahkan dekorator itu akan menunjukkan pohon fungsi yang memakan waktu

@Profiler(depth=4, on_disable=show)

Install by: pip install auto_profiler

Contoh

import time # line number 1
import random

from auto_profiler import Profiler, Tree

def f1():
    mysleep(.6+random.random())

def mysleep(t):
    time.sleep(t)

def fact(i):
    f1()
    if(i==1):
        return 1
    return i*fact(i-1)


def show(p):
    print('Time   [Hits * PerHit] Function name [Called from] [Function Location]\n'+\
          '-----------------------------------------------------------------------')
    print(Tree(p.root, threshold=0.5))

@Profiler(depth=4, on_disable=show)
def main():
    for i in range(5):
        f1()

    fact(3)


if __name__ == '__main__':
    main()

Contoh Output


Time   [Hits * PerHit] Function name [Called from] [function location]
-----------------------------------------------------------------------
8.974s [1 * 8.974]  main  [auto-profiler/profiler.py:267]  [/test/t2.py:30]
├── 5.954s [5 * 1.191]  f1  [/test/t2.py:34]  [/test/t2.py:14]
   └── 5.954s [5 * 1.191]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
       └── 5.954s [5 * 1.191]  <time.sleep>
|
|
|   # The rest is for the example recursive function call fact
└── 3.020s [1 * 3.020]  fact  [/test/t2.py:36]  [/test/t2.py:20]
    ├── 0.849s [1 * 0.849]  f1  [/test/t2.py:21]  [/test/t2.py:14]
       └── 0.849s [1 * 0.849]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
           └── 0.849s [1 * 0.849]  <time.sleep>
    └── 2.171s [1 * 2.171]  fact  [/test/t2.py:24]  [/test/t2.py:20]
        ├── 1.552s [1 * 1.552]  f1  [/test/t2.py:21]  [/test/t2.py:14]
           └── 1.552s [1 * 1.552]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
        └── 0.619s [1 * 0.619]  fact  [/test/t2.py:24]  [/test/t2.py:20]
            └── 0.619s [1 * 0.619]  f1  [/test/t2.py:21]  [/test/t2.py:14]
Ali
sumber
0

Ketika saya tidak melakukan root pada server, saya menggunakan lsprofcalltree.py dan menjalankan program saya seperti ini:

python lsprofcalltree.py -o callgrind.1 test.py

Kemudian saya dapat membuka laporan dengan perangkat lunak yang kompatibel dengan callgrind, seperti qcachegrind

Vincent Fenet
sumber