Actual source code: threadcomm.c

petsc-3.3-p7 2013-05-11
  1: #include <petsc-private/threadcommimpl.h>      /*I "petscthreadcomm.h" I*/

  3: static PetscInt N_CORES = -1;

  5: PetscBool  PetscThreadCommRegisterAllCalled = PETSC_FALSE;
  6: PetscFList PetscThreadCommList              = PETSC_NULL;
  7: PetscMPIInt Petsc_ThreadComm_keyval         = MPI_KEYVAL_INVALID;

 11: /*@
 12:   PetscGetNCores - Gets the number of available cores on the system
 13:                    
 14:   Level: developer

 16:   Notes
 17:   Defaults to 1 if the available core count cannot be found

 19: @*/
 20: PetscErrorCode PetscGetNCores(PetscInt *ncores)
 21: {
 23:   if (N_CORES == -1) {
 24:     N_CORES = 1; /* Default value if number of cores cannot be found out */

 26: #if defined(PETSC_HAVE_SCHED_CPU_SET_T) /* Linux */
 27:     N_CORES = get_nprocs();
 28: #elif defined(PETSC_HAVE_SYS_SYSCTL_H) /* MacOS, BSD */
 29:     {
 31:       size_t         len = sizeof(N_CORES);
 32:       sysctlbyname("hw.activecpu",&N_CORES,&len,NULL,0);
 33:     }
 34: #elif defined(PETSC_HAVE_WINDOWS_H)   /* Windows */
 35:     {
 36:       SYSTEM_INFO sysinfo;
 37:       GetSystemInfo( &sysinfo );
 38:       N_CORES = sysinfo.dwNumberOfProcessors;
 39:     }
 40: #endif
 41:   }
 42:   if (ncores) *ncores = N_CORES;
 43:   return(0);
 44: }
 45: 
 48: /*@C
 49:   PetscCommGetThreadComm - Gets the thread communicator
 50:                            associated with the MPI communicator
 51:   
 52:   Input Parameters:
 53: . comm - the MPI communicator

 55:   Output Parameters:
 56: . tcommp - pointer to the thread communicator

 58:   Level: Intermediate

 60: .seealso: PetscThreadCommCreate(), PetscThreadCommDestroy()
 61: @*/
 62: PetscErrorCode PetscCommGetThreadComm(MPI_Comm comm,PetscThreadComm *tcommp)
 63: {
 65:   PetscMPIInt    flg;
 66:   void*          ptr;
 67:   MPI_Comm       icomm;

 70:   PetscCommDuplicate(comm,&icomm,PETSC_NULL);
 71:   MPI_Attr_get(icomm,Petsc_ThreadComm_keyval,&ptr,&flg);
 72:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"MPI_Comm does not have a thread communicator");
 73:   *tcommp = (PetscThreadComm)ptr;
 74:   PetscCommDestroy(&icomm);
 75:   return(0);
 76: }

 80: /*
 81:    PetscThreadCommCreate - Allocates a thread communicator object
 82:  
 83:    Input Parameters:
 84: .  comm - the MPI communicator

 86:    Output Parameters:
 87: .  tcomm - pointer to the thread communicator object

 89:    Level: developer

 91: .seealso: PetscThreadCommDestroy()
 92: */
 93: PetscErrorCode PetscThreadCommCreate(MPI_Comm comm,PetscThreadComm *tcomm)
 94: {
 95:   PetscErrorCode  ierr;
 96:   PetscThreadComm tcommout;
 97:   PetscInt        i;

101:   *tcomm = PETSC_NULL;

103:   PetscNew(struct _p_PetscThreadComm,&tcommout);
104:   tcommout->refct = 1;
105:   tcommout->nworkThreads =  -1;
106:   tcommout->affinities = PETSC_NULL;
107:   PetscNew(struct _PetscThreadCommOps,&tcommout->ops);
108:   PetscNew(struct _p_PetscThreadCommJobQueue,&tcommout->jobqueue);
109:   for(i=0;i<PETSC_KERNELS_MAX;i++) {
110:     PetscNew(struct _p_PetscThreadCommJobCtx,&tcommout->jobqueue->jobs[i]);
111:   }
112:   tcommout->jobqueue->ctr = 0;
113:   tcommout->leader = 0;
114:   *tcomm = tcommout;

116:   PetscGetNCores(PETSC_NULL);
117:   return(0);
118: }

