{"id":14163,"date":"2026-04-27T12:15:33","date_gmt":"2026-04-27T11:15:33","guid":{"rendered":"https:\/\/www.blopig.com\/blog\/?p=14163"},"modified":"2026-04-27T12:18:50","modified_gmt":"2026-04-27T11:18:50","slug":"speeding-up-python-through-profiling","status":"publish","type":"post","link":"https:\/\/www.blopig.com\/blog\/2026\/04\/speeding-up-python-through-profiling\/","title":{"rendered":"Speeding up python through profiling"},"content":{"rendered":"\n<p class=\"\">Python is a shockingly slow language.  A <a href=\"http:\/\/codeandlife.com\/2012\/07\/03\/benchmarking-raspberry-pi-gpio-speed\/\" data-type=\"link\" data-id=\"http:\/\/codeandlife.com\/2012\/07\/03\/benchmarking-raspberry-pi-gpio-speed\/\">test<\/a> on a raspberry pi of simply &#8220;turn this pin on and off as fast as you can&#8221; gave the results below.<\/p>\n\n\n\n<figure class=\"is-style-stripes wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>System<\/th><th>Library<\/th><th>Speed<\/th><\/tr><\/thead><tbody><tr><td>Shell<\/td><td>\/proc\/mem access<\/td><td>2.8 kHz<\/td><\/tr><tr><td>Shell \/ gpio utility<\/td><td>WiringPi gpio utility<\/td><td>40 Hz<\/td><\/tr><tr><td>Python<\/td><td>RPI.GPIO<\/td><td>70 kHz<\/td><\/tr><tr><td>Python<\/td><td>wiringPi2 bindings<\/td><td>28 kHz<\/td><\/tr><tr><td>Ruby<\/td><td>wiringPi bindings<\/td><td>21 kHz<\/td><\/tr><tr><td>C<\/td><td>Native library<\/td><td>22 MHz<\/td><\/tr><tr><td>C<\/td><td>BCM 2835<\/td><td>5.4 MHz<\/td><\/tr><tr><td>C<\/td><td>wiringPi<\/td><td>4.1 &#8211; 4.6 MHz<\/td><\/tr><tr><td>Perl<\/td><td>BCM 2835<\/td><td>48 kHz<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<!--more-->\n\n\n\n<p class=\"\">So, how do we speed up python?  The simple answer is not to use python, and use a faster language.  Whilst that may sound facetious, some of the most commonly used python libraries are actually written in, or have cores in much faster languages.<\/p>\n\n\n\n<figure class=\"is-style-stripes wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Library<\/th><th>~ % Python<\/th><th>Notes<\/th><\/tr><\/thead><tbody><tr><td>PyTorch<\/td><td>62<\/td><td>Core in C++<\/td><\/tr><tr><td>Numpy<\/td><td>60<\/td><td>Core in C<\/td><\/tr><tr><td>TensorFlow<\/td><td>20<\/td><td>Core in C++<\/td><\/tr><tr><td>OpenCV<\/td><td>3<\/td><td>Core in C++<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"\">If using pre-made libraries with fast cores still doesn&#8217;t provide the speed-up you need, then what?  Find the slow bit &#8211; <em>Test it,\u00a0 Tidy it,\u00a0 Time it.<\/em><br><strong>Test it <\/strong>&#8211; Quite often, things are slow because they&#8217;re a bit buggy.  So a bit more of a concerted effort testing the code wouldn&#8217;t go amiss.  <br><strong>Tidy it<\/strong> &#8211; If the code&#8217;s spaghetti-like and has lost its elegance as you&#8217;ve had to put in workarounds for workarounds, perhaps it&#8217;s going through seldom used pathways and incurring an efficiency hit every time.  Refactoring your code can help its performance.<br><strong>Time it <\/strong>&#8211; If the above are no help, time to reach for the big guns and time each section of code and see where the slow-down is happening.  This can be done with a profiler and\/or a visualiser, a selection of which are mentioned below.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"\"><a href=\"https:\/\/docs.python.org\/3\/library\/timeit.html\">Timeit<\/a> &#8211; Measures the execution time of small code snippets<\/li>\n\n\n\n<li class=\"\"><a href=\"https:\/\/docs.python.org\/3\/library\/profile.html\">Profile <\/a>&#8211; Collect detailed runtime statistics (consider using cProfile or PyInstrument)<br><\/li>\n\n\n\n<li class=\"\"><a href=\"https:\/\/www.turing.com\/kb\/python-code-with-cprofile\">cProfile <\/a>&#8211;\n<ul class=\"wp-block-list\">\n<li class=\"\">Similar to Profile, but better.<\/li>\n\n\n\n<li class=\"\">Deterministic profiler.\u00a0<\/li>\n\n\n\n<li class=\"\">Monitors every function call, return and exception event, records timing for each.<br><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li class=\"\"><a href=\"https:\/\/pyinstrument.readthedocs.io\/en\/stable\/\">PyInstrument <\/a>&#8211; \n<ul class=\"wp-block-list\">\n<li class=\"\">Low overhead profiler and visualiser<\/li>\n\n\n\n<li class=\"\">Statistical profiler.\u00a0<\/li>\n\n\n\n<li class=\"\">Will miss things, but mainly the things which are inherently quick anyway.<\/li>\n\n\n\n<li class=\"\">Measures at repeating intervals which function is being called.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">I would recommend a look at PyInstrument<\/h2>\n\n\n\n<p class=\"\">PyInstrument can be called from the command line as a simple module, where you also specify an HTML file as interactive output on how your code is running. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>python3 -m pyinstrument\u00a0 -o count-char.html count-char.py<\/code><\/pre>\n\n\n\n<p class=\"\">PyInstrument also provides some fairly easy to read visualisations of your code.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-1.png?ssl=1\"><img decoding=\"async\" width=\"1046\" height=\"513\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-1.png?fit=625%2C306&amp;ssl=1\" alt=\"\" class=\"wp-image-14168\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-1.png?w=1046&amp;ssl=1 1046w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-1.png?resize=300%2C147&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-1.png?resize=1024%2C502&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-1.png?resize=768%2C377&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-1.png?resize=624%2C306&amp;ssl=1 624w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-2.png?ssl=1\"><img decoding=\"async\" width=\"1195\" height=\"324\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-2.png?fit=625%2C170&amp;ssl=1\" alt=\"\" class=\"wp-image-14169\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-2.png?w=1195&amp;ssl=1 1195w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-2.png?resize=300%2C81&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-2.png?resize=1024%2C278&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-2.png?resize=768%2C208&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-2.png?resize=624%2C169&amp;ssl=1 624w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n\n\n\n<p class=\"\">Or even more complex code such as:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?ssl=1\"><img decoding=\"async\" width=\"1904\" height=\"654\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?fit=625%2C215&amp;ssl=1\" alt=\"\" class=\"wp-image-14171\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?w=1904&amp;ssl=1 1904w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?resize=300%2C103&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?resize=1024%2C352&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?resize=768%2C264&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?resize=1536%2C528&amp;ssl=1 1536w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?resize=624%2C214&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2026\/04\/image-3.png?w=1250&amp;ssl=1 1250w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Python visualisers<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"\">Runsnakerun (<a href=\"https:\/\/github.com\/Shoobx\/runsnake\">https:\/\/github.com\/Shoobx\/runsnake<\/a>)<\/li>\n\n\n\n<li class=\"\">Snakeviz (<a href=\"https:\/\/jiffyclub.github.io\/snakeviz\/\">https:\/\/jiffyclub.github.io\/snakeviz\/<\/a>)<\/li>\n\n\n\n<li class=\"\">Py-spy (<a href=\"https:\/\/github.com\/benfred\/py-spy\">https:\/\/github.com\/benfred\/py-spy<\/a>)<\/li>\n\n\n\n<li class=\"\">PyInstrument (<a href=\"https:\/\/pyinstrument.readthedocs.io\/en\/stable\/guide.html\">https:\/\/pyinstrument.readthedocs.io\/en\/stable\/guide.html<\/a>)<\/li>\n<\/ul>\n\n\n\n<p class=\"\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">There are some other options which involve very little code change.<\/h2>\n\n\n\n<p class=\"\"><strong><a href=\"https:\/\/pypy.org\/\">PyPy<\/a><\/strong><br>Alternative interpreter and JIT compiler<br>Best for long-running code<\/p>\n\n\n\n<p class=\"\"><a href=\"https:\/\/docs.python.org\/3\/whatsnew\/3.13.html\"><strong>Enable JIT<\/strong><br><\/a>Available in v3.13+<br>activate using &#8211;enable-experimental-jit\u00a0<\/p>\n\n\n\n<p class=\"\"><strong><a href=\"https:\/\/numba.pydata.org\/\">Numba<\/a><\/strong><br>Works best on code that uses NumPy and code can be dramatically sped up just by adding decorators such as<br>@jit decorator<br>@njit(parallel=True)<br><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Python is a shockingly slow language. A test on a raspberry pi of simply &#8220;turn this pin on and off as fast as you can&#8221; gave the results below. System Library Speed Shell \/proc\/mem access 2.8 kHz Shell \/ gpio utility WiringPi gpio utility 40 Hz Python RPI.GPIO 70 kHz Python wiringPi2 bindings 28 kHz [&hellip;]<\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","wikipediapreview_detectlinks":true,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"ngg_post_thumbnail":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[709,226,29,227],"tags":[],"ppma_author":[507],"class_list":["post-14163","post","type-post","status-publish","format-standard","hentry","category-c","category-cpp","category-code","category-python-code"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"authors":[{"term_id":507,"user_id":15,"is_guest":0,"slug":"eoin","display_name":"Eoin Malins","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/e91a9cf8b77625a1bc34e56f5dc36439a1f61476804b087e5b47554425879210?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/14163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/comments?post=14163"}],"version-history":[{"count":4,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/14163\/revisions"}],"predecessor-version":[{"id":14173,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/14163\/revisions\/14173"}],"wp:attachment":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/media?parent=14163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/categories?post=14163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/tags?post=14163"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=14163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}