1 2 #include <petsc-private/matimpl.h> 3 4 #define DEFAULT_STASH_SIZE 10000 5 6 static PetscErrorCode MatStashScatterBegin_Ref(Mat,MatStash*,PetscInt*); 7 static PetscErrorCode MatStashScatterGetMesg_Ref(MatStash*,PetscMPIInt*,PetscInt**,PetscInt**,PetscScalar**,PetscInt*); 8 static PetscErrorCode MatStashScatterEnd_Ref(MatStash*); 9 static PetscErrorCode MatStashScatterBegin_BTS(Mat,MatStash*,PetscInt*); 10 static PetscErrorCode MatStashScatterGetMesg_BTS(MatStash*,PetscMPIInt*,PetscInt**,PetscInt**,PetscScalar**,PetscInt*); 11 static PetscErrorCode MatStashScatterEnd_BTS(MatStash*); 12 static PetscErrorCode MatStashScatterDestroy_BTS(MatStash*); 13 14 /* 15 MatStashCreate_Private - Creates a stash,currently used for all the parallel 16 matrix implementations. The stash is where elements of a matrix destined 17 to be stored on other processors are kept until matrix assembly is done. 18 19 This is a simple minded stash. Simply adds entries to end of stash. 20 21 Input Parameters: 22 comm - communicator, required for scatters. 23 bs - stash block size. used when stashing blocks of values 24 25 Output Parameters: 26 stash - the newly created stash 27 */ 28 #undef __FUNCT__ 29 #define __FUNCT__ "MatStashCreate_Private" 30 PetscErrorCode MatStashCreate_Private(MPI_Comm comm,PetscInt bs,MatStash *stash) 31 { 32 PetscErrorCode ierr; 33 PetscInt max,*opt,nopt,i; 34 PetscBool flg; 35 36 PetscFunctionBegin; 37 /* Require 2 tags,get the second using PetscCommGetNewTag() */ 38 stash->comm = comm; 39 40 ierr = PetscCommGetNewTag(stash->comm,&stash->tag1);CHKERRQ(ierr); 41 ierr = PetscCommGetNewTag(stash->comm,&stash->tag2);CHKERRQ(ierr); 42 ierr = MPI_Comm_size(stash->comm,&stash->size);CHKERRQ(ierr); 43 ierr = MPI_Comm_rank(stash->comm,&stash->rank);CHKERRQ(ierr); 44 ierr = PetscMalloc1(2*stash->size,&stash->flg_v);CHKERRQ(ierr); 45 for (i=0; i<2*stash->size; i++) stash->flg_v[i] = -1; 46 47 48 nopt = stash->size; 49 ierr = PetscMalloc1(nopt,&opt);CHKERRQ(ierr); 50 ierr = PetscOptionsGetIntArray(NULL,"-matstash_initial_size",opt,&nopt,&flg);CHKERRQ(ierr); 51 if (flg) { 52 if (nopt == 1) max = opt[0]; 53 else if (nopt == stash->size) max = opt[stash->rank]; 54 else if (stash->rank < nopt) max = opt[stash->rank]; 55 else max = 0; /* Use default */ 56 stash->umax = max; 57 } else { 58 stash->umax = 0; 59 } 60 ierr = PetscFree(opt);CHKERRQ(ierr); 61 if (bs <= 0) bs = 1; 62 63 stash->bs = bs; 64 stash->nmax = 0; 65 stash->oldnmax = 0; 66 stash->n = 0; 67 stash->reallocs = -1; 68 stash->space_head = 0; 69 stash->space = 0; 70 71 stash->send_waits = 0; 72 stash->recv_waits = 0; 73 stash->send_status = 0; 74 stash->nsends = 0; 75 stash->nrecvs = 0; 76 stash->svalues = 0; 77 stash->rvalues = 0; 78 stash->rindices = 0; 79 stash->nprocessed = 0; 80 stash->reproduce = PETSC_FALSE; 81 stash->blocktype = MPI_DATATYPE_NULL; 82 83 ierr = PetscOptionsGetBool(NULL,"-matstash_reproduce",&stash->reproduce,NULL);CHKERRQ(ierr); 84 ierr = PetscOptionsGetBool(NULL,"-matstash_bts",&flg,NULL);CHKERRQ(ierr); 85 if (flg) { 86 stash->ScatterBegin = MatStashScatterBegin_BTS; 87 stash->ScatterGetMesg = MatStashScatterGetMesg_BTS; 88 stash->ScatterEnd = MatStashScatterEnd_BTS; 89 stash->ScatterDestroy = MatStashScatterDestroy_BTS; 90 } else { 91 stash->ScatterBegin = MatStashScatterBegin_Ref; 92 stash->ScatterGetMesg = MatStashScatterGetMesg_Ref; 93 stash->ScatterEnd = MatStashScatterEnd_Ref; 94 stash->ScatterDestroy = NULL; 95 } 96 PetscFunctionReturn(0); 97 } 98 99 /* 100 MatStashDestroy_Private - Destroy the stash 101 */ 102 #undef __FUNCT__ 103 #define __FUNCT__ "MatStashDestroy_Private" 104 PetscErrorCode MatStashDestroy_Private(MatStash *stash) 105 { 106 PetscErrorCode ierr; 107 108 PetscFunctionBegin; 109 ierr = PetscMatStashSpaceDestroy(&stash->space_head);CHKERRQ(ierr); 110 if (stash->ScatterDestroy) {ierr = (*stash->ScatterDestroy)(stash);CHKERRQ(ierr);} 111 112 stash->space = 0; 113 114 ierr = PetscFree(stash->flg_v);CHKERRQ(ierr); 115 PetscFunctionReturn(0); 116 } 117 118 /* 119 MatStashScatterEnd_Private - This is called as the final stage of 120 scatter. The final stages of message passing is done here, and 121 all the memory used for message passing is cleaned up. This 122 routine also resets the stash, and deallocates the memory used 123 for the stash. It also keeps track of the current memory usage 124 so that the same value can be used the next time through. 125 */ 126 #undef __FUNCT__ 127 #define __FUNCT__ "MatStashScatterEnd_Private" 128 PetscErrorCode MatStashScatterEnd_Private(MatStash *stash) 129 { 130 PetscErrorCode ierr; 131 132 PetscFunctionBegin; 133 ierr = (*stash->ScatterEnd)(stash);CHKERRQ(ierr); 134 PetscFunctionReturn(0); 135 } 136 137 #undef __FUNCT__ 138 #define __FUNCT__ "MatStashScatterEnd_Ref" 139 static PetscErrorCode MatStashScatterEnd_Ref(MatStash *stash) 140 { 141 PetscErrorCode ierr; 142 PetscInt nsends=stash->nsends,bs2,oldnmax,i; 143 MPI_Status *send_status; 144 145 PetscFunctionBegin; 146 for (i=0; i<2*stash->size; i++) stash->flg_v[i] = -1; 147 /* wait on sends */ 148 if (nsends) { 149 ierr = PetscMalloc1(2*nsends,&send_status);CHKERRQ(ierr); 150 ierr = MPI_Waitall(2*nsends,stash->send_waits,send_status);CHKERRQ(ierr); 151 ierr = PetscFree(send_status);CHKERRQ(ierr); 152 } 153 154 /* Now update nmaxold to be app 10% more than max n used, this way the 155 wastage of space is reduced the next time this stash is used. 156 Also update the oldmax, only if it increases */ 157 if (stash->n) { 158 bs2 = stash->bs*stash->bs; 159 oldnmax = ((int)(stash->n * 1.1) + 5)*bs2; 160 if (oldnmax > stash->oldnmax) stash->oldnmax = oldnmax; 161 } 162 163 stash->nmax = 0; 164 stash->n = 0; 165 stash->reallocs = -1; 166 stash->nprocessed = 0; 167 168 ierr = PetscMatStashSpaceDestroy(&stash->space_head);CHKERRQ(ierr); 169 170 stash->space = 0; 171 172 ierr = PetscFree(stash->send_waits);CHKERRQ(ierr); 173 ierr = PetscFree(stash->recv_waits);CHKERRQ(ierr); 174 ierr = PetscFree2(stash->svalues,stash->sindices);CHKERRQ(ierr); 175 ierr = PetscFree(stash->rvalues[0]);CHKERRQ(ierr); 176 ierr = PetscFree(stash->rvalues);CHKERRQ(ierr); 177 ierr = PetscFree(stash->rindices[0]);CHKERRQ(ierr); 178 ierr = PetscFree(stash->rindices);CHKERRQ(ierr); 179 PetscFunctionReturn(0); 180 } 181 182 /* 183 MatStashGetInfo_Private - Gets the relavant statistics of the stash 184 185 Input Parameters: 186 stash - the stash 187 nstash - the size of the stash. Indicates the number of values stored. 188 reallocs - the number of additional mallocs incurred. 189 190 */ 191 #undef __FUNCT__ 192 #define __FUNCT__ "MatStashGetInfo_Private" 193 PetscErrorCode MatStashGetInfo_Private(MatStash *stash,PetscInt *nstash,PetscInt *reallocs) 194 { 195 PetscInt bs2 = stash->bs*stash->bs; 196 197 PetscFunctionBegin; 198 if (nstash) *nstash = stash->n*bs2; 199 if (reallocs) { 200 if (stash->reallocs < 0) *reallocs = 0; 201 else *reallocs = stash->reallocs; 202 } 203 PetscFunctionReturn(0); 204 } 205 206 /* 207 MatStashSetInitialSize_Private - Sets the initial size of the stash 208 209 Input Parameters: 210 stash - the stash 211 max - the value that is used as the max size of the stash. 212 this value is used while allocating memory. 213 */ 214 #undef __FUNCT__ 215 #define __FUNCT__ "MatStashSetInitialSize_Private" 216 PetscErrorCode MatStashSetInitialSize_Private(MatStash *stash,PetscInt max) 217 { 218 PetscFunctionBegin; 219 stash->umax = max; 220 PetscFunctionReturn(0); 221 } 222 223 /* MatStashExpand_Private - Expand the stash. This function is called 224 when the space in the stash is not sufficient to add the new values 225 being inserted into the stash. 226 227 Input Parameters: 228 stash - the stash 229 incr - the minimum increase requested 230 231 Notes: 232 This routine doubles the currently used memory. 233 */ 234 #undef __FUNCT__ 235 #define __FUNCT__ "MatStashExpand_Private" 236 static PetscErrorCode MatStashExpand_Private(MatStash *stash,PetscInt incr) 237 { 238 PetscErrorCode ierr; 239 PetscInt newnmax,bs2= stash->bs*stash->bs; 240 241 PetscFunctionBegin; 242 /* allocate a larger stash */ 243 if (!stash->oldnmax && !stash->nmax) { /* new stash */ 244 if (stash->umax) newnmax = stash->umax/bs2; 245 else newnmax = DEFAULT_STASH_SIZE/bs2; 246 } else if (!stash->nmax) { /* resuing stash */ 247 if (stash->umax > stash->oldnmax) newnmax = stash->umax/bs2; 248 else newnmax = stash->oldnmax/bs2; 249 } else newnmax = stash->nmax*2; 250 if (newnmax < (stash->nmax + incr)) newnmax += 2*incr; 251 252 /* Get a MatStashSpace and attach it to stash */ 253 ierr = PetscMatStashSpaceGet(bs2,newnmax,&stash->space);CHKERRQ(ierr); 254 if (!stash->space_head) { /* new stash or resuing stash->oldnmax */ 255 stash->space_head = stash->space; 256 } 257 258 stash->reallocs++; 259 stash->nmax = newnmax; 260 PetscFunctionReturn(0); 261 } 262 /* 263 MatStashValuesRow_Private - inserts values into the stash. This function 264 expects the values to be roworiented. Multiple columns belong to the same row 265 can be inserted with a single call to this function. 266 267 Input Parameters: 268 stash - the stash 269 row - the global row correspoiding to the values 270 n - the number of elements inserted. All elements belong to the above row. 271 idxn - the global column indices corresponding to each of the values. 272 values - the values inserted 273 */ 274 #undef __FUNCT__ 275 #define __FUNCT__ "MatStashValuesRow_Private" 276 PetscErrorCode MatStashValuesRow_Private(MatStash *stash,PetscInt row,PetscInt n,const PetscInt idxn[],const PetscScalar values[],PetscBool ignorezeroentries) 277 { 278 PetscErrorCode ierr; 279 PetscInt i,k,cnt = 0; 280 PetscMatStashSpace space=stash->space; 281 282 PetscFunctionBegin; 283 /* Check and see if we have sufficient memory */ 284 if (!space || space->local_remaining < n) { 285 ierr = MatStashExpand_Private(stash,n);CHKERRQ(ierr); 286 } 287 space = stash->space; 288 k = space->local_used; 289 for (i=0; i<n; i++) { 290 if (ignorezeroentries && (values[i] == 0.0)) continue; 291 space->idx[k] = row; 292 space->idy[k] = idxn[i]; 293 space->val[k] = values[i]; 294 k++; 295 cnt++; 296 } 297 stash->n += cnt; 298 space->local_used += cnt; 299 space->local_remaining -= cnt; 300 PetscFunctionReturn(0); 301 } 302 303 /* 304 MatStashValuesCol_Private - inserts values into the stash. This function 305 expects the values to be columnoriented. Multiple columns belong to the same row 306 can be inserted with a single call to this function. 307 308 Input Parameters: 309 stash - the stash 310 row - the global row correspoiding to the values 311 n - the number of elements inserted. All elements belong to the above row. 312 idxn - the global column indices corresponding to each of the values. 313 values - the values inserted 314 stepval - the consecutive values are sepated by a distance of stepval. 315 this happens because the input is columnoriented. 316 */ 317 #undef __FUNCT__ 318 #define __FUNCT__ "MatStashValuesCol_Private" 319 PetscErrorCode MatStashValuesCol_Private(MatStash *stash,PetscInt row,PetscInt n,const PetscInt idxn[],const PetscScalar values[],PetscInt stepval,PetscBool ignorezeroentries) 320 { 321 PetscErrorCode ierr; 322 PetscInt i,k,cnt = 0; 323 PetscMatStashSpace space=stash->space; 324 325 PetscFunctionBegin; 326 /* Check and see if we have sufficient memory */ 327 if (!space || space->local_remaining < n) { 328 ierr = MatStashExpand_Private(stash,n);CHKERRQ(ierr); 329 } 330 space = stash->space; 331 k = space->local_used; 332 for (i=0; i<n; i++) { 333 if (ignorezeroentries && (values[i*stepval] == 0.0)) continue; 334 space->idx[k] = row; 335 space->idy[k] = idxn[i]; 336 space->val[k] = values[i*stepval]; 337 k++; 338 cnt++; 339 } 340 stash->n += cnt; 341 space->local_used += cnt; 342 space->local_remaining -= cnt; 343 PetscFunctionReturn(0); 344 } 345 346 /* 347 MatStashValuesRowBlocked_Private - inserts blocks of values into the stash. 348 This function expects the values to be roworiented. Multiple columns belong 349 to the same block-row can be inserted with a single call to this function. 350 This function extracts the sub-block of values based on the dimensions of 351 the original input block, and the row,col values corresponding to the blocks. 352 353 Input Parameters: 354 stash - the stash 355 row - the global block-row correspoiding to the values 356 n - the number of elements inserted. All elements belong to the above row. 357 idxn - the global block-column indices corresponding to each of the blocks of 358 values. Each block is of size bs*bs. 359 values - the values inserted 360 rmax - the number of block-rows in the original block. 361 cmax - the number of block-columsn on the original block. 362 idx - the index of the current block-row in the original block. 363 */ 364 #undef __FUNCT__ 365 #define __FUNCT__ "MatStashValuesRowBlocked_Private" 366 PetscErrorCode MatStashValuesRowBlocked_Private(MatStash *stash,PetscInt row,PetscInt n,const PetscInt idxn[],const PetscScalar values[],PetscInt rmax,PetscInt cmax,PetscInt idx) 367 { 368 PetscErrorCode ierr; 369 PetscInt i,j,k,bs2,bs=stash->bs,l; 370 const PetscScalar *vals; 371 PetscScalar *array; 372 PetscMatStashSpace space=stash->space; 373 374 PetscFunctionBegin; 375 if (!space || space->local_remaining < n) { 376 ierr = MatStashExpand_Private(stash,n);CHKERRQ(ierr); 377 } 378 space = stash->space; 379 l = space->local_used; 380 bs2 = bs*bs; 381 for (i=0; i<n; i++) { 382 space->idx[l] = row; 383 space->idy[l] = idxn[i]; 384 /* Now copy over the block of values. Store the values column oriented. 385 This enables inserting multiple blocks belonging to a row with a single 386 funtion call */ 387 array = space->val + bs2*l; 388 vals = values + idx*bs2*n + bs*i; 389 for (j=0; j<bs; j++) { 390 for (k=0; k<bs; k++) array[k*bs] = vals[k]; 391 array++; 392 vals += cmax*bs; 393 } 394 l++; 395 } 396 stash->n += n; 397 space->local_used += n; 398 space->local_remaining -= n; 399 PetscFunctionReturn(0); 400 } 401 402 /* 403 MatStashValuesColBlocked_Private - inserts blocks of values into the stash. 404 This function expects the values to be roworiented. Multiple columns belong 405 to the same block-row can be inserted with a single call to this function. 406 This function extracts the sub-block of values based on the dimensions of 407 the original input block, and the row,col values corresponding to the blocks. 408 409 Input Parameters: 410 stash - the stash 411 row - the global block-row correspoiding to the values 412 n - the number of elements inserted. All elements belong to the above row. 413 idxn - the global block-column indices corresponding to each of the blocks of 414 values. Each block is of size bs*bs. 415 values - the values inserted 416 rmax - the number of block-rows in the original block. 417 cmax - the number of block-columsn on the original block. 418 idx - the index of the current block-row in the original block. 419 */ 420 #undef __FUNCT__ 421 #define __FUNCT__ "MatStashValuesColBlocked_Private" 422 PetscErrorCode MatStashValuesColBlocked_Private(MatStash *stash,PetscInt row,PetscInt n,const PetscInt idxn[],const PetscScalar values[],PetscInt rmax,PetscInt cmax,PetscInt idx) 423 { 424 PetscErrorCode ierr; 425 PetscInt i,j,k,bs2,bs=stash->bs,l; 426 const PetscScalar *vals; 427 PetscScalar *array; 428 PetscMatStashSpace space=stash->space; 429 430 PetscFunctionBegin; 431 if (!space || space->local_remaining < n) { 432 ierr = MatStashExpand_Private(stash,n);CHKERRQ(ierr); 433 } 434 space = stash->space; 435 l = space->local_used; 436 bs2 = bs*bs; 437 for (i=0; i<n; i++) { 438 space->idx[l] = row; 439 space->idy[l] = idxn[i]; 440 /* Now copy over the block of values. Store the values column oriented. 441 This enables inserting multiple blocks belonging to a row with a single 442 funtion call */ 443 array = space->val + bs2*l; 444 vals = values + idx*bs2*n + bs*i; 445 for (j=0; j<bs; j++) { 446 for (k=0; k<bs; k++) array[k] = vals[k]; 447 array += bs; 448 vals += rmax*bs; 449 } 450 l++; 451 } 452 stash->n += n; 453 space->local_used += n; 454 space->local_remaining -= n; 455 PetscFunctionReturn(0); 456 } 457 /* 458 MatStashScatterBegin_Private - Initiates the transfer of values to the 459 correct owners. This function goes through the stash, and check the 460 owners of each stashed value, and sends the values off to the owner 461 processors. 462 463 Input Parameters: 464 stash - the stash 465 owners - an array of size 'no-of-procs' which gives the ownership range 466 for each node. 467 468 Notes: The 'owners' array in the cased of the blocked-stash has the 469 ranges specified blocked global indices, and for the regular stash in 470 the proper global indices. 471 */ 472 #undef __FUNCT__ 473 #define __FUNCT__ "MatStashScatterBegin_Private" 474 PetscErrorCode MatStashScatterBegin_Private(Mat mat,MatStash *stash,PetscInt *owners) 475 { 476 PetscErrorCode ierr; 477 478 PetscFunctionBegin; 479 ierr = (*stash->ScatterBegin)(mat,stash,owners);CHKERRQ(ierr); 480 PetscFunctionReturn(0); 481 } 482 483 #undef __FUNCT__ 484 #define __FUNCT__ "MatStashScatterBegin_Ref" 485 static PetscErrorCode MatStashScatterBegin_Ref(Mat mat,MatStash *stash,PetscInt *owners) 486 { 487 PetscInt *owner,*startv,*starti,tag1=stash->tag1,tag2=stash->tag2,bs2; 488 PetscInt size=stash->size,nsends; 489 PetscErrorCode ierr; 490 PetscInt count,*sindices,**rindices,i,j,idx,lastidx,l; 491 PetscScalar **rvalues,*svalues; 492 MPI_Comm comm = stash->comm; 493 MPI_Request *send_waits,*recv_waits,*recv_waits1,*recv_waits2; 494 PetscMPIInt *sizes,*nlengths,nreceives; 495 PetscInt *sp_idx,*sp_idy; 496 PetscScalar *sp_val; 497 PetscMatStashSpace space,space_next; 498 499 PetscFunctionBegin; 500 bs2 = stash->bs*stash->bs; 501 502 /* first count number of contributors to each processor */ 503 ierr = PetscCalloc1(size,&sizes);CHKERRQ(ierr); 504 ierr = PetscCalloc1(size,&nlengths);CHKERRQ(ierr); 505 ierr = PetscMalloc1(stash->n+1,&owner);CHKERRQ(ierr); 506 507 i = j = 0; 508 lastidx = -1; 509 space = stash->space_head; 510 while (space != NULL) { 511 space_next = space->next; 512 sp_idx = space->idx; 513 for (l=0; l<space->local_used; l++) { 514 /* if indices are NOT locally sorted, need to start search at the beginning */ 515 if (lastidx > (idx = sp_idx[l])) j = 0; 516 lastidx = idx; 517 for (; j<size; j++) { 518 if (idx >= owners[j] && idx < owners[j+1]) { 519 nlengths[j]++; owner[i] = j; break; 520 } 521 } 522 i++; 523 } 524 space = space_next; 525 } 526 /* Now check what procs get messages - and compute nsends. */ 527 for (i=0, nsends=0; i<size; i++) { 528 if (nlengths[i]) { 529 sizes[i] = 1; nsends++; 530 } 531 } 532 533 {PetscMPIInt *onodes,*olengths; 534 /* Determine the number of messages to expect, their lengths, from from-ids */ 535 ierr = PetscGatherNumberOfMessages(comm,sizes,nlengths,&nreceives);CHKERRQ(ierr); 536 ierr = PetscGatherMessageLengths(comm,nsends,nreceives,nlengths,&onodes,&olengths);CHKERRQ(ierr); 537 /* since clubbing row,col - lengths are multiplied by 2 */ 538 for (i=0; i<nreceives; i++) olengths[i] *=2; 539 ierr = PetscPostIrecvInt(comm,tag1,nreceives,onodes,olengths,&rindices,&recv_waits1);CHKERRQ(ierr); 540 /* values are size 'bs2' lengths (and remove earlier factor 2 */ 541 for (i=0; i<nreceives; i++) olengths[i] = olengths[i]*bs2/2; 542 ierr = PetscPostIrecvScalar(comm,tag2,nreceives,onodes,olengths,&rvalues,&recv_waits2);CHKERRQ(ierr); 543 ierr = PetscFree(onodes);CHKERRQ(ierr); 544 ierr = PetscFree(olengths);CHKERRQ(ierr);} 545 546 /* do sends: 547 1) starts[i] gives the starting index in svalues for stuff going to 548 the ith processor 549 */ 550 ierr = PetscMalloc2(bs2*stash->n,&svalues,2*(stash->n+1),&sindices);CHKERRQ(ierr); 551 ierr = PetscMalloc1(2*nsends,&send_waits);CHKERRQ(ierr); 552 ierr = PetscMalloc2(size,&startv,size,&starti);CHKERRQ(ierr); 553 /* use 2 sends the first with all_a, the next with all_i and all_j */ 554 startv[0] = 0; starti[0] = 0; 555 for (i=1; i<size; i++) { 556 startv[i] = startv[i-1] + nlengths[i-1]; 557 starti[i] = starti[i-1] + 2*nlengths[i-1]; 558 } 559 560 i = 0; 561 space = stash->space_head; 562 while (space != NULL) { 563 space_next = space->next; 564 sp_idx = space->idx; 565 sp_idy = space->idy; 566 sp_val = space->val; 567 for (l=0; l<space->local_used; l++) { 568 j = owner[i]; 569 if (bs2 == 1) { 570 svalues[startv[j]] = sp_val[l]; 571 } else { 572 PetscInt k; 573 PetscScalar *buf1,*buf2; 574 buf1 = svalues+bs2*startv[j]; 575 buf2 = space->val + bs2*l; 576 for (k=0; k<bs2; k++) buf1[k] = buf2[k]; 577 } 578 sindices[starti[j]] = sp_idx[l]; 579 sindices[starti[j]+nlengths[j]] = sp_idy[l]; 580 startv[j]++; 581 starti[j]++; 582 i++; 583 } 584 space = space_next; 585 } 586 startv[0] = 0; 587 for (i=1; i<size; i++) startv[i] = startv[i-1] + nlengths[i-1]; 588 589 for (i=0,count=0; i<size; i++) { 590 if (sizes[i]) { 591 ierr = MPI_Isend(sindices+2*startv[i],2*nlengths[i],MPIU_INT,i,tag1,comm,send_waits+count++);CHKERRQ(ierr); 592 ierr = MPI_Isend(svalues+bs2*startv[i],bs2*nlengths[i],MPIU_SCALAR,i,tag2,comm,send_waits+count++);CHKERRQ(ierr); 593 } 594 } 595 #if defined(PETSC_USE_INFO) 596 ierr = PetscInfo1(NULL,"No of messages: %d \n",nsends);CHKERRQ(ierr); 597 for (i=0; i<size; i++) { 598 if (sizes[i]) { 599 ierr = PetscInfo2(NULL,"Mesg_to: %d: size: %d bytes\n",i,nlengths[i]*(bs2*sizeof(PetscScalar)+2*sizeof(PetscInt)));CHKERRQ(ierr); 600 } 601 } 602 #endif 603 ierr = PetscFree(nlengths);CHKERRQ(ierr); 604 ierr = PetscFree(owner);CHKERRQ(ierr); 605 ierr = PetscFree2(startv,starti);CHKERRQ(ierr); 606 ierr = PetscFree(sizes);CHKERRQ(ierr); 607 608 /* recv_waits need to be contiguous for MatStashScatterGetMesg_Private() */ 609 ierr = PetscMalloc1(2*nreceives,&recv_waits);CHKERRQ(ierr); 610 611 for (i=0; i<nreceives; i++) { 612 recv_waits[2*i] = recv_waits1[i]; 613 recv_waits[2*i+1] = recv_waits2[i]; 614 } 615 stash->recv_waits = recv_waits; 616 617 ierr = PetscFree(recv_waits1);CHKERRQ(ierr); 618 ierr = PetscFree(recv_waits2);CHKERRQ(ierr); 619 620 stash->svalues = svalues; 621 stash->sindices = sindices; 622 stash->rvalues = rvalues; 623 stash->rindices = rindices; 624 stash->send_waits = send_waits; 625 stash->nsends = nsends; 626 stash->nrecvs = nreceives; 627 stash->reproduce_count = 0; 628 PetscFunctionReturn(0); 629 } 630 631 /* 632 MatStashScatterGetMesg_Private - This function waits on the receives posted 633 in the function MatStashScatterBegin_Private() and returns one message at 634 a time to the calling function. If no messages are left, it indicates this 635 by setting flg = 0, else it sets flg = 1. 636 637 Input Parameters: 638 stash - the stash 639 640 Output Parameters: 641 nvals - the number of entries in the current message. 642 rows - an array of row indices (or blocked indices) corresponding to the values 643 cols - an array of columnindices (or blocked indices) corresponding to the values 644 vals - the values 645 flg - 0 indicates no more message left, and the current call has no values associated. 646 1 indicates that the current call successfully received a message, and the 647 other output parameters nvals,rows,cols,vals are set appropriately. 648 */ 649 #undef __FUNCT__ 650 #define __FUNCT__ "MatStashScatterGetMesg_Private" 651 PetscErrorCode MatStashScatterGetMesg_Private(MatStash *stash,PetscMPIInt *nvals,PetscInt **rows,PetscInt **cols,PetscScalar **vals,PetscInt *flg) 652 { 653 PetscErrorCode ierr; 654 655 PetscFunctionBegin; 656 ierr = (*stash->ScatterGetMesg)(stash,nvals,rows,cols,vals,flg);CHKERRQ(ierr); 657 PetscFunctionReturn(0); 658 } 659 660 #undef __FUNCT__ 661 #define __FUNCT__ "MatStashScatterGetMesg_Ref" 662 static PetscErrorCode MatStashScatterGetMesg_Ref(MatStash *stash,PetscMPIInt *nvals,PetscInt **rows,PetscInt **cols,PetscScalar **vals,PetscInt *flg) 663 { 664 PetscErrorCode ierr; 665 PetscMPIInt i,*flg_v = stash->flg_v,i1,i2; 666 PetscInt bs2; 667 MPI_Status recv_status; 668 PetscBool match_found = PETSC_FALSE; 669 670 PetscFunctionBegin; 671 *flg = 0; /* When a message is discovered this is reset to 1 */ 672 /* Return if no more messages to process */ 673 if (stash->nprocessed == stash->nrecvs) PetscFunctionReturn(0); 674 675 bs2 = stash->bs*stash->bs; 676 /* If a matching pair of receives are found, process them, and return the data to 677 the calling function. Until then keep receiving messages */ 678 while (!match_found) { 679 if (stash->reproduce) { 680 i = stash->reproduce_count++; 681 ierr = MPI_Wait(stash->recv_waits+i,&recv_status);CHKERRQ(ierr); 682 } else { 683 ierr = MPI_Waitany(2*stash->nrecvs,stash->recv_waits,&i,&recv_status);CHKERRQ(ierr); 684 } 685 if (recv_status.MPI_SOURCE < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Negative MPI source!"); 686 687 /* Now pack the received message into a structure which is usable by others */ 688 if (i % 2) { 689 ierr = MPI_Get_count(&recv_status,MPIU_SCALAR,nvals);CHKERRQ(ierr); 690 691 flg_v[2*recv_status.MPI_SOURCE] = i/2; 692 693 *nvals = *nvals/bs2; 694 } else { 695 ierr = MPI_Get_count(&recv_status,MPIU_INT,nvals);CHKERRQ(ierr); 696 697 flg_v[2*recv_status.MPI_SOURCE+1] = i/2; 698 699 *nvals = *nvals/2; /* This message has both row indices and col indices */ 700 } 701 702 /* Check if we have both messages from this proc */ 703 i1 = flg_v[2*recv_status.MPI_SOURCE]; 704 i2 = flg_v[2*recv_status.MPI_SOURCE+1]; 705 if (i1 != -1 && i2 != -1) { 706 *rows = stash->rindices[i2]; 707 *cols = *rows + *nvals; 708 *vals = stash->rvalues[i1]; 709 *flg = 1; 710 stash->nprocessed++; 711 match_found = PETSC_TRUE; 712 } 713 } 714 PetscFunctionReturn(0); 715 } 716 717 typedef struct { 718 PetscInt row; 719 PetscInt col; 720 PetscScalar vals[1]; /* Actually an array of length bs2 */ 721 } MatStashBlock; 722 723 #undef __FUNCT__ 724 #define __FUNCT__ "MatStashSortCompress_Private" 725 static PetscErrorCode MatStashSortCompress_Private(MatStash *stash,InsertMode insertmode) 726 { 727 PetscErrorCode ierr; 728 PetscMatStashSpace space; 729 PetscInt n = stash->n,bs = stash->bs,bs2 = bs*bs,cnt,*row,*col,*perm,rowstart,i; 730 PetscScalar **valptr; 731 732 PetscFunctionBegin; 733 ierr = PetscMalloc4(n,&row,n,&col,n,&valptr,n,&perm);CHKERRQ(ierr); 734 for (space=stash->space_head,cnt=0; space; space=space->next) { 735 for (i=0; i<space->local_used; i++) { 736 row[cnt] = space->idx[i]; 737 col[cnt] = space->idy[i]; 738 valptr[cnt] = &space->val[i*bs2]; 739 perm[cnt] = cnt; /* Will tell us where to find valptr after sorting row[] and col[] */ 740 cnt++; 741 } 742 } 743 if (cnt != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"MatStash n %D, but counted %D entries",n,cnt); 744 ierr = PetscSortIntWithArrayPair(n,row,col,perm);CHKERRQ(ierr); 745 /* Scan through the rows, sorting each one, combining duplicates, and packing send buffers */ 746 for (rowstart=0,cnt=0,i=1; i<=n; i++) { 747 if (i == n || row[i] != row[rowstart]) { /* Sort the last row. */ 748 PetscInt colstart; 749 ierr = PetscSortIntWithArray(i-rowstart,&col[rowstart],&perm[rowstart]);CHKERRQ(ierr); 750 for (colstart=rowstart; colstart<i; ) { /* Compress multiple insertions to the same location */ 751 PetscInt j,l; 752 MatStashBlock *block; 753 ierr = PetscSegBufferGet(stash->segsendblocks,1,&block);CHKERRQ(ierr); 754 block->row = row[rowstart]; 755 block->col = col[colstart]; 756 ierr = PetscMemcpy(block->vals,valptr[perm[colstart]],bs2*sizeof(block->vals[0]));CHKERRQ(ierr); 757 for (j=colstart+1; j<i && col[j] == col[colstart]; j++) { /* Add any extra stashed blocks at the same (row,col) */ 758 if (insertmode == ADD_VALUES) { 759 for (l=0; l<bs2; l++) block->vals[l] += valptr[perm[j]][l]; 760 } else { 761 ierr = PetscMemcpy(block->vals,valptr[perm[j]],bs2*sizeof(block->vals[0]));CHKERRQ(ierr); 762 } 763 } 764 colstart = j; 765 } 766 rowstart = i; 767 } 768 } 769 ierr = PetscFree4(row,col,valptr,perm);CHKERRQ(ierr); 770 PetscFunctionReturn(0); 771 } 772 773 #undef __FUNCT__ 774 #define __FUNCT__ "MatStashBlockTypeSetUp" 775 static PetscErrorCode MatStashBlockTypeSetUp(MatStash *stash) 776 { 777 PetscErrorCode ierr; 778 779 PetscFunctionBegin; 780 if (stash->blocktype == MPI_DATATYPE_NULL) { 781 PetscInt bs2 = PetscSqr(stash->bs); 782 PetscMPIInt blocklens[2]; 783 MPI_Aint displs[2]; 784 MPI_Datatype types[2],stype; 785 786 stash->blocktype_size = offsetof(MatStashBlock,vals) + bs2*sizeof(PetscScalar); 787 if (stash->blocktype_size % sizeof(PetscInt)) { /* Implies that PetscInt is larger and does not satisfy alignment without padding */ 788 stash->blocktype_size += sizeof(PetscInt) - stash->blocktype_size % sizeof(PetscInt); 789 } 790 ierr = PetscSegBufferCreate(stash->blocktype_size,1,&stash->segsendblocks);CHKERRQ(ierr); 791 ierr = PetscSegBufferCreate(stash->blocktype_size,1,&stash->segrecvblocks);CHKERRQ(ierr); 792 ierr = PetscSegBufferCreate(sizeof(MatStashFrame),1,&stash->segrecvframe);CHKERRQ(ierr); 793 blocklens[0] = 2; 794 blocklens[1] = bs2; 795 displs[0] = offsetof(MatStashBlock,row); 796 displs[1] = offsetof(MatStashBlock,vals); 797 types[0] = MPIU_INT; 798 types[1] = MPIU_SCALAR; 799 ierr = MPI_Type_create_struct(2,blocklens,displs,types,&stype);CHKERRQ(ierr); 800 ierr = MPI_Type_commit(&stype);CHKERRQ(ierr); 801 ierr = MPI_Type_create_resized(stype,0,stash->blocktype_size,&stash->blocktype);CHKERRQ(ierr); /* MPI-2 */ 802 ierr = MPI_Type_commit(&stash->blocktype);CHKERRQ(ierr); 803 ierr = MPI_Type_free(&stype);CHKERRQ(ierr); 804 } 805 PetscFunctionReturn(0); 806 } 807 808 #undef __FUNCT__ 809 #define __FUNCT__ "MatStashBTSSend_Private" 810 /* Callback invoked after target rank has initiatied receive of rendezvous message. 811 * Here we post the main sends. 812 */ 813 static PetscErrorCode MatStashBTSSend_Private(MPI_Comm comm,const PetscMPIInt tag[],PetscMPIInt rankid,PetscMPIInt rank,void *sdata,MPI_Request req[],void *ctx) 814 { 815 MatStash *stash = (MatStash*)ctx; 816 MatStashHeader *hdr = (MatStashHeader*)sdata; 817 PetscErrorCode ierr; 818 819 PetscFunctionBegin; 820 if (rank != stash->sendranks[rankid]) SETERRQ3(comm,PETSC_ERR_PLIB,"BTS Send rank %d does not match sendranks[%d] %d",rank,rankid,stash->sendranks[rankid]); 821 ierr = MPI_Isend(stash->sendframes[rankid].buffer,hdr->count,stash->blocktype,rank,tag[0],comm,&req[0]);CHKERRQ(ierr); 822 stash->sendframes[rankid].count = hdr->count; 823 stash->sendframes[rankid].pending = 1; 824 PetscFunctionReturn(0); 825 } 826 827 #undef __FUNCT__ 828 #define __FUNCT__ "MatStashBTSRecv_Private" 829 /* Callback invoked by target after receiving rendezvous message. 830 * Here we post the main recvs. 831 */ 832 static PetscErrorCode MatStashBTSRecv_Private(MPI_Comm comm,const PetscMPIInt tag[],PetscMPIInt rank,void *rdata,MPI_Request req[],void *ctx) 833 { 834 MatStash *stash = (MatStash*)ctx; 835 MatStashHeader *hdr = (MatStashHeader*)rdata; 836 MatStashFrame *frame; 837 PetscErrorCode ierr; 838 839 PetscFunctionBegin; 840 ierr = PetscSegBufferGet(stash->segrecvframe,1,&frame);CHKERRQ(ierr); 841 ierr = PetscSegBufferGet(stash->segrecvblocks,hdr->count,&frame->buffer);CHKERRQ(ierr); 842 ierr = MPI_Irecv(frame->buffer,hdr->count,stash->blocktype,rank,tag[0],comm,&req[0]);CHKERRQ(ierr); 843 frame->count = hdr->count; 844 frame->pending = 1; 845 PetscFunctionReturn(0); 846 } 847 848 #undef __FUNCT__ 849 #define __FUNCT__ "MatStashScatterBegin_BTS" 850 /* 851 * owners[] contains the ownership ranges; may be indexed by either blocks or scalars 852 */ 853 static PetscErrorCode MatStashScatterBegin_BTS(Mat mat,MatStash *stash,PetscInt owners[]) 854 { 855 PetscErrorCode ierr; 856 size_t nblocks; 857 char *sendblocks; 858 859 PetscFunctionBegin; 860 if (stash->subset_off_proc && !mat->subsetoffprocentries) { /* We won't use the old scatter context. */ 861 ierr = MatStashScatterDestroy_BTS(stash);CHKERRQ(ierr); 862 } 863 864 ierr = MatStashBlockTypeSetUp(stash);CHKERRQ(ierr); 865 ierr = MatStashSortCompress_Private(stash,mat->insertmode);CHKERRQ(ierr); 866 ierr = PetscSegBufferGetSize(stash->segsendblocks,&nblocks);CHKERRQ(ierr); 867 ierr = PetscSegBufferExtractInPlace(stash->segsendblocks,&sendblocks);CHKERRQ(ierr); 868 if (stash->subset_off_proc && mat->subsetoffprocentries) { /* Set up sendhdrs and sendframes for each rank that we sent before */ 869 PetscInt i,b; 870 for (i=0,b=0; i<stash->nsendranks; i++) { 871 stash->sendframes[i].buffer = &sendblocks[b*stash->blocktype_size]; 872 /* sendhdr is never actually sent, but the count is used by MatStashBTSSend_Private */ 873 stash->sendhdr[i].count = 0; /* Might remain empty (in which case we send a zero-sized message) if no values are communicated to that process */ 874 for ( ; b<nblocks; b++) { 875 MatStashBlock *sendblock_b = (MatStashBlock*)&sendblocks[b*stash->blocktype_size]; 876 if (PetscUnlikely(sendblock_b->row < owners[stash->sendranks[i]])) SETERRQ2(stash->comm,PETSC_ERR_ARG_WRONG,"MAT_SUBSET_OFF_PROC_ENTRIES set, but row %D owned by %d not communicated in initial assembly",sendblock_b->row,stash->sendranks[i]); 877 if (sendblock_b->row >= owners[stash->sendranks[i]+1]) break; 878 stash->sendhdr[i].count++; 879 } 880 } 881 } else { /* Dynamically count and pack (first time) */ 882 PetscInt i,rowstart,sendno; 883 884 /* Count number of send ranks and allocate for sends */ 885 stash->nsendranks = 0; 886 for (rowstart=0; rowstart<nblocks; ) { 887 PetscInt lastowner,owner; 888 MatStashBlock *sendblock_rowstart = (MatStashBlock*)&sendblocks[rowstart*stash->blocktype_size]; 889 ierr = PetscFindInt(sendblock_rowstart->row,stash->size+1,owners,&owner);CHKERRQ(ierr); 890 if (owner < 0) owner = -(owner+2); 891 lastowner = owner; 892 for (i=rowstart+1; i<nblocks; i++) { /* Move forward through a run of blocks with the same owner */ 893 MatStashBlock *sendblock_i = (MatStashBlock*)&sendblocks[i*stash->blocktype_size]; 894 if (sendblock_i->row == sendblock_rowstart->row) continue; 895 ierr = PetscFindInt(sendblock_i->row,stash->size+1,owners,&owner);CHKERRQ(ierr); 896 if (owner < 0) owner = -(owner+2); 897 if (owner != lastowner) break; 898 } 899 stash->nsendranks++; 900 rowstart = i; 901 } 902 ierr = PetscMalloc3(stash->nsendranks,&stash->sendranks,stash->nsendranks,&stash->sendhdr,stash->nsendranks,&stash->sendframes);CHKERRQ(ierr); 903 904 /* Set up sendhdrs and sendframes */ 905 sendno = 0; 906 for (rowstart=0; rowstart<nblocks; ) { 907 PetscInt owner; 908 MatStashBlock *sendblock_rowstart = (MatStashBlock*)&sendblocks[rowstart*stash->blocktype_size]; 909 ierr = PetscFindInt(sendblock_rowstart->row,stash->size+1,owners,&owner);CHKERRQ(ierr); 910 if (owner < 0) owner = -(owner+2); 911 stash->sendranks[sendno] = owner; 912 for (i=rowstart+1; i<nblocks; i++) { /* Move forward through a run of blocks with the same owner */ 913 MatStashBlock *sendblock_i = (MatStashBlock*)&sendblocks[i*stash->blocktype_size]; 914 if (sendblock_i->row == sendblock_rowstart->row) continue; 915 ierr = PetscFindInt(sendblock_i->row,stash->size+1,owners,&owner);CHKERRQ(ierr); 916 if (owner < 0) owner = -(owner+2); 917 if (owner != stash->sendranks[sendno]) break; 918 } 919 stash->sendframes[sendno].buffer = sendblock_rowstart; 920 stash->sendframes[sendno].pending = 0; 921 stash->sendhdr[sendno].count = i - rowstart; 922 stash->sendhdr[sendno].insertmode = mat->insertmode; 923 sendno++; 924 rowstart = i; 925 } 926 if (sendno != stash->nsendranks) SETERRQ2(stash->comm,PETSC_ERR_PLIB,"BTS counted %D sendranks, but %D sends",stash->nsendranks,sendno); 927 } 928 929 if (stash->subset_off_proc && mat->subsetoffprocentries) { 930 PetscMPIInt i,tag; 931 ierr = PetscCommGetNewTag(stash->comm,&tag);CHKERRQ(ierr); 932 for (i=0; i<stash->nrecvranks; i++) { 933 ierr = MatStashBTSRecv_Private(stash->comm,&tag,stash->recvranks[i],&stash->recvhdr[i],&stash->recvreqs[i],stash);CHKERRQ(ierr); 934 } 935 for (i=0; i<stash->nsendranks; i++) { 936 ierr = MatStashBTSSend_Private(stash->comm,&tag,i,stash->sendranks[i],&stash->sendhdr[i],&stash->sendreqs[i],stash);CHKERRQ(ierr); 937 } 938 stash->use_status = PETSC_TRUE; /* Use count from message status. */ 939 } else { 940 ierr = PetscCommBuildTwoSidedFReq(stash->comm,2,MPIU_INT,stash->nsendranks,stash->sendranks,stash->sendhdr, 941 &stash->nrecvranks,&stash->recvranks,&stash->recvhdr,1,&stash->sendreqs,&stash->recvreqs, 942 MatStashBTSSend_Private,MatStashBTSRecv_Private,stash);CHKERRQ(ierr); 943 stash->use_status = PETSC_FALSE; /* Use count from header instead of from message. */ 944 } 945 946 ierr = PetscMalloc2(stash->nrecvranks,&stash->some_indices,stash->nrecvranks,&stash->some_statuses);CHKERRQ(ierr); 947 ierr = PetscSegBufferExtractInPlace(stash->segrecvframe,&stash->recvframes);CHKERRQ(ierr); 948 stash->recvframe_active = NULL; 949 stash->recvframe_i = 0; 950 stash->some_i = 0; 951 stash->some_count = 0; 952 stash->recvcount = 0; 953 stash->subset_off_proc = mat->subsetoffprocentries; 954 PetscFunctionReturn(0); 955 } 956 957 #undef __FUNCT__ 958 #define __FUNCT__ "MatStashScatterGetMesg_BTS" 959 static PetscErrorCode MatStashScatterGetMesg_BTS(MatStash *stash,PetscMPIInt *n,PetscInt **row,PetscInt **col,PetscScalar **val,PetscInt *flg) 960 { 961 PetscErrorCode ierr; 962 MatStashBlock *block; 963 964 PetscFunctionBegin; 965 *flg = 0; 966 while (!stash->recvframe_active || stash->recvframe_i == stash->recvframe_count) { 967 if (stash->some_i == stash->some_count) { 968 if (stash->recvcount == stash->nrecvranks) PetscFunctionReturn(0); /* Done */ 969 ierr = MPI_Waitsome(stash->nrecvranks,stash->recvreqs,&stash->some_count,stash->some_indices,stash->use_status?stash->some_statuses:MPI_STATUSES_IGNORE);CHKERRQ(ierr); 970 stash->some_i = 0; 971 } 972 stash->recvframe_active = &stash->recvframes[stash->some_indices[stash->some_i]]; 973 stash->recvframe_count = stash->recvframe_active->count; /* From header; maximum count */ 974 if (stash->use_status) { /* Count what was actually sent */ 975 ierr = MPI_Get_count(&stash->some_statuses[stash->some_i],stash->blocktype,&stash->recvframe_count);CHKERRQ(ierr); 976 } 977 stash->some_i++; 978 stash->recvcount++; 979 stash->recvframe_i = 0; 980 } 981 *n = 1; 982 block = (MatStashBlock*)&((char*)stash->recvframe_active->buffer)[stash->recvframe_i*stash->blocktype_size]; 983 *row = &block->row; 984 *col = &block->col; 985 *val = block->vals; 986 stash->recvframe_i++; 987 *flg = 1; 988 PetscFunctionReturn(0); 989 } 990 991 #undef __FUNCT__ 992 #define __FUNCT__ "MatStashScatterEnd_BTS" 993 static PetscErrorCode MatStashScatterEnd_BTS(MatStash *stash) 994 { 995 PetscErrorCode ierr; 996 997 PetscFunctionBegin; 998 ierr = MPI_Waitall(stash->nsendranks,stash->sendreqs,MPI_STATUSES_IGNORE);CHKERRQ(ierr); 999 if (!stash->subset_off_proc) { /* Only collect the communication contexts if it won't be reused. */ 1000 ierr = MatStashScatterDestroy_BTS(stash);CHKERRQ(ierr); 1001 } 1002 1003 /* Now update nmaxold to be app 10% more than max n used, this way the 1004 wastage of space is reduced the next time this stash is used. 1005 Also update the oldmax, only if it increases */ 1006 if (stash->n) { 1007 PetscInt bs2 = stash->bs*stash->bs; 1008 PetscInt oldnmax = ((int)(stash->n * 1.1) + 5)*bs2; 1009 if (oldnmax > stash->oldnmax) stash->oldnmax = oldnmax; 1010 } 1011 1012 stash->nmax = 0; 1013 stash->n = 0; 1014 stash->reallocs = -1; 1015 stash->nprocessed = 0; 1016 1017 ierr = PetscMatStashSpaceDestroy(&stash->space_head);CHKERRQ(ierr); 1018 1019 stash->space = 0; 1020 1021 PetscFunctionReturn(0); 1022 } 1023 1024 #undef __FUNCT__ 1025 #define __FUNCT__ "MatStashScatterDestroy_BTS" 1026 static PetscErrorCode MatStashScatterDestroy_BTS(MatStash *stash) 1027 { 1028 PetscErrorCode ierr; 1029 1030 PetscFunctionBegin; 1031 ierr = PetscSegBufferDestroy(&stash->segsendblocks);CHKERRQ(ierr); 1032 ierr = PetscSegBufferDestroy(&stash->segrecvframe);CHKERRQ(ierr); 1033 stash->recvframes = NULL; 1034 ierr = PetscSegBufferDestroy(&stash->segrecvblocks);CHKERRQ(ierr); 1035 if (stash->blocktype != MPI_DATATYPE_NULL) { 1036 ierr = MPI_Type_free(&stash->blocktype);CHKERRQ(ierr); 1037 } 1038 stash->nsendranks = 0; 1039 stash->nrecvranks = 0; 1040 ierr = PetscFree3(stash->sendranks,stash->sendhdr,stash->sendframes);CHKERRQ(ierr); 1041 ierr = PetscFree(stash->sendreqs);CHKERRQ(ierr); 1042 ierr = PetscFree(stash->recvreqs);CHKERRQ(ierr); 1043 ierr = PetscFree(stash->recvranks);CHKERRQ(ierr); 1044 ierr = PetscFree(stash->recvhdr);CHKERRQ(ierr); 1045 ierr = PetscFree2(stash->some_indices,stash->some_statuses);CHKERRQ(ierr); 1046 PetscFunctionReturn(0); 1047 } 1048