source: trunk/examples/extended/parallel/MPI/mpi_interface/src/G4MPImanager.cc @ 1358

Last change on this file since 1358 was 1337, checked in by garnier, 14 years ago

tag geant4.9.4 beta 1 + modifs locales

File size: 16.5 KB
Line 
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// $Id: G4MPImanager.cc,v 1.2 2010/05/18 06:06:21 kmura Exp $
27// $Name: geant4-09-04-beta-01 $
28//
29// ====================================================================
30//   G4MPImanager.cc
31//
32//                                         2007 Q
33// ====================================================================
34#include "G4MPImanager.hh"
35#include "G4MPImessenger.hh"
36#include "G4MPIsession.hh"
37#include "G4MPIbatch.hh"
38#include "G4MPIstatus.hh"
39#include "G4MPIrandomSeedGenerator.hh"
40#include "G4UImanager.hh"
41#include "G4RunManager.hh"
42#include "G4StateManager.hh"
43#include "G4Run.hh"
44#include <time.h>
45#include <stdio.h>
46#include <getopt.h>
47
48G4MPImanager* G4MPImanager::theManager= 0;
49
50// ====================================================================
51// wrappers for thread functions
52// ====================================================================
53
54////////////////////////////////////////////////////////////////
55static void thread_ExecuteThreadCommand(const G4String* command)
56////////////////////////////////////////////////////////////////
57{
58  G4MPImanager::GetManager()-> ExecuteThreadCommand(*command);
59}
60
61
62// ====================================================================
63//
64// class description
65//
66// ====================================================================
67
68////////////////////////////
69G4MPImanager::G4MPImanager()
70  : verbose(0),
71    qfcout(false),
72    qinitmacro(false),
73    qbatchmode(false),
74    threadID(0),
75    masterWeight(1.)
76////////////////////////////
77{
78  //MPI::Init();
79  MPI::Init_thread(MPI::THREAD_SERIALIZED);
80  Initialize();
81}
82
83
84/////////////////////////////////////////////////
85G4MPImanager::G4MPImanager(int argc, char** argv)
86  : verbose(0), qfcout(false),
87    qinitmacro(false), qbatchmode(false),
88    threadID(0),
89    masterWeight(1.)
90/////////////////////////////////////////////////
91{
92  //MPI::Init(argc, argv);
93  MPI::Init_thread(argc, argv, MPI::THREAD_SERIALIZED);
94  Initialize();
95  ParseArguments(argc, argv);
96}
97
98
99/////////////////////////////
100G4MPImanager::~G4MPImanager()
101/////////////////////////////
102{
103  if(isSlave && qfcout) fscout.close();
104
105  delete status;
106  delete messenger;
107  delete session;
108
109  COMM_G4COMMAND.Free();
110
111  MPI::Finalize();
112
113  theManager= 0;
114}
115
116
117////////////////////////////////////////
118G4MPImanager* G4MPImanager::GetManager()
119////////////////////////////////////////
120{
121  if(theManager==0) {
122    G4Exception("G4MPImanager is not created.");
123  }
124  return theManager;
125}
126
127
128///////////////////////////////
129void G4MPImanager::Initialize()
130///////////////////////////////
131{
132  if(theManager != 0) {
133    G4Exception("G4MPImanager is constructed twice.");
134  }
135  theManager= this;
136
137  // get rank information
138  size= MPI::COMM_WORLD.Get_size();
139  rank= MPI::COMM_WORLD.Get_rank();
140  isMaster= (rank == RANK_MASTER);
141  isSlave= (rank != RANK_MASTER);
142
143  // initialize MPI communicator
144  COMM_G4COMMAND= MPI::COMM_WORLD.Dup();
145
146  // new G4MPI stuffs
147  messenger= new G4MPImessenger(this);
148
149  session= new G4MPIsession;
150
151  status= new G4MPIstatus;
152
153  // default seed generator is random generator.
154  seedGenerator= new G4MPIrandomSeedGenerator;
155  DistributeSeeds();
156
157}
158
159
160////////////////////////////////////////////////////////
161void G4MPImanager::ParseArguments(int argc, char** argv)
162////////////////////////////////////////////////////////
163{
164  G4int qhelp= 0;
165  G4String ofprefix="mpi";
166
167  G4int c;
168  while (1) {
169    G4int option_index= 0;
170    static struct option long_options[] = {
171      {"help", 0, 0, 0},
172      {"verbose", 0, 0, 0},
173      {"init", 1, 0, 0},
174      {"ofile", 2, 0, 0},
175      {0, 0, 0, 0}
176    };
177
178    opterr= 0; // suppress message
179    c= getopt_long(argc, argv, "hvi:o", long_options, &option_index);
180    opterr= 1;
181
182    if(c == -1) break;
183
184    switch (c) {
185    case 0:
186      switch(option_index) {
187      case 0 : // --help
188        qhelp= 1;
189        break;
190      case 1 : // --verbose
191        verbose= 1;
192        break;
193      case 2 : // --init
194        qinitmacro= true;
195        initFileName= optarg;
196        break;
197      case 3 : // --ofile
198        qfcout= true;
199        if(optarg) ofprefix= optarg;
200        break;
201      }
202      break;
203    case 'h' :
204      qhelp=1;
205      break;
206    case 'v' :
207      verbose= 1;
208      break;
209    case 'i' :
210      qinitmacro= true;
211      initFileName= optarg;
212      break;
213    case 'o' :
214      qfcout= true;
215      break;
216    default:
217      break;
218    }
219  }
220
221  // show help
222  if(qhelp) {
223    if(isMaster) ShowHelp();
224    MPI::Finalize();
225    exit(0);
226  }
227
228  // file output
229  if(isSlave && qfcout) {
230    G4String prefix= ofprefix+".%03d"+".cout";
231    char str[1024];
232    sprintf(str, prefix.c_str(), rank);
233    G4String fname(str);
234    fscout.open(fname.c_str(), std::ios::out);
235  }
236
237  // non-option ARGV-elements ...
238  if (optind < argc ) {
239    qbatchmode= true;
240    macroFileName= argv[optind];
241  }
242}
243
244
245//////////////////////////////////////////
246void G4MPImanager::Wait(G4int ausec) const
247//////////////////////////////////////////
248{
249  struct timespec treq, trem;
250  treq.tv_sec = 0;
251  treq.tv_nsec = ausec*1000;
252
253  nanosleep(&treq, &trem);
254}
255
256// ====================================================================
257
258/////////////////////////////////
259void G4MPImanager::UpdateStatus()
260/////////////////////////////////
261{
262  G4RunManager* runManager= G4RunManager::GetRunManager();
263  const G4Run* run= runManager-> GetCurrentRun();
264
265  G4int runid, eventid, neventTBP;
266
267  G4StateManager* stateManager= G4StateManager::GetStateManager();
268  G4ApplicationState g4state= stateManager-> GetCurrentState();
269
270  if (run) {
271    runid= run-> GetRunID();
272    neventTBP= run -> GetNumberOfEventToBeProcessed();
273    eventid= run-> GetNumberOfEvent();
274    if(g4state == G4State_GeomClosed || g4state == G4State_EventProc) {
275      status-> StopTimer();
276    }
277  } else {
278    runid= 0;
279    eventid= 0;
280    neventTBP= 0;
281  }
282
283  status-> SetStatus(rank, runid, neventTBP, eventid, g4state);
284}
285
286
287///////////////////////////////
288void G4MPImanager::ShowStatus()
289///////////////////////////////
290{
291  G4int buff[G4MPIstatus::NSIZE];
292
293  UpdateStatus();
294  G4bool gstatus= CheckThreadStatus();
295
296  if(isMaster) {
297    status-> Print();  // for maser itself
298
299    G4int nev= status-> GetEventID();
300    G4int nevtp= status-> GetNEventToBeProcessed();
301    G4double cputime= status-> GetCPUTime();
302
303    // receive from each slave
304    for (G4int islave=1; islave< size; islave++) {
305      COMM_G4COMMAND.Recv(buff, G4MPIstatus::NSIZE, MPI::INT,
306                          islave, TAG_G4STATUS);
307      status-> UnPack(buff);
308      status-> Print();
309
310      // aggregation
311      nev+= status-> GetEventID();
312      nevtp+= status-> GetNEventToBeProcessed();
313      cputime+= status-> GetCPUTime();
314    }
315
316    G4String strStatus;
317    if(gstatus) {
318      strStatus= "Run";
319    } else {
320      strStatus= "Idle";
321    }
322
323    G4cout << "-------------------------------------------------------"
324           << G4endl
325           << "* #ranks= " << size
326           << "   event= " << nev << "/" << nevtp
327           << " state= " << strStatus
328           << " time= " << cputime << "s"
329           << G4endl;
330  } else {
331    status-> Pack(buff);
332    COMM_G4COMMAND.Send(buff, G4MPIstatus::NSIZE, MPI::INT,
333                        RANK_MASTER, TAG_G4STATUS);
334  }
335}
336
337// ====================================================================
338
339////////////////////////////////////
340void G4MPImanager::DistributeSeeds()
341////////////////////////////////////
342{
343  std::vector<G4long> seedList= seedGenerator-> GetSeedList();
344  CLHEP::HepRandom::setTheSeed(seedList[rank]);
345}
346
347
348//////////////////////////////
349void G4MPImanager::ShowSeeds()
350//////////////////////////////
351{
352  G4long buff;
353
354  if(isMaster) {
355    // print master
356    G4cout << "* rank= " << rank
357           << " seed= " << CLHEP::HepRandom::getTheSeed()
358           << G4endl;
359    // receive from each slave
360    for (G4int islave=1; islave< size; islave++) {
361      COMM_G4COMMAND.Recv(&buff, 1, MPI::LONG, islave, TAG_G4SEED);
362      G4cout << "* rank= " << islave
363             << " seed= " << buff
364             << G4endl;
365    }
366  } else { // slaves
367    buff= CLHEP::HepRandom::getTheSeed();
368    COMM_G4COMMAND.Send(&buff, 1, MPI::LONG, RANK_MASTER, TAG_G4SEED);
369  }
370}
371
372
373////////////////////////////////////////////////////
374void G4MPImanager::SetSeed(G4int inode, G4long seed)
375////////////////////////////////////////////////////
376{
377  if(rank==inode) {
378    CLHEP::HepRandom::setTheSeed(seed);
379  }
380}
381
382// ====================================================================
383
384////////////////////////////////////////
385G4bool G4MPImanager::CheckThreadStatus()
386////////////////////////////////////////
387{
388  unsigned buff;
389  G4bool qstatus= false;
390
391  if(isMaster) {
392    qstatus= threadID;
393    // get slave status
394    for (G4int islave=1; islave< size; islave++) {
395      MPI::Request request= COMM_G4COMMAND.Irecv(&buff, 1, MPI::UNSIGNED,
396                                                 islave, TAG_G4STATUS);
397      MPI::Status status;
398      while(! request.Test(status)) {
399        Wait(100);
400      }
401      qstatus |= buff;
402    }
403  } else {
404    buff= unsigned(threadID);
405    COMM_G4COMMAND.Send(&buff, 1, MPI::UNSIGNED, RANK_MASTER, TAG_G4STATUS);
406  }
407
408  // broadcast
409  buff= qstatus; // for master
410  COMM_G4COMMAND.Bcast(&buff, 1, MPI::UNSIGNED, RANK_MASTER);
411  qstatus= buff; // for slave
412
413  return qstatus;
414}
415
416
417////////////////////////////////////////////////////////////////
418void G4MPImanager::ExecuteThreadCommand(const G4String& command)
419////////////////////////////////////////////////////////////////
420{
421  // this method is a thread function.
422  G4UImanager* UI= G4UImanager::GetUIpointer();
423  G4int rc= UI-> ApplyCommand(command);
424
425  G4int commandStatus = rc - (rc%100);
426
427  switch(commandStatus) {
428  case fCommandSucceeded:
429    break;
430  case fIllegalApplicationState:
431    G4cerr << "illegal application state -- command refused" << G4endl;
432    break;
433  default:
434    G4cerr << "command refused (" << commandStatus << ")" << G4endl;
435    break;
436  }
437
438  // thread is joined
439  if(threadID) {
440    pthread_join(threadID, 0);
441    threadID= 0;
442  }
443
444  return;
445}
446
447
448///////////////////////////////////////////////////////////////
449void G4MPImanager::ExecuteBeamOnThread(const G4String& command)
450///////////////////////////////////////////////////////////////
451{
452  G4bool threadStatus= CheckThreadStatus();
453
454  if (threadStatus) {
455    if(isMaster) {
456      G4cout << "G4MPIsession:: beamOn is still running." << G4endl;
457    }
458  } else { // ok
459    static G4String cmdstr;
460    cmdstr= command;
461    G4int rc= pthread_create(&threadID, 0,
462                             (Func_t)thread_ExecuteThreadCommand,
463                             (void*)&cmdstr);
464    if (rc != 0)
465      G4Exception("G4MPIsession:: failed to create a beamOn thread.");
466  }
467}
468
469
470/////////////////////////////////////
471void G4MPImanager::JoinBeamOnThread()
472/////////////////////////////////////
473{
474  if(threadID) {
475    pthread_join(threadID, 0);
476    threadID= 0;
477  }
478}
479
480
481// ====================================================================
482
483////////////////////////////////////////////////////////////
484G4String G4MPImanager::BcastCommand(const G4String& command)
485////////////////////////////////////////////////////////////
486{
487  enum { BUFF_SIZE= 512 };
488  static char sbuff[BUFF_SIZE];
489  command.copy(sbuff,BUFF_SIZE);
490  G4int len= command.size();
491  sbuff[len]='\0';   // no boundary check
492
493  // "command" is not yet fixed in slaves at this time.
494
495  // waiting message exhausts CPU in LAM!
496  //COMM_G4COMMAND.Bcast(sbuff, ssize, MPI::CHAR, RANK_MASTER);
497
498  // another implementation
499  if( isMaster ) {
500    for (G4int islave=1; islave< size; islave++) {
501      COMM_G4COMMAND.Send(sbuff, BUFF_SIZE, MPI::CHAR, islave, TAG_G4COMMAND);
502    }
503  } else {
504    // try non-blocking receive
505    MPI::Request request= COMM_G4COMMAND.Irecv(sbuff, BUFF_SIZE, MPI::CHAR,
506                                               RANK_MASTER, TAG_G4COMMAND);
507    // polling...
508    MPI::Status status;
509    while(! request.Test(status)) {
510      Wait(100);
511    }
512  }
513
514  return G4String(sbuff);
515}
516
517// ====================================================================
518
519/////////////////////////////////////////////////////////////////////////
520void G4MPImanager::ExecuteMacroFile(const G4String& fname, G4bool qbatch)
521/////////////////////////////////////////////////////////////////////////
522{
523  G4bool currentmode= qbatchmode;
524  qbatchmode= true;
525  G4MPIbatch* batchSession= new G4MPIbatch(fname, qbatch);
526  batchSession-> SessionStart();
527  delete batchSession;
528  qbatchmode= currentmode;
529}
530
531
532///////////////////////////////////////////////////////
533void G4MPImanager::BeamOn(G4int nevent, G4bool qdivide)
534///////////////////////////////////////////////////////
535{
536  G4RunManager* runManager= G4RunManager::GetRunManager();
537
538  if(qdivide) { // events are divided
539    G4double ntot= masterWeight+size-1.;
540    G4int nproc= G4int(nevent/ntot);
541    G4int nproc0= nevent-nproc*(size-1);
542
543    if(verbose>0 && isMaster) {
544      G4cout << "#events in master=" << nproc0 << " / "
545             << "#events in slave="  << nproc << G4endl;
546    }
547
548    status-> StartTimer(); // start timer
549    if(isMaster) runManager-> BeamOn(nproc0);
550    else runManager-> BeamOn(nproc);
551    status-> StopTimer(); // stop timer
552
553  } else { // same events are generated in each node (for test use)
554    if(verbose>0 && isMaster) {
555      G4cout << "#events in master=" << nevent << " / "
556             << "#events in slave="  << nevent << G4endl;
557    }
558    status-> StartTimer(); // start timer
559    runManager-> BeamOn(nevent);
560    status-> StopTimer(); // stop timer
561  }
562}
563
564///////////////////////////////
565void G4MPImanager::WaitBeamOn()
566///////////////////////////////
567{
568  G4int buff= 0;
569  if (qbatchmode) {  // valid only in batch mode
570    if(isMaster) {
571      // receive from each slave
572      for (G4int islave=1; islave< size; islave++) {
573        MPI::Request request= COMM_G4COMMAND.Irecv(&buff, 1, MPI::INT,
574                                                   islave, TAG_G4STATUS);
575        MPI::Status status;
576        while(! request.Test(status)) {
577           Wait(1000);
578        }
579      }
580    } else {
581      buff= 1;
582      COMM_G4COMMAND.Send(&buff, 1, MPI::INT, RANK_MASTER, TAG_G4STATUS);
583    }
584  }
585}
586
587/////////////////////////////////////////////////
588void G4MPImanager::Print(const G4String& message)
589/////////////////////////////////////////////////
590{
591  if(isMaster){
592    std::cout << message << std::flush;
593  } else {
594    if(qfcout) { // output to a file
595      fscout << message << std::flush;
596    } else { // output to stdout
597      std::cout << rank << ":" << message << std::flush;
598    }
599  }
600}
601
602
603///////////////////////////////////
604void G4MPImanager::ShowHelp() const
605///////////////////////////////////
606{
607  if(isSlave) return;
608
609  G4cout << "Geant4 MPI interface" << G4endl;
610  G4cout << "usage:" << G4endl;
611  G4cout << "<app> [options] [macro file]"
612         << G4endl << G4endl;
613  G4cout << "   -h, --help              show this message."
614         << G4endl;
615  G4cout << "   -v, --verbose           show verbose message"
616         << G4endl;
617  G4cout << "   -i, --init=FNAME        set an init macro file"
618         << G4endl;
619  G4cout << "   -o, --ofile[=FNAME]     set slave output to a flie"
620         << G4endl;
621  G4cout << G4endl;
622
623}
624
Note: See TracBrowser for help on using the repository browser.