1
+
/*
 
2
+
** $Id: threadutil.c,v 1.28 2009/12/31 01:51:59 rosinski Exp $
 
3
+
**
 
4
+
** Author: Jim Rosinski
 
5
+
** 
 
6
+
** Utility functions handle thread-based GPTL needs.
 
7
+
*/
 
8
+
 
9
+
#include <stdlib.h>
 
10
+
#include <stdio.h>
 
11
+
 
12
+
#include "private.h"
 
13
+
 
14
+
/* Max allowable number of threads (used only when THREADED_PTHREADS is true) */
 
15
+
#define MAX_THREADS 128
 
16
+
 
17
+
/* VERBOSE is a debugging ifdef local to this file */
 
18
+
#undef VERBOSE
 
19
+
 
20
+
/* Ensure that threadinit() is called only once */
 
21
+
static bool first = true;
 
22
+
 
23
+
/**********************************************************************************/
 
24
+
/* 
 
25
+
** 3 sets of routines: OMP threading, PTHREADS, unthreaded
 
26
+
*/
 
27
+
 
28
+
#if ( defined THREADED_OMP )
 
29
+
 
30
+
#include <omp.h>
 
31
+
 
32
+
/* array of thread ids used to determine if thread has been started (omp only) */
 
33
+
static int *threadid_omp;
 
34
+
 
35
+
/*
 
36
+
** threadinit: Initialize threadid_omp and set number of threads
 
37
+
**
 
38
+
** Output arguments:
 
39
+
**   nthreads:   number of threads (set to zero, reset to maxthreads by get_thread_num)
 
40
+
**   maxthreads: max number of threads
 
41
+
*/
 
42
+
 
43
+
int threadinit (int *nthreads, int *maxthreads)
 
44
+
{
 
45
+
  int t;  /* loop index */
 
46
+
 
47
+
  *maxthreads = MAX ((1), (omp_get_max_threads ()));
 
48
+
  *nthreads = 0;
 
49
+
 
50
+
  if (omp_get_thread_num () > 0)
 
51
+
    return GPTLerror ("GPTL: threadinit: MUST be called only by master thread");
 
52
+
 
53
+
  if ( ! first)
 
54
+
    return GPTLerror ("GPTL: threadinit: MUST only be called once");
 
55
+
 
56
+
  first = false;
 
57
+
 
58
+
  threadid_omp = GPTLallocate (*maxthreads * sizeof (int));
 
59
+
  for (t = 0; t < *maxthreads; ++t)
 
60
+
    threadid_omp[t] = -1;
 
61
+
 
62
+
#ifdef VERBOSE
 
63
+
  printf ("OMP threadinit: Set *maxthreads=%d *nthreads=%d\n", *maxthreads, *nthreads);
 
64
+
#endif
 
65
+
  
 
66
+
  return 0;
 
67
+
}
 
68
+
 
69
+
/*
 
70
+
** threadfinalize: clean up
 
71
+
*/
 
72
+
 
73
+
void threadfinalize ()
 
74
+
{
 
75
+
  free (threadid_omp);
 
76
+
  first = true;
 
77
+
}
 
78
+
 
79
+
/*
 
80
+
** get_thread_num: determine thread number of the calling thread
 
81
+
**
 
82
+
** Input args:
 
83
+
**   nthreads:   number of threads
 
84
+
**   maxthreads: number of threads (unused in OpenMP case)
 
85
+
**
 
86
+
** Return value: thread number (success) or GPTLerror (failure)
 
87
+
*/
 
88
+
 
89
+
int get_thread_num (int *nthreads, int *maxthreads)
 
