[ROOT] filling ROOT-Trees from realtime threads

From: Oliver Kuehlert (Oliver.Kuehlert@mpi-hd.mpg.de)
Date: Mon Nov 04 2002 - 23:27:41 MET


  Hello,

this is my first approach for accessing ROOT-Trees from RTLinux.
You can download it from here:
http://pluto.mpi-hd.mpg.de/lisbet/rtltree/rtltree.zip

I've included the README file as an attachement.

Please feel free to write any comments, corrections or questions to me.

Oliver Kuehlert

Oliver.Kuehlert@mpi-hd.mpg.de


REQUIREMENTS

You need an installed and running RTLinux. This version has been tested with
RTLinux-3.1. It may also run with RTAI, but I haven't tried yet.

You also need an installed and running version of ROOT. I've tried hard with 
3.03-9, but there seems to be a bug, so that Trees are not working very well. 
But 3.03-8 works fine with this package. 

I recommend compiling ROOT with thread support, so you can use the 
thread related classes of this package and analyse the tree while it is
filled from your RTLinux application.

During my tests ROOT was compiled for linuxdeb with thread support.


OVERVIEW

A RTLinux application running in Kernel-Space can't access ROOT-Trees in
UserSpace directly. The only interfaces between User- and Kernel-Space are 
FIFOs and shared memory. So one could set the Branch-Variable of a Tree in
shared memory, write data into it from Kernel-Space and fill the Tree from
User-Space. 
But this approach has a disadvantage: it is not predictable, when ROOT
gets time from the scheduler and can fill the tree. In some situations
RTLinux may write the data many times without ROOT having time to handle it.
So data is lost.

This package consists of two parts: 
1. A kernel module for RTLinux which provides a little API for Tree access.
   The commands and the corresponding data is written to a FIFO.

2. Some ROOT-classes which read the stream of commands and data, interpret
   it and finally execute the corresponding Tree functionality.

Please note that RTLinux applications will only write the data and commands
to a buffer. The real work is done with lowest priority by ROOT in User-Space!

how it works internally (an example)

void roottree_setbranch(char* tree,char *branch,void * data,int count);

calling this funtion from a rtlinux application will write the command
and the related data to the fifo. On the User-Space side ROOT will get
a pointer to the tree by calling TTree*t=file->Get(tree). By default file is 
the same as gFile. Now ROOT can get the branch by means of 
TBranch *b=t->GetBranch(). Finally b->GetAddress() is the address of the
branch variable. This variable is now set by copying the data to to it.
Since RTLinux doesn't know  the size of your Branch variable you have
to explicity tell it in the function. If you want to write to a Branch 
variable of the type TDaten, you can do so:

     struct TDaten data;
     ...
     roottree_setbranch("mytree","mybranch",&data,sizeof(struct TDaten));

Make sure, that TDaten is the same in User- and Kernel-Space. (and has the
same size)

other commands are:

void roottree_fill(char * tree);
perfoms a tree->Fill(); in User-Space

void roottree_write(char * tree);
accordingly a tree->Write();


A QUICK WALKTHROUGH

The ROOT-classes were designed for use in your own measurement aquisition
programs or daemons. But testing works fine from within the ROOT-Interpreter.
(But the ROOT-Interpreter #defines all private and protected tags to public.
So maybe the latest version may not be compiled from outside, since I always
want to be as strict as possible and maybe I've forgotten something. In this
case simply move the method/variable to public or protected and write a short
email to me please)

So, lets start with the RTLinux module.

1. Boot into your RTLinux Kernel and start the modules according to the manual
  (starting scripts by calling scripts/insrtl from within your RTLinux 
  Installation)

2. unzip this package and cd to rtltree/rtlinux. Copy rtl.mk from your
   RTLinux Installation to this directory.

3. compile the rtltree module:
   make -f rtl.mk rttree.o 

4. compile the test application
   make -f rtl.mk test.o

5. (as root) load the rtltree-module:
   insmod insmod rttree.o

Now, lets start the root-part

1. cd to rtltree/root

2. start root. you will get a lot of errors since to librarys used in
   rootlogon.C have not been compiled yet.

