Converting .prof Files to .callgrind

alex_ber
4 min readJul 23, 2024

--

Profiling and Performance Conversion Scripts

Performance profiling is an essential aspect of optimizing and understanding the behavior of your Python code. Profiling helps identify bottlenecks and performance-critical sections in your application, allowing you to enhance its efficiency. This story explores a detailed procedure for converting .prof files generated by Python's cProfile module into .callgrind.

The source code you can found here. It is available as part of my AlexBerUtils s project.

You can install AlexBerUtils from PyPi:

python -m pip install -U alex-ber-utils

See here for more details explanation on how to install.

High-Resolution Timer Profiling in Python

Before diving into the conversion process, let’s set up a cProfile profiler in Python using a high-resolution timer based on time.perf_counter_ns. This timer offers greater precision in nanoseconds, which is particularly useful for performance-sensitive applications.

import cProfile
import time
import uvicorn
...

def app_start():
uvicorn.run("main:app", host='0.0.0.0', port=80)


# Define a more precise timer
def precise_timer():
return time.perf_counter_ns()

def profiler_start():
# Create a cProfile.Profile object with the precise timer function
profiler = cProfile.Profile(timer=precise_timer)
profiler.enable()

app_start()

profiler.disable()
profiler.dump_stats('my_program.prof')

# if __name__ == "__main__":
# profiler_start()


if __name__ == "__main__":
uvicorn.run("main:app", host='0.0.0.0', port=80)

# Usage note:
# The profiler is now configured to use the precise_timer function,
# which provides higher resolution timing measurements in nanoseconds.

main.py

With the profiler configured, you can use it to profile your Python code, and it will generate a .prof file.

Converting .prof Files to .callgrind Format

You can Git checkout the source of AlexBerUtils and run prof_to_callgrind.sh. As long as you have Docker installed and internet access to https://hub.docker.com/, it will work seamlessly.

Shell Script: prof_to_callgrind.sh

The prof_to_callgrind.sh script automates the process of converting .prof files to .callgrind format using Docker. This script offers flexibility by allowing users to specify input and output files, project directories, and application directories. You can use it from the source or after installing via pip. You will need to find it in your site-packages directory. Optionally, you can add it to your /bin, PATH, or any other mechanism that will recognize it.

Python Script: prof_to_callgrind.py

The prof_to_callgrind.py script handles the actual conversion of profile statistics from a .prof file to a .callgrind file. This script reads the profile data and writes it in a format compatible with callgrind, which is used by tools like KCachegrind for detailed profiling analysis. This script offers flexibility by allowing users to specify input and output files, project directories, and application directories.

Converting .prof Files to .callgrind Format

  1. From Source or after pip Installation
    You can use the script either from the source repository or after installing it with pip. Locate it in your site-packages directory. Optionally, you can add it to your /bin, PATH, or any other mechanism that will recognize it.
  2. Using in Your Own Script
    You can write your own script to call prof_to_callgrind.py:
from alexber.utils.prof_to_callgrind import main

# your_script.py
if __name__ == "__main__":
main()

Running this script will eliminate the hassle of searching where the files are installed.

3. Integrating into Your Codebase

You can integrate prof_to_callgrind directly into your code:

from alexber.utils.prof_to_callgrind import convert_prof_to_callgrind

def main():
# Your application logic here
input_file = 'input.prof'
output_file = 'output.callgrind'
convert_prof_to_callgrind(input_file, output_file)

if __name__ == "__main__":
main()

cProfile: Profiling Tool for Python

Python’s cProfile module is a built-in tool for profiling Python applications. It provides a way to measure where time is spent in your code, which functions are called, and how often they are called.

Key Features of cProfile:

  • Function Call Statistics: cProfile provides detailed statistics about function calls, including how many times each function is called.
  • Execution Time: It measures the time spent in each function, helping identify performance bottlenecks.
  • Integration with pstats: The output of cProfile can be saved and analyzed using Python’s pstats module, which supports various formatting options.

KCachegrind: Visualizing Profiling Data

KCachegrind is a powerful tool for visualizing profiling data, particularly from .callgrind files. It provides a graphical interface that makes it easier to analyze performance data and understand detailed call paths and time distribution.

Features of KCachegrind:

  • Graphical Representation: It offers a visual representation of function calls and their relationships.
  • Call Graphs: You can explore call graphs that show the sequence of function calls and their execution times.
  • Annotations: Detailed annotations help identify which lines of code are consuming the most time.

Steps to Use KCachegrind:

Install KCachegrind: Depending on your operating system, you can install KCachegrind via package managers like apt, yum, or through direct downloads.

Linux:

sudo apt-get update
sudo apt-get install kcachegrind

Mac

On macOS, you can install KCachegrind using a package manager Homebrew.

  1. Install Homebrew if you haven’t already. Open a terminal and run:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

2. Install KCachegrind:

brew install kcachegrind

Windows

A. Using Windows Subsystem for Linux (WSL2)

  1. Open the installed Linux distribution (e.g., Ubuntu).
  2. Update the package list and install KCachegrind:
sudo apt-get update
sudo apt-get install kcachegrind

B. Using Homebrew on Windows with WSL2

  1. Install Homebrew if you haven’t already. Open a terminal and run:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

2. Add Homebrew to your shell profile. Follow the instructions provided at the end of the installation script or add the following to your ~/.profile or ~/.bashrc:

echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> ~/.profile
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"

3. Once Homebrew is installed and set up, you can install KCachegrind:

brew install kcachegrind

Verification

After installation, you can verify that KCachegrind is installed by running:

kcachegrind

This should open the KCachegrind application.

Open .callgrind Files:

Launch KCachegrind and open the .callgrind file generated by the conversion script. This will display an interactive interface where you can explore the profiling data.

This comprehensive approach facilitates efficient profiling and performance analysis of Python applications, leveraging the precision of high-resolution timers and the visualization capabilities of callgrind-compatible tools like KCachegrind.

P.S. Microbenchmarking

import time

start = time.perf_counter_ns()
operation_to_benchmarknig()
delta = (time.perf_counter_ns() - start) * 10 ** (-9)
print(f"operation_to_benchmarknig took {delta:.4f} seconds")

--

--

alex_ber
alex_ber

Written by alex_ber

Senior Software Engineer at Pursway

No responses yet