मैं पायथन कोड लाइन-बाय-लाइन कैसे प्रोफाइल कर सकता हूं?


116

मैं अपने कोड को प्रोफाइल करने के लिए cProfile का उपयोग कर रहा हूं, और यह बहुत अच्छा काम कर रहा है। मैं परिणामों की कल्पना करने के लिए gprof2dot.py का उपयोग करता हूं (इसे थोड़ा स्पष्ट करता है)।

हालाँकि, cProfile (और सबसे अधिक पायथन प्रोफाइलर्स जो मैंने अब तक देखे हैं) फ़ंक्शन-कॉल स्तर पर केवल प्रोफ़ाइल के लिए प्रतीत होते हैं। यह भ्रम का कारण बनता है जब कुछ कार्यों को अलग-अलग स्थानों से बुलाया जाता है - मुझे नहीं पता कि क्या # 1 कॉल या कॉल # 2 समय का बहुमत ले रहा है। यह तब और भी खराब हो जाता है जब विचाराधीन फ़ंक्शन छह स्तरों में गहरा होता है, जिसे सात अन्य स्थानों से कहा जाता है।

मैं एक लाइन-बाय-लाइन प्रोफाइलिंग कैसे प्राप्त करूं?

इसके अलावा:

function #12, total time: 2.0s

मैं कुछ इस तरह देखना चाहता हूं:

function #12 (called from somefile.py:102) 0.5s
function #12 (called from main.py:12) 1.5s

cProfile यह दर्शाता है कि कुल समय में से कितना समय माता-पिता को "स्थानांतरित" होता है, लेकिन फिर से यह कनेक्शन तब खो जाता है जब आपके पास परतों और परस्पर कॉल का एक गुच्छा होता है।

आदर्श रूप से, मुझे एक GUI रखना पसंद है जो डेटा के माध्यम से पार्स करेगा, फिर मुझे प्रत्येक पंक्ति को दिए गए कुल समय के साथ अपना स्रोत फ़ाइल दिखाएगा। कुछ इस तरह:

main.py:

a = 1 # 0.0s
result = func(a) # 0.4s
c = 1000 # 0.0s
result = func(c) # 5.0s

तब मैं दूसरी "फंक (c)" कॉल पर क्लिक करने में सक्षम होऊंगा यह देखने के लिए कि कॉल में क्या समय लग रहा है, "func (a)" कॉल से अलग।

क्या इसका कोई मतलब है? क्या कोई प्रोफाइलिंग लाइब्रेरी है जो इस प्रकार की जानकारी एकत्र करती है? क्या कोई भयानक उपकरण है जो मैंने याद किया है?


2
मेरा अनुमान है कि आप में रुचि होगी pstats.print_callers। एक उदाहरण यहाँ है
मुहम्मद अलकरौरी

मुहम्मद, यह निश्चित रूप से उपयोगी है! कम से कम यह एक समस्या को ठीक करता है: मूल के आधार पर फ़ंक्शन कॉल को अलग करना। मुझे लगता है कि जो किंग्सटन का जवाब मेरे लक्ष्य के करीब है, लेकिन प्रिंट_कैलर्स () निश्चित रूप से मुझे वहां आधा मिलता है। धन्यवाद!
राकेट

जवाबों:


120

मेरा मानना ​​है कि रॉबर्ट कर्नेल की लाइन_प्रिफ़ाइलर का इरादा क्या है। लिंक से:

File: pystone.py
Function: Proc2 at line 149
Total time: 0.606656 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   149                                           @profile
   150                                           def Proc2(IntParIO):
   151     50000        82003      1.6     13.5      IntLoc = IntParIO + 10
   152     50000        63162      1.3     10.4      while 1:
   153     50000        69065      1.4     11.4          if Char1Glob == 'A':
   154     50000        66354      1.3     10.9              IntLoc = IntLoc - 1
   155     50000        67263      1.3     11.1              IntParIO = IntLoc - IntGlob
   156     50000        65494      1.3     10.8              EnumLoc = Ident1
   157     50000        68001      1.4     11.2          if EnumLoc == Ident1:
   158     50000        63739      1.3     10.5              break
   159     50000        61575      1.2     10.1      return IntParIO

उम्मीद है की वो मदद करदे!


10
क्या Line_profiler पायथन 3 के साथ काम करता है? मुझे उस पर कोई जानकारी नहीं मिली।
user1251007

3
line_profiler मेरे लिए हिट और समय नहीं दिखाता है। क्या कोई मुझे बता सकता है क्यों? और कैसे हल करें?
१५

6
यहाँ सज्जाकार मैंने लिखा है: gist.github.com/kylegibson/6583590 । यदि आप nosetests चला रहे हैं, तो -s विकल्प का उपयोग करना सुनिश्चित करें ताकि stdout तुरंत प्रिंट हो जाए।
काइल गिब्सन

5
इस आउटपुट को बनाने वाला अजगर स्क्रिप्ट कैसा दिखता है? import line_profiler;और फिर ?
ज़ुर्बेर

