Introduction to debugging
From Yade
To debug the code we recommend using:
- kdevelop
- valgrind (also with alleyoop)
- kcachegrind (requries callgrind tool from valgrind to run)
- ddd, gdb
- kompare, kdiff3
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.
#include<yade/base/Logging.hpp>
- In your class declaration (in the header file), say
DECLARE_LOGGER;
. It will create logger member for your class. - In your implementation file, say (at the top level):
CREATE_LOGGER(myPlugin1)
, wheremuPlugin1
is the class for which you declared the logger. - The logger will be called "yade.myPlugin1" and you will be able to filter messages from this logger.
LOG_*
macros expand to stream, therefore you can sayLOG_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.)