122: /*
123:   PetscThreadCommDestroy - Frees a thread communicator object

125:   Input Parameters:
126: . tcomm - the PetscThreadComm object

128:   Level: developer

130: .seealso: PetscThreadCommCreate()
131: */
132: PetscErrorCode PetscThreadCommDestroy(PetscThreadComm tcomm)
133: {
135:   PetscInt       i;


139:   if (!tcomm || --tcomm->refct > 0) return(0);

141:   /* Destroy the implementation specific data struct */
142:   if(tcomm->ops->destroy) {
143:     (*tcomm->ops->destroy)(tcomm);
144:   }

146:   PetscFree(tcomm->affinities);
147:   PetscFree(tcomm->ops);
148:   for(i=0;i<PETSC_KERNELS_MAX;i++) {
149:     PetscFree(tcomm->jobqueue->jobs[i]);
150:   }
151:   PetscFree(tcomm->jobqueue);
152:   PetscThreadCommReductionDestroy(tcomm->red);
153:   PetscFree(tcomm);
154:   return(0);
155: }

159: /*@C
160:    PetscThreadCommView - view a thread communicator

162:    Collective

164:    Input Parameters:
165: +  comm - MPI communicator
166: -  viewer - viewer to display, for example PETSC_VIEWER_STDOUT_WORLD

168:    Level: developer

170: .seealso: PetscThreadCommCreate()
171: @*/
172: PetscErrorCode PetscThreadCommView(MPI_Comm comm,PetscViewer viewer)
173: {
174:   PetscErrorCode  ierr;
175:   PetscBool       iascii;
176:   PetscThreadComm tcomm=0;

179:   PetscCommGetThreadComm(comm,&tcomm);
180:   if(!viewer) {PetscViewerASCIIGetStdout(comm,&viewer);}
181:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
182:   if (iascii) {
183:     PetscViewerASCIIPrintf(viewer,"Thread Communicator\n");
184:     PetscViewerASCIIPushTab(viewer);
185:     PetscViewerASCIIPrintf(viewer,"Number of threads = %D\n",tcomm->nworkThreads);
186:     PetscViewerASCIIPrintf(viewer,"Type = %s\n",tcomm->type);
187:     PetscViewerASCIIPopTab(viewer);
188:     if(tcomm->ops->view) {
189:       PetscViewerASCIIPushTab(viewer);
190:       (*tcomm->ops->view)(tcomm,viewer);
191:       PetscViewerASCIIPopTab(viewer);
192:     }
193:   }
194:   return(0);
195: }

199: /*
200:    PetscThreadCommSetNThreads - Set the thread count for the thread communicator

202:    Not collective

204:    Input Parameters:
205: +  tcomm - the thread communicator
206: -  nthreads - Number of threads

208:    Options Database keys:
209:    -threadcomm_nthreads <nthreads> Number of threads to use

211:    Level: developer

213:    Notes:
214:    Defaults to using 1 thread.

216:    Use nthreads = PETSC_DECIDE or -threadcomm_nthreads PETSC_DECIDE for PETSc to decide the number of threads.


219: .seealso: PetscThreadCommGetNThreads()
220: */
221: PetscErrorCode PetscThreadCommSetNThreads(PetscThreadComm tcomm,PetscInt nthreads)
222: {
224:   PetscBool      flg;
225:   PetscInt       nthr;

228:   if(nthreads == PETSC_DECIDE) {
229:     tcomm->nworkThreads = 1;
230:     PetscOptionsBegin(PETSC_COMM_WORLD,PETSC_NULL,"Thread comm - setting number of threads",PETSC_NULL);
231:     PetscOptionsInt("-threadcomm_nthreads","number of threads to use in the thread communicator","PetscThreadCommSetNThreads",1,&nthr,&flg);
232:     PetscOptionsEnd();
233:     if (flg){
234:       if (nthr == PETSC_DECIDE) {
235:       tcomm->nworkThreads = N_CORES;
236:       } else tcomm->nworkThreads = nthr;
237:     }
238:   } else tcomm->nworkThreads = nthreads;
239:   return(0);
240: }

