wiki:Old/Documentation/OTG/DebugNote

Orbit > OTG > Debug Notes

Steps to debugging OTG on Sandbox without collection server support

  1. install libstdc++6 library in the nodes, which is compatiable with the setting in internal4.
    apt-get update
    apt-get -o APT::Force-LoopBreak=true install libstdc++6
    
  2. If there is no /usr/local/lib/oml2 directory in the node, copy all the files under internal4:/usr/local/lib/oml2/ to the /usr/local/lib/oml2 of the grid nodes.
  3. copy "otg-oml-sample.xml" into sender and set LD_LIBRARY_PATH
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./:/usr/local/lib:/usr/local/lib/oml2
    
  4. OML_CONFIG,OML_NAME can be set by export OML_CONFIG="./otg-oml-sample.xml" and export OML_NAME="Node-1" or in otg command line. For example:
    ./otg --dsthostname=internal2 --protocol=udp --oml-name "foo" --oml-config "../etc/otg-oml-sample.xml"
    
  5. Similarly, copy and set "otr-oml-sample.xml" in receiving node
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./:/usr/local/lib:/usr/local/lib/oml2
    export OML_CONFIG="./otr-oml-sample.xml"
    export OML_NAME="Node-2"
    

The last two "export" commands can also be done in command line as shown before.

Handling "non-virtual destructor" warning message with Gcc 4.0

By default, if destructor is not specified, its non-virtual, but for every class derived from a virutal base class, the destructor have to be virtual.

In particular, here's when you need to make your destructor virtual:

  • if someone will derive from your class,
  • and if someone will say new Derived, where Derived is derived from your class,
  • and if someone will say delete p, where the actual object's type is Derived but the pointer p's type is your class.

Confused? Here's a simplified rule of thumb that usually protects you and usually doesn't cost you anything: make your destructor virtual if your class has any virtual functions. Rationale:

  • that usually protects you because most base classes have at least one virtual function.
  • that usually doesn't cost you anything because there is no added per-object space-cost for the second or subsequent virtual in your class. In other words, you've already paid all the per-object space-cost that you'll ever pay once you add the first virtual function, so the virtual destructor doesn't add any additional per-object space cost. (Everything in this bullet is theoretically compiler-specific, but in practice it will be valid on almost all compilers.)

Note: if your base class has a virtual destructor, then your destructor is automatically virtual. You might need an explicit destructor for other reasons, but there's no need to redeclare a destructor simply to make sure it is virtual. No matter whether you declare it with the virtual keyword, declare it without the virtual keyword, or don't declare it at all, it's still virtual.

Fix is easy: Just add virtual destructor in base class:

public:
virtual ~Foo(){}

Using the external "C" Linkage Specification

calling C functions (LIBMAC) in C++ code (OTG),Solution is :

extern "C" {
#include <libmac/libmac.h>
}

To handle overloaded function names the HP C++ compiler generates new, unique names for all functions declared in a C++ program. To do so, the compiler uses a function-name encoding scheme that is implementation dependent. A linkage directive tells the compiler to inhibit this default encoding of a function name for a particular function.

If you want to call a C function from a C++ program, you must tell the compiler not to use its usual encoding scheme when you declare the C function. In other words, you must tell the compiler not to generate a new name for the function. If you don't turn off the usual encoding scheme, the function name declared in your C++ program won't match the function name in your C module defining the function. If the names don't match, the linker cannot resolve them. To avoid these linkage problems, use a linkage directive when you declare the C function in the C++ program.

Make OTG Software without working client_wrapper libraries

First, get a source package of otg in the node. then prepare additional files. Use w-get to fetch .h .cpp and .a files. As those lib files (.a) cannot be used for some reason, we need manually build them in the node.

  cd otg/src/cpp
  make otg;make otr; make otf
  cp ../../build/include/* ./
  cp ../../build/src/* ./

Get new OML client libraries

scp zhibinwu@external1:tmp/oml_libraries/* /usr/local/lib/oml2

Get oml header files

mkdir oml
scp zhibinwu@external1:tmp/oml/* ./

After this, see

node1-1:~/otg/src/cpp/oml# ls
Metric.h  MetricAggregator.h  OmlContext.h  OmlFilter.h  OmlQueueItem.h  oml.h  oml_def.h  oml_tx.h

Change Makefile
adding new include

         CFLAGS  = -g -Wall -I$(INC_DIR)  -I. -Iauto -I/usr/local/include/scew -Ioml/

adding new sourcecode files

OTG_SRCS = ....
    ...orbit_winlab_otg.cpp
...
...

remove the -l$(OT?_OML_LIB) in each target see:
change from

$(CC) -o $@ $(OTG_OBJS) $(LDFLAGS) $(LIBS) -l$(OTG_OML_LIB)

to

$(CC) -o $@ $(OTG_OBJS) $(LDFLAGS) $(LIBS)

At last,

make clean
make

Another way to use nodehandler

cd tmp
svn co http://svn.orbit-lab.org/svn/orbit/nodeHandler/trunk nodehandler
cd ~/tmp/nodehandler/src/ruby
ruby handler/nodeHandler.rb ~/rate_loop_exp

And the nodehandler will use the otg definition files (otg.rb) in this tmp/nodehandler/src/repository directory

Atheros Driver's Rate Control

AutoRate (SampleRate)

This is the default behavior:

In ath_rate_findrate function of ath_rate/sample/sample.c

   if (sn->static_rate_ndx != -1) {
                ndx = sn->static_rate_ndx;
                *try0 = ATH_TXMAXTRY;
        } else {
                *try0 = mrr ? 2 : ATH_TXMAXTRY;
   ...

Here , try0 means how many transmission attempts should be used for the first-rate-setting. The above code means, if static rate is used, each packet will be retransmit ATH_TXMAXTRY-1 times. But if Mrr/SampleRate is used, the packet will be tried in r0 rate only 2 times. if unsuccessful, r1, r2, r3,.. will be tried. in 3,3,0 times respecitively.

The codes can be found in ath_rate_setupxtxdesc function of sample.c

... 
    ath_hal_setupxtxdesc(sc->sc_ah, ds
                             , rateCode, 3              /* series 1 */
                             , sn->rates[0].rateCode, 3 /* series 2 */
                             , 0, 0                     /* series 3 */
                             );
