python matplotlib - 你如何描述腳本?




performance profiling time-complexity (19)

歐拉項目和其他編碼競賽往往有最大的時間來運行,或者人們吹噓他們的特定解決方案的運行速度。 使用python,有時候這些方法有點奇怪 - 即將時序代碼添加到__main__

什麼是一個好的方法來分析一個python程序需要運行多久?


Answers

還有一個名為statprof的統計分析器。 它是一個採樣分析器,因此它為您的代碼增加了最小的開銷,並且提供了基於行的(而不僅僅是基於函數的)時序。 它更適合於像遊戲這樣的軟實時應用程序,但可能比cProfile的精度要低。

statprofstatprof ,所以可以通過指定git存儲庫來使用pip進行安裝:

pip install git+git://github.com/bos/[email protected]

你可以像這樣運行它:

import statprof

with statprof.profile():
    my_questionable_function()

另請參閱https://stackoverflow.com/a/10333592/320036


有很多很棒的答案,但是他們或者使用命令行或者一些外部程序來分析和/或排序結果。

我真的錯過了一些我可以在我的IDE(eclipse-PyDev)中使用的方式,而無需觸摸命令行或安裝任何東西。 所以在這裡。

無命令行分析

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)

有關更多信息,請參閱文檔或其他答案。


python wiki是分析資源的絕佳頁面: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code : http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

正如python文檔一樣: http : //docs.python.org/library/profile.html

如Chris Lawlor所示cProfile是一個很好的工具,可以輕鬆用於打印到屏幕上:

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

或者提交:

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

PS>如果您使用的是Ubuntu,請確保安裝python-profile

sudo apt-get install python-profiler 

如果你輸出到文件,你可以使用以下工具獲得很好的可視化效果

PyCallGraph:創建通話圖形圖像的工具
安裝:

 sudo pip install pycallgraph

跑:

 pycallgraph mine.py args

視圖:

 gimp pycallgraph.png

你可以使用任何你喜歡的來查看png文件,我用gimp
不幸的是我經常得到

點:圖形對於cairo-renderer位圖來說太大。 按0.257079縮放以適合

這使得我的圖像變得非常小。 所以我通常創建svg文件:

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

PS>確保安裝graphviz(提供點程序):

sudo pip install graphviz

使用gprof2dot通過@maxy / @quodlibetor進行替代圖形化:

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

Python包含一個名為cProfile的分析器。 它不僅提供了總運行時間,而且還分別計算每個函數的時間,並告訴您每個函數被調用的次數,從而可以輕鬆確定應該在哪裡進行優化。

你可以在代碼中或者從解釋器中調用它,如下所示:

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

更有用的是,您可以在運行腳本時調用cProfile:

python -m cProfile myscript.py

為了使它更容易,我創建了一個名為'profile.bat'的小批處理文件:

python -m cProfile %1

所以我所要做的就是運行:

profile euler048.py

我得到這個:

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}

編輯:從PyCon 2013更新了一個很好的視頻資源的鏈接,標題為Python分析


最簡單最快捷的方式找到所有的時間。

1. pip install snakeviz

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

3. snakeviz temp.dat

在瀏覽器中繪製餅圖。 最大的一塊是問題功能。 簡單。


我認為cProfile非常適合分析,而kcachegrind非常適合可視化結果。 pyprof2calltree處理文件轉換。

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

要安裝所需的工具(至少在Ubuntu上):

apt-get install kcachegrind
pip install pyprof2calltree

結果:


另外值得一提的是GUI cProfile轉儲查看器RunSnakeRun 。 它允許您排序和選擇,從而放大程序的相關部分。 圖片中矩形的大小與所花費的時間成正比。 如果將鼠標懸停在矩形上,則會突出顯示表格中以及地圖上每個地方的呼叫。 當你雙擊一個矩形時,它會放大該部分。 它會告訴你誰調用了那部分以及那部分調用的內容。

描述性信息非常有幫助。 它向您顯示該位的代碼,這在處理內置庫調用時可能很有用。 它會告訴你什麼文件和哪一行可以找到代碼。

還想指出,OP說'分析',但他表示他的意思是'時間'。 請記住,在分析時程序運行速度會變慢。


根據Joe Shaw關於多線程代碼不能按預期工作的回答,我認為runcall中的runcall方法僅僅是圍繞profiled函數調用進行self.enable()self.disable()調用,所以你可以簡單地做到這一點你自己並擁有你想要的任何代碼,而對現有代碼的干擾最小。


一個處理Python分析的新工具是PyVmMonitor: http://www.pyvmmonitor.com/ ://www.pyvmmonitor.com/

它有一些獨特的功能,如

  • 將分析器附加到正在運行的(CPython)程序
  • 按需分析與Yappi整合
  • 在不同機器上的配置文件
  • 多進程支持(多處理,Django ...)
  • 實時採樣/ CPU視圖(帶時間範圍選擇)
  • 通過cProfile / profile集成進行確定性分析
  • 分析現有的PStats結果
  • 打開DOT文件
  • 程序化API訪問
  • 按方法或行分組樣本
  • PyDev集成
  • PyCharm集成

