Zoltan2
Loading...
Searching...
No Matches
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
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
28typedef Tpetra::CrsGraph<zlno_t, zgno_t, znode_t> tcrsGraph_t;
29typedef Tpetra::MultiVector<zscalar_t, zlno_t, zgno_t, znode_t> tMVector_t;
31
32
33int 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
Tpetra::Map ::node_type mytest_znode_t
Zoltan2::XpetraCrsGraphAdapter< tcrsGraph_t, tMVector_t > my_adapter_t
Defines the PartitioningProblem class.
common code used by tests
float zscalar_t
Tpetra::Map ::local_ordinal_type zlno_t
Tpetra::Map ::global_ordinal_type zgno_t
Defines XpetraCrsGraphAdapter class.
Defines the XpetraMultiVectorAdapter.
int main()
typename InputTraits< User >::part_t part_t
void getProcTask(part_t *&proc_to_task_xadj_, part_t *&proc_to_task_adj_)
part_t getAssignedProcForTask(part_t taskId)
getAssignedProcForTask function, returns the assigned processor id for the given task
A class that computes and returns quality metrics.
MachineRepresentation Class Base class for representing machine coordinates, networks,...
bool getAllMachineCoordinatesView(pcoord_t **&allCoords) const
getProcDim function set the coordinates of all ranks allCoords[i][j], i=0,...,getMachineDim(),...
int getMachineDim() const
returns the dimension (number of coords per node) in the machine
bool getMachineExtent(int *nxyz) const
sets the number of unique coordinates in each machine dimension
bool getMachineExtentWrapArounds(bool *wrap_around) const
if the machine has a wrap-around tourus link in each dimension.
bool getHopCount(int rank1, int rank2, pcoord_t &hops) const
return the hop count between rank1 and rank2
PartitioningProblem sets up partitioning problems for the user.
Provides access for Zoltan2 to Xpetra::CrsGraph data.
Tpetra::Map map_t
Tpetra::MultiVector< zscalar_t, zlno_t, zgno_t, znode_t > tMVector_t
Tpetra::CrsGraph< zlno_t, zgno_t, znode_t > tcrsGraph_t
SparseMatrixAdapter_t::part_t part_t
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t