The Gaudi Framework  master (d98a2936)
THistSvc.icc
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 #pragma once
12 
13 #include <GaudiKernel/MsgStream.h>
14 #include <GaudiKernel/System.h>
15 #include <TFile.h>
16 #include <TObject.h>
17 #include <map>
18 #include <string>
19 
20 template <typename T>
21 StatusCode THistSvc::regHist_i( std::unique_ptr<T> hist, const std::string& id, bool shared ) {
22  THistID* hid = nullptr;
23  return regHist_i( std::move( hist ), id, shared, hid );
24 }
25 
26 template <typename T>
27 StatusCode THistSvc::regHist_i( std::unique_ptr<T> hist_unique, const std::string& id, bool shared, THistID*& phid ) {
29  phid = nullptr;
30 
31  // It is sad that we lose propper memory management here
32  T* hist = nullptr;
33  if ( hist_unique.get() != nullptr ) { hist = hist_unique.release(); }
34  if ( msgLevel( MSG::DEBUG ) ) {
35  debug() << "regHist_i obj: " << hist << " id: " << id << " s: " << shared << endmsg;
36  }
37 
38  std::string idr( id );
39  removeDoubleSlash( idr );
40 
41  if ( idr.find( "/" ) == idr.length() ) {
42  error() << "Badly formed identifier \"" << idr << "\": "
43  << "Must not end with a /" << endmsg;
44  delete hist;
45  return StatusCode::FAILURE;
46  }
47 
48  TFile* f = nullptr;
49  std::string stream, name;
50  if ( !findStream( idr, stream, name, f ) ) {
51  error() << "Could not register id: \"" << idr << "\"" << endmsg;
52  delete hist;
53  return StatusCode::FAILURE;
54  }
55 
56  std::string uid = "/" + stream + "/" + name;
57 
58  uidMap_t::iterator uitr = m_uids.find( uid );
59  bool exists( false );
60  if ( uitr != m_uids.end() ) {
61  exists = true;
62  TObject* t1 = uitr->second->at( 0 ).obj;
63  if ( hist->Compare( t1 ) != 0 ) {
64  error() << "previously registered object with identifier \"" << uid << "\" does not compare to this one"
65  << endmsg;
66  delete hist;
67  return StatusCode::FAILURE;
68  } else {
69  if ( msgLevel( MSG::DEBUG ) ) {
70  debug() << "previously registered id \"" << uid << "\": num " << uitr->second->size() << endmsg;
71  }
72  }
73  }
74 
75  bool temp = false;
76  if ( !f ) {
77  temp = true;
78  if ( msgLevel( MSG::DEBUG ) ) { debug() << "Historgram with id \"" << idr << "\" is temporary" << endmsg; }
79  }
80 
81  TObject* to = nullptr;
82  THistID hid;
83  // check to see if this hist is to be read in;
84  if ( !temp && m_files.find( stream )->second.second == READ ) {
85  if ( hist != 0 ) { warning() << "Registering id: \"" << idr << "\" with non zero pointer!" << endmsg; }
86 
87  hist = readHist_i<T>( idr );
88  if ( hist == nullptr ) {
89  error() << "Unable to read in hist" << endmsg;
90  delete hist;
91  return StatusCode::FAILURE;
92  }
93  to = dynamic_cast<TObject*>( hist );
94  hid = THistID( uid, temp, to, f, m_files.find( stream )->second.second );
95  } else if ( !hist ) {
96  error() << "Unable to read in hist with id: \"" << idr << "\"" << endmsg;
97  delete hist;
98  return StatusCode::FAILURE;
99  } else {
100  to = dynamic_cast<TObject*>( hist );
101  if ( to == nullptr ) {
102  error() << "Could not dcast to TObject. id: \"" << idr << "\"" << endmsg;
103  delete hist;
104  return StatusCode::FAILURE;
105  }
106 
107  auto oitr = m_tobjs.find( to );
108  if ( oitr != m_tobjs.end() ) {
109  error() << "already registered id: \"" << idr << "\" with identifier \""
110  << oitr->second.first->at( oitr->second.second ).id << "\"" << endmsg;
111  delete hist;
112  return StatusCode::FAILURE;
113  }
114  }
115 
116  const auto findF = m_files.find( stream );
117  hid = ( findF != m_files.end() ? THistID( uid, temp, to, f, findF->second.second ) : THistID( uid, temp, to, f ) );
118 
119  hid.shared = shared;
120  TDirectory* dir = changeDir( hid );
121 
122  if ( TTree* tree = dynamic_cast<TTree*>( hist ) ) {
123  tree->SetDirectory( dir );
124  hid.type = ObjectType::TTREE;
125  m_hasTTrees = true; // at least one TTree is registered
126  } else if ( TH1* th1 = dynamic_cast<TH1*>( hist ) ) {
127  th1->SetDirectory( dir );
128  hid.type = ObjectType::TH1;
129  } else if ( TEfficiency* teff = dynamic_cast<TEfficiency*>( hist ) ) {
130  teff->SetDirectory( dir );
132  } else if ( dynamic_cast<TGraph*>( hist ) ) {
133  dir->Append( hist );
134  hid.type = ObjectType::TGRAPH;
135  } else {
136  error() << "id: \"" << idr << "\" is not a TH, TTree, TGraph, or TEfficiency. Attaching it to current dir."
137  << endmsg;
138  dir->Append( hist );
140  }
141 
142  std::string fname;
143  if ( !f ) {
144  fname = "none";
145  } else {
146  fname = f->GetName();
147  }
148 
149  if ( msgLevel( MSG::DEBUG ) ) {
150  debug() << "Registering" << ( shared ? " shared " : " " ) << System::typeinfoName( typeid( *hist ) ) << " title: \""
151  << hist->GetTitle() << "\" id: \"" << uid
152  << "\" dir: "
153  // << hist->GetDirectory()->GetPath() << " "
154  << changeDir( hid )->GetPath() << " file: " << fname << endmsg;
155  }
156 
157  // create a mutex for all shared histograms
158  if ( shared ) { hid.mutex = new histMut_t; }
159 
160  if ( exists ) {
161  vhid_t* vi = uitr->second;
162  vi->push_back( hid );
163  phid = &( vi->back() );
164 
165  m_tobjs.emplace( to, std::pair<vhid_t*, size_t>( vi, vi->size() - 1 ) );
166  } else {
167  vhid_t* vi = new vhid_t{ hid };
168  m_hlist.emplace( m_hlist.end(), vi );
169 
170  phid = &( vi->back() );
171  m_uids.emplace( uid, vi );
172  m_ids.emplace( name, vi );
173 
174  m_tobjs.emplace( to, std::pair<vhid_t*, size_t>( vi, 0 ) );
175  }
176 
177  if ( msgLevel( MSG::DEBUG ) ) { debug() << "regHist_i THistID: " << hid << endmsg; }
178 
179  return StatusCode::SUCCESS;
180 }
181 
182 template <typename T>
183 T* THistSvc::getHist_i( const std::string& id, const size_t& ind, bool quiet ) const {
184  // id starts with "/": unique
185 
186  GlobalDirectoryRestore restore( m_svcMut );
187 
188  T* hist = nullptr;
189  const THistID* hid = nullptr;
190  size_t num = findHistID( id, hid, ind );
191  if ( num == 0 ) {
192  // no matches found
193  if ( !quiet ) { error() << "could not locate Hist with id \"" << id << "\"" << endmsg; }
194  return nullptr;
195  } else if ( num > 1 ) {
196  if ( !quiet ) {
197  // return failure if trying to GET a single hist
198  error() << "Multiple matches with id \"" << id << "\"."
199  << " Further specifications required." << endmsg;
200  return nullptr;
201  } else {
202  info() << "Found multiple matches with id \"" << id << "\"" << endmsg;
203  // return first match if just INQUIRING (i.e. != nullptr)
204  hist = dynamic_cast<T*>( hid->obj );
205  if ( hist == nullptr ) {
206  error() << "dcast failed, Hist id: \"" << id << "\"" << endmsg;
207  return nullptr;
208  }
209  }
210  } else {
211  hist = dynamic_cast<T*>( hid->obj );
212  if ( hist == nullptr ) {
213  error() << "dcast failed, Hist id: \"" << id << "\"" << endmsg;
214  return nullptr;
215  }
216  if ( msgLevel( MSG::VERBOSE ) ) {
217  verbose() << "found unique Hist title: \"" << hist->GetTitle() << "\" id: \"" << id << "\"" << endmsg;
218  }
219  }
220 
221  return hist;
222 }
223 
224 template <typename T>
225 T* THistSvc::readHist_i( const std::string& id ) const {
226  GlobalDirectoryRestore restore( m_svcMut );
227 
228  std::string idr( id );
229  removeDoubleSlash( idr );
230 
231  std::string stream, rem, dir, fdir, bdir, fdir2;
232  TFile* file = nullptr;
233 
234  if ( !findStream( idr, stream, rem, file ) ) { return nullptr; }
235 
236  if ( !file ) {
237  error() << "no associated file found" << endmsg;
238  return nullptr;
239  }
240 
241  file->cd( "/" );
242 
243  fdir = idr;
244  bdir = stripDirectoryName( fdir );
245  fdir2 = fdir;
246  while ( ( dir = stripDirectoryName( fdir ) ) != "" ) {
247  if ( !gDirectory->GetKey( dir.c_str() ) ) {
248  error() << "Directory \"" << fdir2 << "\" doesnt exist in " << file->GetName() << endmsg;
249  return nullptr;
250  }
251  gDirectory->cd( dir.c_str() );
252  }
253 
254  TObject* to = nullptr;
255  gDirectory->GetObject( fdir.c_str(), to );
256 
257  if ( !to ) {
258  error() << "Could not get obj \"" << fdir << "\" in " << gDirectory->GetPath() << endmsg;
259  return nullptr;
260  }
261 
262  T* hist = dynamic_cast<T*>( to );
263  if ( hist == nullptr ) {
264  error() << "Could not convert \"" << idr << "\" to a " << System::typeinfoName( typeid( *hist ) ) << " as is a "
265  << to->IsA()->GetName() << endmsg;
266  return nullptr;
267  }
268 
269  if ( msgLevel( MSG::DEBUG ) ) {
270  debug() << "Read in " << hist->IsA()->GetName() << " \"" << hist->GetName() << "\" from file " << file->GetName()
271  << endmsg;
272  hist->Print();
273  }
274 
275  return hist;
276 }
277 
278 template <typename T>
279 LockedHandle<T> THistSvc::regShared_i( const std::string& id, std::unique_ptr<T> hist ) {
280  LockedHandle<T> lh( nullptr, nullptr );
281  const THistID* hid = nullptr;
282  if ( findHistID( id, hid ) == 0 ) {
283  T* phist = hist.get();
284  THistID* phid = nullptr;
285  if ( regHist_i( std::move( hist ), id, true, phid ).isSuccess() ) {
286  lh.set( phist, phid->mutex );
287 
288  } else {
289  error() << "regSharedHist: unable to register shared hist with id \"" << id << "\"" << endmsg;
290  }
291  } else {
292  if ( !hid->shared ) {
293  error() << "regSharedHist: previously register Hist with id \"" << id << "\" was not marked shared" << endmsg;
294  }
295 
296  if ( hist->Compare( hid->obj ) != 0 ) {
297  error() << "regSharedHist: Histogram " << id << " does not compare with " << hid << endmsg;
298  } else {
299  T* phist = dynamic_cast<T*>( hid->obj );
300  if ( phist == 0 ) {
301  error() << "regSharedHist: unable to dcast retrieved shared hist \"" << id << "\" of type "
302  << hid->obj->IsA()->GetName() << " to requested type " << System::typeinfoName( typeid( T ) ) << endmsg;
303  } else {
304  lh.set( phist, hid->mutex );
305  delete hist.release();
306  }
307  }
308  }
309  return lh;
310 }
311 
312 template <typename T>
313 LockedHandle<T> THistSvc::getShared_i( const std::string& name ) const {
314  GlobalDirectoryRestore restore( m_svcMut );
315 
316  const THistID* hid = nullptr;
317  size_t i = findHistID( name, hid );
318 
319  LockedHandle<T> hist( nullptr, nullptr );
320 
321  if ( i == 1 ) {
322  if ( !hid->shared ) {
323  error() << "getSharedHist: found Hist with id \"" << name << "\", but it's not marked as shared" << endmsg;
324  return hist;
325  }
326  T* h1 = dynamic_cast<T*>( hid->obj );
327  hist = LockedHandle<T>( h1, hid->mutex );
328 
329  if ( msgLevel( MSG::DEBUG ) ) { debug() << "getSharedHist: found THistID: " << *hid << endmsg; }
330  } else if ( i == 0 ) {
331  error() << "no histograms matching id \"" << name << "\" found" << endmsg;
332  } else {
333  info() << "multiple matches for id \"" << name << "\" found [" << i << "], probably from different streams"
334  << endmsg;
335  }
336  return hist;
337 }
MSG::DEBUG
@ DEBUG
Definition: IMessageSvc.h:22
THistSvc::readHist_i
T * readHist_i(const std::string &name) const
Definition: THistSvc.icc:225
THistSvc::regShared_i
LockedHandle< T > regShared_i(const std::string &id, std::unique_ptr< T > hist)
Definition: THistSvc.icc:279
Write.stream
stream
Definition: Write.py:32
THistSvc::histMut_t
std::mutex histMut_t
Definition: THistSvc.h:200
System.h
LockedHandle::set
void set(T *ptr, MutexType *mut)
Definition: LockedHandle.h:43
THistSvc::m_hlist
hlist_t m_hlist
Definition: THistSvc.h:288
System::typeinfoName
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:260
CommonMessaging< implements< IService, IProperty, IStateful > >::msgLevel
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
Definition: CommonMessaging.h:147
THistSvc::stripDirectoryName
std::string stripDirectoryName(std::string &dir) const
Definition: THistSvc.cpp:1750
THistSvc::vhid_t
std::vector< THistID > vhid_t
Definition: THistSvc.h:279
THistSvc::getShared_i
LockedHandle< T > getShared_i(const std::string &name) const
Definition: THistSvc.icc:313
THistSvc::ObjectType::TEFFICIENCY
@ TEFFICIENCY
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:333
StatusCode
Definition: StatusCode.h:64
THistSvc::findStream
bool findStream(const std::string &name, std::string &root, std::string &rem, TFile *&file) const
Definition: THistSvc.cpp:1817
TemplatedAlg
Definition: TemplatedAlg.cpp:22
THistSvc::m_tobjs
objMap_t m_tobjs
Definition: THistSvc.h:293
THistSvc::changeDir
TDirectory * changeDir(const THistSvc::THistID &hid) const
Definition: THistSvc.cpp:1728
THistSvc::ObjectType::TTREE
@ TTREE
THistSvc::m_ids
idMap_t m_ids
Definition: THistSvc.h:290
genconfuser.verbose
verbose
Definition: genconfuser.py:28
THistSvc::removeDoubleSlash
void removeDoubleSlash(std::string &) const
Definition: THistSvc.cpp:1766
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:198
THistSvc::THistID::obj
TObject * obj
Definition: THistSvc.h:240
THistSvc::THistID::mutex
histMut_t * mutex
Definition: THistSvc.h:242
THistSvc::GlobalDirectoryRestore
Helper class that manages ROOts global directory and file.
Definition: THistSvc.h:203
THistSvc::READ
@ READ
Definition: THistSvc.h:216
THistSvc::getHist_i
T * getHist_i(const std::string &name, const size_t &ind=0, bool quiet=false) const
Definition: THistSvc.icc:183
THistSvc::regHist_i
StatusCode regHist_i(std::unique_ptr< T > hist, const std::string &name, bool shared)
Definition: THistSvc.icc:21
MSG::VERBOSE
@ VERBOSE
Definition: IMessageSvc.h:22
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:99
THistSvc::m_files
std::map< std::string, std::pair< TFile *, Mode > > m_files
Definition: THistSvc.h:295
THistSvc::exists
bool exists(const std::string &name) const override
Check if object with given name is managed by THistSvcMT exists calls existsHist and only works for T...
Definition: THistSvc.cpp:667
THistSvc::m_hasTTrees
bool m_hasTTrees
Definition: THistSvc.h:393
THistSvc::ObjectType::TGRAPH
@ TGRAPH
THistSvc::ObjectType::UNKNOWN
@ UNKNOWN
THistSvc::m_uids
uidMap_t m_uids
Definition: THistSvc.h:289
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:100
LockedHandle
Definition: LockedHandle.h:36
THistSvc::m_svcMut
THistSvcMutex_t m_svcMut
Definition: THistSvc.h:397
THistSvc::findHistID
size_t findHistID(const std::string &id, const THistID *&hid, const size_t &index=0) const
Definition: THistSvc.cpp:1943
THistSvc::ObjectType::TH1
@ TH1
THistSvc::THistID::type
ObjectType type
Definition: THistSvc.h:244
THistSvc::THistID::shared
bool shared
Definition: THistSvc.h:246
THistSvc::THistID
Helper struct that bundles the histogram ID with a mutex, TFile and TObject*.
Definition: THistSvc.h:238
MsgStream.h