90
+
{
 
91
+
  int t;       /* thread number */
 
92
+
 
93
+
  if ((t = omp_get_thread_num ()) >= *maxthreads)
 
94
+
    return GPTLerror ("get_thread_num: returned id=%d exceeds maxthreads=%d\n",
 
95
+
              t, *maxthreads);
 
96
+
 
97
+
  /*
 
98
+
  ** The following test is true only once for each thread, so no need to worry
 
99
+
  ** about false cache sharing
 
100
+
  */
 
101
+
 
102
+
  if (threadid_omp[t] == -1) {
 
103
+
    threadid_omp[t] = t;
 
104
+
 
105
+
#ifdef VERBOSE
 
106
+
    printf ("OMP get_thread_num: 1st call t=%d\n", t);
 
107
+
#endif
 
108
+
 
109
+
#ifdef HAVE_PAPI
 
110
+
    /*
 
111
+
    ** When HAVE_PAPI is true, if 1 or more PAPI events are enabled,
 
112
+
    ** create and start an event set for the new thread.
 
113
+
    */
 
114
+
 
115
+
    if (GPTLget_npapievents () > 0) {
 
116
+
#ifdef VERBOSE
 
117
+
      printf ("OMP get_thread_num: Starting EventSet t=%d\n", t);
 
118
+
#endif
 
119
+
      if (GPTLcreate_and_start_events (t) < 0)
 
120
+
    return GPTLerror ("get_thread_num: error from GPTLcreate_and_start_events for thread %d\n",
 
121
+
              t);
 
122
+
    }
 
123
+
#endif
 
124
+
 
125
+
    *nthreads = *maxthreads;
 
126
+
  }
 
127
+
  return t;
 
128
+
}
 
129
+
 
130
+
void print_threadmapping (int nthreads, FILE *fp)
 
131
+
{
 
132
+
  int n;
 
133
+
 
134
+
  fprintf (fp, "\n");
 
135
+
  fprintf (fp, "Thread mapping:\n");
 
136
+
  for (n = 0; n < nthreads; ++n)
 
137
+
    fprintf (fp, "threadid_omp[%d]=%d\n", n, threadid_omp[n]);
 
138
+
}
 
139
+
 
140
+
/**********************************************************************************/
 
141
+
/* 
 
142
+
** PTHREADS
 
143
+
*/
 
144
+
 
145
+
#elif ( defined THREADED_PTHREADS )
 
146
+
 
147
+
#include <pthread.h>
 
148
+
 
149
+
static int lock_mutex (void);      /* lock a mutex for entry into a critical region */
 
150
+
static int unlock_mutex (void);    /* unlock a mutex for exit from a critical region */
 
151
+
 
152
+
static pthread_mutex_t t_mutex = PTHREAD_MUTEX_INITIALIZER;
 
153
+
static pthread_t *threadid;
 
154
+
 
155
+
/*
 
156
+
** threadinit: Set number of threads and max number of threads
 
157
+
**
 
158
+
** Output arguments:
 
159
+
**   nthreads:   number of threads (init to zero here, increment in get_thread_num)
 
160
+
**   maxthreads: max number of threads (MAX_THREADS)
 
161
+
**
 
162
+
** Return value: 0 (success) or GPTLerror (failure)
 
163
+
*/
 
164
+
 
165
+
int threadinit (int *nthreads, int *maxthreads)
 
166
+
{
 
167
+
  int nbytes;
 
168
+
  int t;
 
169
+
 
170
+
  /* Manage the threadid array which maps physical thread IDs to logical IDs */
 
171
+
 
172
+
  nbytes = MAX_THREADS * sizeof (pthread_t);
 
173
+
  if ( ! (threadid = (pthread_t *) GPTLallocate (nbytes)))
 
174
+
    return GPTLerror ("threadinit: malloc failure for %d items\n", MAX_THREADS);
 
175
+
 
176
+
  if ( ! first)
 
177
+
    return GPTLerror ("GPTL: threadinit: MUST only be called once");
 
178
+
 
179
+
  first = false;
 
180
+
 
181
+
  /*
 
182
+
  ** Initialize nthreads to 0 and define the threadid array now that initialization 
 
183
+
  ** is done. The actual value will be determined as get_thread_num is called.
 
184
+
  */
 
185
+
 
186
+
  *nthreads = 0;
 
187
+
  *maxthreads = MAX_THREADS;
 
188
+
 
189
+
  for (t = 0; t < *maxthreads; ++t)
 
190
+
    threadid[t] = (pthread_t) -1;
 
191
+
 
192
+
#ifdef VERBOSE
 
193
+
  printf ("PTHREADS threadinit: Set *maxthreads=%d *nthreads=%d\n", *maxthreads, *nthreads);
 
194
+
#endif
 
195
+
 
196
+
  return 0;
 
197
+
}
 
