Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/global/management/src/G4MTcoutDestination.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 // G4MTcoutDestination class implementation
 27 //
 28 // Authors: M.Asai, A.Dotti (SLAC) - 23 May 2013
 29 // ---------------------------------------------------------------
 30 
 31 #include "G4MTcoutDestination.hh"
 32 
 33 #include "G4AutoLock.hh"
 34 #include "G4BuffercoutDestination.hh"
 35 #include "G4FilecoutDestination.hh"
 36 #include "G4LockcoutDestination.hh"
 37 #include "G4MasterForwardcoutDestination.hh"
 38 
 39 #include <cassert>
 40 #include <sstream>
 41 
 42 namespace
 43 {
 44   G4String empty = "";
 45 }
 46 
 47 // --------------------------------------------------------------------
 48 G4MTcoutDestination::G4MTcoutDestination(const G4int& threadId)
 49   : id(threadId)
 50 {
 51   // TODO: Move this out of here and in the caller
 52   G4iosSetDestination(this);
 53 
 54   stateMgr = G4StateManager::GetStateManager();
 55   SetDefaultOutput(masterDestinationFlag, masterDestinationFmtFlag);
 56 }
 57 
 58 // --------------------------------------------------------------------
 59 void G4MTcoutDestination::SetDefaultOutput(G4bool addmasterDestination,
 60                                            G4bool formatAlsoMaster)
 61 {
 62   masterDestinationFlag    = addmasterDestination;
 63   masterDestinationFmtFlag = formatAlsoMaster;
 64   // Formatter: add prefix to each thread
 65   const auto f = [this](G4String& msg) -> G4bool {
 66     std::ostringstream str;
 67     str << prefix;
 68     if(id != G4Threading::GENERICTHREAD_ID)
 69     {
 70       str << id;
 71     }
 72     str << " > " << msg;
 73     msg = str.str();
 74     return true;
 75   };
 76   // Block cout if not in correct state
 77   const auto filter_out = [this](G4String&) -> G4bool {
 78     return !(
 79       this->ignoreCout ||
 80       (this->ignoreInit && this->stateMgr->GetCurrentState() == G4State_Init));
 81   };
 82 
 83   // Default behavior, add a destination that uses cout and uses a mutex
 84   auto output    = G4coutDestinationUPtr(new G4LockcoutDestination);
 85   ref_defaultOut = output.get();
 86   output->AddDebugTransformer(filter_out);
 87   output->AddDebugTransformer(f);
 88   output->AddCoutTransformer(filter_out);
 89   output->AddCoutTransformer(f);
 90   output->AddCerrTransformer(f);
 91   push_back(std::move(output));
 92   if(addmasterDestination)
 93   {
 94     AddMasterOutput(formatAlsoMaster);
 95   }
 96 }
 97 
 98 // --------------------------------------------------------------------
 99 void G4MTcoutDestination::AddMasterOutput(G4bool formatAlsoMaster)