244: /*@C
245:    PetscThreadCommGetNThreads - Gets the thread count from the thread communicator
246:                                 associated with the MPI communicator

248:    Not collective

250:    Input Parameters:
251: .  comm - the MPI communicator
252:  
253:    Output Parameters:
254: .  nthreads - number of threads

256:    Level: developer

258: .seealso: PetscThreadCommSetNThreads()
259: @*/
260: PetscErrorCode PetscThreadCommGetNThreads(MPI_Comm comm,PetscInt *nthreads)
261: {
262:   PetscErrorCode  ierr;
263:   PetscThreadComm tcomm=0;

266:   PetscCommGetThreadComm(comm,&tcomm);
267:   *nthreads = tcomm->nworkThreads;
268:   return(0);
269: }

273: /*
274:    PetscThreadCommSetAffinities - Sets the core affinity for threads
275:                                   (which threads run on which cores)
276:    
277:    Not collective

279:    Input Parameters:
280: +  tcomm - the thread communicator
281: .  affinities - array of core affinity for threads

283:    Options Database keys:
284:    -thread_affinities <list of thread affinities> 

286:    Level: developer

288:    Notes:
289:    Use affinities = PETSC_NULL for PETSc to decide the affinities.
290:    If PETSc decides affinities, then each thread has affinity to 
291:    a unique core with the main thread on Core 0, thread0 on core 1,
292:    and so on. If the thread count is more the number of available
293:    cores then multiple threads share a core.

295:    The first value is the affinity for the main thread

297:    The affinity list can be passed as
298:    a comma seperated list:                                 0,1,2,3,4,5,6,7
299:    a range (start-end+1):                                  0-8
300:    a range with given increment (start-end+1:inc):         0-7:2
301:    a combination of values and ranges seperated by commas: 0,1-8,8-15:2

303:    There must be no intervening spaces between the values.

305: .seealso: PetscThreadCommGetAffinities(), PetscThreadCommSetNThreads()
306: */
307: PetscErrorCode PetscThreadCommSetAffinities(PetscThreadComm tcomm,const PetscInt affinities[])
308: {
310:   PetscBool      flg;
311:   PetscInt       nmax=tcomm->nworkThreads;

314:   /* Free if affinities set already */
315:   PetscFree(tcomm->affinities);
316:   PetscMalloc(tcomm->nworkThreads*sizeof(PetscInt),&tcomm->affinities);

318:   if (affinities == PETSC_NULL) {
319:     /* Check if option is present in the options database */
320:     PetscOptionsBegin(PETSC_COMM_WORLD,PETSC_NULL,"Thread comm - setting thread affinities",PETSC_NULL);
321:     PetscOptionsIntArray("-threadcomm_affinities","Set core affinities of threads","PetscThreadCommSetAffinities",tcomm->affinities,&nmax,&flg);
322:     PetscOptionsEnd();
323:     if (flg) {
324:       if (nmax != tcomm->nworkThreads) {
325:         SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Must set affinities for all threads, Threads = %D, Core affinities set = %D",tcomm->nworkThreads,nmax);
326:       }
327:     } else {
328:       /* PETSc default affinities */
329:       PetscInt i;
330:       for(i=0;i<tcomm->nworkThreads;i++) tcomm->affinities[i] = i%N_CORES;
331:     }
332:   } else {
333:     PetscMemcpy(tcomm->affinities,affinities,tcomm->nworkThreads*sizeof(PetscInt));
334:   }
335:   return(0);
336: }

