Introduction to debugging

From Yade

To debug the code we recommend using:

Compile with debug information

Before doing any debugging you must make sure that yade is compiled with debug information (check installation instructions)

When yade is compiled with debug information all its files will be much bigger (like 50 times bigger) than without debug info, resulting in around 100MB in total.

Debugging with iostream

A very simple method is putting

std::cerr << "x= " << x << "\n";

here and there. And in fact I like this method more than kdevelop's builtin debugger, because this method encourages thinking. While built-in debugger does not. You just click, and forget to think.

Debugging with Data Display Debugger

DDD, the Data Display Debugger allows not only to display the values of debugged variables, but also to plot them using interactive graphical data display, where data structures are displayed as graphs. Just take a look at the screenshots on the bottom of ddd's webpage. To use it, simply run:

ddd ./yade

DDD may be an interesting option when debuuging the code. A very nice feature is that it allows to undo last debugging action.

Debugging

Type casts

Use macros YADE_CAST (and YADE_PTR_CAST), they expand to static_cast (static_ptr_cast) in optimized build and to dynamic_cast (dynamic_ptr_cast) in debug build. Dynamic casts are slower, but they will throw if the conversion is invalid. Static cast are fast, but may make debugging very difficult.

  • Use standard static_cast where you are sure that the cast is valid.
  • use standard dynamic_cast if you need to make decisions based on the result of conversion.

In debug build, yade will run debugger if there are "segmentation fault" (SEGV) or abort (ABRT, e.g. from failed assertion) signals. It will show you backtrace of all thread, which makes it possible to identify quickly the place where something went wrong. Therefore: in debug mode, always run yade from console. It shows valuable information.

Logging

To avoid using things like cerr<<"a="<<a<<endl; use macros LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN and LOG_FATAL. You can filter messages of severity of your choice, redirect messages to a file etc.

  1. #include<yade/base/Logging.hpp>
  2. In your class declaration (in the header file), say DECLARE_LOGGER;. It will create logger member for your class.
  3. In your implementation file, say (at the top level): CREATE_LOGGER(myPlugin1), where muPlugin1 is the class for which you declared the logger.
  4. The logger will be called "yade.myPlugin1" and you will be able to filter messages from this logger.
  5. LOG_* macros expand to stream, therefore you can say LOG_WARN("Distance is negative ("<<distance"<<), resetting to zero.");

(This will work fully only if you compile with log4cxx (default), but will still work somewhat if you dont: TRACE and DEBUG messages will be discarded and all other will be written to standard error.)