1a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER 2*bc5ccf88SSatish Balay static char vcid[] = "$Id: stash.c,v 1.20 1999/02/25 22:48:34 balay Exp balay $"; 32d5177cdSBarry Smith #endif 42d5177cdSBarry Smith 52d5177cdSBarry Smith #include "src/vec/vecimpl.h" 670f55243SBarry Smith #include "src/mat/matimpl.h" 79417f4adSLois Curfman McInnes 8*bc5ccf88SSatish Balay #define DEFAULT_STASH_SIZE 10000 99417f4adSLois Curfman McInnes /* 109417f4adSLois Curfman McInnes This stash is currently used for all the parallel matrix implementations. 11d5d45c9bSBarry Smith The stash is where elements of a matrix destined to be stored on other 12d5d45c9bSBarry Smith processors are kept until matrix assembly is done. 139417f4adSLois Curfman McInnes 1490f02eecSBarry Smith This is a simple minded stash. Simply add entry to end of stash. 159417f4adSLois Curfman McInnes */ 169417f4adSLois Curfman McInnes 175615d1e5SSatish Balay #undef __FUNC__ 18*bc5ccf88SSatish Balay #define __FUNC__ "StashCreate_Private" 19*bc5ccf88SSatish Balay int StashCreate_Private(MPI_Comm comm,int bs, Stash *stash) 209417f4adSLois Curfman McInnes { 21*bc5ccf88SSatish Balay int ierr,flg,max=DEFAULT_STASH_SIZE; 22*bc5ccf88SSatish Balay 233a40ed3dSBarry Smith PetscFunctionBegin; 24*bc5ccf88SSatish Balay /* Require 2 tags, get the second using PetscCommGetNewTag() */ 25*bc5ccf88SSatish Balay ierr = PetscCommDuplicate_Private(comm,&stash->comm,&stash->tag1);CHKERRQ(ierr); 26*bc5ccf88SSatish Balay ierr = PetscCommGetNewTag(comm,&stash->tag2); CHKERRQ(ierr); 27*bc5ccf88SSatish Balay ierr = OptionsGetInt(PETSC_NULL,"-stash_initial_size",&max,&flg);CHKERRQ(ierr); 28*bc5ccf88SSatish Balay ierr = StashSetInitialSize_Private(stash,max); CHKERRQ(ierr); 29*bc5ccf88SSatish Balay 30*bc5ccf88SSatish Balay if (bs <= 0) bs = 1; 31*bc5ccf88SSatish Balay stash->bs = bs; 329417f4adSLois Curfman McInnes stash->nmax = 0; 339417f4adSLois Curfman McInnes stash->n = 0; 34*bc5ccf88SSatish Balay stash->reallocs = 0; 359417f4adSLois Curfman McInnes stash->idx = 0; 369417f4adSLois Curfman McInnes stash->idy = 0; 37*bc5ccf88SSatish Balay stash->array = 0; 389417f4adSLois Curfman McInnes 39*bc5ccf88SSatish Balay stash->send_waits = 0; 40*bc5ccf88SSatish Balay stash->recv_waits = 0; 41*bc5ccf88SSatish Balay stash->nsends = 0; 42*bc5ccf88SSatish Balay stash->nrecvs = 0; 43*bc5ccf88SSatish Balay stash->svalues = 0; 44*bc5ccf88SSatish Balay stash->rvalues = 0; 45*bc5ccf88SSatish Balay stash->rmax = 0; 46*bc5ccf88SSatish Balay stash->rdata = 0; 473a40ed3dSBarry Smith PetscFunctionReturn(0); 489417f4adSLois Curfman McInnes } 499417f4adSLois Curfman McInnes 505615d1e5SSatish Balay #undef __FUNC__ 51d4bb536fSBarry Smith #define __FUNC__ "StashDestroy_Private" 529417f4adSLois Curfman McInnes int StashDestroy_Private(Stash *stash) 539417f4adSLois Curfman McInnes { 54*bc5ccf88SSatish Balay int ierr; 55*bc5ccf88SSatish Balay PetscFunctionBegin; 56*bc5ccf88SSatish Balay ierr = PetscCommDestroy_Private(&stash->comm); CHKERRQ(ierr); 57*bc5ccf88SSatish Balay if (stash->array) {PetscFree(stash->array); stash->array = 0;} 58*bc5ccf88SSatish Balay PetscFunctionReturn(0); 59*bc5ccf88SSatish Balay } 60*bc5ccf88SSatish Balay 61*bc5ccf88SSatish Balay #undef __FUNC__ 62*bc5ccf88SSatish Balay #define __FUNC__ "StashReset_Private" 63*bc5ccf88SSatish Balay int StashReset_Private(Stash *stash) 64*bc5ccf88SSatish Balay { 653a40ed3dSBarry Smith PetscFunctionBegin; 66d07ff455SSatish Balay /* Now update nmaxold to be app 10% more than nmax, this way the 67d07ff455SSatish Balay wastage of space is reduced the next time this stash is used */ 68*bc5ccf88SSatish Balay stash->oldnmax = (int)(stash->nmax * 1.1) + 5; 69d07ff455SSatish Balay stash->nmax = 0; 70d07ff455SSatish Balay stash->n = 0; 71*bc5ccf88SSatish Balay stash->reallocs = 0; 72*bc5ccf88SSatish Balay stash->rmax = 0; 73*bc5ccf88SSatish Balay 74*bc5ccf88SSatish Balay if (stash->array) { 75*bc5ccf88SSatish Balay PetscFree(stash->array); 76*bc5ccf88SSatish Balay stash->array = 0; 77*bc5ccf88SSatish Balay stash->idx = 0; 78*bc5ccf88SSatish Balay stash->idy = 0; 79*bc5ccf88SSatish Balay } 80*bc5ccf88SSatish Balay if (stash->send_waits) {PetscFree(stash->send_waits);stash->send_waits = 0;} 81*bc5ccf88SSatish Balay if (stash->recv_waits) {PetscFree(stash->recv_waits);stash->recv_waits =0;} 82*bc5ccf88SSatish Balay if (stash->svalues) {PetscFree(stash->svalues);stash->svalues = 0;} 83*bc5ccf88SSatish Balay if (stash->rvalues) {PetscFree(stash->rvalues); stash->rvalues = 0;} 84*bc5ccf88SSatish Balay if (stash->rdata) {PetscFree(stash->rdata); stash->rdata = 0;} 85*bc5ccf88SSatish Balay 863a40ed3dSBarry Smith PetscFunctionReturn(0); 879417f4adSLois Curfman McInnes } 889417f4adSLois Curfman McInnes 895615d1e5SSatish Balay #undef __FUNC__ 90d4bb536fSBarry Smith #define __FUNC__ "StashInfo_Private" 9197530c3fSBarry Smith int StashInfo_Private(Stash *stash) 9297530c3fSBarry Smith { 933a40ed3dSBarry Smith PetscFunctionBegin; 94*bc5ccf88SSatish Balay PLogInfo(0,"StashInfo_Private:Stash size %d, mallocs incured %d\n",stash->n,stash->reallocs); 95*bc5ccf88SSatish Balay PetscFunctionReturn(0); 96*bc5ccf88SSatish Balay } 97*bc5ccf88SSatish Balay #undef __FUNC__ 98*bc5ccf88SSatish Balay #define __FUNC__ "StashSetInitialSize_Private" 99*bc5ccf88SSatish Balay int StashSetInitialSize_Private(Stash *stash,int max) 100*bc5ccf88SSatish Balay { 101*bc5ccf88SSatish Balay PetscFunctionBegin; 102*bc5ccf88SSatish Balay stash->oldnmax = max; 103*bc5ccf88SSatish Balay stash->nmax = 0; 1043a40ed3dSBarry Smith PetscFunctionReturn(0); 10597530c3fSBarry Smith } 10697530c3fSBarry Smith 1075615d1e5SSatish Balay #undef __FUNC__ 108*bc5ccf88SSatish Balay #define __FUNC__ "StashExpand_Private" 109*bc5ccf88SSatish Balay static int StashExpand_Private(Stash *stash) 1109417f4adSLois Curfman McInnes { 111*bc5ccf88SSatish Balay int *n_idx,*n_idy,newnmax; 112*bc5ccf88SSatish Balay Scalar *n_array; 1139417f4adSLois Curfman McInnes 1143a40ed3dSBarry Smith PetscFunctionBegin; 1159417f4adSLois Curfman McInnes /* allocate a larger stash */ 116d07ff455SSatish Balay if (stash->nmax == 0) newnmax = stash->oldnmax; 117d07ff455SSatish Balay else newnmax = stash->nmax *2; 118d07ff455SSatish Balay 119d07ff455SSatish Balay n_array = (Scalar *)PetscMalloc((newnmax)*(2*sizeof(int)+sizeof(Scalar)));CHKPTRQ(n_array); 120d07ff455SSatish Balay n_idx = (int *) (n_array + newnmax); 121d07ff455SSatish Balay n_idy = (int *) (n_idx + newnmax); 122416022c9SBarry Smith PetscMemcpy(n_array,stash->array,stash->nmax*sizeof(Scalar)); 123416022c9SBarry Smith PetscMemcpy(n_idx,stash->idx,stash->nmax*sizeof(int)); 124416022c9SBarry Smith PetscMemcpy(n_idy,stash->idy,stash->nmax*sizeof(int)); 1250452661fSBarry Smith if (stash->array) PetscFree(stash->array); 126d07ff455SSatish Balay stash->array = n_array; 127d07ff455SSatish Balay stash->idx = n_idx; 128d07ff455SSatish Balay stash->idy = n_idy; 129d07ff455SSatish Balay stash->nmax = newnmax; 130d07ff455SSatish Balay stash->oldnmax = newnmax; 131*bc5ccf88SSatish Balay stash->reallocs++; 132*bc5ccf88SSatish Balay PetscFunctionReturn(0); 133*bc5ccf88SSatish Balay } 134*bc5ccf88SSatish Balay 135*bc5ccf88SSatish Balay /* 136*bc5ccf88SSatish Balay Should do this properly. With a sorted array. 137*bc5ccf88SSatish Balay */ 138*bc5ccf88SSatish Balay #undef __FUNC__ 139*bc5ccf88SSatish Balay #define __FUNC__ "StashValues_Private" 140*bc5ccf88SSatish Balay int StashValues_Private(Stash *stash,int row,int n, int *idxn,Scalar *values,InsertMode addv) 141*bc5ccf88SSatish Balay { 142*bc5ccf88SSatish Balay int ierr,i,found; 143*bc5ccf88SSatish Balay Scalar val; 144*bc5ccf88SSatish Balay 145*bc5ccf88SSatish Balay PetscFunctionBegin; 146*bc5ccf88SSatish Balay for ( i=0; i<n; i++ ) { 147*bc5ccf88SSatish Balay found = 0; 148*bc5ccf88SSatish Balay val = *values++; 149*bc5ccf88SSatish Balay if (!found) { /* not found so add to end */ 150*bc5ccf88SSatish Balay if ( stash->n == stash->nmax ) { 151*bc5ccf88SSatish Balay ierr = StashExpand_Private(stash); CHKERRQ(ierr); 1529417f4adSLois Curfman McInnes } 1539417f4adSLois Curfman McInnes stash->array[stash->n] = val; 1549417f4adSLois Curfman McInnes stash->idx[stash->n] = row; 1559417f4adSLois Curfman McInnes stash->idy[stash->n++] = idxn[i]; 1569417f4adSLois Curfman McInnes } 1579417f4adSLois Curfman McInnes } 1583a40ed3dSBarry Smith PetscFunctionReturn(0); 1599417f4adSLois Curfman McInnes } 160*bc5ccf88SSatish Balay 161*bc5ccf88SSatish Balay #undef __FUNC__ 162*bc5ccf88SSatish Balay #define __FUNC__ "StashScatterBegin_Private" 163*bc5ccf88SSatish Balay int StashScatterBegin_Private(Stash *stash,int *owners) 164*bc5ccf88SSatish Balay { 165*bc5ccf88SSatish Balay MPI_Comm comm = stash->comm; 166*bc5ccf88SSatish Balay MPI_Request *send_waits,*recv_waits; 167*bc5ccf88SSatish Balay Scalar *rvalues,*svalues; 168*bc5ccf88SSatish Balay int *owner,*startv,*starti,tag1=stash->tag1,tag2=stash->tag2; 169*bc5ccf88SSatish Balay int rank,size,*nprocs,i,j,idx,*procs,nsends,nreceives,nmax,*work; 170*bc5ccf88SSatish Balay int count,ierr,*sindices,*rindices,bs=stash->bs; 171*bc5ccf88SSatish Balay 172*bc5ccf88SSatish Balay PetscFunctionBegin; 173*bc5ccf88SSatish Balay 174*bc5ccf88SSatish Balay ierr = MPI_Comm_size(comm,&size); CHKERRQ(ierr); 175*bc5ccf88SSatish Balay ierr = MPI_Comm_rank(comm,&rank); CHKERRQ(ierr); 176*bc5ccf88SSatish Balay 177*bc5ccf88SSatish Balay /* first count number of contributors to each processor */ 178*bc5ccf88SSatish Balay nprocs = (int *) PetscMalloc( 2*size*sizeof(int) ); CHKPTRQ(nprocs); 179*bc5ccf88SSatish Balay PetscMemzero(nprocs,2*size*sizeof(int)); procs = nprocs + size; 180*bc5ccf88SSatish Balay owner = (int *) PetscMalloc( (stash->n+1)*sizeof(int) ); CHKPTRQ(owner); 181*bc5ccf88SSatish Balay for ( i=0; i<stash->n; i++ ) { 182*bc5ccf88SSatish Balay idx = stash->idx[i]; 183*bc5ccf88SSatish Balay for ( j=0; j<size; j++ ) { 184*bc5ccf88SSatish Balay if (idx >= bs*owners[j] && idx < bs*owners[j+1]) { 185*bc5ccf88SSatish Balay nprocs[j]++; procs[j] = 1; owner[i] = j; break; 186*bc5ccf88SSatish Balay } 187*bc5ccf88SSatish Balay } 188*bc5ccf88SSatish Balay } 189*bc5ccf88SSatish Balay nsends = 0; for ( i=0; i<size; i++ ) { nsends += procs[i];} 190*bc5ccf88SSatish Balay 191*bc5ccf88SSatish Balay /* inform other processors of number of messages and max length*/ 192*bc5ccf88SSatish Balay work = (int *)PetscMalloc(size*sizeof(int)); CHKPTRQ(work); 193*bc5ccf88SSatish Balay ierr = MPI_Allreduce(procs,work,size,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr); 194*bc5ccf88SSatish Balay nreceives = work[rank]; 195*bc5ccf88SSatish Balay ierr = MPI_Allreduce(nprocs,work,size,MPI_INT,MPI_MAX,comm);CHKERRQ(ierr); 196*bc5ccf88SSatish Balay nmax = work[rank]; 197*bc5ccf88SSatish Balay PetscFree(work); 198*bc5ccf88SSatish Balay /* post receives: 199*bc5ccf88SSatish Balay since we don't know how long each individual message is we 200*bc5ccf88SSatish Balay allocate the largest needed buffer for each receive. Potentially 201*bc5ccf88SSatish Balay this is a lot of wasted space. 202*bc5ccf88SSatish Balay */ 203*bc5ccf88SSatish Balay rvalues = (Scalar *)PetscMalloc((nreceives+1)*(nmax+1)*(sizeof(Scalar)+2*sizeof(int))); 204*bc5ccf88SSatish Balay CHKPTRQ(rvalues); 205*bc5ccf88SSatish Balay rindices = (int *) (rvalues + nreceives*nmax); 206*bc5ccf88SSatish Balay recv_waits = (MPI_Request *) PetscMalloc((nreceives+1)*2*sizeof(MPI_Request)); 207*bc5ccf88SSatish Balay CHKPTRQ(recv_waits); 208*bc5ccf88SSatish Balay for ( i=0,count=0; i<nreceives; i++ ) { 209*bc5ccf88SSatish Balay ierr = MPI_Irecv(rvalues+nmax*i,nmax,MPIU_SCALAR,MPI_ANY_SOURCE,tag1,comm, 210*bc5ccf88SSatish Balay recv_waits+count++); CHKERRQ(ierr); 211*bc5ccf88SSatish Balay ierr = MPI_Irecv(rindices+2*nmax*i,2*nmax,MPI_INT,MPI_ANY_SOURCE,tag2,comm, 212*bc5ccf88SSatish Balay recv_waits+count++); CHKERRQ(ierr); 213*bc5ccf88SSatish Balay } 214*bc5ccf88SSatish Balay 215*bc5ccf88SSatish Balay /* do sends: 216*bc5ccf88SSatish Balay 1) starts[i] gives the starting index in svalues for stuff going to 217*bc5ccf88SSatish Balay the ith processor 218*bc5ccf88SSatish Balay */ 219*bc5ccf88SSatish Balay svalues = (Scalar *) PetscMalloc((stash->n+1)*(sizeof(Scalar)+2*sizeof(int))); 220*bc5ccf88SSatish Balay CHKPTRQ(svalues); 221*bc5ccf88SSatish Balay sindices = (int *) (svalues + stash->n); 222*bc5ccf88SSatish Balay send_waits = (MPI_Request *) PetscMalloc(2*(nsends+1)*sizeof(MPI_Request)); 223*bc5ccf88SSatish Balay CHKPTRQ(send_waits); 224*bc5ccf88SSatish Balay startv = (int *) PetscMalloc(2*size*sizeof(int) ); CHKPTRQ(startv); 225*bc5ccf88SSatish Balay starti = startv + size; 226*bc5ccf88SSatish Balay /* use 2 sends the first with all_a, the next with all_i and then all_j */ 227*bc5ccf88SSatish Balay startv[0] = 0; starti[0] = 0; 228*bc5ccf88SSatish Balay for ( i=1; i<size; i++ ) { 229*bc5ccf88SSatish Balay startv[i] = startv[i-1] + nprocs[i-1]; 230*bc5ccf88SSatish Balay starti[i] = starti[i-1] + nprocs[i-1]*2; 231*bc5ccf88SSatish Balay } 232*bc5ccf88SSatish Balay for ( i=0; i<stash->n; i++ ) { 233*bc5ccf88SSatish Balay j = owner[i]; 234*bc5ccf88SSatish Balay svalues[startv[j]] = stash->array[i]; 235*bc5ccf88SSatish Balay sindices[starti[j]] = stash->idx[i]; 236*bc5ccf88SSatish Balay sindices[starti[j]+nprocs[j]] = stash->idy[i]; 237*bc5ccf88SSatish Balay startv[j]++; 238*bc5ccf88SSatish Balay starti[j]++; 239*bc5ccf88SSatish Balay } 240*bc5ccf88SSatish Balay startv[0] = 0; 241*bc5ccf88SSatish Balay for ( i=1; i<size; i++ ) { startv[i] = startv[i-1] + nprocs[i-1];} 242*bc5ccf88SSatish Balay for ( i=0,count=0; i<size; i++ ) { 243*bc5ccf88SSatish Balay if (procs[i]) { 244*bc5ccf88SSatish Balay ierr = MPI_Isend(svalues+startv[i],nprocs[i],MPIU_SCALAR,i,tag1,comm, 245*bc5ccf88SSatish Balay send_waits+count++);CHKERRQ(ierr); 246*bc5ccf88SSatish Balay ierr = MPI_Isend(sindices+2*startv[i],2*nprocs[i],MPI_INT,i,tag2,comm, 247*bc5ccf88SSatish Balay send_waits+count++);CHKERRQ(ierr); 248*bc5ccf88SSatish Balay } 249*bc5ccf88SSatish Balay } 250*bc5ccf88SSatish Balay PetscFree(owner); 251*bc5ccf88SSatish Balay PetscFree(startv); 252*bc5ccf88SSatish Balay PetscFree(nprocs); 253*bc5ccf88SSatish Balay stash->svalues = svalues; stash->rvalues = rvalues; 254*bc5ccf88SSatish Balay stash->nsends = nsends; stash->nrecvs = nreceives; 255*bc5ccf88SSatish Balay stash->send_waits = send_waits; stash->recv_waits = recv_waits; 256*bc5ccf88SSatish Balay stash->rmax = nmax; 257*bc5ccf88SSatish Balay 258*bc5ccf88SSatish Balay PetscFunctionReturn(0); 259*bc5ccf88SSatish Balay } 260*bc5ccf88SSatish Balay 261*bc5ccf88SSatish Balay 262*bc5ccf88SSatish Balay #undef __FUNC__ 263*bc5ccf88SSatish Balay #define __FUNC__ "StashScatterEnd_Private" 264*bc5ccf88SSatish Balay int StashScatterEnd_Private(Stash *stash) 265*bc5ccf88SSatish Balay { 266*bc5ccf88SSatish Balay int i,ierr,size,*nprocs; 267*bc5ccf88SSatish Balay MPI_Status *send_status,*recv_status; 268*bc5ccf88SSatish Balay int i1,i2,s1,s2,count,*rindices; 269*bc5ccf88SSatish Balay 270*bc5ccf88SSatish Balay PetscFunctionBegin; 271*bc5ccf88SSatish Balay 272*bc5ccf88SSatish Balay /* wait on receives */ 273*bc5ccf88SSatish Balay ierr = MPI_Comm_size(stash->comm,&size); CHKERRQ(ierr); 274*bc5ccf88SSatish Balay if (stash->nrecvs) { 275*bc5ccf88SSatish Balay recv_status = (MPI_Status *) PetscMalloc(2*(stash->nrecvs+1)*sizeof(MPI_Status)); 276*bc5ccf88SSatish Balay CHKPTRQ(recv_status); 277*bc5ccf88SSatish Balay ierr = MPI_Waitall(2*stash->nrecvs,stash->recv_waits,recv_status);CHKERRQ(ierr); 278*bc5ccf88SSatish Balay /* Now pack the received messages into a structure which is useable by others */ 279*bc5ccf88SSatish Balay stash->rdata = (Stash_rdata *) PetscMalloc(stash->nrecvs*sizeof(Stash_rdata)); 280*bc5ccf88SSatish Balay CHKPTRQ(stash->rdata); 281*bc5ccf88SSatish Balay nprocs = (int *) PetscMalloc((2*size+1)*sizeof(int)); CHKPTRQ(nprocs); 282*bc5ccf88SSatish Balay rindices = (int *) (stash->rvalues + stash->rmax*stash->nrecvs); 283*bc5ccf88SSatish Balay for (i=0; i<2*size+1; i++ ) nprocs[i] = -1; 284*bc5ccf88SSatish Balay for ( i=0; i<stash->nrecvs; i++ ){ 285*bc5ccf88SSatish Balay nprocs[2*recv_status[2*i].MPI_SOURCE] = i; 286*bc5ccf88SSatish Balay nprocs[2*recv_status[2*i+1].MPI_SOURCE+1] = i; 287*bc5ccf88SSatish Balay } 288*bc5ccf88SSatish Balay for (i=0,count=0; i<size; i++) { 289*bc5ccf88SSatish Balay i1 = nprocs[2*i]; 290*bc5ccf88SSatish Balay i2 = nprocs[2*i+1]; 291*bc5ccf88SSatish Balay if (i1 != -1) { 292*bc5ccf88SSatish Balay if (i2 == -1) SETERRQ(1,0,"Internal Error"); 293*bc5ccf88SSatish Balay ierr = MPI_Get_count(recv_status+2*i1,MPIU_SCALAR,&s1);CHKERRQ(ierr); 294*bc5ccf88SSatish Balay ierr = MPI_Get_count(recv_status+2*i2+1,MPI_INT,&s2);CHKERRQ(ierr); 295*bc5ccf88SSatish Balay if (s1*2 != s2) SETERRQ(1,0,"Internal Error"); 296*bc5ccf88SSatish Balay stash->rdata[count].a = stash->rvalues + i1*stash->rmax; 297*bc5ccf88SSatish Balay stash->rdata[count].i = rindices + 2*i2*stash->rmax; 298*bc5ccf88SSatish Balay stash->rdata[count].j = stash->rdata[count].i + s1; 299*bc5ccf88SSatish Balay stash->rdata[count].n = s1; 300*bc5ccf88SSatish Balay count ++; 301*bc5ccf88SSatish Balay } 302*bc5ccf88SSatish Balay } 303*bc5ccf88SSatish Balay PetscFree(recv_status); 304*bc5ccf88SSatish Balay PetscFree(nprocs); 305*bc5ccf88SSatish Balay } 306*bc5ccf88SSatish Balay /* wait on sends */ 307*bc5ccf88SSatish Balay if (stash->nsends) { 308*bc5ccf88SSatish Balay send_status = (MPI_Status *)PetscMalloc(2*stash->nsends*sizeof(MPI_Status)); 309*bc5ccf88SSatish Balay CHKPTRQ(send_status); 310*bc5ccf88SSatish Balay ierr = MPI_Waitall(2*stash->nsends,stash->send_waits,send_status);CHKERRQ(ierr); 311*bc5ccf88SSatish Balay PetscFree(send_status); 312*bc5ccf88SSatish Balay } 313*bc5ccf88SSatish Balay PetscFunctionReturn(0); 314*bc5ccf88SSatish Balay } 315