Slide 1

Slide 1 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 1/58 Statistical Pro ling (and other neat features of the sys module) Statistical Profiling https://github.com/emin63/ox_profile 1 / 58

Slide 2

Slide 2 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 2/58 Outline 1. Why statistical profiling? 2. Various python tools available. 3. Details of ox_profile statistical profiler. Statistical Profiling https://github.com/emin63/ox_profile 2 / 58

Slide 3

Slide 3 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 3/58 Outline 1. Why statistical profiling? 2. Various python tools available. 3. Details of ox_profile statistical profiler. Goal: learn how to use ox_profile, other profilers Statistical Profiling https://github.com/emin63/ox_profile 3 / 58

Slide 4

Slide 4 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 4/58 Outline 1. Why statistical profiling? 2. Various python tools available. 3. Details of ox_profile statistical profiler. Goal: learn how to use ox_profile, other profilers or write your own! Statistical Profiling https://github.com/emin63/ox_profile 4 / 58

Slide 5

Slide 5 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 5/58 What is pro ling? From python.org: "A profile is a set of statistics that describes how often and for how long various parts of the program executed." Profiling is useful to find out which parts of program are slow. Statistical Profiling https://github.com/emin63/ox_profile 5 / 58

Slide 6

Slide 6 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 6/58 Deterministic Pro ling >>> import cProfile, re # could also use pure python `profile` >>> cProfile.run('re.compile("foo|bar")') gives: 197 function calls (192 primitive calls) in 0.002 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.001 0.001 :1() 1 0.000 0.000 0.001 0.001 re.py:212(compile) 1 0.000 0.000 0.001 0.001 re.py:268(_compile) 1 0.000 0.000 0.000 0.000 sre_compile.py:172(_compile_charset) 1 0.000 0.000 0.000 0.000 sre_compile.py:201(_optimize_charset) 4 0.000 0.000 0.000 0.000 sre_compile.py:25(_identityfunction) 3/1 0.000 0.000 0.000 0.000 sre_compile.py:33(_compile) Statistical Profiling https://github.com/emin63/ox_profile 6 / 58

Slide 7

Slide 7 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 7/58 Deterministic pro ling hooks The sys module provides: setprofile: execute function on each call. settrace: like setprofile + each line Used as a hook to inspect stack frame. Statistical Profiling https://github.com/emin63/ox_profile 7 / 58

Slide 8

Slide 8 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 8/58 Python Stack Frame Statistical Profiling https://github.com/emin63/ox_profile 8 / 58

Slide 9

Slide 9 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 9/58 Program Diagram Statistical Profiling https://github.com/emin63/ox_profile 9 / 58

Slide 10

Slide 10 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 10/58 Program Diagram w/Pro ler Statistical Profiling https://github.com/emin63/ox_profile 10 / 58

Slide 11

Slide 11 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 11/58 Drawbacks to deterministic pro ling 1. SLOW: hooks run on each line or each call! Statistical Profiling https://github.com/emin63/ox_profile 11 / 58

Slide 12

Slide 12 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 12/58 Drawbacks to deterministic pro ling 1. SLOW: hooks run on each line or each call! 2. See #1: usually can't profile in production. Statistical Profiling https://github.com/emin63/ox_profile 12 / 58

Slide 13

Slide 13 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 13/58 Drawbacks to deterministic pro ling 1. SLOW: hooks run on each line or each call! 2. See #1: usually can't profile in production. 3. Not thread-aware: "it must be registered using settrace() for each thread being debugged" (similar for setprofile()). Statistical Profiling https://github.com/emin63/ox_profile 13 / 58

Slide 14

Slide 14 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 14/58 Statistical Pro ler (Main Thread) Statistical Profiling https://github.com/emin63/ox_profile 14 / 58

Slide 15

Slide 15 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 15/58 Statistical Pro ler (Sampling) Statistical Profiling https://github.com/emin63/ox_profile 15 / 58

Slide 16

Slide 16 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 16/58 POSIX timer as Sampler Low level timer interrupts your process Periodically check call stack + record it. stat_prof, plop (not available on Windows). Statistical Profiling https://github.com/emin63/ox_profile 16 / 58

Slide 17

Slide 17 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 17/58 POSIX ptrace as Sampler Threads via ptrace. Lets one program control/inspect other. Main/Sampler are different programs! pyflame (not available on Windows). Statistical Profiling https://github.com/emin63/ox_profile 17 / 58

Slide 18

Slide 18 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 18/58 Why do we care about non-POSIX? Statistical Profiling https://github.com/emin63/ox_profile 18 / 58

Slide 19