340: /*@C
341:    PetscThreadCommGetAffinities - Returns the core affinities set for the
342:                                   thread communicator associated with the MPI_Comm

344:     Not collective

346:     Input Parameters:
347: .   comm - MPI communicator

349:     Output Parameters:
350: .   affinities - thread affinities

352:     Level: developer

354:     Notes:
355:     The user must allocate space (nthreads PetscInts) for the
356:     affinities. Must call PetscThreadCommSetAffinities before.

358: */
359: PetscErrorCode PetscThreadCommGetAffinities(MPI_Comm comm,PetscInt affinities[])
360: {
361:   PetscErrorCode  ierr;
362:   PetscThreadComm tcomm=0;

365:   PetscCommGetThreadComm(comm,&tcomm);
367:   PetscMemcpy(affinities,tcomm->affinities,tcomm->nworkThreads*sizeof(PetscInt));
368:   return(0);
369: }
370: 
373: /*
374:    PetscThreadCommSetType - Sets the threading model for the thread communicator

376:    Logically collective

378:    Input Parameters:
379: +  tcomm - the thread communicator
380: -  type  - the type of thread model needed


383:    Options Database keys:
384:    -threadcomm_type <type>

386:    Available types
387:    See "petsc/include/petscthreadcomm.h" for available types

389: */
390: PetscErrorCode PetscThreadCommSetType(PetscThreadComm tcomm,const PetscThreadCommType type)
391: {
392:   PetscErrorCode ierr,(*r)(PetscThreadComm);
393:   char           ttype[256];
394:   PetscBool      flg;

398:   if(!PetscThreadCommRegisterAllCalled) { PetscThreadCommRegisterAll(PETSC_NULL);}

400:   PetscOptionsBegin(PETSC_COMM_WORLD,PETSC_NULL,"Thread comm - setting threading model",PETSC_NULL);
401:   PetscOptionsList("-threadcomm_type","Thread communicator model","PetscThreadCommSetType",PetscThreadCommList,type,ttype,256,&flg);
402:   PetscOptionsEnd();
403:   if(!flg) {
404:     PetscStrcpy(ttype,type);
405:   }
406:   PetscFListFind(PetscThreadCommList,PETSC_COMM_WORLD,ttype,PETSC_TRUE,(void (**)(void)) &r);
407:   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unable to find requested PetscThreadComm type %s",ttype);
408:   (*r)(tcomm);

410:   return(0);
411: }

415: /*  PetscThreadCommBarrier - Apply a barrier on the thread communicator
416:                              associated with the MPI communicator

418:     Input Parameters:
419: .   comm - the MPI communicator

421:     Level: developer

423:     Notes:
424:     This routine provides an interface to put an explicit barrier between
425:     successive kernel calls to ensure that the first kernel is executed
426:     by all the threads before calling the next one.

428:     Called by the main thread only.

430:     May not be applicable to all types.
431: */
432: PetscErrorCode PetscThreadCommBarrier(MPI_Comm comm)
433: {
434:   PetscErrorCode  ierr;
435:   PetscThreadComm tcomm=0;

438:   PetscCommGetThreadComm(comm,&tcomm);
439:   if(tcomm->ops->barrier) {
440:     (*tcomm->ops->barrier)(tcomm);
441:   }
442:   return(0);
443: }

