This guide covers how to profile Python applications running in Slurm jobs on SUNK usingDocumentation Index
Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
Use this file to discover all available pages before exploring further.
py-spy and Linux perf tools. It assumes you have a working SUNK deployment with an active Slurm job to profile.
SUNK compute Pods already have the SYS_PTRACE capability, so profilers can attach to processes without additional Pod configuration.
Prerequisites
To useperf, the Kubernetes Nodes need the kernel.yama.ptrace_scope=0 and kernel.perf_event_paranoid=-1 kernel parameters set. Deploy a DaemonSet that runs a privileged container on each Node to configure these parameters.
- The
kernel.yama.ptrace_scope=0kernel parameter allows processes to attach and read memory from other processes. - The
kernel.perf_event_paranoid=-1kernel parameter allows unprivileged access to performance monitoring.
If you only plan to use
py-spy, the ptrace_scope parameter is the only one required. The perf_event_paranoid parameter is only needed for Linux perf.-
Create a file called
py-perf-ds.yamlwith the following content:This DaemonSet sets the required kernel parameters on every Node.py-perf-ds.yaml- It uses
sleep infinityto keep the container running so that the kernel parameters persist while the container is running. - The
securityContextsection runs the container in privileged mode to allow it to set the kernel parameters.
- It uses
-
Deploy the DaemonSet.
-
Verify the DaemonSet is running on all Nodes.
-
Verify the Pods are running.
-
Verify the kernel parameters are set on one of the Pods. Replace
[POD-NAME]with one of the Pod names from the previous step.
-1 and 0 respectively.
Use py-spy
py-spy is a sampling profiler specifically designed for Python. It shows Python-level stack traces with function names, file paths, and line numbers.
Install py-spy
To install py-spy, start a debug container attached to the compute Pod where your Slurm job is running, then install py-spy in the debug container.
-
Identify the compute Pod running your job. In SUNK, the Slurm node name matches the Kubernetes Pod name. Use
squeuefrom a login node to find the node, then use that name as the Pod name. -
Set the Pod name from the
squeueoutput. -
Start a debug container attached to the compute Pod.
-
Inside the debug container, install
py-spy.
Show live top view in py-spy
In SUNK compute Pods, PID 1 is
slurmd, not your Python application. Find your Python process PID with ps aux | grep python and use that PID in the commands below.%Own: Percentage of time spent in this function itself%Total: Percentage of time spent in this function + functions it callsOwnTime: Total time spent in this function itselfTotalTime: Total time spent in this function + functions it callsGIL: Percentage of time holding the Global Interpreter LockFunction (filename:line): Function name, filename, and line number
Record to SVG flamegraph
To record profiling data and generate an SVG flamegraph:-
Run the following command:
A successful output should show the profiling data has been written to the
/tmp/profile.svgfile. -
Open a new terminal in your local machine and copy the SVG file to your local machine.
-
Open
profile.svgin a browser to see the flamegraph.
Record to Speedscope format
Speedscope is a web-based viewer for performance profiles. To record profiling data and generate a Speedscope JSON file:-
Run the following command:
-
Open a new terminal in your local machine and copy the JSON file to your local machine.
- Upload the JSON file to Speedscope for analysis.
Show thread activity
To show what each thread is doing, run the following command:Only show threads holding GIL
The GIL (Global Interpreter Lock) is a mutex that protects the Python interpreter from concurrent execution. It’s used to ensure that only one thread can execute Python code at a time. Monitoring the GIL can help you understand Python CPU usage (ignoring I/O wait). To only show threads holding GIL, run the following command:py-spy options
py-spy has several options that can be used to configure the profiling data.
rate option
The rate option can be used to set the sampling rate. The default is 100 Hz. To sample at a higher rate, such as 500 Hz, run the following command:
native option
The native option can be used to show native (C/C++) extensions. To show native extensions, run the following command:
idle option
The idle option can be used to show idle threads. To show idle threads, run the following command:
nonblocking option
The nonblocking option can be used to run in non-blocking mode, which doesn’t pause the target process. To run in non-blocking mode, run the following command:
Use perf
Linux perf is a powerful performance analysis tool that shows system-level and native code performance.
Install perf
To install perf, start a debug container attached to the compute Pod where your Slurm job is running, then install perf in the debug container.
-
If you have not already identified the compute Pod, find it using
squeuefrom a login node and set the Pod name. -
Start a debug container with Ubuntu. The Ubuntu distribution has
perftools available. -
Inside the debug container, install
perf. -
Locate the
perfbinary. The location varies by kernel version.
Show live top view in perf
To show real-time usage by function, run the following command:
Overhead: CPU time percentageShared Object: The library/binary (python3.12, kernel, libc)Symbol: Function name[.]: User-space function[k]: Kernel function
Record and generate a report
To record for a specific duration, then generate a report, use therecord command, then the report command.
This records at 99 Hz for 30 seconds with call graphs.
report command to view the report.
report command shows output similar to the following:
Generate a text report
To generate a text report to save or share results, use thereport command with the --stdio option.
View detailed statistics
To view detailed statistics, use thestat command. This shows statistics for the process with the given PID for the specified duration.
Generate flamegraph data
To generate flamegraph data, use therecord command, then the script command. This will output the data as a script that can be used with the FlameGraph tool.
-
Record the data. This records at 99 Hz for 30 seconds with call graphs.
-
Use the
scriptcommand to output the data as a script. -
Copy the script file to your local machine.
- Use the FlameGraph tool to generate a flamegraph from the script file.
perf options
perf has several options that can be used to configure the profiling data.
-F option
The -F option can be used to set the sampling rate. The default is 99 Hz. To sample at a higher rate, such as 999 Hz, run the following command:
-a option can be used to record all CPUs.
-e option can be used to record specific events.
--call-graph option can be used to record with call-graph using dwarf, which is more accurate but also incurs more overhead.
Comparison: py-spy vs perf
py-spy and perf are two different tools for profiling Python applications in Kubernetes. They have different strengths and weaknesses.
| Feature | py-spy | perf |
|---|---|---|
| Focus | Python code only | All code (Python, C, kernel) |
| Output | Function names, file:line | Native symbols, may need debug symbols |
| Ease of use | Very easy, Python-specific | More complex, general purpose |
| Overhead | Very low (~1-2%) | Low (~1-5%) |
| Best for | Python performance issues | System/native code issues, CPU/cache analysis |
| GIL detection | Yes, built-in | No |
| Multi-threaded | Shows Python threads clearly | Shows all threads |
| Setup | Just install py-spy | Need kernel tools, may need debug symbols |
| Output formats | SVG, speedscope, text | Text report, script for flamegraphs |
py-spy when you need to profile pure Python code. It provides a quick, easy-to-read view of the Python code. It has very low overhead, so it’s suitable to use in production. It’s ideal when you need to see Python function names and line numbers, or want to understand GIL contention.
Use perf when you need to profile system-level performance. It provides a detailed view of the C extensions and kernel code, including CPU cache, branch prediction, and hardware counter data. It’s ideal when you suspect issues in native libraries (numpy, pandas C code, etc.), or need to correlate Python and kernel activity.
Use both tools when you need to profile complex performance issues and get a complete picture of the performance. This is particularly useful if your code uses significant C extensions.
Troubleshooting: “Process not found”
Bothpy-spy and perf can encounter a “Process not found” error when trying to profile a process.
Both tools need to attach to the target process. If the target process is not running, or the PID is incorrect, the tools will fail with a “Process not found” error.
To fix this, verify the target process is running and the PID is correct.
- Verify the target process is running:
ps aux | grep python - Verify you are in the right container and namespace:
kubectl get pods -n tenant-slurm - If using
kubectl debug, verify that--targetis set toslurmd.
Troubleshooting py-spy
”Permission Denied” error
You may encounter a “Permission Denied” error when trying to profile a process withpy-spy.
For example:
SYS_PTRACE capability, so this error typically means the kernel parameters are not set correctly. Verify the DaemonSet is running and the ptrace_scope parameter is configured.
-
Verify the DaemonSet is running:
kubectl get pods -n tenant-slurm -l name=perf-debug -
Check the kernel parameters:
A successful output should show the kernel parameter is set to
0. -
Use
--profile=generalwhen runningkubectl debug.
”Failed to find python version” error
You may encounter a “Failed to find python version” error when trying to profile a process withpy-spy. This means the target PID is not a Python process.
For example:
slurmd, not your Python application. Find the correct Python PID first:
Troubleshooting perf
”failed with EPERM” error
You may encounter a “failed with EPERM” error when trying to profile a process withperf.
kernel.perf_event_paranoid is set to -1.
No symbols found
Ifperf shows hex addresses instead of function names, it means the debug symbols are not installed.
To fix this, you need to install the debug symbols for Python.
--call-graph dwarf option for better stack traces.
Tips for successful profiling
- Start with py-spy. It’s easier to use than
perfand usually sufficient for Python issues. - Use low sampling rates in production. 99-100 Hz is usually enough resolution for most applications.
- Record for at least 30 seconds. This gives representative samples.
- Profile during representative load. Idle or startup profiles aren’t useful.
- Copy profiles out immediately. Debug containers are ephemeral and will be deleted after the profiling session.
- Don’t leave the DaemonSet running in production long-term. It uses privileged access and it’s a security risk to leave it running after the profiling session.
- Use flamegraphs. They’re much easier to understand than text output. Flamegraphs show the most time-consuming functions and their callers, making it easy to identify bottlenecks.
- Compare before and after. Profile before optimization to establish baseline. This helps you understand the impact of your optimizations.
Typical workflow
Here’s a typical workflow for profiling a Python application running in a Slurm job on SUNK.-
Deploy the DaemonSet to set the kernel parameters on all Nodes. See the example DaemonSet file in the Prerequisites section. Deploy the DaemonSet:
-
Find the compute Pod running your Slurm job. From a login node, use
squeueto identify the Slurm node, then start a profiling session. -
Inside the debug container, install
py-spy, find your Python process, and check the top view. -
Record a flamegraph for analysis.
-
From another terminal, copy the flamegraph to your local machine. This is important because the debug container will be deleted after the profiling session.
-
If needed, dive deeper with
perf. -
Clean up the DaemonSet when done.