Огромное использование памяти в pyROOT

Мой код анализа pyROOT использует огромное количество памяти. Я свел проблему к примеру кода ниже:

from ROOT import TChain, TH1D

# Load file, chain
chain = TChain("someChain")
inFile = "someFile.root"
chain.Add(inFile)

nentries = chain.GetEntries()

# Declare histograms
h_nTracks = TH1D("h_nTracks", "h_nTracks", 16, -0.5, 15.5)
h_E = TH1D("h_E","h_E",100,-0.1,6.0)
h_p = TH1D("h_p", "h_p", 100, -0.1, 6.0)
h_ECLEnergy = TH1D("h_ECLEnergy","h_ECLEnergy",100,-0.1,14.0)

# Loop over entries
for jentry in range(nentries):
   # Load entry
   entry = chain.GetEntry(jentry)

   # Define variables
   cands = chain.__ncandidates__
   nTracks = chain.nTracks
   E = chain.useCMSFrame__boE__bc
   p = chain.useCMSFrame__bop__bc
   ECLEnergy = chain.useCMSFrame__boECLEnergy__bc

   # Fill histos
   h_nTracks.Fill(nTracks)
   h_ECLEnergy.Fill(ECLEnergy)

   for cand in range(cands):
      h_E.Fill(E[cand])
      h_p.Fill(p[cand])

где someFile.root - корневой файл с 700 000 записей и несколькими кандидатами в частицы.

Когда я запускаю этот скрипт, он использует ~600 МБ памяти. Если я уберу строку

h_p.Fill(p[cand])

он использует ~400 МБ.

Если я тоже уберу строку

h_E.Fill(E[cand])

он использует ~150 МБ.

Если я тоже уберу строки

h_nTracks.Fill(nTracks)
h_ECLEnergy.Fill(ECLEnergy)

нет дальнейшего сокращения использования памяти.

Кажется, что для каждой дополнительной гистограммы, которую я заполняю в форме

h_variable.Fill(variable[cand])

(т.е. гистограммы, которые заполняются один раз на кандидата на каждую запись, в отличие от гистограмм, которые просто заполняются один раз на каждую запись) Я использую дополнительные ~200 МБ памяти. Это становится серьезной проблемой, когда у меня есть 10 или более гистограмм, потому что я использую ГБ памяти и я превышаю пределы моей вычислительной системы. У кого-нибудь есть решение?

Обновление: я думаю, что это проблема Python3.

Если я возьму сценарий в своем исходном посте (выше) и запуском его с использованием python2, то объем используемой памяти будет ~200 МБ, по сравнению с ~600 МБ с python3. Даже если я попытаюсь воспроизвести проблему 2, используя длинные имена переменных, в задании по-прежнему используется только ~200 МБ памяти с python2, по сравнению с ~ 1,3 ГБ с python3.

Во время моего поиска в Google я столкнулся с несколькими другими учетными записями людей, которые сталкиваются с утечками памяти при использовании pyROOT с python3. Кажется, это все еще проблема с Python 3.6.2 и ROOT 6.08/06, и на данный момент вы должны использовать python2, если вы хотите использовать pyROOT.

Итак, использование python2 пока кажется моим "решением", но оно не идеально. Если у кого-либо есть какая-либо дополнительная информация или предложения, я был бы рад услышать от вас!

1 ответ

Я рад, что вы поняли, что проблема в Python3. Но если в будущем у вас (или у кого-либо еще) возникнут проблемы с использованием памяти при работе с гистограммами, вот несколько потенциальных решений, которые, я надеюсь, вы найдете полезными!

THnSparse

использование THnSparse-THnSparse это эффективная многомерная гистограмма, которая показывает свои сильные стороны в гистограммах, где заполнена только небольшая часть от общего числа бинов. Вы можете прочитать больше об этом здесь.

TTree

TTrees это структуры данных в ROOT, которые являются откровенно прославленными таблицами. Тем не менее, они высоко оптимизированы. TTree состоит из branches а также leaves которые содержат данные, к которым через ROOT можно быстро и эффективно получить доступ. Если вы поместите свои данные в TTree Сначала, а затем прочитайте его в гистограмму, я гарантирую, что вы найдете меньшее использование памяти и большее время выполнения.

Вот пример TTree код.

root_file_path = "../hadd_www.root"

muon_ps = ROOT.TFile(root_file_path)
muon_ps_tree = muon_ps.Get("WWWNtuple")
muon_ps_branches = muon_ps_tree.GetListOfBranches()
canv= ROOT.TCanvas()

num_of_events = 5000

ttvhist = ROOT.TH1F('Statistics2', 'Jet eta for ttV (aqua) vs WWW (white); Pseudorapidity',100, -3, 3)
i = 0

muon_ps_tree.GetEntry(i)
print len(muon_ps_tree.jet_eta)

#sys.exit()
while muon_ps_tree.GetEntry(i):
    if i > num_of_events: break
    for k in range(0,len(muon_ps_tree.jet_eta)-1):
        wwwhist.Fill(float(muon_ps_tree.jet_eta[0]), 1)
    i += 1  

ttvhist.Write()
ttvhist.Draw("hist")
ttvhist.SetFillColor(70);

А вот ресурс, где вы можете узнать о том, как фантастически TTreeэто:

TTree ROOT документация

Для получения дополнительной информации, вот обсуждение ускорения создания исторической диаграммы ROOT на справочном форуме CERN:

Консервативные по памяти гистограммы для использования в мониторинге DQ

Желаем удачи в анализе данных и удачного кодирования!

Другие вопросы по тегам