447: /*@C
448:    PetscThreadCommRegisterDestroy - Frees the list of thread communicator models that were
449:    registered by PetscThreadCommRegisterDynamic().

451:    Not Collective

453:    Level: advanced

455: .keywords: PetscThreadComm, register, destroy

457: .seealso: PetscThreadCommRegisterAll()
458: @*/
459: PetscErrorCode  PetscThreadCommRegisterDestroy(void)
460: {

464:   PetscFListDestroy(&PetscThreadCommList);
465:   PetscThreadCommRegisterAllCalled = PETSC_FALSE;
466:   return(0);
467: }

471: /*@C
472:   PetscThreadCommRegister - See PetscThreadCommRegisterDynamic()

474:   Level: advanced
475: @*/
476: PetscErrorCode  PetscThreadCommRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(PetscThreadComm))
477: {
478:   char           fullname[PETSC_MAX_PATH_LEN];

482:   PetscFListConcat(path,name,fullname);
483:   PetscFListAdd(&PetscThreadCommList,sname,fullname,(void (*)(void))function);
484:   return(0);
485: }

489: /*@C
490:    PetscThreadCommGetScalars - Gets pointers to locations for storing three PetscScalars that may be passed
491:                                to PetscThreadCommRunKernel to ensure that the scalar values remain valid
492:                                even after the main thread exits the calling function.

494:    Input Parameters:
495: +  comm - the MPI communicator having the thread communicator
496: .  val1 - pointer to store the first scalar value
497: .  val2 - pointer to store the second scalar value
498: -  val3 - pointer to store the third scalar value

500:    Level: developer

502:    Notes:
503:    This is a utility function to ensure that any scalars passed to PetscThreadCommRunKernel remain 
504:    valid even after the main thread exits the calling function. If any scalars need to passed to 
505:    PetscThreadCommRunKernel then these should be first stored in the locations provided by PetscThreadCommGetScalars()
506:    
507:    Pass PETSC_NULL if any pointers are not needed.

509:    Called by the main thread only, not from within kernels

511:    Typical usage:

513:    PetscScalar *valptr;
514:    PetscThreadCommGetScalar(comm,&valptr,PETSC_NULL,PETSC_NULL);
515:    *valptr = alpha;   (alpha is the scalar you wish to pass in PetscThreadCommRunKernel)

517:    PetscThreadCommRunKernel(comm,(PetscThreadKernel)kernel_func,3,x,y,valptr);

519: .seealso: PetscThreadCommRunKernel()
520: @*/
521: PetscErrorCode PetscThreadCommGetScalars(MPI_Comm comm,PetscScalar **val1, PetscScalar **val2, PetscScalar **val3)
522: {
524:   PetscThreadComm tcomm;
525:   PetscThreadCommJobQueue queue;
526:   PetscThreadCommJobCtx   job;
527:   PetscInt                job_num;

530:   PetscCommGetThreadComm(comm,&tcomm);
531:   queue = tcomm->jobqueue;
532:   if(queue->ctr == PETSC_KERNELS_MAX) job_num = 0;
533:   else job_num = queue->ctr;
534:   job = queue->jobs[job_num];
535:   if(val1) *val1 = &job->scalars[0];
536:   if(val2) *val2 = &job->scalars[1];
537:   if(val3) *val3 = &job->scalars[2];
538: 
539:   return(0);
540: }
541: 
544: /*@C
545:    PetscThreadCommRunKernel - Runs the kernel using the thread communicator
546:                               associated with the MPI communicator

548:    Input Parameters:
549: +  comm  - the MPI communicator
550: .  func  - the kernel (needs to be cast to PetscThreadKernel)
551: .  nargs - Number of input arguments for the kernel
552: -  ...   - variable list of input arguments

554:    Level: developer

556:    Notes:
557:    All input arguments to the kernel must be passed by reference, Petsc objects are
558:    inherrently passed by reference so you don't need to additionally & them.

560:    Example usage - PetscThreadCommRunKernel(comm,(PetscThreadKernel)kernel_func,3,x,y,z);
561:    with kernel_func declared as
562:    PetscErrorCode kernel_func(PetscInt thread_id,PetscInt* x, PetscScalar* y, PetscReal* z)

564:    The first input argument of kernel_func, thread_id, is the thread rank. This is passed implicitly
565:    by PETSc.

567: .seealso: PetscThreadCommCreate(), PetscThreadCommGNThreads()
568: @*/
569: PetscErrorCode PetscThreadCommRunKernel(MPI_Comm comm,PetscErrorCode (*func)(PetscInt,...),PetscInt nargs,...)
570: {
571:   PetscErrorCode          ierr;
572:   va_list                 argptr;
573:   PetscInt                i;
574:   PetscThreadComm         tcomm=0;
575:   PetscThreadCommJobQueue queue;
576:   PetscThreadCommJobCtx   job;

579:   if(nargs > PETSC_KERNEL_NARGS_MAX) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Requested %D input arguments for kernel, max. limit %D",nargs,PETSC_KERNEL_NARGS_MAX);
580:   PetscCommGetThreadComm(comm,&tcomm);
581:   queue = tcomm->jobqueue;
582:   if(queue->ctr == PETSC_KERNELS_MAX) {
583:     /* Put a barrier so that the last given job is finished and reset the
584:        job queue counter
585:     */
586:     PetscThreadCommBarrier(comm);
587:     queue->ctr = 0;
588:   }
589:   job = queue->jobs[queue->ctr];
590:   job->tcomm = tcomm;
591:   job->nargs = nargs;
592:   job->pfunc = func;
593:   va_start(argptr,nargs);
594:   for(i=0; i < nargs; i++) {
595:     job->args[i] = va_arg(argptr,void*);
596:   }
597:   va_end(argptr);
598:   queue->ctr++;
599:   (*tcomm->ops->runkernel)(comm,job);
600:   return(0);
601: }

