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