Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
TaskMappingTest.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Zoltan2_TaskMapping.hpp"
12 #include <Zoltan2_TestHelpers.hpp>
13 
14 #include <string>
15 
16 #include <Teuchos_RCP.hpp>
17 #include <Teuchos_Array.hpp>
18 #include <Teuchos_ParameterList.hpp>
19 #include "Teuchos_XMLParameterListHelpers.hpp"
20 
21 #include "Tpetra_MultiVector.hpp"
22 #include <Tpetra_CrsGraph.hpp>
23 #include <Tpetra_Map.hpp>
24 
27 
28 typedef Tpetra::CrsGraph<zlno_t, zgno_t, znode_t> tcrsGraph_t;
29 typedef Tpetra::MultiVector<zscalar_t, zlno_t, zgno_t, znode_t> tMVector_t;
31 
32 
33 int main(int narg, char *arg[]) {
34 
35  Tpetra::ScopeGuard tscope(&narg, &arg);
36  Teuchos::RCP<const Teuchos::Comm<int> > tcomm = Tpetra::getDefaultComm();
37 
39 
40  int nx = 2, ny = 2, nz = 2;
41  for (int i = 1 ; i < narg ; ++i) {
42  if (0 == strcasecmp( arg[i] , "NX")) {
43  nx = atoi( arg[++i] );
44  }
45  else if (0 == strcasecmp( arg[i] , "NY")) {
46  ny = atoi( arg[++i] );
47  }
48  else if (0 == strcasecmp( arg[i] , "NZ")) {
49  nz = atoi( arg[++i] );
50  }
51  else{
52  std::cerr << "Unrecognized command line argument #"
53  << i << ": " << arg[i] << std::endl ;
54  return 1;
55  }
56  }
57 
58  try{
59 
60  int rank = tcomm->getRank();
61  part_t numProcs = tcomm->getSize();
62 
63  int coordDim = 3;
64  zgno_t numGlobalTasks = nx*ny*nz;
65 
66  zgno_t myTasks = numGlobalTasks / numProcs;
67  zgno_t taskLeftOver = numGlobalTasks % numProcs;
68  if (rank < taskLeftOver ) ++myTasks;
69 
70  zgno_t myTaskBegin = (numGlobalTasks / numProcs) * rank;
71  myTaskBegin += (taskLeftOver < rank ? taskLeftOver : rank);
72  zgno_t myTaskEnd = myTaskBegin + myTasks;
73 
74  zscalar_t **partCenters = NULL;
75  partCenters = new zscalar_t * [coordDim];
76  for(int i = 0; i < coordDim; ++i) {
77  partCenters[i] = new zscalar_t[myTasks];
78  }
79 
80  zgno_t *task_gnos = new zgno_t [myTasks];
81  zlno_t *task_communication_xadj_ = new zlno_t [myTasks + 1];
82  zgno_t *task_communication_adj_ = new zgno_t [myTasks * 6];
83 
84  zlno_t prevNCount = 0;
85  task_communication_xadj_[0] = 0;
86  for (zlno_t i = myTaskBegin; i < myTaskEnd; ++i) {
87  task_gnos[i - myTaskBegin] = i;
88 
89  zlno_t x = i % nx;
90  zlno_t y = (i / (nx)) % ny;
91  zlno_t z = (i / (nx)) / ny;
92  partCenters[0][i - myTaskBegin] = x;
93  partCenters[1][i - myTaskBegin] = y;
94  partCenters[2][i - myTaskBegin] = z;
95 
96  if (x > 0) {
97  task_communication_adj_[prevNCount++] = i - 1;
98  }
99  if (x < nx - 1) {
100  task_communication_adj_[prevNCount++] = i + 1;
101  }
102  if (y > 0) {
103  task_communication_adj_[prevNCount++] = i - nx;
104  }
105  if (y < ny - 1) {
106  task_communication_adj_[prevNCount++] = i + nx;
107  }
108  if (z > 0) {
109  task_communication_adj_[prevNCount++] = i - nx * ny;
110  }
111  if (z < nz - 1) {
112  task_communication_adj_[prevNCount++] = i + nx * ny;
113  }
114  task_communication_xadj_[i + 1 - myTaskBegin] = prevNCount;
115  }
116  using namespace Teuchos;
117  RCP<my_adapter_t> ia;
118  typedef Tpetra::Map<>::node_type mytest_znode_t;
119  typedef Tpetra::Map<zlno_t, zgno_t, mytest_znode_t> map_t;
120  RCP<const map_t> map =
121  rcp(new map_t (numGlobalTasks, myTasks, 0, tcomm));
122 
123  Teuchos::Array<size_t> adjPerTask(myTasks);
124  for (zlno_t lclRow = 0; lclRow < myTasks; lclRow++)
125  adjPerTask[lclRow] = task_communication_xadj_[lclRow+1]
126  - task_communication_xadj_[lclRow];
127  RCP<tcrsGraph_t> TpetraCrsGraph(new tcrsGraph_t (map, adjPerTask()));
128 
129  for (zlno_t lclRow = 0; lclRow < myTasks; ++lclRow) {
130  const zgno_t gblRow = map->getGlobalElement (lclRow);
131  zgno_t begin = task_communication_xadj_[lclRow];
132  zgno_t end = task_communication_xadj_[lclRow + 1];
133  const ArrayView< const zgno_t > indices(task_communication_adj_ + begin,
134  end - begin);
135  TpetraCrsGraph->insertGlobalIndices(gblRow, indices);
136  }
137  TpetraCrsGraph->fillComplete ();
138  RCP<const tcrsGraph_t> const_data =
139  rcp_const_cast<const tcrsGraph_t>(TpetraCrsGraph);
140 
141  ia = RCP<my_adapter_t> (new my_adapter_t(const_data));
142 
143  const int coord_dim = 3;
144  Teuchos::Array<Teuchos::ArrayView<const zscalar_t> > coordView(coord_dim);
145 
146  if(myTasks > 0) {
147  Teuchos::ArrayView<const zscalar_t> a(partCenters[0], myTasks);
148  coordView[0] = a;
149  Teuchos::ArrayView<const zscalar_t> b(partCenters[1], myTasks);
150  coordView[1] = b;
151  Teuchos::ArrayView<const zscalar_t> c(partCenters[2], myTasks);
152  coordView[2] = c;
153  }
154  else {
155  Teuchos::ArrayView<const zscalar_t> a;
156  coordView[0] = a;
157  coordView[1] = a;
158  coordView[2] = a;
159  }
160  RCP<tMVector_t> coords(new tMVector_t(map, coordView.view(0, coord_dim),
161  coord_dim));//= set multivector;
162  RCP<const tMVector_t> const_coords =
163  rcp_const_cast<const tMVector_t>(coords);
164  RCP <Zoltan2::XpetraMultiVectorAdapter<tMVector_t> > adapter(
166  ia->setCoordinateInput(adapter.getRawPtr());
167 
168 // return ia;
169 
170  // Create input adapter
171 // RCP<my_adapter_t> ia = create_problem(tcomm, nx, ny, nz);
172 
173  // Create partitioning problem
174  // xpetra_graph problem type
175  typedef Zoltan2::PartitioningProblem<my_adapter_t> xcrsGraph_problem_t;
177  ParameterList zoltan2_parameters;
178  zoltan2_parameters.set("compute_metrics", true); // bool parameter
179  zoltan2_parameters.set("imbalance_tolerance", 1.0);
180  zoltan2_parameters.set("num_global_parts", tcomm->getSize());
181  zoltan2_parameters.set("algorithm", "multijagged");
182  zoltan2_parameters.set("mj_keep_part_boxes", false); // bool parameter
183  zoltan2_parameters.set("mj_recursion_depth", 3);
184 
185  RCP<xcrsGraph_problem_t> partition_problem;
186  partition_problem =
187  RCP<xcrsGraph_problem_t> (new xcrsGraph_problem_t(
188  ia.getRawPtr(),&zoltan2_parameters,tcomm));
189 
190  // Solve the partitioning problem.
191  partition_problem->solve();
192  tcomm->barrier();
193  RCP<const Zoltan2::Environment> env = partition_problem->getEnvironment();
194 
195  RCP<quality_t>metricObject =
196  rcp(new quality_t(ia.getRawPtr(), &zoltan2_parameters, tcomm,
197  &partition_problem->getSolution()));
198 
199  if (tcomm->getRank() == 0) {
200  metricObject->printMetrics(std::cout);
201  }
202  partition_problem->printTimers();
203 
204  part_t *proc_to_task_xadj_ = NULL;
205  part_t *proc_to_task_adj_ = NULL;
206 
207  // Create the zoltan2 machine representation object
209 
210  // Create the mapper and map the partitioning solution.
212  tcomm,
213  Teuchos::rcpFromRef(mach),
214  ia,
215  rcpFromRef(partition_problem->getSolution()),
216  env);
217 
218  // Get the results and print
219  ctm.getProcTask(proc_to_task_xadj_, proc_to_task_adj_);
220 // part_t numProcs = tcomm->getSize();
221  if (tcomm->getRank() == 0) {
222  for (part_t i = 0; i < numProcs; ++i) {
223  std::cout << "\nProc i:" << i << " ";
224  for (part_t j = proc_to_task_xadj_[i];
225  j < proc_to_task_xadj_[i + 1]; ++j) {
226  std::cout << " " << proc_to_task_adj_[j];
227  }
228  }
229  std::cout << std::endl;
230  }
231 
232  // Below is to calculate the result hops. this uses the global graph
233  // also this is used for debug, as the hops are also calculated in mapper.
234  {
235  zlno_t prevNCount_tmp = 0;
236  zgno_t *task_communication_adj_tmp = new zgno_t [numGlobalTasks * 6];
237  zlno_t *task_communication_xadj_tmp = new zlno_t [numGlobalTasks + 1];
238  task_communication_xadj_tmp[0] = 0;
239 
240  for (zlno_t i = 0; i < numGlobalTasks; ++i) {
241  zlno_t x = i % nx;
242  zlno_t y = (i / (nx)) % ny;
243  zlno_t z = (i / (nx)) / ny;
244 
245  if (x > 0) {
246  task_communication_adj_tmp[prevNCount_tmp++] = i - 1;
247  }
248  if (x < nx - 1) {
249  task_communication_adj_tmp[prevNCount_tmp++] = i + 1;
250  }
251  if (y > 0) {
252  task_communication_adj_tmp[prevNCount_tmp++] = i - nx;
253  }
254  if (y < ny - 1) {
255  task_communication_adj_tmp[prevNCount_tmp++] = i + nx;
256  }
257  if (z > 0) {
258  task_communication_adj_tmp[prevNCount_tmp++] = i - nx * ny;
259  }
260  if (z < nz - 1) {
261  task_communication_adj_tmp[prevNCount_tmp++] = i + nx * ny;
262  }
263  task_communication_xadj_tmp[i + 1] = prevNCount_tmp;
264  }
265 
266  int mach_coord_dim = mach.getMachineDim();
267  std::vector <int> mach_extent(mach_coord_dim);
268  mach.getMachineExtent(&(mach_extent[0]));
269 
270  std::vector <part_t> all_parts(numGlobalTasks), copy(numGlobalTasks, 0);
271 
272  const part_t *parts =
273  partition_problem->getSolution().getPartListView();
274 
275 // typedef Tpetra::Map<>::node_type mytest_znode_t;
276 // typedef Tpetra::Map<zlno_t, zgno_t, mytest_znode_t> map_t;
277 // RCP<const map_t> map =
278 // rcp(new map_t (numGlobalTasks, myTasks, 0, tcomm));
279 
280  for (part_t i = 0; i < myTasks; ++i) {
281  zgno_t g = map->getGlobalElement(i);
282  copy[g] = parts[i];
283  }
284 
285  reduceAll<int, part_t>(
286  *tcomm,
287  Teuchos::REDUCE_SUM,
288  numGlobalTasks,
289  &(copy[0]),
290  &(all_parts[0])
291  );
292 
293  zscalar_t **proc_coords;
294  mach.getAllMachineCoordinatesView(proc_coords);
295  part_t hops=0;
296  part_t hops2 = 0;
297  int *machine_extent = new int [mach_coord_dim];
298  bool *machine_extent_wrap_around = new bool[mach_coord_dim];
299 
300  // Adding this to avoid uninitialized memory read below
301  for(int n = 0; n < mach_coord_dim; ++n) {
302  machine_extent_wrap_around[n] = false;
303  }
304 
305  mach.getMachineExtent(machine_extent);
306  mach.getMachineExtentWrapArounds(machine_extent_wrap_around);
307 
308  for (zlno_t i = 0; i < numGlobalTasks; ++i) {
309  zlno_t b = task_communication_xadj_tmp[i];
310  zlno_t e = task_communication_xadj_tmp[i + 1];
311 
312  part_t procId1 = ctm.getAssignedProcForTask(all_parts[i]);
313 
314  for (zlno_t j = b; j < e; ++j) {
315  zgno_t n = task_communication_adj_tmp[j];
316  part_t procId2 = ctm.getAssignedProcForTask(all_parts[n]);
317 
318  zscalar_t distance2 = 0;
319  mach.getHopCount(procId1, procId2, distance2);
320 
321  hops2 += distance2;
322  for (int k = 0 ; k < mach_coord_dim ; ++k){
323  part_t distance = std::abs(proc_coords[k][procId1] - proc_coords[k][procId2]);
324  if (machine_extent_wrap_around[k]){
325  if (machine_extent[k] - distance < distance){
326  distance = machine_extent[k] - distance;
327  }
328  }
329  hops += distance;
330  }
331  }
332  }
333  delete [] machine_extent_wrap_around;
334  delete [] machine_extent;
335 
336  if (tcomm->getRank() == 0)
337  std::cout << "HOPS:" << hops << " HOPS2:" << hops2 << std::endl;
338 
339  delete [] task_communication_xadj_tmp;
340  delete [] task_communication_adj_tmp;
341  }
342  /*
343  part_t *machineDimensions = NULL;
344  //machineDimensions = hopper;
345  Zoltan2::coordinateTaskMapperInterface<part_t, zscalar_t, zscalar_t>(
346  tcomm,
347  procDim,
348  numProcs,
349  procCoordinates,
350 
351  coordDim,
352  numGlobalTasks,
353  partCenters,
354 
355  task_communication_xadj_,
356  task_communication_adj_,
357  NULL,
358 
359  proc_to_task_xadj_,
360  proc_to_task_adj_,
361 
362  partArraysize,
363  partArray,
364  machineDimensions
365  );
366  */
367 
368  if (tcomm->getRank() == 0) {
369  std::cout << "PASS" << std::endl;
370  }
371 
372 
373  for (int i = 0; i < coordDim; i++) delete [] partCenters[i];
374  delete [] partCenters;
375 
376  }
377  catch(std::string &s) {
378  std::cerr << s << std::endl;
379  }
380 
381  catch(char * s) {
382  std::cerr << s << std::endl;
383  }
384 }
385 
Zoltan2::XpetraCrsGraphAdapter< tcrsGraph_t, tMVector_t > my_adapter_t
bool getHopCount(int rank1, int rank2, pcoord_t &hops) const
return the hop count between rank1 and rank2
Provides access for Zoltan2 to Xpetra::CrsGraph data.
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t
int main(int narg, char **arg)
Definition: coloring1.cpp:164
common code used by tests
typename InputTraits< User >::part_t part_t
Tpetra::Map::node_type mytest_znode_t
part_t getAssignedProcForTask(part_t taskId)
getAssignedProcForTask function, returns the assigned processor id for the given task ...
Defines the XpetraMultiVectorAdapter.
Defines XpetraCrsGraphAdapter class.
SparseMatrixAdapter_t::part_t part_t
int getMachineDim() const
returns the dimension (number of coords per node) in the machine
bool getAllMachineCoordinatesView(pcoord_t **&allCoords) const
getProcDim function set the coordinates of all ranks allCoords[i][j], i=0,...,getMachineDim(), j=0,...,getNumRanks(), is the i-th dimensional coordinate for rank j. return true if coordinates are available for all ranks
void getProcTask(part_t *&proc_to_task_xadj_, part_t *&proc_to_task_adj_)
bool getMachineExtentWrapArounds(bool *wrap_around) const
if the machine has a wrap-around tourus link in each dimension.
Tpetra::Map map_t
Definition: mapRemotes.cpp:25
An adapter for Xpetra::MultiVector.
MachineRepresentation Class Base class for representing machine coordinates, networks, etc.
Tpetra::Map::local_ordinal_type zlno_t
Tpetra::CrsGraph< zlno_t, zgno_t, znode_t > tcrsGraph_t
PartitioningProblem sets up partitioning problems for the user.
Defines the PartitioningProblem class.
A class that computes and returns quality metrics.
float zscalar_t
Tpetra::MultiVector< zscalar_t, zlno_t, zgno_t, znode_t > tMVector_t
bool getMachineExtent(int *nxyz) const
sets the number of unique coordinates in each machine dimension
Tpetra::Map::global_ordinal_type zgno_t