Debugging Python with Pybind and TotalView
February 22, 2021

Debugging Python in Mixed-Language Apps With Pybind and TotalView

Technologies & Languages

Python is one of the most widely used programming languages. It can be used to call other high level languages such as C, C++ and Fortran in order to provide access to high performance routines without having to rewrite existing code.

In this article we will see how to debug a mixed language Python/C++ and Python/C++/Fortran example using the Pybind framework and TotalView.

What Is Pybind?

Pybind is a lightweight header-only library that exposes C++ types in Python and vice versa, mainly to create Python bindings of existing C++ code. - Source

Python/C++ Example Using Pybind

Requirements

This example uses Ubuntu 19 and Python 3.7.

sudo apt-get install python-dev
sudo apt-get install python-dbg
sudo apt-get install pybind11
pip install pybind

 

Step by Step

1. Start with an example.cpp file.

#include <pybind11/pybind11.h>
int add(int i, int j) {
    return i + j;
}
PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring
    m.def("add", &add, "A function which adds two numbers");
}

 

2. Pybind11 is a header-only library, hence it is not necessary to link against any special libraries and there are no intermediate (magic) translation steps. On Linux, the above example can be compiled using the following command:

g++ -g -O3 -Wall -shared -std=c++11 -fPIC -I/usr/include/python3.7dm example.cpp -o example$(python3.7dm-config --extension-suffix)

This creates a shared library named (similar to) example.cpython-37dm-x86_64-linux-gnu.so.

3. Test the Python module by importing example and calling the add function.

Python Pybind Module

4. Write a Python test wrapper test_example.py

import example
result = example.add(1,2)
print("Result = ", result)

 

5. Start TotalView debugger to debug the Python / C++ code: 

$totalview -args python3-dbg test_wrapper.py

6. Set a pending breakpoint on the C++ add function.

Python Set a Pending Breakpoint

7. TotalView shows the C++ code when you press GO.

Enable stack frame filtering by clicking on the orange filter button in the Call Stack window.

TotalView Call Stack Window

8. And the Python code.

TotalView Python Code

Python/C++/Fortran Example Using Pybind

This uses the same requirements noted in the above example.

Step by Step

1. Start with a Fortran module fortmodule.f90 that prints “Hello from Fortran!” and assigns integer values to an array

! fortmodule.f90

module fortmodule

use iso_c_binding

implicit none

integer(C_INT), bind(C), dimension(5) :: numbers

contains

subroutine fortransub() bind(C)
   print *, "Hello from Fortran!"
   numbers(1) = 1
   numbers(2) = 2
   numbers(3) = 3
   numbers(4) = 4
   numbers(5) = 5
end subroutine

end module

 

2. Compile the Fortran module to a shared library:

gfortran -g -fPIC -c fortmodule.f90

3. Create a CPP file TestFortran.cpp which calls the Fortran module fortransub() subroutine and contains a Pybind reference (TestFortran).

// TestFortran.cpp
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <stdio.h>

extern "C" void fortransub();
extern "C" int numbers[5];

int makeMe()
{
   int i;
   printf("Hello from C!\n");
   fortransub();
   for (i=0; i<5; i=i+1)
      printf("%d ", numbers[i]);
   printf("\n");

return 0;
}


PYBIND11_MODULE(TestFortran, m) {
    
    m.def("makeMe", &makeMe, "Test fortran/C/python");
}

 

4. Compile the TestFortran.cpp code into a shared library linking the fortmodule.o library:

g++ -g -O3 -Wall -shared -std=c++11 -fPIC -I/usr/include/python3.7dm TestFortran.cpp fortmodule.o -lgfortran -o TestFortran$(python3.7dm-config --extension-suffix)

The output should be a shared library names similar to TestPython.cypthon-37dm-x86_64-linux-gnu.so.

5. Test the Python module.

Python Pybind Module C++/Fortran

6. Write a Python test wrapper test_fortran.py file.

import TestFortran
TestFortran.makeMe()

 

7. Start TotalView debugger to debug the Python / C++ / Fortran code:

$totalview -args python3-dbg test_fortran.py

8. Set a pending breakpoint on the makeMe() C++ function.

Set a Pending Breakpoint C++/Fortran

9. TotalView shows the C++ code when you press GO. Enable stack frame filtering by clicking on the orange filter button in the Call Stack window.

TotalView Call Stack Window C++/Fortran

10. Advance to the fortransub() function call on line 13 and Step into the function. TotalView shows the Fortran code and the Fortran stack frame.

TotalView Fortran Code

11. Select the Python module from the Call Stack TotalView displays the Python module.

TotalView Python Module

Further Reading

More details on Python debugging support can be found in the TotalView video tutorial below.

 

Debugging Your Mixed-Language Applications

Test TotalView and it's multi-language debugging capabilities with your application today.

Request a free trial