← Back to team overview

yade-users team mailing list archive

Re: Re : Triaxial Test

 

Bruno Chareyre said:     (by the date of Mon, 13 Feb 2006 16:33:28 +0100)

> Hello Janek
> 
> I've written new classes in order to 1) control the triaxial stress in a 
> box and 2) compute an accurate critical time-step.
> Point 1. is complete and has a dedicated FileGenerator ("TriaxialTest"). 
> Point 2. is not complete but I have almost everything in hands to do it 
> now :), it should arrive soon.

wow! I am truly amazed at how much work you did put into it! I will
gladly incorporate this to svn :) But before I start doing that I prefer
to wait till you will have the "final" version. As it will be much
easier for both of us, if there are less changes done at later time.

By "final" I mean following:

imagine that for example there is another yade release, you download it,
unpack, compile and run. And there lies your great shiny new plugin, you
just click it and run. And for most of the time you will use it - you
will not need to recompile yade (and this plugin) just to change one or
two lines inside the plugin, just because you need that something works
in a different way.


What I explained above is a so called OCP (Open-Closed Principle) - the
code is open for extension, but closed for modification. This is a
correct way to write software ;)

Of course under reasonable circumstances code has to be modified. This
rule guides us to try to minimize the amount of required changes in
possible fiture. Admit yourself, that less changes, means less work and
more pleasure ;)

You pick the class names. The classes are yours, you name them. Renaming
them later is very easy with the scripts I've written (scripts/renameClassFirst,
etc..). So if you change your mind - don't worry.


> While writing this classes, I have navigated a lot in Yade code, and I 
> have a lot of questions...
> I will only  write few of them now :
> 
> Some of them turn around debug options and debugging, they are not 100% 
> yade related :
> 1 - It is said in the "INSTALL" that option -g may be used to generate 
> debug symbols. However there are debug flags in all *.pro files (before 
> one uses the "make_release" script...). So what happens if I compile 
> with "debug" flags in pro files but without -g option?

without -g you get no debug information ;) there are two ways to get debug information:

1. if compiling from command line, then -g option decides
2. if compiling from inside kdevelop, then setDebug/setRelease scripts decide
 
> 2 - I was never able to really debug my code. The only way of debugging 
> I found was based on including lots of cerr << "something" in the code 
> to have an idea of what happened (I forgot to 
> DeusExMachina::registerAttributes in 
> ResultantForceEngine::registerAttributes, so subscribedBodies was 
> empty...). What do you use for debug? Kdevelop? gdb in command-line 
> mode? Do you know a link to a good debugging tutorial for 
> gcc/kdevelop/gdb/* ?

let me be honest at this one :)

1. I managed one or two times to debug from inside kdevelop, by clicking
buttons "next command" etc. That feature is there. From menu you choose
Debug->start. However, unfortunately kdevelop seems to be unable do
debug across separate plugin files, which is the case for yade. That's
exactly for what yade-flat directory appeared. I use it sometimes to
compile yade to one HUGE binary with all debug information inside (the
exacutable file is then about 200MB big).

You can validate that Debug->start works, by trying some other very
small program, like typical "hello world".

But then, even when kdevelop's built-in debugger works with yade, it
becomes hugely inconvenient. You start to spend hours clicking "next
command" button, placing breakpoints, etc. Just to accidentally click
one time too far. And the program crashes, and you need to start
clicking over and over again. Breakpoints of course help with that, but
not that much.

2. Not that much, because there is a way which I like better. Far better.

First of all, you need to compile yade with -g, with the debug
information. All the files will get much, much bigger.

then before you run yade from command line type this command:

ulimit -c unlimited
./yade

then do whatever you want inside yade, until it crashes. A new file
called core* will appear. Beware, that file will be huge. On each crash
a new core appears, because they are big, you can quickly run out of
disc space if you forget to delete them. Now type this:

gdb ./yade ./core.53414

(of course the name core.53414 will be different on each time, you can
pick the correct one, by looking at the date/time at which they were
created (command: ls -la )). Then gdb runs. It will load all the debug
information (it can take a while), when it finishes that, it will be
ready, so you can input a command. Type this:

bt

and now, you will see a backtrace. Backtrace of program crash. read it
carefully, and you will quickly understand if you compiled with -g. It
will be an unreadable gibberish if you compiled without -g.

That's all :)

3. Third method, is very useful, when there is an error which does not
lead to program crash. So you cannot get a "core" file. Just run:

valgrind ./yade

instead of just running ./yade. It will execute about 10x slower. But oh
well, better 10x times slower than an error inside ;) Alternatively you can run:

alleyoop ./yade

Both of them are in fact the same command. Just one displays a nice
graphical window, while other prints everything to terminal.

OK, so when you have started that, then yade is analyzed by valgrind.
Ultra powerful tool. It will spot every place where there is a chance to
get an error. And tell you about it. However one thing is very
unfortunate: nvidia graphic drivers have one place where an error is
possible, and valgrind starts to flood printing endless messages about
this place. I'm waiting till nvidia will fix their drivers.

It means that:

1. if you want to debug your FileGenerator with valgrind,
then do not open that graphical window which displays OpenGL graphics.
You will avoid flood of errors from nvidia's libglcore.
2. if you want to debug the actual calculation (which is displayed
inside OpenGL window), then you must use NullGUI instead, to run the
calculation inside valgrind.

I have succesfully employed both of those methods, and they are indeed
very good. Because valgrind prints for example this:

"file SomeNewClass.cpp:123, suspicius place"

it means that you should look into file SomeNewClass.cpp at line 123,
and consider if there is an error, or MOST LIKELY somewhere earlier
during the code execution is an error which remains hidden until this
line, where valgrind dicovers, that something went wrong before.

Unfortunately valgrind is unable to tell you where you made mistake. It
can only discover where that mistake resurfaces during program execution.

Every once and then I make sure that yade executes cleanly inside
valgrind with ZERO errors. This is an absolute prerequiste for making a
release.


4. Fourth method is putting std::cerr << "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. This method is as good as other two
methods above.


Which method you will pick, just depends on what kind of error you expect.


> Compilation :
> 
> 3 - I tried to compile a complete project (e.g. DEM-package) from 
> Kdevelop. It works! No problem with YADE_QMAKE_PATH as long as you don't 
> try to compile a sub-project. However, it results in compiled objects 
> that are 3 times bigger than those compiled with a "make 
> CXXFLAGS='-pthread -lpthread' " from the command line!! Do you know the 
> reason why? (debug symbols...?)

yep, exaclty. debug symbols ;) btw, YADE_QMAKE_PATH is not a thing I
like, it just turned out to be currently necessery. Maybe later I'll
find a way to avoid it.

 
> Optimisation :
> 
> 4 More generally, I would really appreciate having your point of view on 
> where I should start if I plan to get faster computations.

first of all - compiling without debug symbols, and with -O3 flag, leads
to maximum possible code optimization during compilation. But -O3 is not
everything ;) We should seek slow spots using kcachegrind, and think
about how to remove them ;)

there are however some C++ coding techniques leading to faster code,
some of them are so "basics" of C++ that I even forget that I'm using
them.

1. most important - use references:

bad:

void SomeClass::function(somethingBig s)
{ /*...*/ }