注意:它是商業的,但對開源免費。


在Virtaal的source有一個非常有用的類和裝飾器,可以使分析(即使是特定的方法/函數)非常簡單。 然後可以在KCacheGrind中非常舒適地查看輸出。


pprofile

line_profiler (這裡已經介紹過)也啟發了pprofile ,它被描述為:

行粒度,線程感知確定性和統計純python分析器

它提供line_profiler行粒度,是純Python,可以用作獨立命令或模塊,甚至可以生成可通過[k|q]cachegrind輕鬆分析的callgrind格式文件。

vprof

還有一個vprof ,一個Python包,描述如下:

為各種Python程序特性(如運行時間和內存使用情況)提供豐富且交互式的可視化。


研究此主題時,我遇到了一個名為SnakeViz的方便工具。 SnakeViz是一個基於Web的概要分析可視化工具。 這是非常容易安裝和使用。 我使用它的通常方法是用%prun生成一個stat文件,然後在SnakeViz中進行分析。

所使用的主要技術是Sunburst圖表 ,如下所示,其中函數調用的層次結構安排為以角度寬度編碼的弧形和時間信息層。

最好的事情是你可以與圖表互動。 例如,放大一個可以點擊一個弧線,並且弧線及其後代將被放大為一個新的陽光來顯示更多細節。


@ Maxy對這個答案的評論幫了我很大的印象,我認為它應該有自己的答案:我已經有了cProfile生成的.pstats文件,我不想用pycallgraph重新運行,所以我使用了gprof2dot , 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

和BLAM!

它使用點(與pycallgraph使用的一樣),所以輸出看起來很相似。 我認為gprof2dot丟失的信息較少:


當我不在服務器上的根目錄時,我使用lsprofcalltree.py並像這樣運行我的程序:

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

然後我可以用任何與callgrind兼容的軟件打開報告,例如qcachegrind


我的方法是使用yappi( https://code.google.com/p/yappi/ )。 與RPC服務器結合使用(甚至只是為了調試),您可以註冊方法來啟動,停止和打印分析信息,例如以這種方式:

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

然後,當你的程序工作時,你可以通過調用startProfiler RPC方法並通過調用printProfiler (或者修改rpc方法將它返回給調用者)將日誌文件信息轉儲到日誌文件來隨時啟動分析器,並獲得如下輸出:

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 

對於短腳本來說它可能不是很有用,但有助於優化服務器類型的進程,特別是考慮到printProfiler方法可以隨時調用多次來分析和比較不同的程序使用場景。


一個很好的剖析模塊是line_profiler(使用腳本kernprof.py調用)。 它可以在here下載。

我的理解是,cProfile只給出每個函數花費的總時間的信息。 所以單獨的代碼行不是定時的。 這是科學計算中的一個問題,因為通常一條線可能需要很長時間。 另外,據我記得,cProfile沒有趕上我花numpy.dot花費的時間。


想知道python腳本正在做什麼? 進入Inspect Shell。 Inspect Shell允許您在不中斷運行腳本的情況下打印/更改全局變量並運行函數。 現在具有自動完成和命令歷史記錄(僅在Linux上)。

Inspect Shell不是一個pdb樣式的調試器。

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

你可以使用那個(和你的手錶)。


值得指出的是,使用分析器只能在主線程上工作(默認情況下),並且如果使用它們,則不會從其他線程獲取任何信息。 這可能是一個小問題,因為它在profiler文檔中完全沒有提到。

如果您還想要配置線程,您需要查看文檔中的threading.setprofile()函數

你也可以創建自己的threading.Thread子類來完成它:

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

並使用ProfiledThread類而不是標準類。 它可能會給你更多的靈活性,但我不確定它是否值得,尤其是如果你使用的第三方代碼不會使用你的類。


使用Intel x86仿真器加速器

首先,安裝Intel x86仿真器加速器(HAXM)。 這可以直接從英特爾下載或使用Android SDK Manager下載。 在SDK Manager中,它位於Extras下。

在我使用的Android Studio版本(0.8.9)中,Android SDK Manager下載了HAXM,但實際上並沒有運行安裝程序(我假設這將在以後的版本中修復)。 要運行已安裝的我必須轉到C:\ Program Files(x86)\ Android \ android-studio \ sdk \ extras \ intel \ Hardware_Accelerated_Execution_Manager並手動啟動intelhaxm.exe。

HAXM與英特爾設備配合使用,因此創建了一個帶有英特爾CPU的新仿真器。

使用Intel Atom x86創建新的AVD

這大大改善了一些事情,但模擬器仍然感覺有些遲鈍。 最後一步是在Android虛擬設備管理器(AVD)中選擇使用主機GPU。

在這些更改之後,Android Emulator在5-10秒內啟動並且運行時沒有任何明顯的延遲。 請注意,這些功能與硬件有關(CPU / GPU),可能無法在某些系統上運行。





python performance profiling time-complexity