603: EXTERN_C_BEGIN
606: /*
607:   This frees the thread communicator attached to MPI_Comm

609:   This is called by MPI, not by users. This is called when MPI_Comm_free() is called on the communicator.

611:   Note: this is declared extern "C" because it is passed to MPI_Keyval_create()
612: */
613: PetscMPIInt MPIAPI Petsc_DelThreadComm(MPI_Comm comm,PetscMPIInt keyval,void* attr,void* extra_state)
614: {
615:   PetscErrorCode  ierr;
616:   PetscThreadComm tcomm;
617:   PetscMPIInt     flg;

620:   MPI_Attr_get(comm,keyval,(PetscThreadComm*)&tcomm,&flg);
621:   if(flg) {
622:     PetscThreadCommDestroy((PetscThreadComm)tcomm);
623:     PetscInfo1(0,"Deleting thread communicator data in an MPI_Comm %ld\n",(long)comm);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr);
624:   }
625:   return(0);
626: }
627: EXTERN_C_END

631: /*
632:   PetscThreadCommInitialize - Initializes the thread communicator object 
633:                               and stashes it inside PETSC_COMM_WORLD
634:                               
635:   PetscThreadCommInitialize() defaults to using the nonthreaded communicator.
636: */
637: PetscErrorCode PetscThreadCommInitialize(void)
638: {
639:   PetscErrorCode  ierr;
640:   PetscThreadComm tcomm;
641:   MPI_Comm        icomm,icomm1;

644:   if(Petsc_ThreadComm_keyval == MPI_KEYVAL_INVALID) {
645:     MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelThreadComm,&Petsc_ThreadComm_keyval,(void*)0);
646:   }
647:   PetscThreadCommCreate(PETSC_COMM_WORLD,&tcomm);
648:   PetscThreadCommSetNThreads(tcomm,PETSC_DECIDE);
649:   PetscThreadCommSetAffinities(tcomm,PETSC_NULL);
650:   PetscCommDuplicate(PETSC_COMM_WORLD,&icomm,PETSC_NULL);
651:   MPI_Attr_put(icomm,Petsc_ThreadComm_keyval,(void*)tcomm);