3. compile the classes with ACLiC:
   .L RTLTreeWatcher.C+
   .L RTLThreadTree.C+
   .L RTLThreadTreeWatcher.C+

4. quit ROOT and start it again. You should now see something like 
   "ROOT Watching on RTLinux". If you get the error 
   "Exception caught:Cannot open RTL-FIFO" make sure you have loaded the
   kernel module properly. Press return, you should be able to use ROOT as
   usual.

5. RTLinux can only access existing TTrees in a given file. This is
   gFile by default. So you have to create a TTree. There is a macro which
   creates a testing TFile and a TTree with a branch for the test.o 
   application. Start it with .x TreeTest.C.

6. The rtltree package can also handle ordinary TTrees. But if you want to have
   access to the TTress during data aquisition you need a locking mechanism,
   otherwise you will run into big trouble when the TTree is changed while you
   are accessing it. So there is an extension to TTrees which provides a
   lockin mechanism. You can get access to the RTLThreadTree by typing:
   RTLThreadTree *t=gFile->Get("mytree")

7. Try  t->Lock(); t->Scan(); t->UnLock()
   you will see an empty Tree. From the rtltree/rtlinux directory (as root)
   you can start the test application: insmod test.o (don't leave ROOT)
   Now try   t->Lock(); t->Scan(); t->UnLock() from within ROOT again 
   some times and you can see how the Tree is filled.
   You can stop the test by unloading the module: rmmod test
  
DETAILS ON THE KERNEL MODULE

RTLinux communicates with ROOT via a FIFO. By default, FIFO 0 is used. If
you use this number for your own needs, you can change the used number when 
loading the rttree module: insmod rttree.o roottree_fifo=xx 

Your RTLinux application writes data to the FIFO buffer. If you lock a 
RTLThreadTree in User-Space for a long time, the buffer may overrun. To
prevent this, you can set the buffer-size. The default is 4096 and 
quite small:   

insmod rttree.o roottree_fifo_size=8192

Look into rttree.h to see the quite small API.
The first 3 command will work with any combination of 
TTree, RTLThreadTree, RTLTreeWatcher and RTLThreadTreeWatcher in User-Space

The last two locking commands work only if you use RTLThreadTree and 
RTLThreadTreeWatcher. Please keep in mind, that no locking is performed
in Kernel-Space! Locking takes only place in User-Space! 

DETAILS ON THE ROOT CLASSES

The RTL...Watcher classes are reading the stream from the FIFO and doing
the real work. They both can handle TTrees. The main difference is that
RTLTreeWatcher doesnt't return when calling the watch() method. 
RTLThreadTreeWatcher instead starts a seperate thread which does the 
work and returns almost immediately. If you use RTLThreadTrees instead of 
TTrees the RTLThreadTreeWatcher can lock/unlock them if your RTLinux 
application demands this for a setbranch/fill sequence. If you do it in
your data analysis too, you can use the RTLThreadTree during it is filled
by RTLinux. But never access the Tree or make suggestion about the 
Branch-Variables, when it is unlocked!!! And don't lock it over long periods,
otherwise your buffer may overrun.

Let's take a short look on the constructor:

RTLTreeWatcher(char *fifo="/dev/rtf0",TFile *f=gFile);

In most cases, you can use the default values. If you used another
fifo when loading the kernel module, use the same here.

If you want a special TFile where your Trees should be accessed, mention
it here. 
If you call the constructor when gFile is still NULL, it won't matter.
But you have to be sure that it is not NULL when the first RTLinux command
arrives.
  
TODO

In this version the whole errorhandling is performed in User-Space. RTLinux
application will never know when something went wrong. This is, because
the commands must be performed in realtime. It could take a long time until
ROOT has time to do the real work and send back any errors. It is no good
idea to block a RTLinux Thread and wait for an answer from ROOT...
But an asynchrous callback mechanism may be possible. This will be done in the 
next version.

Creating Trees and Branches (and Branch Variables!!!) from within RTLinux
may also be desireable.

Oliver.Kuehlert@mpi-hd.mpg.de



This archive was generated by hypermail 2b29 : Sat Jan 04 2003 - 23:51:16 MET