1 /* 2 Build a few basic tools to help with partitioned domains. 3 4 1) 5 On each processor, have a DomainExchangerTopology. 6 This is a doubly-connected edge list which enumerates the 7 communication paths between connected processors. By numbering 8 these paths we can always uniquely assign message identifiers. 9 10 edge 11 10 12 proc ---------> proc 13 0 <-------- 1 14 11 15 twin 16 17 Eg: Proc 0 send to proc 1 with message id is 10. To receive the correct 18 message, proc 1 looks for the edge connected to proc 0, and then the 19 message id comes from the twin of that edge 20 21 2) 22 A DomainExchangerArrayPacker. 23 A little function which given a piece of data, will memcpy the data into 24 an array (which will be sent to procs) into the correct place. 25 26 On Proc 1 we sent data to procs 0,2,3. The data is on different lengths. 27 All data gets jammed into single array. Need to "jam" data into correct locations 28 The Packer knows how much is to going to each processor and keeps track of the inserts 29 so as to avoid ever packing TOO much into one slot, and inevatbly corrupting some memory 30 31 data to 0 data to 2 data to 3 32 33 |--------|-----------------|--| 34 35 User has to unpack message themselves. I can get you the pointer for each i 36 entry, but you'll have to cast it to the appropriate data type. 37 38 Phase A: Build topology 39 40 Phase B: Define message lengths 41 42 Phase C: Pack data 43 44 Phase D: Send data 45 46 + Constructor 47 DMSwarmDataExCreate() 48 + Phase A 49 DMSwarmDataExTopologyInitialize() 50 DMSwarmDataExTopologyAddNeighbour() 51 DMSwarmDataExTopologyAddNeighbour() 52 DMSwarmDataExTopologyFinalize() 53 + Phase B 54 DMSwarmDataExZeroAllSendCount() 55 DMSwarmDataExAddToSendCount() 56 DMSwarmDataExAddToSendCount() 57 DMSwarmDataExAddToSendCount() 58 + Phase C 59 DMSwarmDataExPackInitialize() 60 DMSwarmDataExPackData() 61 DMSwarmDataExPackData() 62 DMSwarmDataExPackFinalize() 63 +Phase D 64 DMSwarmDataExBegin() 65 ... perform any calculations ... 66 DMSwarmDataExEnd() 67 68 ... user calls any getters here ... 69 70 */ 71 #include <petscvec.h> 72 #include <petscmat.h> 73 #include <petsc/private/petscimpl.h> 74 75 #include "../src/dm/impls/swarm/data_ex.h" 76 77 const char *status_names[] = {"initialized", "finalized", "unknown"}; 78 79 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerTopologySetup; 80 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerBegin; 81 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerEnd; 82 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerSendCount; 83 PETSC_EXTERN PetscLogEvent DMSWARM_DataExchangerPack; 84 85 PetscErrorCode DMSwarmDataExCreate(MPI_Comm comm, const PetscInt count, DMSwarmDataEx *ex) 86 { 87 DMSwarmDataEx d; 88 89 PetscFunctionBegin; 90 PetscCall(PetscNew(&d)); 91 PetscCallMPI(MPI_Comm_dup(comm, &d->comm)); 92 PetscCallMPI(MPI_Comm_rank(d->comm, &d->rank)); 93 94 d->instance = count; 95 96 d->topology_status = DEOBJECT_STATE_UNKNOWN; 97 d->message_lengths_status = DEOBJECT_STATE_UNKNOWN; 98 d->packer_status = DEOBJECT_STATE_UNKNOWN; 99 d->communication_status = DEOBJECT_STATE_UNKNOWN; 100 101 d->n_neighbour_procs = -1; 102 d->neighbour_procs = NULL; 103 104 d->messages_to_be_sent = NULL; 105 d->message_offsets = NULL; 106 d->messages_to_be_recvieved = NULL; 107 108 d->unit_message_size = (size_t)-1; 109 d->send_message = NULL; 110 d->send_message_length = -1; 111 d->recv_message = NULL; 112 d->recv_message_length = -1; 113 d->total_pack_cnt = -1; 114 d->pack_cnt = NULL; 115 116 d->send_tags = NULL; 117 d->recv_tags = NULL; 118 119 d->_stats = NULL; 120 d->_requests = NULL; 121 *ex = d; 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 /* 126 This code is horrible, who let it get into main. 127 128 Should be printing to a viewer, should not be using PETSC_COMM_WORLD 129 130 */ 131 PetscErrorCode DMSwarmDataExView(DMSwarmDataEx d) 132 { 133 PetscMPIInt p; 134 135 PetscFunctionBegin; 136 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "DMSwarmDataEx: instance=%" PetscInt_FMT "\n", d->instance)); 137 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " topology status: %s \n", status_names[d->topology_status])); 138 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " message lengths status: %s \n", status_names[d->message_lengths_status])); 139 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " packer status status: %s \n", status_names[d->packer_status])); 140 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " communication status: %s \n", status_names[d->communication_status])); 141 142 if (d->topology_status == DEOBJECT_FINALIZED) { 143 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " Topology:\n")); 144 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] neighbours: %d \n", d->rank, d->n_neighbour_procs)); 145 for (p = 0; p < d->n_neighbour_procs; p++) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] neighbour[%d] = %d \n", d->rank, p, d->neighbour_procs[p])); 146 PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout)); 147 } 148 149 if (d->message_lengths_status == DEOBJECT_FINALIZED) { 150 PetscCall(PetscPrintf(PETSC_COMM_WORLD, " Message lengths:\n")); 151 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] atomic size: %ld \n", d->rank, (long int)d->unit_message_size)); 152 for (p = 0; p < d->n_neighbour_procs; p++) PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] >>>>> ( %" PetscInt_FMT " units :: tag = %d) >>>>> [%d] \n", d->rank, d->messages_to_be_sent[p], d->send_tags[p], d->neighbour_procs[p])); 153 for (p = 0; p < d->n_neighbour_procs; p++) { 154 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [%d] <<<<< ( %" PetscInt_FMT " units :: tag = %d) <<<<< [%d] \n", d->rank, d->messages_to_be_recvieved[p], d->recv_tags[p], d->neighbour_procs[p])); 155 } 156 PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, stdout)); 157 } 158 if (d->packer_status == DEOBJECT_FINALIZED) { } 159 if (d->communication_status == DEOBJECT_FINALIZED) { } 160 PetscFunctionReturn(PETSC_SUCCESS); 161 } 162 163 PetscErrorCode DMSwarmDataExDestroy(DMSwarmDataEx d) 164 { 165 PetscFunctionBegin; 166 PetscCallMPI(MPI_Comm_free(&d->comm)); 167 if (d->neighbour_procs) PetscCall(PetscFree(d->neighbour_procs)); 168 if (d->messages_to_be_sent) PetscCall(PetscFree(d->messages_to_be_sent)); 169 if (d->message_offsets) PetscCall(PetscFree(d->message_offsets)); 170 if (d->messages_to_be_recvieved) PetscCall(PetscFree(d->messages_to_be_recvieved)); 171 if (d->send_message) PetscCall(PetscFree(d->send_message)); 172 if (d->recv_message) PetscCall(PetscFree(d->recv_message)); 173 if (d->pack_cnt) PetscCall(PetscFree(d->pack_cnt)); 174 if (d->send_tags) PetscCall(PetscFree(d->send_tags)); 175 if (d->recv_tags) PetscCall(PetscFree(d->recv_tags)); 176 if (d->_stats) PetscCall(PetscFree(d->_stats)); 177 if (d->_requests) PetscCall(PetscFree(d->_requests)); 178 PetscCall(PetscFree(d)); 179 PetscFunctionReturn(PETSC_SUCCESS); 180 } 181 182 /* === Phase A === */ 183 184 PetscErrorCode DMSwarmDataExTopologyInitialize(DMSwarmDataEx d) 185 { 186 PetscFunctionBegin; 187 d->topology_status = DEOBJECT_INITIALIZED; 188 d->n_neighbour_procs = 0; 189 PetscCall(PetscFree(d->neighbour_procs)); 190 PetscCall(PetscFree(d->messages_to_be_sent)); 191 PetscCall(PetscFree(d->message_offsets)); 192 PetscCall(PetscFree(d->messages_to_be_recvieved)); 193 PetscCall(PetscFree(d->pack_cnt)); 194 PetscCall(PetscFree(d->send_tags)); 195 PetscCall(PetscFree(d->recv_tags)); 196 PetscFunctionReturn(PETSC_SUCCESS); 197 } 198 199 PetscErrorCode DMSwarmDataExTopologyAddNeighbour(DMSwarmDataEx d, const PetscMPIInt proc_id) 200 { 201 PetscMPIInt n, found; 202 PetscMPIInt size; 203 204 PetscFunctionBegin; 205 PetscCheck(d->topology_status != DEOBJECT_FINALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology has been finalized. To modify or update call DMSwarmDataExTopologyInitialize() first"); 206 PetscCheck(d->topology_status == DEOBJECT_INITIALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first"); 207 208 /* error on negative entries */ 209 PetscCheck(proc_id >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Trying to set proc neighbour with a rank < 0"); 210 /* error on ranks larger than number of procs in communicator */ 211 PetscCallMPI(MPI_Comm_size(d->comm, &size)); 212 PetscCheck(proc_id < size, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Trying to set proc neighbour %d with a rank >= size %d", proc_id, size); 213 if (d->n_neighbour_procs == 0) PetscCall(PetscMalloc1(1, &d->neighbour_procs)); 214 /* check for proc_id */ 215 found = 0; 216 for (n = 0; n < d->n_neighbour_procs; n++) { 217 if (d->neighbour_procs[n] == proc_id) found = 1; 218 } 219 if (found == 0) { /* add it to list */ 220 PetscCall(PetscRealloc(sizeof(PetscMPIInt) * (d->n_neighbour_procs + 1), &d->neighbour_procs)); 221 d->neighbour_procs[d->n_neighbour_procs] = proc_id; 222 d->n_neighbour_procs++; 223 } 224 PetscFunctionReturn(PETSC_SUCCESS); 225 } 226 227 /* 228 counter: the index of the communication object 229 N: the number of processors 230 r0: rank of sender 231 r1: rank of receiver 232 233 procs = { 0, 1, 2, 3 } 234 235 0 ==> 0 e=0 236 0 ==> 1 e=1 237 0 ==> 2 e=2 238 0 ==> 3 e=3 239 240 1 ==> 0 e=4 241 1 ==> 1 e=5 242 1 ==> 2 e=6 243 1 ==> 3 e=7 244 245 2 ==> 0 e=8 246 2 ==> 1 e=9 247 2 ==> 2 e=10 248 2 ==> 3 e=11 249 250 3 ==> 0 e=12 251 3 ==> 1 e=13 252 3 ==> 2 e=14 253 3 ==> 3 e=15 254 255 If we require that proc A sends to proc B, then the SEND tag index will be given by 256 N * rank(A) + rank(B) + offset 257 If we require that proc A will receive from proc B, then the RECV tag index will be given by 258 N * rank(B) + rank(A) + offset 259 260 */ 261 static void _get_tags(PetscInt counter, PetscMPIInt N, PetscMPIInt r0, PetscMPIInt r1, PetscMPIInt maxtag, PetscMPIInt *_st, PetscMPIInt *_rt) 262 { 263 PetscMPIInt st, rt; 264 265 st = (N * r0 + r1 + N * N * counter) % maxtag; 266 rt = (N * r1 + r0 + N * N * counter) % maxtag; 267 *_st = st; 268 *_rt = rt; 269 } 270 271 /* 272 Makes the communication map symmetric 273 */ 274 static PetscErrorCode DMSwarmDataExCompleteCommunicationMap_Private(MPI_Comm comm, PetscMPIInt n, const PetscMPIInt proc_neighbours[], PetscMPIInt *n_new, PetscMPIInt **proc_neighbours_new) 275 { 276 Mat A; 277 PetscInt i, j, nc; 278 PetscInt n_, *proc_neighbours_; 279 PetscInt rank_; 280 PetscMPIInt size, rank; 281 PetscScalar *vals; 282 const PetscInt *cols; 283 const PetscScalar *red_vals; 284 PetscMPIInt _n_new, *_proc_neighbours_new; 285 286 PetscFunctionBegin; 287 n_ = n; 288 PetscCall(PetscMalloc1(n_, &proc_neighbours_)); 289 for (i = 0; i < n_; ++i) proc_neighbours_[i] = proc_neighbours[i]; 290 PetscCallMPI(MPI_Comm_size(comm, &size)); 291 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 292 rank_ = rank; 293 294 PetscCall(MatCreate(comm, &A)); 295 PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, size, size)); 296 PetscCall(MatSetType(A, MATAIJ)); 297 PetscCall(MatSeqAIJSetPreallocation(A, 1, NULL)); 298 PetscCall(MatMPIAIJSetPreallocation(A, n_, NULL, n_, NULL)); 299 PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE)); 300 /* Build original map */ 301 PetscCall(PetscMalloc1(n_, &vals)); 302 for (i = 0; i < n_; ++i) vals[i] = 1.0; 303 PetscCall(MatSetValues(A, 1, &rank_, n_, proc_neighbours_, vals, INSERT_VALUES)); 304 PetscCall(MatAssemblyBegin(A, MAT_FLUSH_ASSEMBLY)); 305 PetscCall(MatAssemblyEnd(A, MAT_FLUSH_ASSEMBLY)); 306 /* Now force all other connections if they are not already there */ 307 /* It's more efficient to do them all at once */ 308 for (i = 0; i < n_; ++i) vals[i] = 2.0; 309 PetscCall(MatSetValues(A, n_, proc_neighbours_, 1, &rank_, vals, INSERT_VALUES)); 310 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 311 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 312 /* 313 PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO)); 314 PetscCall(MatView(A,PETSC_VIEWER_STDOUT_WORLD)); 315 PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD)); 316 */ 317 if ((n_new != NULL) && (proc_neighbours_new != NULL)) { 318 PetscCall(MatGetRow(A, rank_, &nc, &cols, &red_vals)); 319 PetscCall(PetscMPIIntCast(nc, &_n_new)); 320 PetscCall(PetscMalloc1(_n_new, &_proc_neighbours_new)); 321 for (j = 0; j < nc; ++j) PetscCall(PetscMPIIntCast(cols[j], &_proc_neighbours_new[j])); 322 PetscCall(MatRestoreRow(A, rank_, &nc, &cols, &red_vals)); 323 *n_new = _n_new; 324 *proc_neighbours_new = _proc_neighbours_new; 325 } 326 PetscCall(MatDestroy(&A)); 327 PetscCall(PetscFree(vals)); 328 PetscCall(PetscFree(proc_neighbours_)); 329 PetscCallMPI(MPI_Barrier(comm)); 330 PetscFunctionReturn(PETSC_SUCCESS); 331 } 332 333 PetscErrorCode DMSwarmDataExTopologyFinalize(DMSwarmDataEx d) 334 { 335 PetscMPIInt symm_nn = 0, *symm_procs = NULL, r0, n, st, rt, size, *maxtag, iflg; 336 337 PetscFunctionBegin; 338 PetscCheck(d->topology_status == DEOBJECT_INITIALIZED, d->comm, PETSC_ERR_ARG_WRONGSTATE, "Topology must be initialised. Call DMSwarmDataExTopologyInitialize() first"); 339 340 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerTopologySetup, 0, 0, 0, 0)); 341 /* given information about all my neighbours, make map symmetric */ 342 PetscCall(DMSwarmDataExCompleteCommunicationMap_Private(d->comm, d->n_neighbour_procs, d->neighbour_procs, &symm_nn, &symm_procs)); 343 /* update my arrays */ 344 PetscCall(PetscFree(d->neighbour_procs)); 345 d->n_neighbour_procs = symm_nn; 346 d->neighbour_procs = symm_procs; 347 /* allocates memory */ 348 if (!d->messages_to_be_sent) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->messages_to_be_sent)); 349 if (!d->message_offsets) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->message_offsets)); 350 if (!d->messages_to_be_recvieved) PetscCall(PetscMalloc1(d->n_neighbour_procs + 1, &d->messages_to_be_recvieved)); 351 if (!d->pack_cnt) PetscCall(PetscMalloc(sizeof(PetscInt) * d->n_neighbour_procs, &d->pack_cnt)); 352 if (!d->_stats) PetscCall(PetscMalloc(sizeof(MPI_Status) * 2 * d->n_neighbour_procs, &d->_stats)); 353 if (!d->_requests) PetscCall(PetscMalloc(sizeof(MPI_Request) * 2 * d->n_neighbour_procs, &d->_requests)); 354 if (!d->send_tags) PetscCall(PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->send_tags)); 355 if (!d->recv_tags) PetscCall(PetscMalloc(sizeof(int) * d->n_neighbour_procs, &d->recv_tags)); 356 /* compute message tags */ 357 PetscCallMPI(MPI_Comm_size(d->comm, &size)); 358 PetscCallMPI(MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &maxtag, &iflg)); 359 PetscCheck(iflg, d->comm, PETSC_ERR_LIB, "MPI error: MPI_Comm_get_attr() is not returning a MPI_TAG_UB"); 360 r0 = d->rank; 361 for (n = 0; n < d->n_neighbour_procs; ++n) { 362 PetscMPIInt r1 = d->neighbour_procs[n]; 363 364 _get_tags(d->instance, size, r0, r1, *maxtag, &st, &rt); 365 d->send_tags[n] = st; 366 d->recv_tags[n] = rt; 367 } 368 d->topology_status = DEOBJECT_FINALIZED; 369 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerTopologySetup, 0, 0, 0, 0)); 370 PetscFunctionReturn(PETSC_SUCCESS); 371 } 372 373 /* === Phase B === */ 374 static PetscErrorCode _DMSwarmDataExConvertProcIdToLocalIndex(DMSwarmDataEx de, PetscMPIInt proc_id, PetscMPIInt *local) 375 { 376 PetscMPIInt i, np; 377 378 PetscFunctionBegin; 379 np = de->n_neighbour_procs; 380 *local = -1; 381 for (i = 0; i < np; ++i) { 382 if (proc_id == de->neighbour_procs[i]) { 383 *local = i; 384 break; 385 } 386 } 387 PetscFunctionReturn(PETSC_SUCCESS); 388 } 389 390 PetscErrorCode DMSwarmDataExInitializeSendCount(DMSwarmDataEx de) 391 { 392 PetscMPIInt i; 393 394 PetscFunctionBegin; 395 PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized"); 396 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerSendCount, 0, 0, 0, 0)); 397 de->message_lengths_status = DEOBJECT_INITIALIZED; 398 for (i = 0; i < de->n_neighbour_procs; ++i) de->messages_to_be_sent[i] = 0; 399 PetscFunctionReturn(PETSC_SUCCESS); 400 } 401 402 /* 403 1) only allows counters to be set on neighbouring cpus 404 */ 405 PetscErrorCode DMSwarmDataExAddToSendCount(DMSwarmDataEx de, const PetscMPIInt proc_id, const PetscInt count) 406 { 407 PetscMPIInt local_val; 408 409 PetscFunctionBegin; 410 PetscCheck(de->message_lengths_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths have been defined. To modify these call DMSwarmDataExInitializeSendCount() first"); 411 PetscCheck(de->message_lengths_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first"); 412 413 PetscCall(_DMSwarmDataExConvertProcIdToLocalIndex(de, proc_id, &local_val)); 414 PetscCheck(local_val != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Proc %d is not a valid neighbour rank", (int)proc_id); 415 416 de->messages_to_be_sent[local_val] = de->messages_to_be_sent[local_val] + count; 417 PetscFunctionReturn(PETSC_SUCCESS); 418 } 419 420 PetscErrorCode DMSwarmDataExFinalizeSendCount(DMSwarmDataEx de) 421 { 422 PetscFunctionBegin; 423 PetscCheck(de->message_lengths_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths must be defined. Call DMSwarmDataExInitializeSendCount() first"); 424 425 de->message_lengths_status = DEOBJECT_FINALIZED; 426 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerSendCount, 0, 0, 0, 0)); 427 PetscFunctionReturn(PETSC_SUCCESS); 428 } 429 430 /* === Phase C === */ 431 /* 432 zero out all send counts 433 free send and recv buffers 434 zeros out message length 435 zeros out all counters 436 zero out packed data counters 437 */ 438 static PetscErrorCode _DMSwarmDataExInitializeTmpStorage(DMSwarmDataEx de) 439 { 440 PetscMPIInt i, np; 441 442 PetscFunctionBegin; 443 np = de->n_neighbour_procs; 444 for (i = 0; i < np; ++i) { 445 /* de->messages_to_be_sent[i] = -1; */ 446 de->messages_to_be_recvieved[i] = -1; 447 } 448 PetscCall(PetscFree(de->send_message)); 449 PetscCall(PetscFree(de->recv_message)); 450 PetscFunctionReturn(PETSC_SUCCESS); 451 } 452 453 /* 454 Zeros out pack data counters 455 Ensures mesaage length is set 456 Checks send counts properly initialized 457 allocates space for pack data 458 */ 459 PetscErrorCode DMSwarmDataExPackInitialize(DMSwarmDataEx de, size_t unit_message_size) 460 { 461 PetscMPIInt i, np; 462 PetscInt total; 463 464 PetscFunctionBegin; 465 PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized"); 466 PetscCheck(de->message_lengths_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths not finalized"); 467 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerPack, 0, 0, 0, 0)); 468 de->packer_status = DEOBJECT_INITIALIZED; 469 PetscCall(_DMSwarmDataExInitializeTmpStorage(de)); 470 np = de->n_neighbour_procs; 471 de->unit_message_size = unit_message_size; 472 total = 0; 473 for (i = 0; i < np; ++i) { 474 if (de->messages_to_be_sent[i] == -1) { 475 PetscMPIInt proc_neighour = de->neighbour_procs[i]; 476 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ORDER, "Messages_to_be_sent[neighbour_proc=%d] is un-initialised. Call DMSwarmDataExSetSendCount() first", proc_neighour); 477 } 478 total = total + de->messages_to_be_sent[i]; 479 } 480 /* create space for the data to be sent */ 481 PetscCall(PetscMalloc(unit_message_size * (total + 1), &de->send_message)); 482 /* initialize memory */ 483 PetscCall(PetscMemzero(de->send_message, unit_message_size * (total + 1))); 484 /* set total items to send */ 485 de->send_message_length = total; 486 de->message_offsets[0] = 0; 487 total = de->messages_to_be_sent[0]; 488 for (i = 1; i < np; ++i) { 489 de->message_offsets[i] = total; 490 total = total + de->messages_to_be_sent[i]; 491 } 492 /* init the packer counters */ 493 de->total_pack_cnt = 0; 494 for (i = 0; i < np; ++i) de->pack_cnt[i] = 0; 495 PetscFunctionReturn(PETSC_SUCCESS); 496 } 497 498 /* 499 Ensures data gets been packed appropriately and no overlaps occur 500 */ 501 PetscErrorCode DMSwarmDataExPackData(DMSwarmDataEx de, PetscMPIInt proc_id, PetscInt n, void *data) 502 { 503 PetscMPIInt local; 504 PetscInt insert_location; 505 void *dest; 506 507 PetscFunctionBegin; 508 PetscCheck(de->packer_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Packed data have been defined. To modify these call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first"); 509 PetscCheck(de->packer_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Packed data must be defined. Call DMSwarmDataExInitializeSendCount(), DMSwarmDataExAddToSendCount(), DMSwarmDataExPackInitialize() first"); 510 511 PetscCheck(de->send_message, de->comm, PETSC_ERR_ORDER, "send_message is not initialized. Call DMSwarmDataExPackInitialize() first"); 512 PetscCall(_DMSwarmDataExConvertProcIdToLocalIndex(de, proc_id, &local)); 513 PetscCheck(local != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "proc_id %d is not registered neighbour", proc_id); 514 PetscCheck(n + de->pack_cnt[local] <= de->messages_to_be_sent[local], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to pack too many entries to be sent to proc %d. Space requested = %" PetscInt_FMT ": Attempt to insert %" PetscInt_FMT, proc_id, de->messages_to_be_sent[local], n + de->pack_cnt[local]); 515 516 /* copy memory */ 517 insert_location = de->message_offsets[local] + de->pack_cnt[local]; 518 dest = ((char *)de->send_message) + de->unit_message_size * insert_location; 519 PetscCall(PetscMemcpy(dest, data, de->unit_message_size * n)); 520 /* increment counter */ 521 de->pack_cnt[local] = de->pack_cnt[local] + n; 522 PetscFunctionReturn(PETSC_SUCCESS); 523 } 524 525 /* 526 *) Ensures all data has been packed 527 */ 528 PetscErrorCode DMSwarmDataExPackFinalize(DMSwarmDataEx de) 529 { 530 PetscMPIInt i, np; 531 PetscInt total; 532 533 PetscFunctionBegin; 534 PetscCheck(de->packer_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Packer has not been initialized. Must call DMSwarmDataExPackInitialize() first."); 535 np = de->n_neighbour_procs; 536 for (i = 0; i < np; ++i) { 537 PetscCheck(de->pack_cnt[i] == de->messages_to_be_sent[i], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not all messages for neighbour[%d] have been packed. Expected %" PetscInt_FMT " : Inserted %" PetscInt_FMT, de->neighbour_procs[i], de->messages_to_be_sent[i], de->pack_cnt[i]); 538 } 539 /* init */ 540 for (i = 0; i < np; ++i) de->messages_to_be_recvieved[i] = -1; 541 /* figure out the recv counts here */ 542 for (i = 0; i < np; ++i) PetscCallMPI(MPIU_Isend(&de->messages_to_be_sent[i], 1, MPIU_INT, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i])); 543 for (i = 0; i < np; ++i) PetscCallMPI(MPIU_Irecv(&de->messages_to_be_recvieved[i], 1, MPIU_INT, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np + i])); 544 PetscCallMPI(MPI_Waitall(2 * np, de->_requests, de->_stats)); 545 /* create space for the data to be recvieved */ 546 total = 0; 547 for (i = 0; i < np; ++i) total = total + de->messages_to_be_recvieved[i]; 548 PetscCall(PetscMalloc(de->unit_message_size * (total + 1), &de->recv_message)); 549 /* initialize memory */ 550 PetscCall(PetscMemzero(de->recv_message, de->unit_message_size * (total + 1))); 551 /* set total items to receive */ 552 de->recv_message_length = total; 553 de->packer_status = DEOBJECT_FINALIZED; 554 de->communication_status = DEOBJECT_INITIALIZED; 555 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerPack, 0, 0, 0, 0)); 556 PetscFunctionReturn(PETSC_SUCCESS); 557 } 558 559 /* do the actual message passing */ 560 PetscErrorCode DMSwarmDataExBegin(DMSwarmDataEx de) 561 { 562 PetscMPIInt i, np; 563 void *dest; 564 565 PetscFunctionBegin; 566 PetscCheck(de->topology_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Topology not finalized"); 567 PetscCheck(de->message_lengths_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Message lengths not finalized"); 568 PetscCheck(de->packer_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Packer not finalized"); 569 PetscCheck(de->communication_status != DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ORDER, "Communication has already been finalized. Must call DMSwarmDataExInitialize() first."); 570 PetscCheck(de->recv_message, de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first"); 571 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerBegin, 0, 0, 0, 0)); 572 np = de->n_neighbour_procs; 573 /* == NON BLOCKING == */ 574 for (i = 0; i < np; ++i) { 575 dest = ((char *)de->send_message) + de->unit_message_size * de->message_offsets[i]; 576 PetscCallMPI(MPIU_Isend(dest, de->messages_to_be_sent[i] * de->unit_message_size, MPI_CHAR, de->neighbour_procs[i], de->send_tags[i], de->comm, &de->_requests[i])); 577 } 578 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerBegin, 0, 0, 0, 0)); 579 PetscFunctionReturn(PETSC_SUCCESS); 580 } 581 582 /* do the actual message passing now */ 583 PetscErrorCode DMSwarmDataExEnd(DMSwarmDataEx de) 584 { 585 PetscMPIInt i, np; 586 PetscInt total; 587 PetscInt *message_recv_offsets; 588 void *dest; 589 590 PetscFunctionBegin; 591 PetscCheck(de->communication_status == DEOBJECT_INITIALIZED, de->comm, PETSC_ERR_ORDER, "Communication has not been initialized. Must call DMSwarmDataExInitialize() first."); 592 PetscCheck(de->recv_message, de->comm, PETSC_ERR_ORDER, "recv_message has not been initialized. Must call DMSwarmDataExPackFinalize() first"); 593 PetscCall(PetscLogEventBegin(DMSWARM_DataExchangerEnd, 0, 0, 0, 0)); 594 np = de->n_neighbour_procs; 595 PetscCall(PetscMalloc1(np + 1, &message_recv_offsets)); 596 message_recv_offsets[0] = 0; 597 total = de->messages_to_be_recvieved[0]; 598 for (i = 1; i < np; ++i) { 599 message_recv_offsets[i] = total; 600 total = total + de->messages_to_be_recvieved[i]; 601 } 602 /* == NON BLOCKING == */ 603 for (i = 0; i < np; ++i) { 604 dest = ((char *)de->recv_message) + de->unit_message_size * message_recv_offsets[i]; 605 PetscCallMPI(MPIU_Irecv(dest, de->messages_to_be_recvieved[i] * de->unit_message_size, MPI_CHAR, de->neighbour_procs[i], de->recv_tags[i], de->comm, &de->_requests[np + i])); 606 } 607 PetscCallMPI(MPI_Waitall(2 * np, de->_requests, de->_stats)); 608 PetscCall(PetscFree(message_recv_offsets)); 609 de->communication_status = DEOBJECT_FINALIZED; 610 PetscCall(PetscLogEventEnd(DMSWARM_DataExchangerEnd, 0, 0, 0, 0)); 611 PetscFunctionReturn(PETSC_SUCCESS); 612 } 613 614 PetscErrorCode DMSwarmDataExGetSendData(DMSwarmDataEx de, PetscInt *length, void **send) 615 { 616 PetscFunctionBegin; 617 PetscCheck(de->packer_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being packed."); 618 *length = de->send_message_length; 619 *send = de->send_message; 620 PetscFunctionReturn(PETSC_SUCCESS); 621 } 622 623 PetscErrorCode DMSwarmDataExGetRecvData(DMSwarmDataEx de, PetscInt *length, void **recv) 624 { 625 PetscFunctionBegin; 626 PetscCheck(de->communication_status == DEOBJECT_FINALIZED, de->comm, PETSC_ERR_ARG_WRONGSTATE, "Data has not finished being sent."); 627 *length = de->recv_message_length; 628 *recv = de->recv_message; 629 PetscFunctionReturn(PETSC_SUCCESS); 630 } 631 632 PetscErrorCode DMSwarmDataExTopologyGetNeighbours(DMSwarmDataEx de, PetscMPIInt *n, PetscMPIInt *neigh[]) 633 { 634 PetscFunctionBegin; 635 if (n) *n = de->n_neighbour_procs; 636 if (neigh) *neigh = de->neighbour_procs; 637 PetscFunctionReturn(PETSC_SUCCESS); 638 } 639