653:   tcomm->refct++;               /* Share the threadcomm with PETSC_COMM_SELF */
654:   PetscCommDuplicate(PETSC_COMM_SELF,&icomm1,PETSC_NULL);
655:   MPI_Attr_put(icomm1,Petsc_ThreadComm_keyval,(void*)tcomm);

657:   /* This routine leaves extra references to the inner comms. They are released in PetscThreadCommFinalizePackage(). */

659:   PetscThreadCommSetType(tcomm,NOTHREAD);
660:   PetscThreadCommReductionCreate(tcomm,&tcomm->red);
661:   return(0);
662: }

664: PetscErrorCode PetscRunKernel(PetscInt trank,PetscInt nargs,PetscThreadCommJobCtx job)
665: {
666:   switch(nargs) {
667:   case 0:
668:     (*job->pfunc)(trank);
669:     break;
670:   case 1:
671:     (*job->pfunc)(trank,job->args[0]);
672:     break;
673:   case 2:
674:     (*job->pfunc)(trank,job->args[0],job->args[1]);
675:     break;
676:   case 3:
677:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2]);
678:     break;
679:   case 4:
680:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2],job->args[3]);
681:     break;
682:   case 5:
683:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2],job->args[3],job->args[4]);
684:     break;
685:   case 6:
686:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2],job->args[3],job->args[4],job->args[5]);
687:     break;
688:   case 7:
689:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2],job->args[3],job->args[4],job->args[5],job->args[6]);
690:     break;
691:   case 8:
692:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2],job->args[3],job->args[4],job->args[5],job->args[6],job->args[7]);
693:     break;
694:   case 9:
695:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2],job->args[3],job->args[4],job->args[5],job->args[6],job->args[7],job->args[8]);
696:     break;
697:   case 10:
698:     (*job->pfunc)(trank,job->args[0],job->args[1],job->args[2],job->args[3],job->args[4],job->args[5],job->args[6],job->args[7],job->args[8],job->args[9]);
699:     break;
700:   }
701:   return 0;
702: }

706: /*
707:    PetscThreadComMGetOwnershipRanges - Given the global size of an array, computes the local sizes and sets
708:                                        the starting array indices

710:    Input Parameters:
711: +  comm - the MPI communicator which holds the thread communicator
712: -  N    - the global size of the array

714:    Output Parameters:
715: .  trstarts - The starting array indices for each thread. the size of trstarts is nthreads+1

717:    Notes:
718:    trstarts is malloced in this routine
719: */
720: PetscErrorCode PetscThreadCommGetOwnershipRanges(MPI_Comm comm,PetscInt N,PetscInt *trstarts[])
721: {
722:   PetscErrorCode  ierr;
723:   PetscInt        Q,R;
724:   PetscBool       S;
725:   PetscThreadComm tcomm;
726:   PetscInt        *trstarts_out,nloc,i;

729:   PetscCommGetThreadComm(comm,&tcomm);

731:   PetscMalloc((tcomm->nworkThreads+1)*sizeof(PetscInt),&trstarts_out);
732:   trstarts_out[0] = 0;
733:   Q = N/tcomm->nworkThreads;
734:   R = N - Q*tcomm->nworkThreads;
735:   for(i=0;i<tcomm->nworkThreads;i++) {
736:     S = (PetscBool)(i < R);
737:     nloc = S?Q+1:Q;
738:     trstarts_out[i+1] = trstarts_out[i] + nloc;
739:   }

741:   *trstarts = trstarts_out;

743:   return(0);
744: }

746: PetscInt PetscThreadCommGetRank(PetscThreadComm tcomm)
747: {
748:   PetscInt trank = 0;

750:   if(tcomm->ops->getrank) {
751:     trank = (*tcomm->ops->getrank)();
752:   }
753:   return trank;
754: }