... para pessoas que
não sabem c++
Alexandre Suaide
aula 2
O lego
Organização das aulas
• Aula 1
– Comandos (realmente) básicos do ROOT
– Um pouco de c++ para usuários de ROOT
– Criando objetos simples (histogramas, gráficos, etc)
– Manuseando gráficos e histogramas.
• A interface gráfica
– Funções e ajustes de gráficos
• Aula 2
– Macros
– Inovando sem perder a classe.
– Análise de dados no Pelletron
• ScanRoot e PelTools
– Debug, memory leaks e administrando objetos
Macros no ROOT
• O que é um macro?
– Conjunto de comandos (como um programa)
gravados em um arquivo.
– Em geral é interpretado, mas pode-se compilar
• O processo de compilação exige que o macro esteja
consistente com o c++ standard
• Como ler e executar
– .L – carrega um macro na memória
– .x – carrega e executa a função do macro cujo
nome seja o mesmo do macro
• Ex: .x teste.C
– Carrega o macro teste.C e executa a função teste()
Exemplos simples
• Para executar
– Método 1
root.exe [0] .L hello.C
root.exe [1] hello()
– Método 2
hello.C
void hello()
{
cout <<"Hello world"<<endl;
}
root.exe [0] .x hello.C
• Passando parâmetros
– Método 1
root.exe [0] .L hist.C
root.exe [1] hist(20,3)
– Método 2
root.exe [0] .x hist.C(20,3)
hist.C
void hist(float mean, float RMS)
{
TH1F *h = new TH1F("h","teste",50,mean-4*RMS, mean+4*RMS);
for(int i = 0;i<2000;i++) h->Fill(gRandom->Gaus(mean,RMS));
h->Draw();
}
Compilando macros... Tornando a execução mais
rápida
• Compilar macros torna a execução 10-1000 vezes
mais rápida
• Para compilar um macro, digite, no prompt do linux
compileMacro macro.C
– Esse comando só está disponível no PelTools
é uma variável
• O macro compilado gera uma gSystem
biblioteca
de ambiente do ROOT
compartilhada (.so)
(classe TSystem)
– Para carregar a biblioteca digite, no ROOT
root.exe [0] gSystem->Load(“macro.so”)
• Ex: macro hist.C
compileMacro hist.C
root
root.exe [0] gSystem->Load(“hist.so”)
root.exe [1] hist(20,3)
Alguns cuidados na hora de compilar macros
• O processo de compilação utiliza um compilador padrão c++
– Cuidado com a sintaxe. Em geral, o ROOT é muito tolerante
com a sintaxe em c++. Macros interpretados rodam sem
problemas mas na hora de compilar a estória é outra
• O compilador não sabe sobre as definições do ROOT
– Deve-se incluir explicitamente as definições de classes do
ROOT (#include)
• O macro hist.C ficaria assim:
#include “TRandom.h”
#include “TH1.h”
void hist(float mean, float RMS)
{
TH1F *h = new TH1F("h","teste",50,mean-4*RMS, mean+4*RMS);
for(int i = 0;i<2000;i++) h->Fill(gRandom->Gaus(mean,RMS));
h->Draw();
}
Criando sem perder a classe
• O ROOT oferece a possibilidade de criar as suas
próprias classes
– Utilize o mesmo padrão de programação em c++
• Porém o ROOT oferece algumas vantagens
– Integração completa com o framework do ROOT
• Criação de dicionários para utilizar o prompt de comando,
incluindo a tecla TAB para completar comandos
• Gerenciamento de IO.
– Pode-se gravar objetos de classes criadas pelo usuário
em arquivos root
– Atualização de versões.
» O ROOT gerencia automaticamente a evolução das
classes que são criadas.
– Para usar essas benfeitorias deve-se seguir
algumas regras
Regras para criação de classes
(necessárias somente se você quiser integração total com o ROOT)
• Classes devem ser derivadas do TObject ou TNamed (ou de
outras classes derivadas delas)
– Isso inclui automaticamente métodos de IO, como Write(),
Get(), etc...
• Utilizar os macros ClassDef e ClassImp na definição da classe
– Esses macros são essenciais na geração do dicionário e
também no gerenciamento de versões
• O dicionário faz com que possa-se utilizar o prompt de comandos
para manusear objetos definidos a partir de novas classes
• O gerenciamento de versões faz com que possa-se ler objetos
de arquivos root criados a partir de definições antigas de novas
classes.
– Ex: cria-se uma classe para cuidar de um telescópio E-DE.
Faz-se algumas análises e grava-se alguns objetos em um
arquivo. Após um tempo, muda-se a estrutura dessa classe
para torná-la melhor. O gerenciamento de versões faz com
que consiga-se ler os objetos definidos com a versão antiga
da classe.
Exemplo
TTeste.h
#include "TObject.h"
class TTeste: public TObject
{
public:
TTeste();
TTeste.cxx
virtual ~TTeste();
ClassDef(TTeste,1)
};
#include "TTeste.h"
#include <iostream>
using namespace std;
ClassImp(TTeste)
Versão da classe
TTeste::TTeste()
{
cout <<"Esse é o construtor"<<endl;
}
TTeste::~TTeste()
{
cout <<"Esse é o destrutor"<<endl;
}
Compilando classes
• Classes podem ser lidas do mesmo jeito que
macros, porém compilar é muito mais eficiente
• Compilar classes no ROOT é algo que exige uns 3-4
comandos no prompt do Linux
– Compilar os arquivos propriamente ditos
– Gerar o dicionário com o comando rootcint
– Linkar o dicionário compilado com os outros
arquivos compilados e gerar uma biblioteca
compartilhada (.so)
• Assim, para facilitar a vida, existe o comando
compile (somente no PelTools)
– Macro que compila todos os .cxx em um diretório,
gera os dicionários, compila tudo e cria um arquivo
.so
Algumas regras para o comando compile
• Todos os arquivos devem estar em um único
diretório
• Os headers devem ter extensão .h e os códigos,
.cxx
• Cada classe deve ser definida em um arquivo .h
cujo nome deve ser o mesmo da classe (facilita
geração do dicionário)
– Ex: a classe TTeste deve ser definida no arquivo
TTeste.h
• Uso:
– cd para o diretório onde estão as classes
– Digite compile [nome do arquivo .so]
ScanRoot e PelTools
• ScanRoot
– Versão modificada do ROOT que inclui bibliotecas
e métodos para análise dos dados tomados no
Pelletron
• Agrupa as funções do SCAN + DAMM
• Abre e lê arquivo de dados brutos (.FIL)
• Preenche histogramas a partir dos dados, etc
• PelTools
– Classe definida com algumas funções básicas para
análise de dados no Pelletron, como traçar bananas,
projeções, ajustes de picos etc.
• Setup
– Inclua no seu arquivo de login
• source /mnt/software/setup
Idéia por trás do ScanRoot
• Os dados são adquiridos no Pelletron e gravados em
um formato especial (.FIL)
– Bastante compacto
– Informação de cada evento separadamente
• Os dados devem ser processados para gerar os
histogramas ou qualquer outra figura
– Aqui entra o ScanRoot
• ScanRoot em 4 etapas
– Abrir um arquivo de dados (.FIL)
– Abrir uma biblioteca com as funções que processarão
os eventos
– Processar os eventos
– Gravar os resultados
ScanRoot
• Iniciando o programa.
– Digite:
scanroot
– Para um help, digite:
scanroot -h
*******************************************
**
**
**
S c a n R o o t v 2.0
**
**
**
**
(c) 2003-2004 A. A. P. Suaide
**
**
**
*******************************************
Running ScanRoot. type scanroot -help for options
type menu() to open the ScanRoot Menu
ScanRoot [0]>
*******************************************
**
**
**
S c a n R o o t v 2.0
**
**
**
**
(c) 2003-2004 A. A. P. Suaide
**
**
**
*******************************************
usage: spmroot [-h|help] [-d|debug] [-t|tools] [file1] [file2] ...
-h or -help
displays this message
-d or -debug
turns on debug mode and display event by event information
-n or -nogui
does not open the ScanRoot Menu
file1, file2,... open root files and display the browser
A interface gráfica
• Como processar um arquivo .FIL
– Clique em Open .FIL e selecione o
arquivo
– Clique em Load Histograms e
selecione a biblioteca com as
definições dos histogramas
– Clique em GO
– Clique em Save Histograms para
salvar os histogramas gerados
– Para abrir a janela de análise, clique
em PelTools Menu
Além da interface gráfica, há comandos para o
prompt
• Comandos básicos
– hac(“filename”)
• Carrega arquivo de definição de histogramas
– openInput(“filename”)
• Abre o .FIL
– openOutput(“filename”,outNumber)
• Abre um novo arquivo FIL para gravação
– loadL2(“filename”)
• Carrega definição de trigger de software
– saveHist(“filename”)
• Grava arquivo de histogramas
– go(N)
• Processa N eventos (N=0 processa o arquivo inteiro)
– tools()
• Abre a janela de PelTools
– help()
Analisando dados
• Usando o prompt de comando
(RootCint)
– Alta flexibilidade
• Interpretador c++/ROOT
• Usando o PelTools
– Pequena interface gráfica que
auxilia, dentre outras coisas
• Criação de bananas (TCutG)
• Projeção de histogramas
• Ajustes de picos, etc
– Ajuste bastante rudimentar
(precisa desenvolvimento)
Como fazer histogramas
• Pequena rotina em c++
– Todo o poder do c++ e do
ROOT disponíveis
• Não precisa compilar
– O ScanRoot compila
sozinho
• Mesmo programa pode ser
usado para aquisição de
dados (SPMRoot)
• Header
– Incluir bibliotecas básicas
– Definir variáveis globais
• 4 funções (2 obrigatórias)
– bookHistograms()
– fillHistograms()
– init()
– finish()
Mantendo a memória em ordem
• Objetos criados no heap (comando new) só são
deletados quando explicitamente requisitados
– Isso gera um problema de gerenciamento de
memória
• Considere o seguinte exemplo
void hist()
{
TH1F *h = new TH1F("h","teste",50,0,10);
}
root.exe [0] for(int i=0;i<10;i++) hist();
Vários objetos são criados
com o mesmo nome, além
disso, os ponteiros são
perdidos. Perdeu-se o acesso
àquele objeto mas a memória
continua alocada
MEMORY LEAK
Algumas ferramentas no auxílio de gerenciamento
• O ROOT possui alguma classes para ajudar no gerenciamento
do sistema como um todo
– TROOT
• Ponto de entrada do ROOT. Permite acesso a cada objeto criado
dentro do ROOT, além de outras informações do sistema
(variável global gROOT)
– TSystem
• Define a interface básica com o sistema operacional (variável
global gSystem)
– TMemStat
• Auxilia na monitoração do uso de memória
– TBenchmark
• Auxilia na medida de tempo (total e CPU) de processamento de
um certo processo
Procurando objetos na memória (gROOT)
• O ROOT mantém uma lista de objetos criados na memória.
Essa lista é indexada pelo nome do objeto.
– TROOT::FindObject(char* name);
• Retorna o ponteiro para o objeto cujo nome é “name”
• Resolve somente casos onde o endereço (ponteiro) do objeto foi
perdido. Objetos criados com o mesmo nome são perdidos, a
menos que se tome o cuidado de guardar os ponteiros dos
mesmos
root.exe [0] TH1F *h = gROOT->FindObject(“h”);
– TROOT::ls();
• Lista o conteúdo da memória do ROOT
root.exe [0] gROOT->ls();
TROOT*
OBJ: TH1F
Rint
h
The ROOT of EVERYTHING
teste : 0 at: 0x8d4ca20
TMemStat
• TMemStat fornece informação sobre o uso de
memória no ROOT
– TMemStat::PrintMem(“”);
• Fornece a quantidade de memória sendo usada e quanto
essa memória cresceu/diminuiu desde a última solicitação
root.exe [60] TMemStat m
root.exe [61] m.PrintMem("")
TMemStat::
total = 41.175781 heap = 15.332096 ( +0.102976)
root.exe [62] for (int i=0;i<10000;i++) hist()
Warning in <TH1::Build>: Replacing existing histogram: h (Potential memory leak).
Warning in <TH1::Build>: Replacing existing histogram: h (Potential memory leak).
...
Warning in <TH1::Build>: Replacing existing histogram: h (Potential memory leak).
root.exe [64] m.PrintMem("")
TMemStat::
total = 51.562500 heap = 26.420584 (+10.080040)
Essa mensagem aparece
porque tenta-se criar vários
objetos com o mesmo
TBenchmark
• TBenchmark é um relógio para medir o desempenho
de execução do código
– Vários métodos
• Start(“”) – Inicia relógio
• Stop(“”) – Para relógio
• GetRealTime(“”) – Fornece tempo real de execução
• GetCpuTime(“”) – Fornece tempo de cpu
root.exe [67] TBenchmark b
root.exe [68] b.Start(""); for(int i=0;i<1000;i++) hist(); b.Stop("");
Warning in <TH1::Build>: Replacing existing histogram: h (Potential memory leak).
...
Warning in <TH1::Build>: Replacing existing histogram: h (Potential memory leak).
root.exe [69] b.GetRealTime("")
(Float_t)1.09000003337860107e+00
root.exe [70] b.GetCpuTime("")
(Float_t)4.69999998807907104e-01
Como resolver o nosso problema de memory leak
• Duas situações diferentes
– Eu só quero 1 histograma por vez na memória
• Tenho que destruir o velho antes de criar o novo
• Nesse caso, costuma-se dizer que o objeto pertence à
função pois a função decide se o objeto continua vivendo
ou não
– Eu realmente necessito de vários histogramas na
memória
• Ou eu ponho nomes diferentes para cada histograma...
• ...ou eu mantenho os ponteiros de cada histograma
construído com o mesmo nome
• Nesse caso, costuma-se dizer que o objeto não pertence à
função pois ela não controla a vida do mesmo
Caso 1: Eu só quero 1 histograma por vez
• Usar o ROOT para verificar se o objeto já existe
na memória e deletá-lo, caso necessário
void hist()
{
TH1F *h = gROOT->FindObject("h");
if (h) delete h;
h = new TH1F("h","teste",50,0,10);
}
Esse procedimento é lento
pois, a cada chamada da
função, a mesma precisa
procurar pelo objeto.
Porém, é seguro.
root.exe [1] TMemStat m;
root.exe [2] m.PrintMem("")
TMemStat::
total = 35.445312 heap = 10.857408 (+10.857408)
root.exe [3] for(int i =0;i<10000;i++) hist()
root.exe [4] m.PrintMem("")
TMemStat::
total = 35.445312 heap = 10.857464 ( +0.000056)
Não foi alocada
memória
adicional
Caso 2: o usuário controla o número de histogramas
• Vamos fazer direito
– Cada objeto possui um nome distinto
– A função retorna um ponteiro do objeto criado
TH1F* hist(int index)
{
TString nome = "hist";
nome+=index; // cria um histograma cujo nome é histxxxx
TH1F *h = new TH1F(nome,nome,50,0,10);
return h; // retorna o ponteiro do objeto recem criado
}
root.exe [1] TH1F *hist[10000]
root.exe [2] TMemStat m;
root.exe [3] m.PrintMem("")
TMemStat::
total = 35.144531 heap = 10.863632 (+10.863632)
root.exe [4] for(int i =0;i<10000;i++) hist[i] = hist(i)
root.exe [5] m.PrintMem("")
TMemStat::
total = 46.007812 heap = 22.093968 (+11.230336)
root.exe [6] for(int i =0;i<10000;i++) delete hist[i]
root.exe [7] m.PrintMem("")
TMemStat::
total = 46.007812 heap = 10.920744 (-11.173224)
Houve aumento
da memória
utilizada...
...mas o usuário
tem controle
sobre ela
Quando gerenciamento de memória é importante
• Do ponto de vista do programador
– Sempre
• Do ponto de vista do cientista
– Quando não fazer gerenciamento causar problema
Na prática, deve-se tomar cuidado com a memória. Quando um trabalho for feito
de tal forma que cria-se algumas centenas ou milhares de objetos, dependendo
do tamanho de cada um, pode-se, facilmente, alocar praticamente toda a memória
disponível, o que pode acarretar no término do programa por falta de memória ou
na completa degradação da performance devido ao fato do computador começar
a fazer swap em disco.
Programinhas onde somente são criados alguns objetos, apesar de não ser elegante,
pode-se viver com um pequeno vazamento de memória.
Como conseguir mais informação
• Site do ROOT
– http://root.cern.ch
• Documentação das classes
– http://root.cern.ch/root/Reference.html
• Alguns documentos interessantes (root, c++)
– Incluindo essas aulas
– http://dfn.if.usp.br/~suaide/pelletron/links.htm
• Download ROOT (+scanroot e PelTools)
– http://dfn.if.usp.br/~suaide/pelletron/download.htm
... Para finalizar
Download

aula 2