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: }