Modifications for TAU tracing in the Charm++ framework.
[charm.git] / src / arch / origin-pthreads / machine.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /** @file
9  * Origin Pthreads machine layer
10  * @ingroup Machine
11  * @{
12  */
13
14 #include <errno.h>
15 #include <pthread.h>
16 #include <sched.h>
17 #include <time.h>
18
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <sys/time.h>
22 #include <limits.h>
23 #include <unistd.h>
24
25 #include "converse.h"
26
27 #define BLK_LEN  512
28
29 typedef struct {
30   pthread_mutex_t mutex;
31   pthread_cond_t cond;
32   int waiting;
33   CdsFifo q;
34 } McQueue;
35
36 static McQueue *McQueueCreate(void);
37 static void McQueueAddToBack(McQueue *queue, void *element);
38 static void *McQueueRemoveFromFront(McQueue *queue);
39 static McQueue **MsgQueue;
40
41 CpvDeclare(void*, CmiLocalQueue);
42
43 int Cmi_argc;
44 int _Cmi_numpes;
45 int Cmi_usched;
46 int Cmi_initret;
47 CmiStartFn Cmi_startFn;
48
49 pthread_key_t perThreadKey;
50
51 static void *threadInit(void *arg);
52
53 pthread_mutex_t memory_mutex;
54
55 void CmiMemLock() {pthread_mutex_lock(&memory_mutex);}
56 void CmiMemUnlock() {pthread_mutex_unlock(&memory_mutex);}
57
58 int barrier;
59 pthread_cond_t barrier_cond;
60 pthread_mutex_t barrier_mutex;
61
62 void CmiNodeBarrier(void)
63 {
64   pthread_mutex_lock(&barrier_mutex);
65   barrier++;
66   if(barrier!=CmiNumPes())
67     pthread_cond_wait(&barrier_cond, &barrier_mutex);
68   else {
69     barrier = 0;
70     pthread_cond_broadcast(&barrier_cond);
71   }
72   pthread_mutex_unlock(&barrier_mutex);
73 }
74
75 void CmiNodeAllBarrier(void)
76 {
77   pthread_mutex_lock(&barrier_mutex);
78   barrier++;
79   if(barrier!=CmiNumPes()+1)
80     pthread_cond_wait(&barrier_cond, &barrier_mutex);
81   else {
82     barrier = 0;
83     pthread_cond_broadcast(&barrier_cond);
84   }
85   pthread_mutex_unlock(&barrier_mutex);
86 }
87
88 CmiNodeLock CmiCreateLock(void)
89 {
90   pthread_mutex_t *lock;
91   lock = (pthread_mutex_t *) CmiAlloc(sizeof(pthread_mutex_t));
92   pthread_mutex_init(lock, (pthread_mutexattr_t *) 0);
93   return lock;
94 }
95
96 void CmiLock(CmiNodeLock lock)
97 {
98   pthread_mutex_lock(lock);
99 }
100
101 void CmiUnlock(CmiNodeLock lock)
102 {
103   pthread_mutex_unlock(lock);
104 }
105
106 int CmiTryLock(CmiNodeLock lock)
107 {
108   return pthread_mutex_trylock(lock);
109 }
110
111 void CmiDestroyLock(CmiNodeLock lock)
112 {
113   pthread_mutex_destroy(lock);
114 }
115
116 int CmiMyPe()
117 {
118   int mype = (size_t) pthread_getspecific(perThreadKey);
119   return mype;
120 }
121
122 /***********************************************************************
123  *
124  * Abort function:
125  *
126  ************************************************************************/
127
128 void CmiAbort(const char *message)
129 {
130   CmiError(message);
131   abort();
132 }
133
134 int CmiAsyncMsgSent(CmiCommHandle msgid)
135 {
136   return 1;
137 }
138
139
140 typedef struct {
141   char       **argv;
142   int        mype;
143 } USER_PARAMETERS;
144
145 void ConverseInit(int argc, char **argv, CmiStartFn fn, int usched, int initret)
146 {
147   int i;
148   USER_PARAMETERS *usrparam;
149   pthread_t *aThread;
150  
151   _Cmi_numpes = 0; 
152   Cmi_usched = usched;
153   Cmi_initret = initret;
154   Cmi_startFn = fn;
155
156   CmiGetArgInt(argv,"+p",&_Cmi_numpes);
157   if (_Cmi_numpes <= 0)
158   {
159     CmiError("Error: requested number of processors is invalid %d\n",
160               _Cmi_numpes);
161     abort();
162   }
163
164
165   pthread_mutex_init(&memory_mutex, (pthread_mutexattr_t *) 0);
166
167   MsgQueue=(McQueue **)CmiAlloc(_Cmi_numpes*sizeof(McQueue *));
168   for(i=0; i<_Cmi_numpes; i++) 
169     MsgQueue[i] = McQueueCreate();
170
171   pthread_key_create(&perThreadKey, (void *) 0);
172   barrier = 0;
173   pthread_cond_init(&barrier_cond, (pthread_condattr_t *) 0);
174   pthread_mutex_init(&barrier_mutex, (pthread_mutexattr_t *) 0);
175
176   /* suggest to IRIX that we actually use the right number of processors */
177   pthread_setconcurrency(_Cmi_numpes);
178
179   Cmi_argc = CmiGetArgc(argv);
180   aThread = (pthread_t *) CmiAlloc(sizeof(pthread_t) * _Cmi_numpes);
181   for(i=1; i<_Cmi_numpes; i++) {
182     usrparam = (USER_PARAMETERS *) CmiAlloc(sizeof(USER_PARAMETERS));
183     usrparam->argv = CmiCopyArgs(argv);
184     usrparam->mype = i;
185
186           printf("calling tau_pthread_create");
187     tau_pthread_create(&aThread[i],(pthread_attr_t *)0,threadInit,(void *)usrparam);
188   }
189   usrparam = (USER_PARAMETERS *) CmiAlloc(sizeof(USER_PARAMETERS));
190   usrparam->argv = CmiCopyArgs(argv);
191   usrparam->mype = 0;
192   threadInit(usrparam);
193 }
194
195 void CmiTimerInit(void);
196
197 static void *threadInit(void *arg)
198 {
199   USER_PARAMETERS *usrparam;
200   usrparam = (USER_PARAMETERS *) arg;
201
202
203   pthread_setspecific(perThreadKey, (void *) usrparam->mype);
204
205   CthInit(usrparam->argv);
206   ConverseCommonInit(usrparam->argv);
207   CpvInitialize(void*, CmiLocalQueue);
208   CpvAccess(CmiLocalQueue) = CdsFifo_Create();
209   CmiTimerInit();
210   if (Cmi_initret==0) {
211     Cmi_startFn(Cmi_argc, usrparam->argv);
212     if (Cmi_usched==0) CsdScheduler(-1);
213     ConverseExit();
214   }
215   return (void *) 0;
216 }
217
218
219 void ConverseExit(void)
220 {
221   ConverseCommonExit();
222   CmiNodeBarrier();
223 }
224
225
226 void CmiDeclareArgs(void)
227 {
228 }
229
230
231 void CmiNotifyIdle()
232 {
233   McQueue *queue = MsgQueue[CmiMyPe()];
234   struct timespec ts;
235   pthread_mutex_lock(&(queue->mutex));
236   if(CdsFifo_Empty(queue->q)){
237     queue->waiting++;
238     ts.tv_sec = (time_t) 0;
239     ts.tv_nsec = 10000000L;
240     pthread_cond_timedwait(&(queue->cond), &(queue->mutex), &ts);
241     queue->waiting--;
242   }
243   pthread_mutex_unlock(&(queue->mutex));
244   return;
245 }
246
247 void *CmiGetNonLocal()
248 {
249   return McQueueRemoveFromFront(MsgQueue[CmiMyPe()]);
250 }
251
252
253 void CmiSyncSendFn(int destPE, int size, char *msg)
254 {
255   char *buf;
256
257   buf=(void *)CmiAlloc(size);
258   memcpy(buf,msg,size);
259   McQueueAddToBack(MsgQueue[destPE],buf); 
260   CQdCreate(CpvAccess(cQdState), 1);
261 }
262
263
264 CmiCommHandle CmiAsyncSendFn(int destPE, int size, char *msg)
265 {
266   CmiSyncSendFn(destPE, size, msg); 
267   return 0;
268 }
269
270
271 void CmiFreeSendFn(int destPE, int size, char *msg)
272 {
273   if (CmiMyPe()==destPE) {
274     CdsFifo_Enqueue(CpvAccess(CmiLocalQueue),msg);
275   } else {
276     McQueueAddToBack(MsgQueue[destPE],msg); 
277   }
278   CQdCreate(CpvAccess(cQdState), 1);
279 }
280
281 void CmiSyncBroadcastFn(int size, char *msg)
282 {
283   int i;
284   for(i=0; i<_Cmi_numpes; i++)
285     if (CmiMyPe() != i) CmiSyncSendFn(i,size,msg);
286 }
287
288 CmiCommHandle CmiAsyncBroadcastFn(int size, char *msg)
289 {
290   CmiSyncBroadcastFn(size, msg);
291   return 0;
292 }
293
294 void CmiFreeBroadcastFn(int size, char *msg)
295 {
296   CmiSyncBroadcastFn(size,msg);
297   CmiFree(msg);
298 }
299
300 void CmiSyncBroadcastAllFn(int size, char *msg)
301 {
302   int i;
303   for(i=0; i<CmiNumPes(); i++) 
304     CmiSyncSendFn(i,size,msg);
305 }
306
307
308 CmiCommHandle CmiAsyncBroadcastAllFn(int size, char *msg)
309 {
310   CmiSyncBroadcastAllFn(size, msg);
311   return 0; 
312 }
313
314
315 void CmiFreeBroadcastAllFn(int size, char *msg)
316 {
317   int i;
318   for(i=0; i<CmiNumPes(); i++) {
319     if(CmiMyPe() != i) {
320       CmiSyncSendFn(i,size,msg);
321     }
322   }
323   CdsFifo_Enqueue(CpvAccess(CmiLocalQueue),msg);
324   CQdCreate(CpvAccess(cQdState), 1);
325 }
326
327 /* ****************************************************************** */
328 /*    The following internal functions implements FIFO queues for     */
329 /*    messages. These queues are shared among threads                 */
330 /* ****************************************************************** */
331
332 static void ** AllocBlock(unsigned int len)
333 {
334   void **blk;
335
336   blk=(void **)CmiAlloc(len*sizeof(void *));
337   return blk;
338 }
339
340 static void 
341 SpillBlock(void **srcblk, void **destblk, unsigned int first, unsigned int len)
342 {
343   memcpy(destblk, &(srcblk[first]), (len-first)*sizeof(void *));
344   memcpy(&(destblk[len-first]),srcblk,first*sizeof(void *));
345 }
346
347 McQueue * McQueueCreate(void)
348 {
349   McQueue *queue;
350
351   queue = (McQueue *) CmiAlloc(sizeof(McQueue));
352   pthread_mutex_init(&(queue->mutex), (pthread_mutexattr_t *) 0);
353   pthread_cond_init(&(queue->cond), (pthread_condattr_t *) 0);
354   queue->waiting = 0;
355   queue->q = CdsFifo_Create_len(BLK_LEN);
356   return queue;
357 }
358
359 void McQueueAddToBack(McQueue *queue, void *element)
360 {
361   pthread_mutex_lock(&(queue->mutex));
362   CdsFifo_Enqueue(queue->q, element);
363   if(queue->waiting) {
364     pthread_cond_broadcast(&(queue->cond));
365   }
366   pthread_mutex_unlock(&(queue->mutex));
367 }
368
369
370 void * McQueueRemoveFromFront(McQueue *queue)
371 {
372   void *element = 0;
373   pthread_mutex_lock(&(queue->mutex));
374   element = CdsFifo_Dequeue(queue->q);
375   pthread_mutex_unlock(&(queue->mutex));
376   return element;
377 }
378
379 /* Timer Routines */
380
381
382 CpvStaticDeclare(double,inittime_wallclock);
383 CpvStaticDeclare(double,inittime_virtual);
384
385 void CmiTimerInit(void)
386 {
387   struct timespec temp;
388   CpvInitialize(double, inittime_wallclock);
389   CpvInitialize(double, inittime_virtual);
390   clock_gettime(CLOCK_SGI_CYCLE, &temp);
391   CpvAccess(inittime_wallclock) = (double) temp.tv_sec +
392                                   1e-9 * temp.tv_nsec;
393   CpvAccess(inittime_virtual) = CpvAccess(inittime_wallclock);
394 }
395
396 double CmiWallTimer(void)
397 {
398   struct timespec temp;
399   double currenttime;
400
401   clock_gettime(CLOCK_SGI_CYCLE, &temp);
402   currenttime = (double) temp.tv_sec +
403                 1e-9 * temp.tv_nsec;
404   return (currenttime - CpvAccess(inittime_wallclock));
405 }
406
407 double CmiCpuTimer(void)
408 {
409   struct timespec temp;
410   double currenttime;
411
412   clock_gettime(CLOCK_SGI_CYCLE, &temp);
413   currenttime = (double) temp.tv_sec +
414                 1e-9 * temp.tv_nsec;
415   return (currenttime - CpvAccess(inittime_virtual));
416 }
417
418 double CmiTimer(void)
419 {
420   return CmiCpuTimer();
421 }
422
423 /*@}*/