Slide 19 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 19/58 Why do we care about non-POSIX? 1. Nice to have "portable" implementation. Statistical Profiling https://github.com/emin63/ox_profile 19 / 58

Slide 20

Slide 20 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 20/58 Why do we care about non-POSIX? 1. Nice to have "portable" implementation. 2. Using only python features may be easier to understand/modify. Understandable implementation essential if run in production. Statistical Profiling https://github.com/emin63/ox_profile 20 / 58

Slide 21

Slide 21 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 21/58 Why do we care about non-POSIX? 1. Nice to have "portable" implementation. 2. Using only python features may be easier to understand/modify. Understandable implementation essential if run in production. 3. Consumer software (e.g., games) often run in Windows. Statistical Profiling https://github.com/emin63/ox_profile 21 / 58

Slide 22

Slide 22 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 22/58 Python sys._current_frames lists each thread's current frame. ox_profile, pprofile, (works on windows!) Statistical Profiling https://github.com/emin63/ox_profile 22 / 58

Slide 23

Slide 23 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 23/58 _current_frames (Function 2) lists each thread's current frame. ox_profile, pprofile, (works on windows!) Statistical Profiling https://github.com/emin63/ox_profile 23 / 58

Slide 24

Slide 24 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 24/58 _current_frames (Function 3) lists each thread's current frame. ox_profile, pprofile, (works on windows!) Statistical Profiling https://github.com/emin63/ox_profile 24 / 58

Slide 25

Slide 25 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 25/58 Logistics: How do we pro le? Install via the usual $ pip install ox_profile Then start your python interpreter and: >>> from ox_profile.core.launchers import SimpleLauncher >>> profiler = SimpleLauncher.launch() # Create + start >>> # call some functions >>> print(profiler.show()) # Show results >>> profiler.cancel() # Turn off Statistical Profiling https://github.com/emin63/ox_profile 25 / 58

Slide 26

Slide 26 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 26/58 Sampling loop Oversimplified illustration of sampler loop: while 1: time.sleep(self.interval) for id, frame in sys._current_frames().items(): self.my_db[frame.f_code.co_name] += 1 Sampling loop runs in separate thread. Statistical Profiling https://github.com/emin63/ox_profile 26 / 58

Slide 27

Slide 27 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 27/58 Sampling Interval Control overhead based on sampling interval: >>> profiler.set_interval(5) # changes profiler.interval 5 second sampling = negligible overhead. Trade-off between various goals: accuracy, collection time, overhead May want to also add random jitter Statistical Profiling https://github.com/emin63/ox_profile 27 / 58

Slide 28

Slide 28 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 28/58 Pro ler output >>> profiler.show() Output shows: Function name (and module). How many times function was seen. Function Hits % --------------------------------------------------------- send(requests.sessions) 10082 2.8 request(requests.api) 7710 2.1 get(requests.api) 7710 2.1 (__main__) 7710 2.1 __call__(ox_profile.core.sampling) 7710 2.1 request(requests.sessions) 7698 2.1 send(requests.adapters) 6897 1.9 _make_request(urllib3.connectionpool) 6893 1.9 urlopen(urllib3.connectionpool) 6893 1.9 connect(urllib3.connection) 5602 1.5 Statistical Profiling https://github.com/emin63/ox_profile 28 / 58

Slide 29

Slide 29 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 29/58 Basic theory of sys._current_frames 1. Start thread doing mostly time.sleep. 2. Periodically wake + sys._current_frames() 3. Record current stack frame(s) info. In theory, you can write simple statistical profiler with just these. Statistical Profiling https://github.com/emin63/ox_profile 29 / 58

Slide 30

Slide 30 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 30/58 Basic theory of sys._current_frames 1. Start thread doing mostly time.sleep. 2. Periodically wake + sys._current_frames() 3. Record current stack frame(s) info. In theory, you can write simple statistical profiler with just these. In theory, there is no difference between theory and practice. Statistical Profiling https://github.com/emin63/ox_profile 30 / 58

Slide 31

Slide 31 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 31/58 Basic theory of sys._current_frames 1. Start thread doing mostly time.sleep. 2. Periodically wake + sys._current_frames() 3. Record current stack frame(s) info. In theory, you can write simple statistical profiler with just these. In theory, there is no difference between theory and practice. But, in practice, there is. Statistical Profiling https://github.com/emin63/ox_profile 31 / 58

Slide 32

Slide 32 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 32/58 Using sys._current_frames In theory, iter sys._current_frames() + record. for dummy_frame_id, frame in (sys._current_frames().items()): self.my_db.record(measure_tool(frame)) Statistical Profiling https://github.com/emin63/ox_profile 32 / 58

