aboutsummaryrefslogtreecommitdiff
path: root/content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md
diff options
context:
space:
mode:
authorMitja Felicijan <m@mitjafelicijan.com>2023-07-08 23:25:41 +0200
committerMitja Felicijan <m@mitjafelicijan.com>2023-07-08 23:25:41 +0200
commitcd6644ea4ddc78597934ab0ef5ba50e3c3daa927 (patch)
tree03de331a8db6386dfd6fa75155bfbcea6b4feaf3 /content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md
parent84ed124529ffeee1590295b8de3a8faf51848680 (diff)
downloadmitjafelicijan.com-cd6644ea4ddc78597934ab0ef5ba50e3c3daa927.tar.gz
Moved to a simpler SSG
Diffstat (limited to 'content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md')
-rw-r--r--content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md205
1 files changed, 0 insertions, 205 deletions
diff --git a/content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md b/content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md
deleted file mode 100644
index 2e36eaf..0000000
--- a/content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md
+++ /dev/null
@@ -1,205 +0,0 @@
1---
2title: Profiling Python web applications with visual tools
3url: profiling-python-web-applications-with-visual-tools.html
4date: 2017-04-21T12:00:00+02:00
5draft: false
6---
7
8I have been profiling my software with KCachegrind for a long time now and I was
9missing this option when I am developing API's or other web services. I always
10knew that this is possible but never really took the time and dive into it.
11
12Before we begin there are some requirements. We will need to:
13
14- implement [cProfile](https://docs.python.org/2/library/profile.html#module-cProfile) into our web app,
15- convert output to [callgrind](http://valgrind.org/docs/manual/cl-manual.html) format with [pyprof2calltree](https://pypi.python.org/pypi/pyprof2calltree/),
16- visualize data with [KCachegrind](http://kcachegrind.sourceforge.net/html/Home.html) or [Profiling Viewer](http://www.profilingviewer.com/).
17
18
19If you are using MacOS you should check out [Profiling
20Viewer](http://www.profilingviewer.com/) or
21[MacCallGrind](http://www.maccallgrind.com/).
22
23![KCachegrind](/assets/python-profiling/kcachegrind.png)
24
25We will be dividing this post into two main categories:
26
27- writing simple web-service,
28- visualize profile of this web-service.
29
30## Simple web-service
31
32Let's use virtualenv so we won't pollute our base system. If you don't have
33virtualenv installed on your system you can install it with pip command.
34
35```bash
36# let's install virtualenv globally
37$ sudo pip install virtualenv
38
39# let's also install pyprof2calltree globally
40$ sudo pip install pyprof2calltree
41
42# now we create project
43$ mkdir demo-project
44$ cd demo-project/
45
46# now let's create folder where we will store profiles
47$ mkdir prof
48
49# now we create empty virtualenv in venv/ folder
50$ virtualenv --no-site-packages venv
51
52# we now need to activate virtualenv
53$ source venv/bin/activate
54
55# you can check if virtualenv was correctly initialized by
56# checking where your python interpreter is located
57# if command bellow points to your created directory and not some
58# system dir like /usr/bin/python then everything is fine
59$ which python
60
61# we can check now if all is good ➜ if ok couple of
62# lines will be displayed
63$ pip freeze
64# appdirs==1.4.3
65# packaging==16.8
66# pyparsing==2.2.0
67# six==1.10.0
68
69# now we are ready to install bottlepy ➜ web micro-framework
70$ pip install bottle
71
72# you can deactivate virtualenv but you will then go
73# under system domain ➜ for now don't deactivate
74$ deactivate
75```
76
77We are now ready to write simple web service. Let's create file app.py and paste
78code bellow in this newly created file.
79
80```python
81# -*- coding: utf-8 -*-
82
83import bottle
84import random
85import cProfile
86
87app = bottle.Bottle()
88
89# this function is a decorator and encapsulates function
90# and performs profiling and then saves it to subfolder
91# prof/function-name.prof
92# in our example only awesome_random_number function will
93# be profiled because it has do_cprofile defined
94def do_cprofile(func):
95 def profiled_func(*args, **kwargs):
96 profile = cProfile.Profile()
97 try:
98 profile.enable()
99 result = func(*args, **kwargs)
100 profile.disable()
101 return result
102 finally:
103 profile.dump_stats("prof/" + str(func.__name__) + ".prof")
104 return profiled_func
105
106
107# we use profiling over specific function with including
108# @do_cprofile above function declaration
109@app.route("/")
110@do_cprofile
111def awesome_random_number():
112 awesome_random_number = random.randint(0, 100)
113 return "awesome random number is " + str(awesome_random_number)
114
115@app.route("/test")
116def test():
117 return "dummy test"
118
119if __name__ == '__main__':
120 bottle.run(
121 app = app,
122 host = "0.0.0.0",
123 port = 4000
124 )
125
126# run with 'python app.py'
127# open browser 'http://0.0.0.0:4000'
128```
129
130When browser hits awesome\_random\_number() function profile is created in prof/
131subfolder.
132
133## Visualize profile
134
135Now let's create callgrind format from this cProfile output.
136
137```bash
138$ cd prof/
139$ pyprof2calltree -i awesome_random_number.prof
140# this creates 'awesome_random_number.prof.log' file in the same folder
141```
142
143This file can be opened with visualizing tools listed above. In this case we
144will be using Profilling Viewer under MacOS. You can open image in new tab. As
145you can see from this example there is hierarchy of execution order of your
146code.
147
148![Profilling Viewer](/assets/python-profiling/profiling-viewer.png)
149
150> Make sure you convert output of the cProfile output every time you want to
151refresh and take a look at your possible optimizations because cProfile updates
152.prof file every time browser hits the function.
153
154This is just a simple example but when you are developing real-life applications
155this can be very illuminating, especially to see which parts of your code are
156bottlenecks and need to be optimized.
157
158## Update 2017-04-22
159
160Reddit user [mvt](https://www.reddit.com/user/mvt) also recommended this awesome
161web based profile visualizer [SnakeViz](https://jiffyclub.github.io/snakeviz/)
162that directly takes output from
163[cProfile](https://docs.python.org/2/library/profile.html#module-cProfile)
164module.
165
166<div class="reddit-embed" data-embed-media="www.redditmedia.com" data-embed-parent="false" data-embed-live="false" data-embed-uuid="583880c1-002e-41ed-a373-020a0ef2cff9" data-embed-created="2017-04-22T19:46:54.810Z"><a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dgljhsb/">Comment</a> from discussion <a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/">Profiling Python web applications with visual tools</a>.</div><script async src="https://www.redditstatic.com/comment-embed.js"></script>
167
168```bash
169# let's install it globally as well
170$ sudo pip install snakeviz
171
172# now let's visualize
173$ cd prof/
174$ snakeviz awesome_random_number.prof
175# this automatically opens browser window and
176# shows visualized profile
177```
178
179![SnakeViz](/assets/python-profiling/snakeviz.png)
180
181Reddit user [ccharles](https://www.reddit.com/user/ccharles) suggested a better
182way for installing pip software by targeting user level instead of using sudo.
183
184<div class="reddit-embed" data-embed-media="www.redditmedia.com" data-embed-parent="false" data-embed-live="false" data-embed-uuid="f4f0459e-684d-441e-bebe-eb49b2f0a31d" data-embed-created="2017-04-22T19:46:10.874Z"><a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dglpzkx/">Comment</a> from discussion <a href="https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/">Profiling Python web applications with visual tools</a>.</div><script async src="https://www.redditstatic.com/comment-embed.js"></script>
185
186```bash
187# now we need to add this path to our $PATH variable
188# we do this my adding this line at the end of your
189# ~/.bashrc file
190PATH=$PATH:$HOME/.local/bin/
191
192# in order to use this new configuration you can close
193# and reopen terminal or reload .bashrc file
194$ source ~/.bashrc
195
196# now let's test if new directory is present in $PATH
197$ echo $PATH
198
199# now we can install on user level by adding --user
200# without use of sudo
201$ pip install snakeviz --user
202```
203
204Or as suggested by [mvt](https://www.reddit.com/user/mvt) you can
205use [pipsi](https://github.com/mitsuhiko/pipsi).