Difference between revisions of "HowTo debugging"

From OpenFOAMWiki
(Starting to add information about built-in debug feedback. Will continue editing the sub-section in the next step...)
(Getting built-in feedback from OpenFOAM: "Looking at the source code" complete)
Line 92: Line 92:
  
 
=== Getting built-in feedback from OpenFOAM ===
 
=== Getting built-in feedback from OpenFOAM ===
OpenFOAM provides a built-in feature for providing debug output on-demand. For example, check the source code for {{tt|polyMesh.C}} (see online [https://github.com/OpenFOAM/OpenFOAM-2.1.x/blob/master/src/OpenFOAM/meshes/polyMesh/polyMesh.C {{tt|OpenFOAM-2.1.x/src/OpenFOAM/meshes/polyMesh/polyMesh.C}} at Github]):
+
OpenFOAM provides a built-in feature for providing debug output on-demand. This sub-section will detail how and where these options can be found and subsequently used.
TODO
+
  
 +
==== Looking at the source code ====
 +
For example, check the source code for {{tt|polyMesh.C}} (see online [https://github.com/OpenFOAM/OpenFOAM-2.1.x/blob/master/src/OpenFOAM/meshes/polyMesh/polyMesh.C {{tt|OpenFOAM-2.1.x/src/OpenFOAM/meshes/polyMesh/polyMesh.C}} at Github]), where the following ''code snippets'' can be found:
 +
<ol>
 +
<li>Near the top, you'll find this piece of code:
 +
<cpp>defineTypeNameAndDebug(Foam::polyMesh, 0);</cpp>
 +
It defines that this class {{tt|Foam::polyMesh}} should have the type name {{tt|"Foam::polyMesh"}} associated to the class and that it should start by default with the debug flag at {{tt|0}}.
 +
</li>
 +
<li>At around the line #866 you'll find this piece of code:
 +
<cpp>        if (debug)
 +
        {
 +
            WarningIn("const labelList& polyMesh::tetBasePtIs() const")
 +
                << "Tet base point indices not available. "
 +
                << "Forcing storage of base points."
 +
                << endl;
 +
        }</cpp>
 +
Notice the variable {{tt|debug}}? This variable is the one that was implicitly initialized in the previous code block. Whenever {{tt|debug}} is set to a value different than 0, it will trigger this if block and therefore issue this warning. Said warning will appear while an OpenFOAM solver or utility executed and only if there is a reason for this warning, as indicated in the line #864:
 +
<cpp>if (tetBasePtIsPtr_.empty())</cpp></li>
 +
<li>Wondering where the macro {{tt|defineTypeNameAndDebug}} is defined in the first place? It is defined in the file {{tt|src/OpenFOAM/db/typeInfo/className.H}} (see online [https://github.com/OpenFOAM/OpenFOAM-2.1.x/blob/master/src/OpenFOAM/db/typeInfo/className.H {{tt|OpenFOAM-2.1.x/src/OpenFOAM/db/typeInfo/className.H}} at Github])</li>
 +
</ol>
 +
 +
==== Where to turn ''on'' the built-in flags ====
 +
TODO
 
[[Category:Develop]]
 
[[Category:Develop]]

Revision as of 12:29, 6 April 2013

1 Motivation

If your application crashes it will usually output a stack trace, e.g.

#0 Foam::error::printStack(Foam::-Ostream&) in "/home/ivan/OpenFOAM/OpenFOAM-1.4.1/lib/linuxGccDPOpt/libOpenFOAM.so"
#1 Foam::sigFpe::sigFpeHandler(int) in "/home/ivan/OpenFOAM/OpenFOAM-1.4.1/lib/linuxGccDPOpt/libOpenFOAM.so"
#2 Uninterpreted: [0xb7f8b420]
#3 Foam::divide(Foam::Field<double>&, Foam::UList<double> const&, Foam::UList<double> const&) in "/home/ivan/OpenFOAM/OpenFOAM-1.4.1/lib/linuxGccDPOpt/libOpenFOAM.so"
#4 void Foam::divide<foam::fvpatchfield,>(Foam::GeometricField<double,>&, Foam::GeometricField<double,> const&, Foam::GeometricField<double,> const&) in "/home/ivan/OpenFOAM/OpenFOAM-1.4.1/lib/linuxGccDPOpt/libincompressibleTurbulenceModels.so"
#5 Foam::tmp<foam::geometricfield<double,> > Foam::operator/<foam::fvpatchfield,>(Foam::tmp<foam::geometricfield<double,> > const&, Foam::GeometricField<double,> const&) in "/home/ivan/OpenFOAM/OpenFOAM-1.4.1/lib/linuxGccDPOpt/libincompressibleTurbulenceModels.so"
#6 Foam::turbulenceModels::kEpsilon::correct() in "/home/ivan/OpenFOAM/OpenFOAM-1.4.1/lib/linuxGccDPOpt/libincompressibleTurbulenceModels.so"

There is lots of interesting information in there. It shows the type of error (sigFpe which means a division by zero or any other operation causing an invalid floating point number) and who caused it (operator/ of an fvPatchField). Further down is the origin, kEpsilon::correct(), which obviously does some divisions. A good guess is that one of the patch fields of k or epsilon is 0.

From experience sigfpe originate from three sources:

  • as above - division by 0 from having an initial field set to 0.
  • when using floatTransfer = 1. This will truncate doubles into floats before doing parallel transfer so if the double does not fit it will produce a sigfpe. Check the traceback for a call to 'compressedSend'.
  • when using FOAM_SETNAN (initialises allocated memory to NaN) and accessing uninitialised memory.

The other common error is a segmentation violation (sigSegv) which is caused by an application accessing memory outside the allocated space. These are nearly always caused by a programming error.

2 FULLDEBUG - libraries

To enable the most thorough level of debugging, you'll have to recompile OpenFOAM with the debug switch enabled. To do so, set WM_COMPILE_OPTION=Debug. To go back to a normal build, set WM_COMPILE_OPTION to 'Opt'. You can set WM_COMPILE_OPTION in the bashrc file of OpenFOAM, or temporarily using 'export WM_COMPILE_OPTION=Debug', which will only last for the life of the current terminal session. Keep in mind that though very useful, a full debug build will double up the hard disk space that OpenFOAM needs and run much slower.

3 Top-Level debugging

If you want to find out more but not create a complete debugging build.

  • Find out from the printed stack trace which files contain the functions that crash. Copy these into your local directory.
  • Add the files to your Make/files
  • in Make/options, add
 -DFULLDEBUG -g -O0

to EXE_INC and recompile. The FULLDEBUG-flag causes amongst others full range checking on Lists.

In order to go step by step through the sources of the full debug objects, you'll need a debugger.

4 Tools

4.1 Serial debuggers

4.1.1 gdb

Can be invoked on the command line like

gdb xxxFoam

4.1.2 nemiver

Is a nice GTK+ based GUI frontend for gdb. Your solver can be launched like

nemiver xxxFoam <FoamOptions>

4.1.3 ddd

Is another more complex frontend for gbd. You can launch your solver with the following command

ddd --args xxxFoam <FoamOptions>

4.1.4 Limitations

gdb seems to have problems to step into expressions like

return autoPtr<basicThermo>(cstrIter()(mesh));

4.2 Parallel debuggers

4.2.1 mpirunDebug

Is a bash script which can start each process of the parallel run in an extra gdb session. This script can easily extended to start a gdb frontend for each process (download patched mpirunDebug file). Once this is done you'll get a separate GUI instance for each process, where you can set breakpoints etc. separately. This behaviour is similar to Totalview. Maybe one can utilise the session features from the GUI's in order to remember e.g. breakpoints.

mpirunDebug -np 2 xxxFoam -parallel

4.2.2 Eclipse PTP

Eclipse PTP - Parallel Tools Platform [1] is an open-source platform that provides a highly integrated environment specifically designed for parallel application development. In parallel it provides and manages a graphical user interface to a number of serial gdb processes.

4.2.3 Totalview

Totalview is a commercial debugger with many features. It can debug your application in parallel out of the box.

5 Additional Info

5.1 Manual Assistance for Breakpoints

Sometimes it might be helpful to set an endless loop somewhere into solver, and change the variable inside the debugger after launching. This is similar, but less nice, to setting a breakpoint.

int myi = 0;
while (0 == myi)
    Foam::sleep(5);

5.2 Getting built-in feedback from OpenFOAM

OpenFOAM provides a built-in feature for providing debug output on-demand. This sub-section will detail how and where these options can be found and subsequently used.

5.2.1 Looking at the source code

For example, check the source code for polyMesh.C (see online OpenFOAM-2.1.x/src/OpenFOAM/meshes/polyMesh/polyMesh.C at Github), where the following code snippets can be found:

  1. Near the top, you'll find this piece of code:
    defineTypeNameAndDebug(Foam::polyMesh, 0);

    It defines that this class Foam::polyMesh should have the type name "Foam::polyMesh" associated to the class and that it should start by default with the debug flag at 0.

  2. At around the line #866 you'll find this piece of code:
            if (debug)
            {
                WarningIn("const labelList& polyMesh::tetBasePtIs() const")
                    << "Tet base point indices not available. "
                    << "Forcing storage of base points."
                    << endl;
            }

    Notice the variable debug? This variable is the one that was implicitly initialized in the previous code block. Whenever debug is set to a value different than 0, it will trigger this if block and therefore issue this warning. Said warning will appear while an OpenFOAM solver or utility executed and only if there is a reason for this warning, as indicated in the line #864:

    if (tetBasePtIsPtr_.empty())
  3. Wondering where the macro defineTypeNameAndDebug is defined in the first place? It is defined in the file src/OpenFOAM/db/typeInfo/className.H (see online OpenFOAM-2.1.x/src/OpenFOAM/db/typeInfo/className.H at Github)

5.2.2 Where to turn on the built-in flags

TODO