TTree sent via TSocket and analysed with TSelector

Dear rooters,

I am trying to write a small server and a small client. The first one fill and send few events of a TTree
to the second one which analyse them with a TSelector (which has be created already for analysing TTree in ROOT files).

The server/client part seems to work (I simply use TSocket::Send/Recv).
The problem comes with the analysis : since I want to analyse the data “on the fly” my TSelector process can not be run via TTree::Process because the Begin/Init and Terminate should be call only once.
I then run the process “by hand” : see the minimal example below. I copied the code on TTree::Process and simplified it.

 void test_client(){
  TSocket *sock = new TSocket("localhost", 9090);Char_t filename[512];
  sock->Recv(filename, 512);
  Bool_t kToInit = kTRUE; 
  TSelector *selector = TSelector::GetSelector("macros/ttree_analysis.C+O");
  selector->SetOption("Bin=100,Erel,1n,PID1,noout");
   TTree *tree ;
  TMemFile *fin = new TMemFile(filename,"new");
  while(1){
    TMessage *mess = new TMessage();
     if(sock->Recv(mess)){
      if(!mess) break;
      if(!mess->GetClass()) break;
       if(mess->GetClass()->InheritsFrom(TTree::Class())) {
	fin->cd();	
	TTree *tree_server = (TTree*) mess->ReadObject(mess->GetClass());
	tree_server->Write("",TObject::kOverwrite);
 	tree = (TTree*)fin->Get("C");
	tree->SetNotify(selector);
 	if(kToInit) {
	  selector->Begin(tree);
	  kToInit = kFALSE;
	}
	selector->Init(tree);
	selector->Notify();
	TTreeCache *tpf = 0;	tree->SetCacheSize(tree->GetCacheSize());
	tpf = (TTreeCache*)fin->GetCacheRead(tree);
	if (tpf) tpf->SetEntryRange(0,tree->GetEntries());
	for (int entry=0;entry<tree->GetEntries();entry++) {
	  tree->LoadTree(entry);
	  selector->Process(entry);
	}
 	if (tpf) tpf->SetEntryRange(0,0);
     }
     delete mess;
   }
 }
  selector->Terminate(); 
 fin->Close();
 }

This code is doing the job in creating histograms, analysing the TTree and saving them.
The problem is that the memory used quickly explodes, which is not the case while analysing the tree from a normal file. What I am doing wrong and which memory I forgot to free ?

Best regards
Julien

PS : A priori a need to use a TMemfile because my TSelector is calling the GetCurrentFile, but this can be worked out if necessary

Hi,

I do not understand the part[code] TTree tree_server = (TTree) mess->ReadObject(mess->GetClass());
tree_server->Write("",TObject::kOverwrite);

        tree = (TTree*)fin->Get("C");

[/code]Why not use tree_server directly?

Either way, neither tree_server nor tree are deleted and thus you (seem to) get a two new tree at each iteration. In addition, the TMemFile is never ‘reset’ and thus also grows linearly with the number of trees (via 'tree_server->Write).

Cheers,
Philippe

Dear Philippe,

Thank you for your answer.

This was my feeling before writing this post. I did try a few delete and reset which did not change much things. I did not though that mess->ReadObject(mess->GetClass()); was not replacing the previous TTree.
Now that I have deleted everything necessary, the result is better. Below the new code : I believe several lines are overkill but it does the job. It did also correct the sloppy double call the TTree within TMemfile (historical).

  TSocket *sock = new TSocket("localhost", 9090);
  Char_t filename[512];
  sock->Recv(filename, 512);
  Bool_t kToInit = kTRUE; 
  TSelector *selector = TSelector::GetSelector("macros/ttree_analysis.C+O");
  selector->SetOption("Bin=100,Erel,1n,PID1,noout");
  while(1){
    TMessage *mess = new TMessage(kMESS_OBJECT); 
    if(sock->Recv(mess)){
      if(!mess) break;
      if(!mess->GetClass()) break;
      if (mess->GetClass()->InheritsFrom(TTree::Class())) {
	TMemFile *fin = new TMemFile(filename,"new");
	fin->cd();	
	TTree *tree = (TTree*) mess->ReadObject(mess->GetClass());
	tree->SetDirectory(fin);
	tree = (TTree*)fin->Get("C");
	tree->SetNotify(selector);
	if(kToInit) {
	  selector->Begin(tree);
	  kToInit = kFALSE;
	}
	selector->Init(tree);
	selector->Notify();
	for (int entry=0;entry<tree->GetEntries();entry++) {
	  tree->LoadTree(entry);
	  selector->Process(entry);
	}
	fin->Clear();
	fin->Close();
	fin->Delete("slow");
	tree->Delete("slow");
      }
      mess->Delete("slow");
    }
  }

Now this is not yet perfect : the memory usage keeps increasing. Thus my question : am I still missing something? If not, then I suspect the problem comes from the TSelector, although with a normal use i.e. from a real file, I did not see anything problematic. Is there a standard way to “flush” gROOT to a temporary file? I attempted to write the histograms to a TFile directly it is somehow worst.

Regards
Julien

Hi Julien,

Try:TSocket *sock = new TSocket("localhost", 9090); Char_t filename[512]; sock->Recv(filename, 512); Bool_t kToInit = kTRUE; TSelector *selector = TSelector::GetSelector("macros/ttree_analysis.C+O"); selector->SetOption("Bin=100,Erel,1n,PID1,noout"); TMessage *mess = new TMessage(kMESS_OBJECT); while(1){ if(sock->Recv(mess)){ if(!mess) break; if(!mess->GetClass()) break; if (mess->GetClass()->InheritsFrom(TTree::Class())) { fin->cd(); TTree *tree = (TTree*) mess->ReadObject(mess->GetClass()); tree->SetNotify(selector); if (kToInit) { selector->Begin(tree); kToInit = kFALSE; } selector->Init(tree); selector->Notify(); for (int entry=0;entry<tree->GetEntries();entry++) { tree->LoadTree(entry); selector->Process(entry); } delete tree; } } mess->Reset(); }

Cheers,
Philippe.