198
+
 
199
+
/*
 
200
+
** threadfinalize: clean up
 
201
+
*/
 
202
+
 
203
+
void threadfinalize ()
 
204
+
{
 
205
+
  free (threadid);
 
206
+
  first = true;
 
207
+
}
 
208
+
 
209
+
/*
 
210
+
** get_thread_num: determine zero-based thread number of the calling thread.
 
211
+
**                 Also: update nthreads and maxthreads if necessary.
 
212
+
**
 
213
+
** Input/output args:
 
214
+
**   nthreads:   number of threads
 
215
+
**   maxthreads: max number of threads
 
216
+
**
 
217
+
** Return value: thread number (success) or GPTLerror (failure)
 
218
+
*/
 
219
+
 
220
+
int get_thread_num (int *nthreads, int *maxthreads)
 
221
+
{
 
222
+
  int n;                 /* return value: loop index over number of threads */
 
223
+
  pthread_t mythreadid;  /* thread id from pthreads library */
 
224
+
 
225
+
  mythreadid = pthread_self ();
 
226
+
 
227
+
  if (lock_mutex () < 0)
 
228
+
    return GPTLerror ("get_thread_num: mutex lock failure\n");
 
229
+
 
230
+
  /*
 
231
+
  ** Loop over known physical thread IDs.  When my id is found, map it 
 
232
+
  ** to logical thread id for indexing.  If not found return a negative 
 
233
+
  ** number.
 
234
+
  ** A critical region is necessary because acess to
 
235
+
  ** the array threadid must be by only one thread at a time.
 
236
+
  */
 
237
+
 
238
+
  for (n = 0; n < *nthreads; ++n)
 
239
+
    if (pthread_equal (mythreadid, threadid[n]))
 
240
+
      break;
 
241
+
 
242
+
  /*
 
243
+
  ** If our thread id is not in the known list, add to it after checking that
 
244
+
  ** we do not have too many threads.
 
245
+
  */
 
246
+
 
247
+
  if (n == *nthreads) {
 
248
+
    if (*nthreads >= MAX_THREADS) {
 
249
+
      if (unlock_mutex () < 0)
 
250
+
    fprintf (stderr, "get_thread_num: mutex unlock failure\n");
 
251
+
 
252
+
      return GPTLerror ("get_thread_num: nthreads=%d is too big Recompile "
 
253
+
            "with larger value of MAX_THREADS\n", *nthreads);
 
254
+
    }    
 
255
+
 
256
+
    threadid[n] = mythreadid;
 
257
+
 
258
+
#ifdef VERBOSE
 
259
+
    printf ("PTHREADS get_thread_num: 1st call threadid=%lu maps to location %d\n", (unsigned long) mythreadid, n);
 
260
+
#endif
 
261
+
 
262
+
#ifdef HAVE_PAPI
 
263
+
 
264
+
    /*
 
265
+
    ** When HAVE_PAPI is true, if 1 or more PAPI events are enabled,
 
266
+
    ** create and start an event set for the new thread.
 
267
+
    */
 
268
+
 
269
+
    if (GPTLget_npapievents () > 0) {
 
270
+
#ifdef VERBOSE
 
271
+
      printf ("PTHREADS get_thread_num: Starting EventSet threadid=%lu location=%d\n", 
 
272
+
          (unsigned long) mythreadid, n);
 
273
+
#endif
 
274
+
      if (GPTLcreate_and_start_events (n) < 0) {
 
275
+
    if (unlock_mutex () < 0)
 
276
+
      fprintf (stderr, "get_thread_num: mutex unlock failure\n");
 
277
+
 
278
+
    return GPTLerror ("get_thread_num: error from GPTLcreate_and_start_events for thread %d\n",
 
279
+
              n);
 
280
+
      }
 
281
+
    }
 
282
+
#endif
 
283
+
 
284
+
    ++*nthreads;
 
285
+
#ifdef VERBOSE
 
286
+
    printf ("PTHREADS get_thread_num: *nthreads=%d\n", *nthreads);
 
287
+
#endif
 
288
+
  }
 
289
+
    
 
290
+
  if (unlock_mutex () < 0)
 
291
+
    return GPTLerror ("get_thread_num: mutex unlock failure\n");
 
292
+
 
293
+
  return n;
 
294
+
}
 
