#include "moab/MOABConfig.h"
#include "moab/TupleList.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/ErrorHandler.hpp"
#include <ctime>
#include <iostream>
#include <sstream>
Go to the source code of this file.
Functions | |
int | main (int argc, char **argv) |
Variables | |
const char | BRIEF_DESC [] = "Example of gather scatter with tuple lists \n" |
std::ostringstream | LONG_DESC |
int main | ( | int | argc, |
char ** | argv | ||
) |
Definition at line 62 of file CrystalRouterExample.cpp.
63 {
64 #ifdef MOAB_HAVE_MPI
65 MPI_Init( &argc, &argv );
66
67 // Initialize error handler, required for this example (not using a moab instance)
68 MBErrorHandler_Init();
69
70 ProcConfig pc( MPI_COMM_WORLD );
71 int size = pc.proc_size();
72 int rank = pc.proc_rank();
73
74 // Start copy
75 LONG_DESC << "This program does a gather scatter with a list of tuples. \n"
76 " It tries to see how much communication costs in terms of time and memory. \n"
77 << "It starts with creating a list of tuples to be sent from each processor, \n to a "
78 "list of other processors.\n"
79 << "The number of tuples and how many tasks to communicate to are controlled by "
80 "input parameters.\n"
81 << "After communication, we verify locally if we received what we expected. \n";
82 ProgOptions opts( LONG_DESC.str(), BRIEF_DESC );
83
84 // How many procs communicate to current proc, on average (we will vary that too)
85 int num_comms = 2;
86 opts.addOpt< int >( "num_comms,n", "each task will send to about num_comms other tasks some tuples (default 2)",
87 &num_comms );
88
89 int num_tuples = 4;
90 opts.addOpt< int >( "num_tuples,t", "each task will send to some task about num_tuples tuples (default 4)",
91 &num_tuples );
92
93 int reportrank = size + 1;
94 opts.addOpt< int >( "reporting_rank,r",
95 "this rank will report the tuples sent and the tuples received; it could "
96 "be higher than num_procs, then no reporting",
97 &reportrank );
98
99 opts.parseCommandLine( argc, argv );
100
101 if( rank == reportrank || ( reportrank >= size && 0 == rank ) )
102 {
103 cout << " There are " << size << " tasks in example.\n";
104 cout << " We will send groups of " << num_tuples << " from each task towards " << num_comms
105 << " other tasks.\n";
106 }
107
108 // Send some data from proc i to i + n/2, also to i + n/2 + 1 modulo n, where n is num procs
109
110 gs_data::crystal_data* cd = pc.crystal_router();
111
112 long total_n_tuples = num_comms * num_tuples;
113
114 // Vary the number of tasks to send to, and the number of tuples to send
115 if( rank < size / 2 )
116 num_comms--;
117 else
118 num_comms++;
119
120 if( rank < size / 3 )
121 num_tuples *= 2;
122 else if( rank > size - size / 3 )
123 num_tuples /= 2;
124
125 TupleList tl;
126 // At most num_tuples* num_comms to send
127 // We do a preallocate with this; some tuples on some processors might need more memory, to be
128 // able to grow locally; Some tasks might receive more tuples though, and in the process, some
129 // might grow more than others. By doing these logP sends/receives, we do not grow local memory
130 // too much.
131 tl.initialize( 1, 1, 0, 1, num_tuples * num_comms );
132 tl.enableWriteAccess();
133 // Form num_tuples*num_comms tuples, send to various ranks
134 unsigned int n = tl.get_n();
135 for( int i = 0; i < num_comms; i++ )
136 {
137 int sendTo = rank + i * size / 2 + 1; // Spread out the send to, for a stress-like test
138 sendTo = sendTo % size; //
139 long intToSend = 1000 * rank + 100000 * sendTo;
140 for( int j = 0; j < num_tuples; j++ )
141 {
142 n = tl.get_n();
143 tl.vi_wr[n] = sendTo;
144 tl.vl_wr[n] = intToSend + j;
145 tl.vr_wr[n] = 10000. * rank + j;
146 tl.inc_n();
147 }
148 }
149
150 if( rank == reportrank )
151 {
152 cout << "rank " << rank << "\n";
153 tl.print( " before sending" );
154 }
155
156 clock_t tt = clock();
157 // All communication happens here; no mpi calls for the user
158 ErrorCode rval = cd->gs_transfer( 1, tl, 0 );MB_CHK_SET_ERR( rval, "Error in tuple transfer" );
159
160 double secs = 0;
161 if( rank == reportrank || ( reportrank >= size && 0 == rank ) )
162 {
163 secs = ( clock() - tt ) / (double)CLOCKS_PER_SEC;
164 }
165 if( rank == reportrank )
166 {
167 cout << "rank " << rank << "\n";
168 tl.print( " after transfer" );
169 }
170
171 // Check that all tuples received have the form 10000*rank + 100*from
172 unsigned int received = tl.get_n();
173 for( int i = 0; i < (int)received; i++ )
174 {
175 int from = tl.vi_rd[i];
176 long valrec = tl.vl_rd[i];
177 int remainder = valrec - 100000 * rank - 1000 * from;
178 if( remainder < 0 || remainder >= num_tuples * 4 )
179 cout << " error: tuple " << i << " received at proc rank " << rank << " from proc " << from << " has value "
180 << valrec << " remainder " << remainder << "\n";
181 }
182
183 if( rank == reportrank || ( reportrank >= size && 0 == rank ) )
184 {
185 cout << "communication of about " << total_n_tuples << " tuples/per proc took " << secs << " seconds"
186 << "\n";
187 tt = clock();
188 }
189
190 // Finalize error handler, required for this example (not using a moab instance)
191 MBErrorHandler_Finalize();
192
193 MPI_Finalize();
194 #else
195 std::cout << " Build with MPI for this example to work\n";
196 #endif
197
198 return 0;
199 }
References ProgOptions::addOpt(), BRIEF_DESC, moab::ProcConfig::crystal_router(), moab::TupleList::enableWriteAccess(), ErrorCode, moab::TupleList::get_n(), moab::TupleList::inc_n(), moab::TupleList::initialize(), LONG_DESC, MB_CHK_SET_ERR, moab::MBErrorHandler_Finalize(), moab::MBErrorHandler_Init(), ProgOptions::parseCommandLine(), moab::TupleList::print(), moab::ProcConfig::proc_rank(), moab::ProcConfig::proc_size(), size, moab::TupleList::vi_rd, moab::TupleList::vi_wr, moab::TupleList::vl_rd, moab::TupleList::vl_wr, and moab::TupleList::vr_wr.
const char BRIEF_DESC[] = "Example of gather scatter with tuple lists \n" |
Definition at line 56 of file CrystalRouterExample.cpp.
Referenced by main().
std::ostringstream LONG_DESC |
Definition at line 57 of file CrystalRouterExample.cpp.
Referenced by main().