Bagaimana bisa kau profil Python script?

Project Euler dan lainnya coding kontes sering memiliki waktu maksimal untuk menjalankan atau orang-orang yang membanggakan seberapa cepat mereka solusi tertentu berjalan. Dengan python, kadang-kadang pendekatan yang agak kludgey - yaitu, menambahkan waktu kode untuk __main__.

Apa adalah cara yang baik untuk profil berapa lama python program yang diperlukan untuk menjalankan?

Mengomentari pertanyaan (4)
Larutan

Python termasuk profiler disebut cProfile. Tidak hanya memberikan total waktu berjalan, tetapi juga kali setiap fungsi secara terpisah, dan memberitahu anda berapa banyak setiap kali fungsi dipanggil, sehingga mudah untuk menentukan di mana anda harus melakukan optimasi.

Anda dapat memanggil dari dalam kode anda, atau dari penerjemah, seperti ini:

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

Bahkan lebih berguna, anda dapat memanggil cProfile ketika menjalankan script:

python -m cProfile myscript.py

Untuk membuatnya bahkan lebih mudah, saya membuat sedikit batch file yang bernama 'profil.bat':

python -m cProfile %1

Jadi semua 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 :1()
 1000    0.051    0.000    0.051    0.000 euler048.py:2()
    1    0.005    0.005    0.061    0.061 euler048.py:2()
    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: Update link ke video yang baik sumber daya dari PyCon 2013 yang berjudul Python Profiling [Juga via YouTube](https://www.youtube.com/watch?v=QJwVYlDzAXs).

Komentar (13)

Beberapa waktu lalu saya membuat pycallgraph yang menghasilkan visualisasi dari kode Python. Edit: I've diperbarui contoh untuk bekerja dengan 3.3, rilis terbaru seperti tulisan ini.

Setelah pip menginstal pycallgraph dan menginstal GraphViz anda dapat menjalankannya dari baris perintah:

pycallgraph graphviz -- ./mypythonscript.py

Atau, anda dapat profil bagian-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.png file yang mirip dengan gambar di bawah ini:

Komentar (10)

It's worth menunjukkan bahwa menggunakan profiler hanya bekerja (secara default) di thread utama, dan anda tidak't mendapatkan informasi dari thread lain jika anda menggunakan mereka. Hal ini dapat menjadi sedikit gotcha seperti itu adalah benar-benar tidak disebutkan dalam profiler dokumentasi.

Jika anda juga ingin profil benang, anda'll ingin melihat threading.setprofile() fungsi di docs.

Anda juga bisa membuat sendiri threading.Thread subclass 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 itu ProfiledThread kelas bukan satu standar. Hal ini mungkin memberi anda fleksibilitas yang lebih, tapi aku'm tidak yakin itu's layak, terutama jika anda menggunakan kode pihak ketiga yang tidak't menggunakan kelas anda.

Komentar (6)

Python wiki merupakan halaman untuk profil sumber daya: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

seperti 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 

atau untuk file:

python -m cProfile -o output.file mine.py 

PS> Jika anda menggunakan Ubuntu, pastikan untuk menginstal python-profil

sudo apt-get install python-profiler 

Jika anda output ke file anda bisa mendapatkan bagus visualisasi menggunakan alat-alat berikut

PyCallGraph : alat untuk membuat panggilan grafik gambar
menginstal:

 sudo pip install pycallgraph

run:

 pycallgraph mine.py args

lihat:

 gimp pycallgraph.png

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

dot: grafik yang terlalu besar untuk kairo-penyaji bitmap. Scaling dengan 0.257079 untuk fit

yang membuat saya gambar unusably kecil. Jadi saya biasanya membuat file svg:

pycallgraph -f svg -o pycallgraph.svg mine.py 

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

sudo pip install graphviz

Alternatif Grafik menggunakan gprof2dot via @maxy / @quodlibetor :

sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
Komentar (2)

@Maxy's komentar pada jawaban membantu saya keluar cukup bahwa saya pikir itu layak jawabannya sendiri: saya sudah punya cProfile yang dihasilkan .pstats file dan saya didn't ingin kembali menjalankan hal-hal dengan pycallgraph, jadi saya menggunakan gprof2dot, dan punya cukup svg:

$ 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!

Menggunakan dot (hal yang sama bahwa pycallgraph menggunakan) sehingga output yang terlihat mirip. Saya mendapatkan kesan bahwa gprof2dot kehilangan informasi yang kurang meskipun:

Komentar (9)

Aku berlari ke sebuah alat yang berguna yang disebut SnakeViz ketika meneliti topik ini. SnakeViz adalah web-based profiling alat visualisasi. Hal ini sangat mudah untuk menginstal dan menggunakan. Cara yang biasa saya gunakan adalah untuk menghasilkan stat file %prun dan kemudian melakukan analisis di SnakeViz.

Utama yaitu teknik yang digunakan adalah Sunburst grafik seperti yang ditampilkan di bawah ini, di mana hirarki fungsi panggilan diatur sebagai lapisan busur dan waktu info dikodekan dalam sudut lebar.

Hal terbaik adalah anda dapat berinteraksi dengan grafik. Misalnya, untuk zoom in one dapat klik pada busur dan busur dan keturunannya akan membesar seperti baru sunburst untuk menampilkan rincian lebih lanjut.

Komentar (2)

Saya berpikir bahwa cProfile lebih besar untuk profiling, sementara kcachegrind sangat bagus untuk memvisualisasikan hasil. The pyprof2calltree di antara menangani konversi file.

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

Untuk menginstal alat-alat yang diperlukan (pada Ubuntu, setidaknya):

apt-get install kcachegrind
pip install pyprof2calltree

Hasilnya:

Komentar (1)

Juga layak disebutkan adalah GUI cProfile dump viewer RunSnakeRun. Hal ini memungkinkan anda untuk memilah dan memilih, sehingga pembesaran pada bagian yang relevan dari program ini. Ukuran dari persegi panjang pada gambar tersebut adalah berbanding lurus dengan waktu yang dibutuhkan. Jika anda mengarahkan mouse di atas persegi panjang ini menyoroti bahwa panggilan di meja dan di mana-mana di peta. Ketika anda double-klik pada persegi panjang itu zoom in pada bagian itu. Ini akan menunjukkan kepada anda yang menyebut bahwa sebagian dan apa yang porsi panggilan.

Deskriptif informasi ini sangat membantu. Hal itu menunjukkan kode untuk yang sedikit yang dapat membantu ketika anda berurusan dengan built-in perpustakaan panggilan. Ini memberitahu anda apa file dan apa line untuk menemukan kode.

Juga ingin menunjukkan bahwa OP kata 'profil' tapi tampaknya ia berarti 'waktu'. Perlu diingat program akan berjalan lebih lambat ketika diprofilkan.

Komentar (0)

Sederhana dan cepat cara untuk menemukan di mana sepanjang waktu pergi.

1. pip install snakeviz

2. python -m cProfile -o temp.dat .py

3. snakeviz temp.dat

Menarik pie chart di browser. Potongan terbesar adalah masalah fungsi. Sangat sederhana.

Komentar (1)

Bagus profiling modul line_profiler (disebut menggunakan script kernprof.py). Hal ini dapat diunduh disini.

Pemahaman saya adalah bahwa cProfile hanya memberikan informasi tentang jumlah waktu yang dihabiskan di masing-masing fungsi. Jadi individu baris kode tidak memiliki batas waktu. Ini adalah sebuah masalah pada komputasi ilmiah karena sering satu baris tunggal dapat mengambil banyak waktu. Juga, seperti yang saya ingat, cProfile didn't menangkap waktu saya belanja di katakan numpy.dot.

Komentar (0)

pprofile

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

Line-granularity, sadar benang deterministik dan statistik murni-python profiler

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

vprof

Ada juga vprof, paket Python digambarkan sebagai:

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

Komentar (0)

Saya baru-baru ini dibuat tuna untuk memvisualisasikan Python runtime dan profil impor; ini dapat membantu di sini.

Install dengan pip3 menginstal tuna Membuat runtime profil python -mcProfile -o program.prof yourfile.py atau mengimpor profil (Python 3.7+ diperlukan) python -X importprofile yourfile.py 2> impor.log Kemudian hanya menjalankan tuna pada file tuna program.prof

Komentar (0)

Ada's banyak jawaban yang besar tetapi mereka juga menggunakan command line atau beberapa program eksternal untuk profiling dan/atau pemilahan hasil.

Aku benar-benar merindukan beberapa cara yang bisa saya gunakan dalam IDE (eclipse-PyDev) tanpa menyentuh baris perintah atau menginstal apapun. Jadi di sini adalah.

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 docs atau jawaban lainnya untuk info lebih lanjut.

Komentar (1)

Berikut Joe Shaw's jawaban tentang multi-threaded kode tidak bekerja seperti yang diharapkan, saya pikir bahwa runcall metode dalam cProfile hanya melakukan self.aktifkan() dan diri.menonaktifkan() panggilan sekitar diprofilkan fungsi panggilan, sehingga anda hanya dapat melakukan itu sendiri dan memiliki apapun kode yang anda inginkan di antara dengan gangguan minimal dengan kode yang ada.

Komentar (2)

Di Virtaal's sumber di sana's sangat berguna kelas dan dekorator yang dapat membuat profiling (bahkan untuk menemukan metode/fungsi) sangat mudah. Output yang kemudian dapat dilihat dengan sangat nyaman di KCacheGrind.

Komentar (1)

cProfile lebih besar untuk cepat profiling tetapi sebagian besar waktu itu adalah akhir bagi saya dengan kesalahan. Fungsi runctx memecahkan masalah ini dengan menginisialisasi dengan benar lingkungan dan variabel, berharap hal ini dapat berguna bagi seseorang:

import cProfile
cProfile.runctx('foo()', None, locals())
Komentar (0)

Cara saya adalah dengan menggunakan yappi (https://code.google.com/p/yappi/). It's sangat berguna dikombinasikan dengan RPC server mana (bahkan hanya untuk debugging) anda mendaftar metode untuk memulai, berhenti dan cetak profiling informasi, misalnya dalam 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 mulai profiler setiap saat dengan memanggil startProfiler RPC metode dan dump profiling informasi ke file log dengan memanggil printProfiler (atau memodifikasi rpc metode untuk kembali 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
.__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
.__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 

Hal itu mungkin tidak akan sangat berguna untuk jangka pendek script tapi membantu untuk mengoptimalkan server-jenis proses terutama mengingat printProfiler metode dapat disebut beberapa kali dari waktu ke waktu untuk profil dan bandingkan misalnya program yang berbeda skenario penggunaan.

Komentar (2)

Jika anda ingin membuat kumulatif profiler, artinya untuk menjalankan fungsi beberapa kali berturut-turut dan menonton jumlah hasil.

anda dapat menggunakan ini cumulative_profiler dekorator:

it's python >= 3.6 tertentu, tetapi anda dapat menghapus nonlokal untuk bekerja pada versi yang lebih tua.

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

profil fungsi baz

import time

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

baz()

baz berlari 5 kali dan dicetak 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 :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():
    ...
Komentar (0)

Untuk menambahkan pada https://stackoverflow.com/a/582337/1070617,

Saya menulis ini modul yang memungkinkan anda untuk menggunakan cProfile dan melihat output dengan mudah. Lebih lanjut di sini: https://github.com/ymichael/cprofilev

$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.

Juga melihat: http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html tentang cara untuk membuat rasa yang dikumpulkan statistik.

Komentar (0)

Sebuah alat baru untuk menangani profil di Python adalah PyVmMonitor: http://www.pyvmmonitor.com/

Ini memiliki beberapa fitur unik seperti

  • Melampirkan profiler untuk berjalan (CPython) program
  • Pada permintaan profiling dengan Yappi integrasi Profil pada mesin yang berbeda
  • Beberapa proses pendukung (multiprocessing, django...)
  • Hidup sampling/CPU melihat (dengan rentang waktu seleksi)
  • Deterministik profiling melalui cProfile/profil integrasi
  • Menganalisis ada PStats hasil
  • Buka file DOT
  • Programatic akses API
  • Kelompok sampel dengan metode atau line
  • PyDev integrasi
  • PyCharm integrasi

Catatan:'s komersial, tetapi gratis untuk open source.

Komentar (0)