PyGotham 2014
Introduction to
Profiling
Perrin Harkins
“We should forget about small efficiencies, say
about 97% of the time: premature optimization is
the root of all evil. Yet ...
“Bottlenecks occur in surprising places, so don't
try to second guess and put in a speed hack until
you have proven that's...
What will a profiler tell us?
❖ Function execution time!
❖ Memory usage, etc. are possible, but for another day!
❖ More ab...
cProfile
❖ Generates profile data that can be read in shell or GUI
tools!
❖ 30% or more speed penalty
cProfile
From command line:!
$ python -m cProfile -o myscript.prof myscript.py
cProfile
Or, in your program:!
import cProfile	
cProfile.run('slow_function', 'myscript.prof')
cProfile
Or, even more flexible:!
pr = cProfile.Profile()	
pr.enable()	
… thing you want to profile …!
pr.disable()
pstats
import pstats	
profile = pstats.Stats('myscript.prof')	
profile.add('myscript.prof2')	
profile.strip_dirs()	
profil...
12192418 function calls (11990470 primitive calls) in 84.268 seconds	
!
Ordered by: cumulative time	
List reduced from 121...
profile.print_callees('full_clean', 10)	
!
List reduced from 1211 to 2 due to restriction <'full_clean'>	
!
Function calle...
profile.print_callers('full_clean')	
!
List reduced from 1211 to 2 due to restriction <'full_clean'>	
!
Function was calle...
KCacheGrind
!
❖ GUI for viewing profile data!
❖ Run your profile output through pyprof2calltree!
❖ On a Mac, qcachegrind is ...
RunSnakeRun
❖ Squaremap of call tree!
❖ Maybe useful for spotting large exclusive time functions
Using your results
❖ Bottom up approach!
❖ Start with a large exclusive time sub!
❖ Climb up call graph to find something y...
Using your results
❖ Top down approach!
❖ Start with a large inclusive time sub!
❖ Walk down call graph to find something y...
Line profiling
❖ line_profiler does exist!
❖ Results are not very actionable!
❖ If you get this far, you probably should st...
Good profiling technique
❖ Create a repeatable benchmark test!
❖ Allows you to measure progress!
❖ Iterations/second!
❖ Ti...
What usually helps
❖ Removing unnecessary work!
❖ “We load that config data every time, even when we don’t
use it.”!
❖ Usin...
What usually helps
❖ Batching I/O (disk or net) operations!
❖ Database stuff!
❖ SQL tuning!
❖ Indexes!
❖ Transactions
What usually helps
❖ Caching!
❖ Easy to add, hard to live with!
❖ Code complexity!
❖ Invalidation calls!
❖ Dependency trac...
Thank you!
PyGotham 2014 Introduction to Profiling
PyGotham 2014 Introduction to Profiling
PyGotham 2014 Introduction to Profiling
PyGotham 2014 Introduction to Profiling
Upcoming SlideShare
Loading in …5
×

PyGotham 2014 Introduction to Profiling

647 views

Published on

This is a breezy introduction to profiling in Python that I presented at PyGotham 2014.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
647
On SlideShare
0
From Embeds
0
Number of Embeds
19
Actions
Shares
0
Downloads
4
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