Slide 33

Slide 33 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 33/58 Using sys._current_frames In theory, iter sys._current_frames() + record. for dummy_frame_id, frame in (sys._current_frames().items()): self.my_db.record(measure_tool(frame)) What could go wrong? Statistical Profiling https://github.com/emin63/ox_profile 33 / 58

Slide 34

Slide 34 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 34/58 Using sys._current_frames In theory, iter sys._current_frames() + record. for dummy_frame_id, frame in (sys._current_frames().items()): self.my_db.record(measure_tool(frame)) What could go wrong? thread context could switch Statistical Profiling https://github.com/emin63/ox_profile 34 / 58

Slide 35

Slide 35 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 35/58 Using sys._current_frames In theory, iter sys._current_frames() + record. for dummy_frame_id, frame in (sys._current_frames().items()): self.my_db.record(measure_tool(frame)) What could go wrong? thread context could switch attempt to read stale frame = CRASH! Statistical Profiling https://github.com/emin63/ox_profile 35 / 58

Slide 36

Slide 36 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 36/58 Using sys._current_frames In theory, iter sys._current_frames() + record. switch_interval = sys.getswitchinterval() sys.setswitchinterval(10000) for dummy_frame_id, frame in (sys._current_frames().items()): self.my_db.record(measure_tool(frame)) sys.setswitchinterval(switch_interval) sys.setswitchinterval prevents context switch. Now, what could go wrong? Statistical Profiling https://github.com/emin63/ox_profile 36 / 58

Slide 37

Slide 37 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 37/58 Using sys._current_frames In theory, iter sys._current_frames() + record. switch_interval = sys.getswitchinterval() sys.setswitchinterval(10000) for dummy_frame_id, frame in (sys._current_frames().items()): self.my_db.record(measure_tool(frame)) sys.setswitchinterval(switch_interval) sys.setswitchinterval prevents context switch. Now, what could go wrong? Exception prevents switch interval being reset! Statistical Profiling https://github.com/emin63/ox_profile 37 / 58

Slide 38

Slide 38 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 38/58 Using sys._current_frames In theory, iter sys._current_frames() + record. switch_interval = sys.getswitchinterval() try: sys.setswitchinterval(10000) for dummy_frame_id, frame in ( sys._current_frames().items()): self.my_db.record(measure_tool(frame)) finally: sys.setswitchinterval(switch_interval) sys.setswitchinterval prevents context switch. Need try/finally to protect thread logic. Now, what could go wrong? Statistical Profiling https://github.com/emin63/ox_profile 38 / 58

Slide 39

Slide 39 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 39/58 Using sys._current_frames In theory, iter sys._current_frames() + record. switch_interval = sys.getswitchinterval() try: sys.setswitchinterval(10000) for dummy_frame_id, frame in ( sys._current_frames().items()): self.my_db.record(measure_tool(frame)) finally: sys.setswitchinterval(switch_interval) sys.setswitchinterval prevents context switch. Need try/finally to protect thread logic. Now, what could go wrong? We are just getting started. Statistical Profiling https://github.com/emin63/ox_profile 39 / 58

Slide 40

Slide 40 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 40/58 Recording a sample Simple function to record a sample in dict: def record(self, measurement): record = self.my_db.get(measurement.name, 0) self.my_db[measurement.name] = record + 1 keep dict of measurements find + increment hit for given function What could go wrong? Statistical Profiling https://github.com/emin63/ox_profile 40 / 58

Slide 41

Slide 41 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 41/58 Recording sample changing dict Imagine getting profile results def record(self, measurement): record = self.my_db.get(measurement.name, 0) self.my_db[measurement.name] = record + 1 If record being called change dict during iteration = CRASH! Statistical Profiling https://github.com/emin63/ox_profile 41 / 58

Slide 42

Slide 42 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 42/58 Recording a sample def __init__(self): self.db_lock = threading.Lock() def record(self, measurement): with self.db_lock: record = self.my_db.get(measurement.name, 0) self.my_db[measurement.name] = record + 1 Need to use threading.Lock Must check lock in viewing self.my_db Prevents simultaneous access to my_db What could go wrong? Statistical Profiling https://github.com/emin63/ox_profile 42 / 58

Slide 43

Slide 43 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 43/58 Recording a sample def __init__(self): self.db_lock = threading.Lock() def record(self, measurement): with self.db_lock: record = self.my_db.get(measurement.name, 0) self.my_db[measurement.name] = record + 1 Need to use threading.Lock Must check lock in viewing self.my_db Prevents simultaneous access to my_db What could go wrong? Unknown unknowns: use faulthandler.enable() at startup Statistical Profiling https://github.com/emin63/ox_profile 43 / 58

