Geant4 Cross Reference |
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