Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
testTMPIFile.C
Go to the documentation of this file.
1/// \file
2/// \ingroup tutorial_io
3/// \notebook
4/// This macro shows the usage of TMPIFile to simulate event
5/// reconstruction and merging them in parallel.
6/// The JetEvent class is in $ROOTSYS/tutorials/io/tree/JetEvent.h,cxx
7///
8/// To run this macro do the following:
9/// ~~~{.bash}
10/// mpirun -np 4 root -b -l -q testTMPIFile.C
11/// ~~~
12///
13/// \macro_code
14///
15/// \author Taylor Childers, Yunsong Wang
16
17#include "TMPIFile.h"
18
19#ifdef TMPI_SECOND_RUN
20
21#include <chrono>
22#include <sstream>
23
24/* ---------------------------------------------------------------------------
25
26The idea of TMPIFile is to run N MPI ranks where some ranks are
27producing data (called workers), while other ranks are collecting data and
28writing it to disk (called collectors). The number of collectors can be
29configured and this should be optimized for each workflow and data size.
30
31This example uses a typical event processing loop, where every N events the
32TMPIFile::Sync() function is called. This call triggers the local TTree data
33to be sent via MPI to the collector rank where it is merged with all the
34other worker rank data and written to a TFile.
35
36An MPI Sub-Communictor is created for each collector which equally distributes
37the remaining ranks to distribute the workers among collectors.
38
39--------------------------------------------------------------------------- */
40
41void test_tmpi()
42{
43
44 Int_t N_collectors = 2; // specify how many collectors to run
45 Int_t sync_rate = 2; // workers sync every sync_rate events
46 Int_t events_per_rank = 6; // total events each rank will produce then exit
47 Int_t sleep_mean = 5; // simulate compute time for event processing
48 Int_t sleep_sigma = 2; // variation in compute time
49
50 // using JetEvent generator to create a data structure
51 // these parameters control this generator
52 Int_t jetm = 25;
53 Int_t trackm = 60;
54 Int_t hitam = 200;
55 Int_t hitbm = 100;
56
57 std::string treename = "test_tmpi";
58 std::string branchname = "event";
59
60 // set output filename
61 std::stringstream smpifname;
62 smpifname << "/tmp/merged_output_" << getpid() << ".root";
63
64 // Create new TMPIFile, passing the filename, setting read/write permissions
65 // and setting the number of collectors.
66 // If MPI_INIT has not been called already, the constructor of TMPIFile
67 // will call this.
68 TMPIFile *newfile = new TMPIFile(smpifname.str().c_str(), "RECREATE", N_collectors);
69 // set random number seed that is based on MPI rank
70 // this avoids producing the same events in each MPI rank
71 gRandom->SetSeed(gRandom->GetSeed() + newfile->GetMPIGlobalRank());
72
73 // only print log messages in MPI Rank 0
74 if (newfile->GetMPIGlobalRank() == 0) {
75 Info("test_tmpi", " running with parallel ranks: %d", newfile->GetMPIGlobalSize());
76 Info("test_tmpi", " running with collecting ranks: %d", N_collectors);
77 Info("test_tmpi", " running with working ranks: %d", (newfile->GetMPIGlobalSize() - N_collectors));
78 Info("test_tmpi", " running with sync rate: %d", sync_rate);
79 Info("test_tmpi", " running with events per rank: %d", events_per_rank);
80 Info("test_tmpi", " running with sleep mean: %d", sleep_mean);
81 Info("test_tmpi", " running with sleep sigma: %d", sleep_sigma);
82 Info("test_tmpi", " running with seed: %d", gRandom->GetSeed());
83 }
84
85 // print filename for each collector Rank
86 if (newfile->IsCollector()) {
87 Info("Collector", "[%d]\troot output filename = %s", newfile->GetMPIGlobalRank(), smpifname.str().c_str());
88 }
89
90 // This if statement splits the run-time functionality of
91 // workers and collectors.
92 if (newfile->IsCollector()) {
93 // Run by collector ranks
94 // This will run until all workers have exited
95 newfile->RunCollector();
96 } else {
97 // Run by worker ranks
98 // these ranks generate data to be written to TMPIFile
99
100 // create a TTree to store event data
101 treename.c_str(), "Event example with Jets");
102 // set the AutoFlush rate to be the same as the sync_rate
103 // this synchronizes the TTree branch compression
104 sync_rate);
105
106 // Create our fake event data generator
107 JetEvent *event = new JetEvent;
108
109 // add our branch to the TTree
110 branchname.c_str(), "JetEvent", &event, 8000, 2);
111
112 // monitor timing
113 auto sync_start = std::chrono::high_resolution_clock::now();
114
115 // generate the specified number of events
116 for (int i = 0; i < events_per_rank; i++) {
117
118 auto start = std::chrono::high_resolution_clock::now();
119 // Generate one event
120 event->Build(jetm, trackm, hitam, hitbm);
121
122 auto evt_built = std::chrono::high_resolution_clock::now();
123 double start).count();
124
125 Info("Rank", "[%d] [%d]\tevt = %d;\tbuild_time = %f", newfile->GetMPIColor(), newfile->GetMPILocalRank(), i,
126 build_time);
127
128 // if our build time was significant, subtract that from the sleep time
131
132 // simulate the time taken by more complicated event generation
133 std::this_thread::sleep_for(std::chrono::seconds(int(sleep)));
134
135 // Fill the tree
136 tree->Fill();
137
138 // every sync_rate events, call the TMPIFile::Sync() function
139 // to trigger MPI collection of local data
140 if ((i + 1) % sync_rate == 0) {
141 // call TMPIFile::Sync()
142 newfile->Sync();
143
144 auto end = std::chrono::high_resolution_clock::now();
145 double sync_start).count();
146 Info("Rank", "[%d] [%d]\tevent collection time: %f", newfile->GetMPIColor(), newfile->GetMPILocalRank(),
147 sync_time);
148 sync_start = std::chrono::high_resolution_clock::now();
149 }
150 }
151
152 // synchronize any left over events
153 if (events_per_rank % sync_rate != 0) {
154 newfile->Sync();
155 }
156 }
157
158 // call Close on the file for clean exit.
159 Info("Rank", "[%d] [%d]\tclosing file", newfile->GetMPIColor(), newfile->GetMPILocalRank());
160 newfile->Close();
161
162 // open file and test contents
163 if (newfile->GetMPILocalRank() == 0) {
164 TString filename = newfile->GetMPIFilename();
165 Info("Rank", "[%d] [%d]\topening file: %s", newfile->GetMPIColor(), newfile->GetMPILocalRank(), filename.Data());
166 TFile file(filename.Data());
167 if (file.IsOpen()) {
168 file.ls();
169 treename.c_str());
170 if (tree)
171 tree->Print();
172
173 Info("Rank", "[%d] [%d]\tfile should have %d events and has %lld", newfile->GetMPIColor(),
174 tree->GetEntries());
175 }
176 }
177}
178
180{
181 auto start = std::chrono::high_resolution_clock::now();
182
183 test_tmpi();
184
185 auto end = std::chrono::high_resolution_clock::now();
186 double time = std::chrono::duration_cast<std::chrono::duration<double>>(start).count();
187 std::string msg = "Total elapsed time: ";
188 msg += std::to_string(time);
189 Info("testTMPIFile", "%s", msg.c_str());
190 Info("testTMPIFile", "exiting");
191}
192
193#else
194
195void testTMPIFile()
196{
197 Int_t flag;
199 if (!flag) {
201 }
202
203 // Get rank and size
204 Int_t rank, size;
207
208
209 // Procecss 0 generates JetEvent library
210 if (rank == 0) {
211 TString tutdir = gROOT->GetTutorialDir();
212 gSystem->Exec("cp " + tutdir + "/tree/JetEvent* .");
213 gROOT->ProcessLine(".L JetEvent.cxx+");
214 }
215 // Wait until it's done
217
218 gROOT->ProcessLine("#define TMPI_SECOND_RUN yes");
219 gROOT->ProcessLine("#include \"" __FILE__ "\"");
220 gROOT->ProcessLine("testTMPIFile(true)");
221
222 // TMPIFile will do MPI_Finalize() when closing the file
223 Int_t finalized = 0;
225 if (!finalized) {
226 MPI_Finalize();
227 }
228}
229
230#endif
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Definition RtypesCore.h:63
int Int_t
Definition RtypesCore.h:45
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
R__EXTERN C unsigned int sleep(unsigned int seconds)
#define gROOT
Definition TROOT.h:414
R__EXTERN TRandom * gRandom
Definition TRandom.h:62
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:131
virtual Double_t Gaus(Double_t mean=0, Double_t sigma=1)
Samples a random number from the standard Normal (Gaussian) Distribution with the given mean and sigm...
Definition TRandom.cxx:275
virtual void SetSeed(ULong_t seed=0)
Set the random generator seed.
Definition TRandom.cxx:615
virtual UInt_t GetSeed() const
Get the random generator seed.
Definition TRandom.cxx:651
Basic string class.
Definition TString.h:139
virtual Int_t Exec(const char *shellcmd)
Execute a command.
Definition TSystem.cxx:653
A TTree represents a columnar dataset.
Definition TTree.h:84
RVec< PromoteType< T > > abs(const RVec< T > &v)
Definition RVec.hxx:1833
std::ostream & Info()
Definition hadd.cxx:171