Slide 44

Slide 44 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 44/58 Additional Issues Sampler thread still alive on exit program Set self.daemon = True for sampler Minimum sleep time ~ 1--10 milliseconds For time.sleep or wait on a thread event. Granularity about 10 milliseconds. Statistical Profiling https://github.com/emin63/ox_profile 44 / 58

Slide 45

Slide 45 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 45/58 Using Flask If you are running a flask web server, do: from ox_profile.ui.flask.views import OX_PROF_BP app.register_blueprint(OX_PROF_BP) app.config['OX_PROF_USERS'] = {, , ...} for easy way to profile production code: ox_profile/unpause: Start (or unpause) ox_profile/pause: Pause profiler ox_profile/status: Shows current results ox_profile/set_interval: sample frequency Statistical Profiling https://github.com/emin63/ox_profile 45 / 58

Slide 46

Slide 46 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 46/58 Additional Uses What else can you do with sys._current_frames()? Statistical Profiling https://github.com/emin63/ox_profile 46 / 58

Slide 47

Slide 47 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 47/58 Additional Uses What else can you do with sys._current_frames()? Major damage that is very hard to track down! Statistical Profiling https://github.com/emin63/ox_profile 47 / 58

Slide 48

Slide 48 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 48/58 Additional Uses What else can you do with sys._current_frames()? Major damage that is very hard to track down! Be careful! Statistical Profiling https://github.com/emin63/ox_profile 48 / 58

Slide 49

Slide 49 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 49/58 Idea: Data Snapshot Periodically snapshot specific function data Instead of frame.f_code.co_name, Just look at frame.f_locals Statistical Profiling https://github.com/emin63/ox_profile 49 / 58

Slide 50

Slide 50 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 50/58 Idea: Data Snapshot Periodically snapshot specific function data Instead of frame.f_code.co_name, Just look at frame.f_locals Can even modify f_locals! Statistical Profiling https://github.com/emin63/ox_profile 50 / 58

Slide 51

Slide 51 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 51/58 Idea: Statistical Debugger Periodically snapshot debug info full stack backtrace + locals Either dump these to logs or store locally and report on "failure". Statistical Profiling https://github.com/emin63/ox_profile 51 / 58

Slide 52

Slide 52 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 52/58 Idea: Statistical code coverage Like coverage.py, but in production Periodically turn on tracing After brief sample, turn back off Statistical Profiling https://github.com/emin63/ox_profile 52 / 58

Slide 53

Slide 53 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 53/58 Summary 1. Profiling find bottlenecks + improve your code. Statistical Profiling https://github.com/emin63/ox_profile 53 / 58

Slide 54

Slide 54 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 54/58 Summary 1. Profiling find bottlenecks + improve your code. 2. Statistical profiler samples code periodically use to analyze production with low overhead. Statistical Profiling https://github.com/emin63/ox_profile 54 / 58

Slide 55

Slide 55 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 55/58 Summary 1. Profiling find bottlenecks + improve your code. 2. Statistical profiler samples code periodically use to analyze production with low overhead. 3. Use ox_profile or write your own profiler. Statistical Profiling https://github.com/emin63/ox_profile 55 / 58

Slide 56

Slide 56 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 56/58 Summary 1. Profiling find bottlenecks + improve your code. 2. Statistical profiler samples code periodically use to analyze production with low overhead. 3. Use ox_profile or write your own profiler. 4. sys.setprofile, sys.settrace, sys._current_frames Statistical Profiling https://github.com/emin63/ox_profile 56 / 58

Slide 57

Slide 57 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 57/58 Summary 1. Profiling find bottlenecks + improve your code. 2. Statistical profiler samples code periodically use to analyze production with low overhead. 3. Use ox_profile or write your own profiler. 4. sys.setprofile, sys.settrace, sys._current_frames 5. Simple in theory; but be careful with threads: try/finally, locks, switch interval, faulthandler Statistical Profiling https://github.com/emin63/ox_profile 57 / 58

Slide 58

Slide 58 text

5/2/2019 Title file:///U:/code/ox_profile/docs/overview_slides.html#58 58/58 Further investigations Slides, ox_profile, etc. at https://github.com/emin63/ox_profile Clone, fork, or file issues for questions. About presenter: Name: Emin Martinian Role: software, technology, finance consulting at www.aocks.com Contact: emin.martinian@gmail.com Statistical Profiling https://github.com/emin63/ox_profile 58 / 58