...

Static Rate

In ath/if_athvar.h

#define ATH_TXMAXTRY    11   

So, when it is set to fix rate, each packet will be transmit at this rate 11 times.

Wrapping Linux Threads in C++ classes

Refer to Root software:

esting the root TThread class, we made some experiences running a class member function as a (Linux-)pthread, which might help you.

Since pthread_create (and also the TThread constructor) expects a C function to be run, it needs the pointer to the class instance as function argument (4th argument of pthread_create), if you want to run a member function of this C++ class. When C++ methods are called from within a class, internally the class instance pointer ("this") is always passed as invisible first argument. Thus the "C" call of any C++ member function by pointer requires the class object address as first argument…

For example, in root TThread class, the implementation for pthreads (THREAD_PosixThread.cxx) starts the member function void* TThread::Fun (which calls your own function passed to the TThread constructor) as pthread with the pointer to the TThread instance TThread* th as argument:

int ierr = pthread_create(&id, attr, &TThread::Fun,th);

(in method TPosixThread::Run(TThread* th))

Additionally, if you want to run a member void myfunction of any class Myclass as TThread, you also have to pass the address to the class as function argument of TThread constructor, since TThread::Fun uses a C function call to invoke your function:

 TThread* mythread= new TThread("My Thread",
         (void(*) (void *)) &Myclass::myfunction,
         (void*) &Myclass);
  mythread->Run();

when you create TThread from within class Myclass, you may write

TThread* mythread= new TThread("My Thread",
         (void(*) (void *)) &myfunction,
         (void*) this);
  mythread->Run();

The required cast of &myfunction produced a compiler warning in our tests (egcs-2.91.66 Debian GNU/Linux (egcs-1.1.2 release)); however, the example was compiled and runs.

And please don't mix a ptr-to-function and a ptr-to-member-function. The former is just the address of a function. The later is a structure containing

  • the function address for non-virtual functions
  • the vtable index for virtual functions
  • the this pointer offset

The representation of the structure is implementation specific, and does for some compilers even depend on whether the class has virtual functions or multiple inheritance or not.

All this is needed to calculate

  • the actual entry point address
  • and the effective this pointer

when the ptr-to-member-function is finally used in a call. In cases like multiple inherited base classes with virtual functions in virtual base classes things get nontrivial here!

Inspect the C++ lanuage definition for the allowed conversions and casts of a ptr-to-member-function, and you'll see, there are very few.

In the light of all this I wonder portable Joern's code example is.

Beyond that, the code

 TThread* mythread= new TThread("My Thread",
         (void(*) (void *)) &Myclass::myfunction,
         (void*) &Myclass);

will probably not give the desired result if Myclass uses multiple inheritance and myfunction is from one of the base classes (that's why the PTMF struct may contain a this offset).

And

Pthread standard allows only simple C function.

TThread::Fun is static member of a class. A static member function == C function. So it will work with all compilers/platforms. I introduced static member function TThread::Fun and not simple C function only do not pollute the name space.

But you still can use nonstatic virtual member function in Pthread.

For example you want to call virtual finction void A::F() By C++ rules you mas provide 2 pointers:

 A* p  - pointer to class instance
 void (A::*f)()  - pointer to function

Then you calculate pointer

 f = &A::F;

User function for Pthread

user(void* adr)
{
  A inst;
  (A::*f)() = ((A::*)())adr;
  (inst.*f)();
}

In the example instance of A:: created inside of function. But it is easy to pass this pointer via intermediate object which keeps both poiners, to instance and to function. Pointer to this object passed by adr uf user routine.

So, there is no any limitation in THread::

Last modified 17 years ago Last modified on Nov 14, 2006, 9:26:09 PM
Note: See TracWiki for help on using the wiki.