100 {
101   // Add a destination, that forwards the message to the master thread
102   auto forwarder = G4coutDestinationUPtr(new G4MasterForwardcoutDestination);
103   ref_masterOut  = forwarder.get();
104   const auto filter_out = [this](G4String&) -> G4bool {
105     return !(
106       this->ignoreCout ||
107       (this->ignoreInit && this->stateMgr->GetCurrentState() == G4State_Idle));
108   };
109   forwarder->AddDebugTransformer(filter_out);
110   forwarder->AddCoutTransformer(filter_out);
111   if(formatAlsoMaster)
112   {
113     // Formatter: add prefix to each thread
114     const auto f = [this](G4String& msg) -> G4bool {
115       std::ostringstream str;
116       str << prefix;
117       if(id != G4Threading::GENERICTHREAD_ID)
118       {
119         str << id;
120       }
121       str << " > " << msg;
122       msg = str.str();
123       return true;
124     };
125     forwarder->AddDebugTransformer(f);
126     forwarder->AddCoutTransformer(f);
127     forwarder->AddCerrTransformer(f);
128   }
129   push_back(std::move(forwarder));
130 }
131 
132 // --------------------------------------------------------------------
133 G4MTcoutDestination::~G4MTcoutDestination()
134 {
135   if(useBuffer)
136   {
137     DumpBuffer();
138   }
139 }
140 
141 // --------------------------------------------------------------------
142 void G4MTcoutDestination::Reset()
143 {
144   clear();
145   SetDefaultOutput(masterDestinationFlag, masterDestinationFmtFlag);
146 }
147 
148 // --------------------------------------------------------------------
149 void G4MTcoutDestination::HandleFileCout(const G4String& fileN, G4bool ifAppend,
150                                          G4bool suppressDefault)
151 {
152   // Logic: we create a file destination. We want this to get only the G4cout
153   // stream and should discard everything in G4cerr.
154   // First we create the destination with the appropriate open mode
155 
156   std::ios_base::openmode mode =
157     (ifAppend ? std::ios_base::app : std::ios_base::trunc);
158   auto output = G4coutDestinationUPtr(new G4FilecoutDestination(fileN, mode));
159 
160   // This reacts only to G4cout, so let's make a filter that ignores all other streams
161   output->AddDebugTransformer([](G4String&) { return false; });
162   output->AddCerrTransformer([](G4String&) { return false; });
163   push_back(std::move(output));
164   // Silence G4cout from default formatter
165   if(suppressDefault)
166   {
167     ref_defaultOut->AddCoutTransformer([](G4String&) { return false; });
168     if(ref_masterOut != nullptr)
169     {
170       ref_masterOut->AddCoutTransformer([](G4String&) { return false; });
171     }
172   }
173 }
174 
175 // --------------------------------------------------------------------
176 void G4MTcoutDestination::HandleFileCerr(const G4String& fileN, G4bool ifAppend,
177                                          G4bool suppressDefault)
178 {
179   // See HandleFileCout for explanation, switching cout with cerr
180 
181   std::ios_base::openmode mode =
182     (ifAppend ? std::ios_base::app : std::ios_base::trunc);
183   auto output = G4coutDestinationUPtr(new G4FilecoutDestination(fileN, mode));
184   output->AddDebugTransformer([](G4String&) { return false; });
185   output->AddCoutTransformer([](G4String&) { return false; });
186   push_back(std::move(output));
187   if(suppressDefault)
188   {
189     ref_defaultOut->AddCerrTransformer([](G4String&) { return false; });
190     if(ref_masterOut != nullptr)
191     {
192       ref_masterOut->AddCerrTransformer([](G4String&) { return false; });
193     }
194   }
195 }
196 
197 // --------------------------------------------------------------------
198 void G4MTcoutDestination::SetCoutFileName(const G4String& fileN,
199                                           G4bool ifAppend)
200 {
201   // First let's go back to the default
202   Reset();
203   if(fileN != "**Screen**")
204   {
205     HandleFileCout(fileN, ifAppend, true);
206   }
207 }
208 
209 // --------------------------------------------------------------------
210 void G4MTcoutDestination::EnableBuffering(G4bool flag)
211 {
212   // I was using buffered output and now I want to turn it off, dump current
213   // buffer content and reset output
214   if(useBuffer && !flag)
215   {
216     DumpBuffer();
217     Reset();
218   }
219   else if(useBuffer && flag)
220   { /* do nothing: already using */
221   }
222   else if(!useBuffer && !flag)
223   { /* do nothing: not using */
224   }
225   else if(!useBuffer && flag)
226   {
227     // Remove everything, in this case also removing the forward to the master
228     // thread, we want everything to be dumpled to a file
229     clear();
230     const size_t infiniteSize = 0;
231     push_back(G4coutDestinationUPtr(new G4BuffercoutDestination(infiniteSize)));
232   }
233   else  // Should never happen
234   {
235     assert(false);
236   }
237   useBuffer = flag;
238 }
239 
240 // --------------------------------------------------------------------
241 void G4MTcoutDestination::AddCoutFileName(const G4String& fileN,
242                                           G4bool ifAppend)
243 {
244   // This is like the equivalent SetCoutFileName, but in this case we do not
245   // remove or silence what is already exisiting
246   HandleFileCout(fileN, ifAppend, false);
247 }
248 
249 // --------------------------------------------------------------------
250 void G4MTcoutDestination::SetCerrFileName(const G4String& fileN,
251                                           G4bool ifAppend)
252 {
253   // See SetCoutFileName for explanation
254   Reset();
255   if(fileN != "**Screen**")
256   {
257     HandleFileCerr(fileN, ifAppend, true);
258   }
259 }
260 
261 // --------------------------------------------------------------------
262 void G4MTcoutDestination::AddCerrFileName(const G4String& fileN,
263                                           G4bool ifAppend)
264 {
265   HandleFileCerr(fileN, ifAppend, false);
266 }
267 
268 // --------------------------------------------------------------------
269 void G4MTcoutDestination::SetIgnoreCout(G4int tid)
270 {
271   if(tid < 0)
272   {
273     ignoreCout = false;
274   }
275   else
276   {
277     ignoreCout = (tid != id);
278   }
279 }
280 
281 namespace
282 {
283   G4Mutex coutm = G4MUTEX_INITIALIZER;
284 }
285 
286 // --------------------------------------------------------------------
287 void G4MTcoutDestination::DumpBuffer()
288 {
289   G4AutoLock l(&coutm);
290   std::ostringstream msg;
291   G4bool sep = false;
292 
293   sep = false;
294   msg.str("");
295   msg.clear();
296   msg << "=======================\n";
297   msg << "debug buffer(s) for worker with ID:" << id << std::endl;
298   G4coutDestination::ReceiveG4cout(msg.str());
299   std::for_each(begin(), end(), [this, &sep](G4coutDestinationUPtr& el) {
300     auto cout = dynamic_cast<G4BuffercoutDestination*>(el.get());
301     if(cout != nullptr)
302     {
303       cout->FlushG4debug();
304       if(sep)
305       {
306         G4coutDestination::ReceiveG4cout("==========\n");
307       }
308       else
309       {
310         sep = true;
311       }
312     }
313   });
314 
315   sep = false;
316   msg.str("");
317   msg.clear();
318   msg << "=======================\n";
319   msg << "cout buffer(s) for worker with ID:" << id << std::endl;
320   G4coutDestination::ReceiveG4cout(msg.str());
321   std::for_each(begin(), end(), [this, &sep](G4coutDestinationUPtr& el) {
322     auto cout = dynamic_cast<G4BuffercoutDestination*>(el.get());
323     if(cout != nullptr)
324     {
325       cout->FlushG4cout();
326       if(sep)
327       {
328         G4coutDestination::ReceiveG4cout("==========\n");
329       }
330       else
331       {
332         sep = true;
333       }
334     }
335   });
336 
337   sep = false;
338   msg.str("");
339   msg.clear();
340   msg << "=======================\n";
341   msg << "cerr buffer(s) for worker with ID:" << id << " (goes to std error)"
342       << std::endl;
343   G4coutDestination::ReceiveG4cout(msg.str());
344   std::for_each(begin(), end(), [this, &sep](G4coutDestinationUPtr& el) {
345     auto cout = dynamic_cast<G4BuffercoutDestination*>(el.get());
346     if(cout != nullptr)
347     {
348       cout->FlushG4cerr();
349       if(sep)
350       {
351         G4coutDestination::ReceiveG4cout("==========\n");
352       }
353       else
354       {
355         sep = true;
356       }
357     }
358   });
359 
360   G4coutDestination::ReceiveG4cout("=======================\n");
361 }
362