[ROOT] RE:Re: loop function

From: Masaharu Goto (MXJ02154@nifty.ne.jp)
Date: Fri Dec 15 2000 - 10:57:25 MET


Hello Rene,

I understand. G__CallFunc is too cumbersome. In that case,
I recommend using template function and predicate. This technique
is used in STL generic algorithm. The concept Renard wants to 
achieve is similar to that of generic algorithm.  This will
provide a reasonable solution.  Please examine following code.
If you want to know more about this technique, please refer to
books about STL.

Good things about this solution  are
 - cint can bytecode most of the execution. 
 - flexibility for adding arguments to predicate object
 - used in STL C++ standard library. So the concept is standard

Drawback is
 - You need to learn concept of template and generic algorithm 
   which is a little complex.

Thank you
Masaharu Goto


// A frame method
template<class Action>
void frameMethod(Action& f,int n)
{
  for(int i=0;i<n;i++) {
    f(i);
  }
}

// a class with operator() to be used as predicate of the frameMethod
// This first example is the simplest one. You just have operator()
class Print {
 public:
  void operator()(int a) { printf("print %d\n",a); }
};

// a class with operator() to be used as predicate of the frameMethod
// Second example, you can give an argument. This will give you extra
// flexibility
class Add {
  int c; // argument buffer
 public:
  Add(int x=0) { c=x; } // initialization of the argument
  void operator()(int a) { printf("add %d\n",a+c); }
};


// main routine
int main() {
  for(int i=0;i<2;i++) {
    frameMethod(Print(),2); //give Print object as a predicate
  }
  for(int i=0;i<2;i++) {
    frameMethod(Add(1),2); //give Add object with an argument as predicate
  }
}




>
>Hi Masa,
>The solution via G__CallFunc is OK for system developpers, but not
>for the end user. It would be good if you could find a solution to this
>problem. 
>
>Rene
>
>
>Masaharu Goto wrote:
>> 
>> Hello Renard,
>> 
>> The reason of pointer to function being slow in the interpreter
>> is because Cint handles pointer to interpreted function and
>> compiled functions in the same context.  When Cint gets pointer
>> to function, it searches through both interpreted and compiled
>> function table. And bytecode compilation is voided. So, speed
>> penalty is 2 fold, for not using bytecode and searching function
>> table.
>> 
>> I understand what you want to do. For this purpose there is
>> G__CallFunc utility class.  This class must be used in an compiled
>> code, so you need to precompile readPreanRootSkeleton(). G__CallFunc
>> is documented in $CINTSYSDIR/doc/ref.txt
>> 
>> Thank you
>> Masaharu Goto
>> 
>> >Date: Tue, 12 Dec 2000 16:32:35 +0100
>> >From: "F. Renard" <frenard@cea.fr>
>> >To: rootdev@pcroot.cern.ch
>> >Subject: loop function
>> >
>> >Hello Root team,
>> >intro : i want to loop on events in a root ntuple to produce histos in
>> >an interactive way
>> >(with macros in a interactive root session). I used the example and
>> >evrything works fine.
>> >But i don't want to copy-paste the common part of initializing and
>> >looping over events
>> >in every new macro. So i tried (and succeed) to make a common fonction
>> >which calls a user function
>> >
>> >It looks like this :
>> >/************************************************************************/
>> >
>> >void readPreanRootSkeleton(TTree *t1, void (*userFunc)(), int nEvent)
>> >/************************************************************************/
>> >
>> >{
>> >   Int_t nevent = t1->GetEntries();
>> >   cout<<"Il y a "<<nevent<<" evenements"<<endl;
>> >   Int_t nbb = 0;
>> >   if (userFunc == 0)   { cout << "!! userFunc=0 !! Rien a
>> >faire"<<endl;}
>> >
>> >   if (nEvent > 0)   { nevent = nevent > nEvent ? nEvent : nevent;}
>> >   cout<<"Je traite "<<nevent<<" evenements" << endl ;
>> >
>> >   for (Int_t i=0;i<nevent;i++)
>> >   {
>> >      nbb += t1->GetEvent(i);  //read complete event in memory
>> >
>> >      (*userFunc)();
>> >   }
>> >}
>> >
>> >This part is located in a macro file common to every user macros
>> >
>> >Then  i can write a simple macro :
>> >int macro()
>> >{
>> >    // do initialization
>> >    // .......
>> >
>> >    // event loop
>> >    readPreanRootSkeleton(tree, &(myFunc), 0);
>> >}
>> >
>> >void myFunc()
>> >{
>> >    // operations on event to fill histograms...
>> >}
>> >
>> >I find this an elegant way because the loop function
>> >readPreanRootSkeleton(...) is
>> >common to every user of the ntuple, and this allow writing macros in a
>> >very light way.
>> >The most important point is to use a pointer to a function which allows
>> >for flexibility.
>> >
>> >First Question
>> >Why is this so slow ? I compared with the same macros, changing only the
>> >pointer function call
>> >ォ (*userFunc)(); サ
>> >to the real name
>> >myFunc();
>> >and the time spent was largely reduced
>> >I wasn't expecting this because in principle the only difference is the
>> >need for dereferencing
>> >the pointer
>> >Can you help me improving this loop function performances ?
>> >
>> >Second Question
>> >I tried then to first make a shared library from the common parts
>> >ォreadPreanRootSkeleton()サ
>> >I used your example to generate the dictionnary... and everything works
>> >fine.
>> >But when i call the function in root, with a pointer to myFunc() which
>> >is still loaded from a macro, i get :
>> >
>> >Limitation: Precompiled function can not get pointer to interpreted
>> >function as argument FILE:ana1212.cxx LINE:67
>> >
>> >So i cannot use this loop function in a shared library loaded in root. I
>> >am surprised  because other functions in ROOT
>> >are allowed to use pointers to interactively defined functions. For
>> >example :
>> >http://root.cern.ch/root/htmldoc/TFitter.html#TFitter:SetFCN
>> >which as a prototype
>> > void SetFCN(void *fcn)
>> >
>> >Is there a way to have root accept these king of argument in my function
>> >?
>> >
>> >Thank you
>> >
>> >FRenard
>> >
>> >PS:
>> >if you need extra info or listings, please ask me
>> >



This archive was generated by hypermail 2b29 : Tue Jan 02 2001 - 11:50:39 MET