PyGotham 2014 Introduction to Profiling

  1. 1. PyGotham 2014 Introduction to Profiling Perrin Harkins
  2. 2. “We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified.” –Donald Knuth
  3. 3. “Bottlenecks occur in surprising places, so don't try to second guess and put in a speed hack until you have proven that's where the bottleneck is.” –Rob Pike
  4. 4. What will a profiler tell us? ❖ Function execution time! ❖ Memory usage, etc. are possible, but for another day! ❖ More about line profiling later! ❖ Real (wall clock) time! ❖ Inclusive vs exclusive time! ❖ Number of calls, primitive and recursive
  5. 5. cProfile ❖ Generates profile data that can be read in shell or GUI tools! ❖ 30% or more speed penalty
  6. 6. cProfile From command line:! $ python -m cProfile -o myscript.prof myscript.py
  7. 7. cProfile Or, in your program:! import cProfile cProfile.run('slow_function', 'myscript.prof')
  8. 8. cProfile Or, even more flexible:! pr = cProfile.Profile() pr.enable() … thing you want to profile …! pr.disable()
  9. 9. pstats import pstats profile = pstats.Stats('myscript.prof') profile.add('myscript.prof2') profile.strip_dirs() profile.sort_stats('cumulative') profile.print_stats(20)
  10. 10. 12192418 function calls (11990470 primitive calls) in 84.268 seconds ! Ordered by: cumulative time List reduced from 1211 to 20 due to restriction <20> ! ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 84.402 84.402 <string>:1(<module>) 1 0.021 0.021 84.402 84.402 act_bench.py:243(_do_act) 500 0.096 0.000 84.381 0.169 __init__.py:170(act) 500 0.007 0.000 35.874 0.072 petition_actions.py:460(save) 500 0.066 0.000 33.431 0.067 action_processor.py:1303(save) 500 0.160 0.000 22.684 0.045 users.py:1002(save) 10501 0.175 0.000 21.963 0.002 query.py:852(_fetch_all) 14001 0.286 0.000 21.472 0.002 compiler.py:758(execute_sql) 6501 0.047 0.000 14.200 0.002 query.py:76(__len__)
  11. 11. profile.print_callees('full_clean', 10) ! List reduced from 1211 to 2 due to restriction <'full_clean'> ! Function called... ncalls tottime cumtime forms.py:260(full_clean) -> 500 0.177 2.855 forms.py: 277(_clean_fields) 500 0.003 0.030 forms.py:298(_clean_form) 500 0.031 2.784 models.py: 393(_post_clean) base.py:918(full_clean) -> 500 0.001 0.001 base.py:738(clean) 500 0.096 2.399 base.py:952(clean_fields)
  12. 12. profile.print_callers('full_clean') ! List reduced from 1211 to 2 due to restriction <'full_clean'> ! Function was called by... ncalls tottime cumtime forms.py:260(full_clean) <- 500 0.009 5.678 forms.py:117(errors) base.py:918(full_clean) <- 500 0.005 2.405 models.py: 393(_post_clean)
  13. 13. KCacheGrind ! ❖ GUI for viewing profile data! ❖ Run your profile output through pyprof2calltree! ❖ On a Mac, qcachegrind is easier to install
  14. 14. RunSnakeRun ❖ Squaremap of call tree! ❖ Maybe useful for spotting large exclusive time functions
  15. 15. Using your results ❖ Bottom up approach! ❖ Start with a large exclusive time sub! ❖ Climb up call graph to find something you can affect! ❖ "We're spending a lot of time in deepcopy(). What's calling that so much?"! ❖ Might miss higher-level fixes
  16. 16. Using your results ❖ Top down approach! ❖ Start with a large inclusive time sub! ❖ Walk down call graph to find something you can affect! ❖ "We're spending a lot of time in this validate() method. What's it doing that takes so long?"! ❖ Look for structural changes
  17. 17. Line profiling ❖ line_profiler does exist! ❖ Results are not very actionable! ❖ If you get this far, you probably should stop (or refactor your methods!)
  18. 18. Good profiling technique ❖ Create a repeatable benchmark test! ❖ Allows you to measure progress! ❖ Iterations/second! ❖ Time for n iterations
  19. 19. What usually helps ❖ Removing unnecessary work! ❖ “We load that config data every time, even when we don’t use it.”! ❖ Using a more efficient algorithm
  20. 20. What usually helps ❖ Batching I/O (disk or net) operations! ❖ Database stuff! ❖ SQL tuning! ❖ Indexes! ❖ Transactions
  21. 21. What usually helps ❖ Caching! ❖ Easy to add, hard to live with! ❖ Code complexity! ❖ Invalidation calls! ❖ Dependency tracking! ❖ Business customers care about data freshness
  22. 22. Thank you!

×