good:

void SomeClass::function(somethingBig& s)
{ /*...*/ }

beware however, that the sole purpose of reference is to NOT duplicate
data. So if you modify domethingBig inside your function, then it will
be also modified outside. But when you modify somethingBig which was
passed without '&' then it will NOT be modified outside of the function.

It is much faster. If somethingBig takes 10MB in memory, then
duplicating it takes a lot of time.

2. use const:

bad:

void SomeClass::function(something& s)
{ /*...*/ }

good:

void SomeClass::function(const something& s)
{ /*...*/ }

even better:

void SomeClass::function(const something& s) const
{ /*...*/ }

this works only when you do not modify the argument something& inside
function code. Second const, after function name, works only if you do
not modify the content of SomeClass (the way to workaround this is to
use the keyword 'mutable' - it simply nullifies 'const' for a chosen
variable).

Using 'const' can allow the compiler to make further optimisations in
the code to make it faster. And (more importantly in fact) makes
your C++ code easier to manage, are more compatibile with OCP principle,
and other programming priciples ;)

3. use prefix instead of postfix:

bad:

i++

good:

++i

sometimes this can make code considerably faster. I leave it up to you,
to discover why and when ;)

4. avoid declaring too much variables which are big in the memory. Their
initialization takes longer, than reusing some old variable of the same
type. But do not over-exaggerate with this rule. The code can become
dirty if you try to optimise in this aspect too much.

this rule is not about float, or int. It is about vector<shared_ptr<SomeClass> >;
initializing float or int costs almost nothing.

5. declare variables as references, if possible and makes sense. I'm
doing that in almost every place where I loop over Interactions or
Bodies. Just look there:

Body& b = something;

6. ok, I ran out of the ideas. But generally over the years I discovered
that more thoughtful programmming, paying more attention to correct
class design, and to discover underlying abstract do lead to faster code.

Sometimes I have to make one part much slower, because a new class
design requires this. I make this because I think that new design is
better, using those hard to define abstract criterions of good and bad
design. So I make it slower. And later I discover, that "wow! with that
change I can make some other part of the code much faster, becuase the
design became more flexible". So here the rule is, just to follow the
instinct and pursue clean clode.

So write clean, and you will get fast code as a reward.

7. and last, most important: DO NOT OPTIMIZE.

this one is very difficult to understand. Only absolute gurus know how
to do that (surely not me ;). The pun here, is that concious
optimisation leads to dirty, unportable, buggy and bad code.



if you got more questions, just ask :)

-- 
Janek Kozicki                                                         |
_______________________________________________
Yade-users mailing list
Yade-users@xxxxxxxxxxxxxxxx
http://lists.berlios.de/mailman/listinfo/yade-users



Follow ups

References