295
+
 
296
+
/*
 
297
+
** lock_mutex: lock a mutex for private access
 
298
+
*/
 
299
+
 
300
+
static int lock_mutex ()
 
301
+
{
 
302
+
  if (pthread_mutex_lock (&t_mutex) != 0)
 
303
+
    return GPTLerror ("pthread_lock_mutex failure\n");
 
304
+
  return 0;
 
305
+
}
 
306
+
 
307
+
/*
 
308
+
** unlock_mutex: unlock a mutex from private access
 
309
+
*/
 
310
+
 
311
+
static int unlock_mutex ()
 
312
+
{
 
313
+
  if (pthread_mutex_unlock (&t_mutex) != 0)
 
314
+
    return GPTLerror ("pthread_unlock_mutex failure\n");
 
315
+
  return 0;
 
316
+
}
 
317
+
 
318
+
void print_threadmapping (int nthreads, FILE *fp)
 
319
+
{
 
320
+
  int n;
 
321
+
 
322
+
  fprintf (fp, "\n");
 
323
+
  fprintf (fp, "Thread mapping:\n");
 
324
+
  for (n = 0; n < nthreads; ++n)
 
325
+
    fprintf (fp, "threadid[%d]=%d\n", n, (int) threadid[n]);
 
326
+
}
 
327
+
 
328
+
/**********************************************************************************/
 
329
+
/*
 
330
+
** Unthreaded case
 
331
+
*/
 
332
+
 
333
+
#else
 
334
+
 
335
+
static int threadid = -1;
 
336
+
 
337
+
int threadinit (int *nthreads, int *maxthreads)
 
338
+
{
 
339
+
  if ( ! first)
 
340
+
    return GPTLerror ("GPTL: threadinit: MUST only be called once");
 
341
+
 
342
+
  first = false;
 
343
+
  *nthreads = 0;
 
344
+
  *maxthreads = 1;
 
345
+
  return 0;
 
346
+
}
 
347
+
 
348
+
void threadfinalize ()
 
349
+
{
 
350
+
  threadid = -1;
 
351
+
  first = true;
 
352
+
}
 
353
+
 
354
+
int get_thread_num (int *nthreads, int *maxthreads)
 
355
+
{
 
356
+
#ifdef HAVE_PAPI
 
357
+
  /*
 
358
+
  ** When HAVE_PAPI is true, if 1 or more PAPI events are enabled,
 
359
+
  ** create and start an event set for the new thread.
 
360
+
  */
 
361
+
 
362
+
  if (threadid == -1 && GPTLget_npapievents () > 0) {
 
363
+
    if (GPTLcreate_and_start_events (0) < 0)
 
364
+
      return GPTLerror ("get_thread_num: error from GPTLcreate_and_start_events for thread %0\n");
 
365
+
 
366
+
    threadid = 0;
 
367
+
  }
 
368
+
#endif
 
369
+
 
370
+
  *nthreads = 1;
 
371
+
  return 0;
 
372
+
}
 
373
+
 
374
+
void print_threadmapping (int nthreads, FILE *fp)
 
375
+
{
 
376
+
  fprintf (fp, "\n");
 
377
+
  fprintf (fp, "threadid[0]=0\n");
 
378
+
}
 
379
+
 
380
+
#endif