e0ab2b505b2175a8d25d8c164eb1ba1e975be8df
[IRC.git] / Robust / src / Runtime / mlp_runtime.c
1 #include "runtime.h"
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <assert.h>
6
7 #include "mem.h"
8 #include "mlp_runtime.h"
9 #include "workschedule.h"
10
11
12 /*
13 __thread struct Queue* seseCallStack;
14 __thread pthread_once_t mlpOnceObj = PTHREAD_ONCE_INIT;
15 void mlpInitOncePerThread() {
16   seseCallStack = createQueue();
17 }
18 */
19 __thread SESEcommon_p seseCaller;
20
21
22 void* mlpAllocSESErecord( int size ) {
23   void* newrec = RUNMALLOC( size );  
24   if( newrec == 0 ) {
25     printf( "mlpAllocSESErecord did not obtain memory!\n" );
26     exit( -1 );
27   }
28   return newrec;
29 }
30
31
32 void mlpFreeSESErecord( void* seseRecord ) {
33   RUNFREE( seseRecord );
34 }
35
36 MemoryQueue** mlpCreateMemoryQueueArray(int numMemoryQueue){
37   int i;
38   MemoryQueue** newMemoryQueue=(MemoryQueue**)RUNMALLOC( sizeof( MemoryQueue* ) * numMemoryQueue );
39   for(i=0; i<numMemoryQueue; i++){
40     newMemoryQueue[i]=createMemoryQueue();
41   }
42   return newMemoryQueue;
43 }
44
45 REntry* mlpCreateREntryArray(){
46   REntry* newREntryArray=(REntry*)RUNMALLOC(sizeof(REntry)*NUMRENTRY);
47   return newREntryArray;
48 }
49
50 REntry* mlpCreateFineREntry(int type, void* seseToIssue, void* dynID){
51   REntry* newREntry=(REntry*)RUNMALLOC(sizeof(REntry));
52   newREntry->type=type;
53   newREntry->seseRec=seseToIssue;
54   newREntry->dynID=dynID; 
55   return newREntry;
56 }
57
58 REntry* mlpCreateREntry(int type, void* seseToIssue){
59   REntry* newREntry=(REntry*)RUNMALLOC(sizeof(REntry));
60   newREntry->type=type;
61   newREntry->seseRec=seseToIssue;
62   return newREntry;
63 }
64
65 int isParent(REntry *r) {
66   if (r->type==PARENTREAD || r->type==PARENTWRITE) {
67     return TRUE;
68   } else {
69     return FALSE;
70   }
71 }
72
73 int isParentCoarse(REntry *r){
74   if (r->type==PARENTCOARSE){
75     return TRUE;
76   }else{
77     return FALSE;
78   }
79 }
80
81 int isFineRead(REntry *r) {
82   if (r->type==READ || r->type==PARENTREAD) {
83     return TRUE;
84   } else {
85     return FALSE;
86   }
87 }
88
89 int isFineWrite(REntry *r) {
90   if (r->type==WRITE || r->type==PARENTWRITE) {
91     return TRUE;
92   } else {
93     return FALSE;
94   }
95 }
96
97 int isCoarse(REntry *r){
98   if(r->type==COARSE || r->type==PARENTCOARSE){
99     return TRUE;
100   } else {
101     return FALSE;
102   }
103 }
104
105 int isSCC(REntry *r){
106   if(r->type==SCCITEM){
107     return TRUE;
108   } else {
109     return FALSE;
110   }
111 }
112
113 int isSingleItem(MemoryQueueItem *qItem){
114   if(qItem->type==SINGLEITEM){
115     return TRUE;
116   } else {
117     return FALSE;
118   }
119 }
120
121 int isHashtable(MemoryQueueItem *qItem){
122   if(qItem->type==HASHTABLE){
123     return TRUE;
124   } else {
125     return FALSE;
126   }
127 }
128
129 int isVector(MemoryQueueItem *qItem){
130   if(qItem->type==VECTOR){
131     return TRUE;
132   } else {
133     return FALSE;
134   }
135 }
136
137 int isReadBinItem(BinItem* b){
138   if(b->type==READBIN){
139     return TRUE;
140   }else{
141     return FALSE;
142   }
143 }
144
145 int isWriteBinItem(BinItem* b){
146   if(b->type==WRITEBIN){
147     return TRUE;
148   }else{
149     return FALSE;
150   }
151 }
152
153 int generateKey(unsigned int data){
154   return (data&H_MASK)>> 4;
155 }
156
157 Hashtable* createHashtable(){
158   int i=0;
159   Hashtable* newTable=(Hashtable*)RUNMALLOC(sizeof(Hashtable));
160   newTable->item.type=HASHTABLE;
161   for(i=0;i<NUMBINS;i++){
162     newTable->array[i]=(BinElement*)RUNMALLOC(sizeof(BinElement));
163     newTable->array[i]->head=NULL;
164     newTable->array[i]->tail=NULL;
165   }
166   return newTable;
167 }
168
169 WriteBinItem* createWriteBinItem(){
170   WriteBinItem* binitem=(WriteBinItem*)RUNMALLOC(sizeof(WriteBinItem));
171   binitem->item.type=WRITEBIN;
172   return binitem;
173 }
174
175 ReadBinItem* createReadBinItem(){
176   ReadBinItem* binitem=(ReadBinItem*)RUNMALLOC(sizeof(ReadBinItem));
177   binitem->index=0;
178   binitem->item.type=READBIN;
179   return binitem;
180 }
181
182 Vector* createVector(){
183   Vector* vector=(Vector*)RUNMALLOC(sizeof(Vector));
184   vector->index=0;
185   vector->item.type=VECTOR;
186   return vector;
187 }
188
189 SCC* createSCC(){
190   SCC* scc=(SCC*)RUNMALLOC(sizeof(SCC));
191   scc->item.type=SINGLEITEM;
192   return scc;
193 }
194
195 MemoryQueue* createMemoryQueue(){
196   MemoryQueue* queue = (MemoryQueue*)RUNMALLOC(sizeof(MemoryQueue));
197   MemoryQueueItem* dummy=(MemoryQueueItem*)RUNMALLOC(sizeof(MemoryQueueItem));
198   dummy->type=3; // dummy type
199   dummy->total=0;
200   dummy->status=READY;
201   queue->head = dummy;
202   queue->tail = dummy;
203   return queue;
204 }
205
206 int ADDRENTRY(MemoryQueue * q, REntry * r) {
207   if (isFineRead(r) || isFineWrite(r)) { 
208     return ADDTABLE(q, r);
209   } else if (isCoarse(r)) {
210     return ADDVECTOR(q, r);
211   } else if (isSCC(r)) {
212     return ADDSCC(q, r);
213   }
214 }
215
216 int ADDTABLE(MemoryQueue *q, REntry *r) {
217   if(!isHashtable(q->tail)) {
218     //Fast Case
219     MemoryQueueItem* tail=q->tail;
220     if (isParent(r) && tail->total==0 && q->tail==q->head) {
221       return READY;
222     }
223
224     //Add table
225     Hashtable* h=createHashtable();
226     tail->next=(MemoryQueueItem*)h;
227     //************NEED memory barrier here to ensure compiler does not cache Q.tail.status********
228     if (BARRIER() && tail->status==READY && tail->total==0 && q->tail==q->head) { 
229       //previous Q item is finished
230       h->item.status=READY;
231     }
232     q->tail=(MemoryQueueItem*)h;
233     // handle the the queue item case
234     if(q->head->type==3){
235       q->head=(MemoryQueueItem*)h;
236     }
237   }
238
239   //at this point, have table
240   Hashtable* table=(Hashtable*)q->tail;
241   BinItem * val;
242   int key=generateKey((unsigned int)r->dynID);
243   do {  
244     val=(BinItem*)0x1;       
245     BinElement* bin=table->array[key];
246     val=(BinItem*)LOCKXCHG((unsigned int*)&(bin->head), (unsigned int)val);//note...talk to me about optimizations here. 
247   } while(val==(BinItem*)0x1);
248   //at this point have locked bin
249   if (val==NULL) {
250     return EMPTYBINCASE(table, table->array[key], r);
251   } else {
252     if (isFineWrite(r)) {
253       return WRITEBINCASE(table, r, val, key);
254     } else if (isFineRead(r)) {
255       return READBINCASE(table, r, val, key);
256     }
257   }
258 }
259
260 int EMPTYBINCASE(Hashtable *T, BinElement* be, REntry *r) {
261   int retval;
262   BinItem* b;
263   if (isFineWrite(r)) {
264     b=(BinItem*)createWriteBinItem();
265     ((WriteBinItem*)b)->val=r;//<-only different statement
266   } else if (isFineRead(r)) {
267     b=(BinItem*)createReadBinItem();
268     ReadBinItem* readbin=(ReadBinItem*)b;
269     readbin->array[readbin->index++]=r;
270   }
271   b->total=1;
272
273   if (T->item.status==READY) { 
274     //current entry is ready
275     b->status=READY;
276     retval=READY;
277     if (isParent(r)) {
278       be->head=NULL; // released lock
279       return retval;
280     }
281   } else {
282     b->status=NOTREADY;
283     retval=NOTREADY;
284   }
285
286   atomic_inc(&T->item.total);
287   r->hashtable=T;
288   r->binitem=b;
289   be->tail=b;
290   be->head=b;//released lock
291   return retval;
292 }
293
294 int WRITEBINCASE(Hashtable *T, REntry *r, BinItem *val, int key) {
295   //chain of bins exists => tail is valid
296   //if there is something in front of us, then we are not ready
297
298   int retval;
299   BinElement* be=T->array[key];
300
301   BinItem *bintail=be->tail;
302
303   WriteBinItem *b=createWriteBinItem();
304   b->val=r;
305   b->item.total=1;
306
307   // note: If current table clears all dependencies, then write bin is ready
308   if (T->item.total==0){
309     retval=READY;    
310   }else{
311     retval=NOTREADY;
312   }
313   b->item.status=retval;
314   //  b->item.status=NOTREADY;
315   
316   atomic_inc(&T->item.total);
317
318   r->hashtable=T;
319   r->binitem=(BinItem*)b;
320
321   be->tail->next=(BinItem*)b;
322   be->tail=(BinItem*)b;
323   be->head=val;
324   return retval;
325 }
326
327 READBINCASE(Hashtable *T, REntry *r, BinItem *val, int key) {
328   BinItem * bintail=T->array[key]->tail;
329   if (isReadBinItem(bintail)) {
330     return TAILREADCASE(T, r, val, bintail, key);
331   } else if (!isReadBinItem(bintail)) {
332     TAILWRITECASE(T, r, val, bintail, key);
333     return NOTREADY;
334   }
335 }
336
337 int TAILREADCASE(Hashtable *T, REntry *r, BinItem *val, BinItem *bintail, int key) {
338   ReadBinItem * readbintail=(ReadBinItem*)T->array[key]->tail;
339   int status, retval;
340   if (readbintail->item.status=READY) { 
341     status=READY;
342     retval=READY;
343     if (isParent(r)) {
344       T->array[key]->head=val;//released lock
345       return READY;
346     }
347   } else {
348     status=NOTREADY;
349     retval=NOTREADY;
350   }
351
352   if (readbintail->index==NUMREAD) { // create new read group
353     ReadBinItem* rb=createReadBinItem();
354     rb->array[rb->index++]=r;
355     rb->item.total=1;//safe only because item could not have started
356     rb->item.status=status;
357     T->array[key]->tail->next=(BinItem*)rb;
358     T->array[key]->tail=(BinItem*)rb;
359     r->binitem=(BinItem*)rb;
360   } else { // group into old tail
361     readbintail->array[readbintail->index++]=r;
362     atomic_inc(&readbintail->item.total);
363     r->binitem=(BinItem*)readbintail;
364     //printf("grouping with %d\n",readbintail->index);
365   }
366   atomic_inc(&T->item.total);
367   r->hashtable=T;
368   T->array[key]->head=val;//released lock
369   return retval;
370 }
371
372 TAILWRITECASE(Hashtable *T, REntry *r, BinItem *val, BinItem *bintail, int key) {
373   //  WriteBinItem* wb=createWriteBinItem();
374   //wb->val=r;
375   //wb->item.total=1;//safe because item could not have started
376   //wb->item.status=NOTREADY;
377   ReadBinItem* rb=createReadBinItem();
378   rb->array[rb->index++]=r;
379   rb->item.total=1;//safe because item could not have started
380   rb->item.status=NOTREADY;
381   atomic_inc(&T->item.total);
382   r->hashtable=T;
383   r->binitem=(BinItem*)rb;
384   T->array[key]->tail->next=(BinItem*)rb;
385   T->array[key]->tail=(BinItem*)rb;
386   T->array[key]->head=val;//released lock
387 }
388
389 ADDVECTOR(MemoryQueue *Q, REntry *r) {
390   if(!isVector(Q->tail)) {
391     //Fast Case
392     if (isParentCoarse(r) && Q->tail->total==0 && Q->tail==Q->head) { 
393       return READY;
394     }
395
396     //added vector
397     Vector* V=createVector();
398     Q->tail->next=(MemoryQueueItem*)V;     
399     //************NEED memory barrier here to ensure compiler does not cache Q.tail.status******
400     if (BARRIER() && Q->tail->status==READY&&Q->tail->total==0) { 
401       //previous Q item is finished
402       V->item.status=READY;
403     }
404     Q->tail=(MemoryQueueItem*)V;
405     // handle the the queue item case
406     if(Q->head->type==3){
407       Q->head=(MemoryQueueItem*)V;
408     }
409   }
410   //at this point, have vector
411   Vector* V=(Vector*)Q->tail;
412   if (V->index==NUMITEMS) {
413     //vector is full
414     //added vector
415     V=createVector();
416     V->item.status=NOTREADY;
417     Q->tail->next=(MemoryQueueItem*)V;
418     //***NEED memory barrier here to ensure compiler does not cache Q.tail.status******
419     if (BARRIER() && Q->tail->status==READY) { 
420       V->item.status=READY;
421     }
422     Q->tail=(MemoryQueueItem*)V;
423   }
424
425   atomic_inc(&V->item.total);
426   //expose entry
427   int index=V->index;
428   V->array[index]=r;
429   //*****NEED memory barrier here to ensure compiler does not reorder writes to V.array and V.index
430   BARRIER();
431   V->index++;
432   //*****NEED memory barrier here to ensure compiler does not cache V.status*********
433   r->vector=V;
434   if (BARRIER() && V->item.status==READY) {
435     void* flag=NULL;
436     flag=(void*)LOCKXCHG((unsigned int*)&(V->array[index]), (unsigned int)flag); 
437     if (flag!=NULL) {
438       if (isParent(r)) { //parent's retire immediately
439         atomic_dec(&V->item.total);
440       }
441       return READY;
442     } else {
443       return NOTREADY;//<- means that some other dispatcher got this one...so need to do accounting correctly
444     }
445   } else {
446     return NOTREADY;
447   }
448 }
449
450
451 //SCC's don't come in parent variety
452 ADDSCC(MemoryQueue *Q, REntry *r) {
453   //added SCC
454   SCC* S=createSCC();
455   S->item.total=1; 
456   S->val=r;
457   r->scc=S;
458   Q->tail->next=(MemoryQueueItem*)S;
459   //*** NEED BARRIER HERE
460   if (BARRIER() && Q->tail->status==READY && Q->tail->total==0 && Q->tail==Q->head) {
461     //previous Q item is finished
462     S->item.status=READY;
463     Q->tail=(MemoryQueueItem*)S;
464     // handle the the queue item case
465     if(Q->head->type==3){
466       Q->head=(MemoryQueueItem*)S;
467     }
468     void* flag=NULL;
469     flag=(void*)LOCKXCHG((unsigned int*)&(S->val), (unsigned int)flag);
470     if (flag!=NULL) {
471       return READY;
472     } else {
473       return NOTREADY;//<- means that some other dispatcher got this one...so need to do accounting correctly
474     }
475   } else {
476     Q->tail=(MemoryQueueItem*)S;
477     return NOTREADY;
478   }
479 }
480
481
482 void RETIRERENTRY(MemoryQueue* Q, REntry * r) {
483   if (isFineWrite(r)||isFineRead(r)) {
484     RETIREHASHTABLE(Q, r);
485   } else if (isCoarse(r)) {
486     RETIREVECTOR(Q, r);
487   } else if (isSCC(r)) {
488     RETIRESCC(Q, r);
489   }
490 }
491
492 RETIRESCC(MemoryQueue *Q, REntry *r) {
493   SCC* s=r->scc;
494   s->item.total=0;//don't need atomicdec
495   RESOLVECHAIN(Q);
496 }
497
498
499 RETIREHASHTABLE(MemoryQueue *q, REntry *r) {
500   Hashtable *T=r->hashtable;
501   BinItem *b=r->binitem;
502   RETIREBIN(T,r,b);
503   atomic_dec(&T->item.total);
504   if (T->item.next!=NULL && T->item.total==0) { 
505     RESOLVECHAIN(q);
506   }
507 }
508
509 RETIREBIN(Hashtable *T, REntry *r, BinItem *b) {
510   int key=generateKey((unsigned int)r->dynID);
511   if(isFineRead(r)) {
512     atomic_dec(&b->total);
513   }
514   if (isFineWrite(r) || (isFineRead(r) && b->next!=NULL && b->total==0)) {
515       // CHECK FIRST IF next is nonnull to guarantee that b.total cannot change
516     BinItem * val;
517     do {  
518       val=(BinItem*)1;
519       val=(BinItem*)LOCKXCHG((unsigned int*)&(T->array[key]->head), (unsigned int)val);
520     } while(val==(BinItem*)1);
521     // at this point have locked bin
522     BinItem *ptr=val;
523     int haveread=FALSE;
524
525     int i;
526     while (ptr!=NULL) {
527       if (isReadBinItem(ptr)) {
528         ReadBinItem* rptr=(ReadBinItem*)ptr;
529         if (rptr->item.status==NOTREADY) {
530           for (i=0;i<rptr->index;i++) {     
531             resolveDependencies(rptr->array[i]);
532             if (isParent(rptr->array[i])) {
533               //parents go immediately
534               atomic_dec(&rptr->item.total);
535               atomic_dec(&T->item.total);
536             }
537           }
538         }
539         rptr->item.status=READY; 
540         if (rptr->item.next==NULL) {
541           break;
542         }
543         if (rptr->item.total!=0) {
544           haveread=TRUE; 
545         } else if ((BinItem*)rptr==val) {
546           val=val->next;
547         }
548       } else if(isWriteBinItem(ptr)) {
549         if (haveread)  
550           break;
551         if(ptr->status==NOTREADY){
552           resolveDependencies(((WriteBinItem*)ptr)->val);
553           ptr->status=READY;
554           if(isParent(((WriteBinItem*)ptr)->val)){
555             atomic_dec(&T->item.total);
556             val=val->next;        
557           }else
558             break;
559         }else{ // write bin is already resolved
560           val=val->next;
561         }
562         /*
563         if(ptr->status==NOTREADY) {   
564           resolveDependencies(((WriteBinItem*)ptr)->val);
565         }        
566           ptr->status=READY;      
567           if (isParent(((WriteBinItem*)ptr)->val)) {  
568             atomic_dec(&T->item.total);
569             //val=val->next;
570             val=ptr->next;
571           } else
572             break;
573         } 
574         */
575       } 
576       ptr=ptr->next;
577     }
578     T->array[key]->head=val; // release lock
579   }
580 }
581
582
583 RETIREVECTOR(MemoryQueue *Q, REntry *r) {
584   Vector* V=r->vector;
585   atomic_dec(&V->item.total);
586   if (V->item.next!=NULL && V->item.total==0) { //NOTE: ORDERING CRUCIAL HERE
587     RESOLVECHAIN(Q);
588   }
589 }
590
591 RESOLVECHAIN(MemoryQueue *Q) {
592   while(TRUE) {
593     MemoryQueueItem* head=Q->head;
594     if (head->next==NULL||head->total!=0) { 
595       //item is not finished
596       if (head->status!=READY) {  
597         //need to update status
598         head->status=READY;
599         if (isHashtable(head)) {
600           RESOLVEHASHTABLE(Q, head);
601         } else if (isVector(head)) {
602           RESOLVEVECTOR(Q, head);
603         } else if (isSingleItem(head)) {
604           RESOLVESCC(head);
605         }
606         if (head->next==NULL)
607           break;
608         if (head->total!=0)
609           break;
610       } else
611         break;
612     }
613     MemoryQueueItem* nextitem=head->next;
614     CAS32((unsigned int*)&(Q->head), (unsigned int)head, (unsigned int)nextitem);
615     //oldvalue not needed...  if we fail we just repeat
616   }
617 }
618
619
620 RESOLVEHASHTABLE(MemoryQueue *Q, Hashtable *T) {  
621   int binidx;
622   for (binidx=0;binidx<NUMBINS;binidx++) {    
623     BinElement* bin=T->array[binidx];
624     BinItem* val;
625     do {
626       val=(BinItem*)1;
627       val=(BinItem*)LOCKXCHG((unsigned int*)&(bin->head), (unsigned int)val);
628     } while (val==(BinItem*)1);
629     //at this point have locked bin    
630     int haveread=FALSE; 
631     BinItem* ptr=val;
632     if(ptr!=NULL&&ptr->status==NOTREADY) {
633       do {
634         if (isWriteBinItem(ptr)) {
635           if (haveread)
636             break;        
637           resolveDependencies(((WriteBinItem*)ptr)->val);
638           ptr->status=READY;  
639           if (isParent(((WriteBinItem*)ptr)->val)) {
640             atomic_dec(&T->item.total);
641             val=val->next;
642           } else
643             break;
644         } else if (isReadBinItem(ptr)) {
645           int i;
646           ReadBinItem* rptr=(ReadBinItem*)ptr;
647           for(i=0;i<rptr->index;i++) {
648             resolveDependencies(rptr->array[i]);
649             if (isParent(rptr->array[i])) {
650               atomic_dec(&rptr->item.total);
651               atomic_dec(&T->item.total);
652             }
653           }
654           if (rptr->item.next==NULL||rptr->item.total!=0) {
655             haveread=TRUE;
656           } else if((BinItem*)rptr==val) {
657             val=val->next;
658           }
659           rptr->item.status=READY; { 
660           }
661           ptr=ptr->next;
662         } 
663       }while(ptr!=NULL);   
664     }
665     bin->head=val; // released lock;
666   }
667 }
668
669 RESOLVEVECTOR(MemoryQueue *q, Vector *V) {
670   int i;
671   Vector* tmp=V;
672   //handle ready cases
673   while(TRUE) {
674     //enqueue everything
675     for (i=0;i<NUMITEMS;i++) {
676       REntry* val=NULL;
677       val=(REntry*)LOCKXCHG((unsigned int*)&(tmp->array[i]), (unsigned int)val); 
678       if (val!=NULL) { 
679         resolveDependencies(val);
680         if (isParent(val)) {
681           atomic_dec(&tmp->item.total);
682         }
683       }
684     }
685     if (tmp->item.next!=NULL&&isVector(tmp->item.next)) {
686       tmp=(Vector*)tmp->item.next;
687     } else {
688       break;
689     }
690   }
691 }
692
693 RESOLVESCC(SCC *S) {
694   //precondition: SCC's state is READY
695   void* flag=NULL;
696   flag=(void*)LOCKXCHG((unsigned int*)&(S->val), (unsigned int)flag); 
697   if (flag!=NULL) {
698     resolveDependencies(flag);
699   }
700 }
701
702
703 resolveDependencies(REntry* rentry){
704   SESEcommon* seseCommon=(SESEcommon*)rentry->seseRec;
705   if(rentry->type==READ || rentry->type==WRITE || rentry->type==COARSE || rentry->type==SCCITEM){    
706     if( atomic_sub_and_test(1, &(seseCommon->unresolvedDependencies)) ){
707       workScheduleSubmit(seseCommon);
708     }   
709   }else if(rentry->type==PARENTREAD || rentry->type==PARENTWRITE ||rentry->type==PARENTCOARSE){
710      psem_give(&(rentry->parentStallSem));
711   }
712 }