10
क्या कोई दिखा सकता है कि वास्तव में इस पुस्तकालय का उपयोग कैसे किया जाए? रेडमी सिखाता है कि कैसे स्थापित करें, और विभिन्न FAQs का उत्तर दें, लेकिन एक पाइप स्थापित करने के बाद इसका उपयोग करने का उल्लेख नहीं करता है ..
cryanbhu

47

तुम भी pprofile ( pypi ) का उपयोग कर सकते हैं । यदि आप संपूर्ण निष्पादन को प्रोफाइल करना चाहते हैं, तो उसे स्रोत कोड संशोधन की आवश्यकता नहीं है। आप दो तरीकों से एक बड़े कार्यक्रम के सबसेट को भी प्रोफाइल कर सकते हैं:

  • कोड में किसी विशिष्ट बिंदु तक पहुँचने पर रूपरेखा टॉगल करें, जैसे:

    import pprofile
    profiler = pprofile.Profile()
    with profiler:
        some_code
    # Process profile content: generate a cachegrind file and send it to user.
    
    # You can also write the result to the console:
    profiler.print_stats()
    
    # Or to a file:
    profiler.dump_stats("/tmp/profiler_stats.txt")
  • कॉल स्टैक से अतुल्य रूप से रूपरेखा टॉगल करें (सांख्यिकीय अनुप्रयोग में इस कोड को ट्रिगर करने के लिए एक तरीका आवश्यक है, उदाहरण के लिए एक सिग्नल हैंडलर या एक उपलब्ध कर्मचारी धागा)।

    import pprofile
    profiler = pprofile.StatisticalProfile()
    statistical_profiler_thread = pprofile.StatisticalThread(
        profiler=profiler,
    )
    with statistical_profiler_thread:
        sleep(n)
    # Likewise, process profile content

कोड एनोटेशन आउटपुट फॉर्मेट लाइन प्रोफाइलर की तरह है:

$ pprofile --threads 0 demo/threads.py
Command line: ['demo/threads.py']
Total duration: 1.00573s
File: demo/threads.py
File duration: 1.00168s (99.60%)
Line #|      Hits|         Time| Time per hit|      %|Source code
------+----------+-------------+-------------+-------+-----------
     1|         2|  3.21865e-05|  1.60933e-05|  0.00%|import threading
     2|         1|  5.96046e-06|  5.96046e-06|  0.00%|import time
     3|         0|            0|            0|  0.00%|
     4|         2|   1.5974e-05|  7.98702e-06|  0.00%|def func():
     5|         1|      1.00111|      1.00111| 99.54%|  time.sleep(1)
     6|         0|            0|            0|  0.00%|
     7|         2|  2.00272e-05|  1.00136e-05|  0.00%|def func2():
     8|         1|  1.69277e-05|  1.69277e-05|  0.00%|  pass
     9|         0|            0|            0|  0.00%|
    10|         1|  1.81198e-05|  1.81198e-05|  0.00%|t1 = threading.Thread(target=func)
(call)|         1|  0.000610828|  0.000610828|  0.06%|# /usr/lib/python2.7/threading.py:436 __init__
    11|         1|  1.52588e-05|  1.52588e-05|  0.00%|t2 = threading.Thread(target=func)
(call)|         1|  0.000438929|  0.000438929|  0.04%|# /usr/lib/python2.7/threading.py:436 __init__
    12|         1|  4.79221e-05|  4.79221e-05|  0.00%|t1.start()
(call)|         1|  0.000843048|  0.000843048|  0.08%|# /usr/lib/python2.7/threading.py:485 start
    13|         1|  6.48499e-05|  6.48499e-05|  0.01%|t2.start()
(call)|         1|   0.00115609|   0.00115609|  0.11%|# /usr/lib/python2.7/threading.py:485 start
    14|         1|  0.000205994|  0.000205994|  0.02%|(func(), func2())
(call)|         1|      1.00112|      1.00112| 99.54%|# demo/threads.py:4 func
(call)|         1|  3.09944e-05|  3.09944e-05|  0.00%|# demo/threads.py:7 func2
    15|         1|  7.62939e-05|  7.62939e-05|  0.01%|t1.join()
(call)|         1|  0.000423908|  0.000423908|  0.04%|# /usr/lib/python2.7/threading.py:653 join
    16|         1|  5.26905e-05|  5.26905e-05|  0.01%|t2.join()
(call)|         1|  0.000320196|  0.000320196|  0.03%|# /usr/lib/python2.7/threading.py:653 join

ध्यान दें कि क्योंकि pprofile कोड संशोधन पर भरोसा नहीं करता है इसलिए यह टॉप-लेवल मॉड्यूल स्टेटमेंट्स को प्रोफाइल कर सकता है, प्रोफाइल प्रोग्राम स्टार्टअप टाइम (इंपोर्ट मॉड्यूल्स को इनिशियलाइज़ करने में कितना समय लगता है, ...)।

