Answering my own question in the hope others might find it useful in the future.
I've been able to use py-spy's top command on my program as it was running inside the container and its output has showed me that the hupper library is the cause of the high CPU usage.
Here are the steps that I've taken:
- I had to spin up a new container with the
SYS_PTRACE capability otherwise py-spy can't run inside it: docker run -it --cap-add SYS_PTRACE python:3.9.13-buster /bin/bash
- I cloned my app into the container, built it, and ran it.
- I ran
top to see what the process id is for my program (identifiable by its high CPU usage). - I ran
py-spy top --pid <process id> to see a live table showing me the most active parts of my code.
Similar to this:
(python v3.9.13) Total Samples 78500 GIL: 15.00%, Active: 103.00%, Threads: 4 %Own %Total OwnTime TotalTime Function (filename) 92.00% 92.00% 717.0s 717.0s get_mtime (hupper/polling.py) 3.00% 3.00% 41.27s 67.08s walk (dash/_watch.py) 7.00% 99.00% 35.86s 752.9s check_reload (hupper/polling.py) 1.00% 100.00% 20.21s 773.1s run (hupper/polling.py) 0.00% 0.00% 17.08s 18.78s _walk (os.py) 0.00% 0.00% 4.24s 4.24s <listcomp> (dash/_watch.py) 0.00% 0.00% 2.49s 2.89s join (posixpath.py) 0.00% 0.00% 1.60s 1.60s islink (posixpath.py) 0.00% 0.00% 0.400s 0.400s _get_sep (posixpath.py) 0.00% 3.00% 0.210s 67.29s watch (dash/_watch.py) 0.00% 0.00% 0.030s 0.030s _run_worker (hupper/reloader.py) 0.00% 0.00% 0.020s 0.020s _recv_packet (hupper/ipc.py) 0.00% 3.00% 0.000s 67.31s run (threading.py) 0.00% 0.00% 0.000s 0.030s start_reloader (hupper/reloader.py) 0.00% 0.00% 0.000s 0.030s <module> (<string>) 0.00% 3.00% 0.000s 67.29s <lambda> (dash/dash.py) 0.00% 0.00% 0.000s 0.030s serve (myapp/cli/main.py) 0.00% 103.00% 0.000s 840.4s _bootstrap (threading.py) 0.00% 0.00% 0.000s 0.030s serve_dashboard (myapp/dashboard/__init__.py) 0.00% 0.00% 0.000s 0.030s wrapper (myapp/cli/main.py) 0.00% 0.00% 0.000s 0.020s _read_loop (hupper/ipc.py) 0.00% 0.00% 0.000s 0.030s main (myapp/cli/main.py) 0.00% 0.00% 0.000s 0.030s run (hupper/reloader.py)