From charlesreid1

This page explains how to run Cantera in debug mode via Python.

Creating a Cantera Debug Build

Before following this guide, you'll probably have to rebuild Cantera to include debugging symbols. See the Debugging Cantera page for instructions.

The Relation between Cantera and Python

Cantera is, at the core, a C++ library. When you download a copy of Cantera and build it, you are compiling C++ code into libraries of executable code. So, what does this have to do with Python?

Cantera has a Python interface - essentially, Python classes that are wrappers for the C++ interface. You have much of the same functionality with the Python and C++ libraries, but instead of a Cantera developer rewriting everything from C++ to Python (and probably making it run a lot slower in the process), the wrapper classes provide Python bindings for the underlying C++ code.

To run Cantera in debug mode through Python, what we'll do is run a Python driver, attach GDB to that process, and when Python calls the C++ library, GDB will follow the execution thread into the C++ library. At that point, GDB can halt, hit breakpoints, print stack traces, etc.

Running Cantera Through GDB and Python

Create Your Driver

Now that you have a debug build of Cantera, you'll need to create a driver, in Python, that uses the Cantera libraries. I'm going to issue a few simple commands. First I'll create a GRI Mech gas, then I'll equilibrate it. But I'll put a breakpoint in the equilibrate routine, to stop the code.

For this example, I'll use the following simple sequence of Python commands:

>>> from Cantera import *
>>> gas = GRI30()
>>> gas.set(T=320.0, P=OneAtm, X='CH4:1,O2:2,N2:7.52')
>>> gas.equilibrate('HP')

We will jump into the C++ core of Cantera, at the equilibrate() function, using gdb.

I'll need to attach GDB to the Python process in the midst of these commands. Order is very important here.

Using Cantera 1.8

Step 1: Import Python Module

The first step is to run

>>> from Cantera import *

This will load all of the Cantera libraries and hook them into Python.

Step 2: Determine Python PID, Attach GDB

The second step is to fire up GDB and attach it to the Python process. Do this by running ps, and determine the process id (pid) of the Python instance.

For example, if you see this:

$ ps

  PID TTY           TIME CMD
11832 ttys000    0:00.39 -bash
12071 ttys001    0:01.11 -bash
86612 ttys001    0:02.05 python

then your PID is 88612.

Fire up gdb, and run the attach command:

$ gdb
GNU gdb 6.3.50-20050815 (Apple version gdb-1515) (Sat Jan 15 08:33:48 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".

(gdb) attach 86612

Now you will see the reason for importing the module from Python before attaching gdb to the Python process: the import command loads the C++ libraries.

Running this attach command will spew a bunch of stuff about libraries and such, debug information not being available, unfound object files, etc. Don't worry. What's happening here is, gdb is loading every library that Python is using (including, now that you've executed from Cantera import *, every library that Cantera loads in).

A Note on Passing Control Between Python and GDB

When you attach gdb to the Python process, it will freeze the Python process and hand control over to gdb. When you issue the gdb command continue, it will hand control back over to Python. Note that control must be passed to Python to execute Python commands, and must be passed to gdb to execute gdb commands.

If Python has control of the program, and you want to give control to gdb, you can switch to your gdb window and use Control+C to stop execution. You can do this with an interactive Python shell because it is interactive, and always listening.

If you want to switch control from gdb back to Python, you can use gdb's continue command, which hands control of execution back to Python. Because Python is running as an interactive shell, Python returns to "listening" mode.

Step 3: Set Breakpoint

As mentioned, we'll be looking at a simple breakpoint example, specifically the equilibrate() command. First, we'll set the breakpoint in gdb:

(gdb) break equilibrate.cpp:44
Breakpoint 1 at 0x101099bd9: file equilibrate.cpp, line 44.

Note: the equilibrate class is located in /path/to/cantera/src/equil/equilibrate.cpp.

If you see something like this:

(gdb) break equilibrate.cpp:44
No source file named equilibrate.cpp.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (equilibrate.cpp:44) pending.

it means you didn't follow the instructions I gave at the top of the page! You have to create a debug build of Cantera.

Next, hand control back to Python:

(gdb) continue

Control has now been passed back to Python.

Step 4: Run Python Driver

Next step is to run the Python driver (the short set of commands listed above, which create a gas and equilibrate it).

>>> gas = GRI30()
>>> gas.set(T=320.0, P=OneAtm, X='CH4:1,O2:2,N2:7.52')
>>> gas.equilibrate('HP')

The Python process should hang, and when you switch over to gdb, you should see a message about the breakpoint you have reached:

(gdb) continue
Continuing.

Breakpoint 2, Cantera::equilibrate (s=@0x101f29130, XY=0x101b8a4b4 "HP", tol=1.0000000000000001e-09, maxsteps=1000, maxiter=100, loglevel=-1) at equilibrate.cpp:44
44	    if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) {
(gdb)
Continuing.
Current language:  auto; currently c++

Voila! From here you can get a backtrace, step through code, etc etc etc.


Cantera 2.0

Step 1: Import Python Module

Step 2: Determine Python PID, Attach GDB

Step 3: Set Breakpoint

Step 4: Run Python Driver