यह कैशग्रिंड-स्वरूपित आउटपुट उत्पन्न कर सकता है, ताकि आप बड़े परिणाम आसानी से ब्राउज़ करने के लिए kcachegrind का उपयोग कर सकें ।

प्रकटीकरण: मैं पवित्र लेखक हूँ।


1
+1 आपके योगदान के लिए धन्यवाद। यह अच्छी तरह से किया जाता है। मेरा थोड़ा अलग दृष्टिकोण है - बयानों और कार्यों द्वारा लिया गया समावेशी समय को मापना एक उद्देश्य है। कोड को तेज बनाने के लिए क्या किया जा सकता है, यह पता लगाना एक अलग उद्देश्य है। कोड के बड़े होने पर अंतर स्पष्ट रूप से स्पष्ट हो जाता है - जैसे कोड की 10 ^ 6 लाइनें। कोड समय के बड़े प्रतिशत को बर्बाद कर सकता है। जिस तरह से मुझे लगता है कि यह बहुत ही विस्तृत नमूनों की एक छोटी संख्या को ले कर है, और उन्हें मानवीय आंखों से जांचना है - संक्षेप में नहीं। समय व्यर्थ होने के अंश से समस्या उजागर होती है।
माइक डनलैवी

1
आप सही हैं, मैंने छोटे उपसमुच्चय को प्रोफाइल करने के लिए किसी भी समय उपयोग करने का उल्लेख नहीं किया। इसके उदाहरण जोड़ने के लिए मैंने अपनी पोस्ट संपादित की।
vpelletier 6

3
यह वही है जो मैं देख रहा था: गैर-घुसपैठ और व्यापक।
6

1
अच्छा उपकरण, लेकिन यह मूल कोड की तुलना में कई गुना धीमा है।
rominf

4

इसके लिए आप line_profiler पैकेज की मदद ले सकते हैं

1. 1 पैकेज स्थापित करें:

    pip install line_profiler

2. अपने अजगर / नोटबुक वातावरण के लिए पैकेज को लोड करने के लिए जादू कमांड का उपयोग करें

    %load_ext line_profiler

3. यदि आप किसी फ़ंक्शन के लिए कोड को प्रोफाइल करना चाहते हैं तो
निम्नानुसार करें:

    %lprun -f demo_func demo_func(arg1, arg2)

यदि आप इन चरणों का पालन करते हैं तो आपको सभी विवरणों के साथ एक अच्छा स्वरूपित आउटपुट मिलेगा :)

Line #      Hits      Time    Per Hit   % Time  Line Contents
 1                                           def demo_func(a,b):
 2         1        248.0    248.0     64.8      print(a+b)
 3         1         40.0     40.0     10.4      print(a)
 4         1         94.0     94.0     24.5      print(a*b)
 5         1          1.0      1.0      0.3      return a/b

4

बस @Joe Kington के उपर्युक्त उत्तर को सुधारने के लिए ।

के लिए अजगर 3.x , उपयोग line_profiler :


स्थापना:

pip install line_profiler

उपयोग:

मान लें कि आपके पास कार्यक्रम है main.pyऔर इसके भीतर, कार्य fun_a()और fun_b()आप समय के संबंध में प्रोफ़ाइल करना चाहते हैं; आपको @profileफ़ंक्शन परिभाषाओं से ठीक पहले डेकोरेटर का उपयोग करने की आवश्यकता होगी । उदाहरण के लिए,

@profile
def fun_a():
    #do something

@profile
def fun_b():
    #do something more

if __name__ == '__main__':
    fun_a()
    fun_b()

शेल कमांड को निष्पादित करके कार्यक्रम को पूरा किया जा सकता है:

$ kernprof -l -v main.py

तर्कों का उपयोग करके प्राप्त किया जा सकता है $ kernprof -h

Usage: kernprof [-s setupfile] [-o output_file_path] scriptfile [arg] ...

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -l, --line-by-line    Use the line-by-line profiler from the line_profiler
                        module instead of Profile. Implies --builtin.
  -b, --builtin         Put 'profile' in the builtins. Use 'profile.enable()'
                        and 'profile.disable()' in your code to turn it on and
                        off, or '@profile' to decorate a single function, or
                        'with profile:' to profile a single section of code.
  -o OUTFILE, --outfile=OUTFILE
                        Save stats to <outfile>
  -s SETUP, --setup=SETUP
                        Code to execute before the code to profile
  -v, --view            View the results of the profile in addition to saving
                        it.

परिणाम कंसोल पर मुद्रित किए जाएंगे:

Total time: 17.6699 s
File: main.py
Function: fun_a at line 5

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    5                                           @profile
    6                                           def fun_a():
...

EDIT: प्रोफाइलर्स के परिणामों को TAMPPA पैकेज का उपयोग करके पार्स किया जा सकता है । इसका उपयोग करके, हम लाइन-बाय-लाइन वांछित भूखंडों को प्राप्त कर सकते हैं भूखंड


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.