changes
[IRC.git] / Robust / src / Runtime / STM / stats.c
1 #include "tm.h"
2 #include "garbage.h"
3
4 #define PERCENT_ALLOWED_ABORT 0.7
5 #ifdef STMSTATS
6 /* Thread variable for locking/unlocking */
7 __thread threadrec_t *trec;
8 __thread struct objlist * lockedobjs;
9 __thread int t_objnumcount=0;
10
11 /* Collect stats for object classes causing abort */
12 objtypestat_t typesCausingAbort[TOTALNUMCLASSANDARRAY];
13
14 void freelockedobjs() {
15   struct objlist *ptr=lockedobjs;
16   while(ptr->next!=NULL) {
17     struct objlist *tmp=ptr->next;
18     free(ptr);
19     ptr=tmp;
20   }
21   ptr->offset=0;
22   lockedobjs=ptr;
23 }
24
25 INLINE void getTransSize(objheader_t *header , int *isObjTypeTraverse) {
26   (typesCausingAbort[TYPE(header)]).numabort++;
27   if(isObjTypeTraverse[TYPE(header)] != 1) {
28     (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
29     (typesCausingAbort[TYPE(header)]).numtrans+=1; //should this count be kept per object
30   }
31   isObjTypeTraverse[TYPE(header)]=1;
32 }
33
34 /*** Global variables *****/
35 objlockstate_t *objlockscope;
36 /**
37  * ABORTCOUNT
38  * params: object header
39  * Increments the abort count for each object
40  **/
41 void ABORTCOUNT(objheader_t * x) {
42   int avgTransSize = typesCausingAbort[TYPE(x)].numaccess / typesCausingAbort[TYPE(x)].numtrans; 
43   float transAbortProbForObj = (PERCENT_ALLOWED_ABORT*FACTOR)/(float) avgTransSize;
44   float ObjAbortProb = x->abortCount/(float) (x->accessCount);
45   DEBUGSTM("ABORTSTATS: oid= %x, type= %2d, transAbortProb= %2.2f, ObjAbortProb= %2.2f, Typenumaccess= %3d, avgtranssize = %2d, ObjabortCount= %2d, ObjaccessCount= %3d\n", OID(x), TYPE(x), transAbortProbForObj, ObjAbortProb, typesCausingAbort[TYPE(x)].numaccess, avgTransSize, x->abortCount, x->accessCount);
46   /* Condition for locking objects */
47   if (((ObjAbortProb*100) >= transAbortProbForObj) && (x->riskyflag != 1)) {     
48     DEBUGSTATS("AFTER LOCK ABORTSTATS: oid= %x, type= %2d, transAbortProb= %2.2f, ObjAbortProb= %2.2f, Typenumaccess= %3d, avgtranssize = %2d, ObjabortCount= %2d, ObjaccessCount= %3d\n", OID(x), TYPE(x), transAbortProbForObj, ObjAbortProb, typesCausingAbort[TYPE(x)].numaccess, avgTransSize, x->abortCount, x->accessCount);
49     //makes riskflag sticky
50     pthread_mutex_lock(&lockedobjstore); 
51     if (objlockscope->offset<MAXOBJLIST) { 
52       x->objlock=&(objlockscope->lock[objlockscope->offset++]);
53     } else { 
54       objlockstate_t *tmp=malloc(sizeof(objlockstate_t)); 
55       tmp->next=objlockscope; 
56       tmp->offset=1; 
57       x->objlock=&(tmp->lock[0]); 
58       objlockscope=tmp;
59     } 
60     pthread_mutex_unlock(&lockedobjstore); 
61     pthread_mutex_init(x->objlock, NULL);
62     //should put a memory barrier here
63     x->riskyflag = 1;                    
64   }
65 }
66 #endif
67
68 #if defined(STMSTATS)||defined(SOFTABORT)
69 /** ========================================================================================
70  * getTotalAbortCount (for traverseCache only)
71  * params : start: start index of the loop
72  *        : stop: stop index of the loop
73  *        : startptr: pointer that points to where to start looking in the cache hash table
74  *        : numoidrdlocked : number of objects read that are locked
75  *        : oidrdlocked : array of objects read and currently locked
76  *        : oidrdversion : array of versions of object read
77  *        : oidrdage : array of ages of objects read ina transaction cache
78  *        : ObjSeqId : sequence Id/age to start the comparision with
79  * =========================================================================================
80  **/
81 int getTotalAbortCount(int start, int stop, void *startptr, int numoidrdlocked, 
82     void *oidrdlocked, int *oidrdversion, int *oidrdage, int ObjSeqId, objheader_t *header, int *isObjTypeTraverse) {
83   int i;
84   int hardabort=0;
85   int isFirstTime=0;
86   objheader_t *ObjToBeLocked=header;
87   chashlistnode_t *curr = (chashlistnode_t *) startptr;
88   chashlistnode_t *ptr = c_table;
89   /* First go through all objects left in the cache that have not been covered yet */
90   for(i = start; i < stop; i++) {
91     if(!isFirstTime)
92       curr = &ptr[i];
93     /* Inner loop to traverse the linked list of the cache lookupTable */
94     while(curr != NULL) {
95       if(curr->key == NULL)
96         break;
97       objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
98       objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
99       unsigned int version = headeraddr->version;
100       /* versions do not match */
101       if(version != header->version) {
102 #ifdef STMSTATS
103         header->abortCount++;
104         if(ObjSeqId > headeraddr->accessCount) {
105           ObjSeqId = headeraddr->accessCount;
106           ObjToBeLocked = header;
107         }
108         getTransSize(header, isObjTypeTraverse);
109 #endif
110         hardabort=1;
111       }
112       curr = curr->next;
113     }
114     isFirstTime = 1;
115   }
116
117   /* Then go through all objects that are read and are currently present in the readLockedArray */
118   if(numoidrdlocked>0) {
119     for(i=0; i<numoidrdlocked; i++) {
120       objheader_t *header = ((void **) oidrdlocked)[i];
121       int OidAge = oidrdage[i];
122       unsigned int version = oidrdversion[i];
123       if(version != header->version) { /* versions do not match */
124 #ifdef STMSTATS
125         header->abortCount++;
126         if(ObjSeqId > OidAge) {
127           ObjSeqId = OidAge;
128           ObjToBeLocked = header;
129         }
130         getTransSize(header, isObjTypeTraverse);
131 #endif
132         hardabort=1;
133       }
134     }
135   }
136
137   /* Acquire lock on the oldest object accessed in the transaction cache */
138   if(ObjToBeLocked != NULL) {
139     ABORTCOUNT(ObjToBeLocked);
140   }
141
142   return hardabort;
143 }
144
145 /** ========================================================================================
146  * getTotalAbortCount2 (for alttraverseCache only)
147  * params : startptr: pointer that points to where to start looking in the cache hash table
148  *        : numoidrdlocked : number of objects read that are locked
149  *        : oidrdlocked : array of objects read and currently locked
150  *        : oidrdversion : array of versions of object read
151  *        : oidrdage : array of ages of objects read ina transaction cache
152  *        : ObjSeqId : sequence Id/age to start the comparision with
153  * =========================================================================================
154  **/
155 int getTotalAbortCount2(void *startptr, int numoidrdlocked, void *oidrdlocked, 
156     int *oidrdversion, int *oidrdage, int ObjSeqId, objheader_t *header, int *isObjTypeTraverse) {
157   int hardabort=0;
158   chashlistnode_t *curr = (chashlistnode_t *) startptr;
159   objheader_t *ObjToBeLocked=header;
160
161   /* Inner loop to traverse the linked list of the cache lookupTable */
162   while(curr != NULL) {
163     objheader_t *headeraddr=&((objheader_t *) curr->val)[-1];
164     objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
165     unsigned int version = headeraddr->version;
166     /* versions do not match */
167     if(version != header->version) {
168 #ifdef STMSTATS
169       header->abortCount++;
170       if(ObjSeqId > headeraddr->accessCount) {
171         ObjSeqId = headeraddr->accessCount;
172         ObjToBeLocked = header;
173       }
174       getTransSize(header, isObjTypeTraverse);
175 #endif
176       hardabort=1;
177     }
178     curr = curr->next;
179   }
180
181   /* Then go through all objects that are read and are currently present in the readLockedArray */
182   if(numoidrdlocked>0) {
183     int i;
184     for(i=0; i<numoidrdlocked; i++) {
185       objheader_t *header = ((void **)oidrdlocked)[i];
186       unsigned int version = oidrdversion[i];
187       int OidAge = oidrdage[i];
188       if(version != header->version) { /* versions do not match */
189 #ifdef STMSTATS
190         header->abortCount++;
191         if(ObjSeqId > OidAge) {
192           ObjSeqId = OidAge;
193           ObjToBeLocked = header;
194         }
195         getTransSize(header, isObjTypeTraverse);
196 #endif
197         hardabort=1;
198       }
199     }
200   }
201
202   if(ObjToBeLocked!=NULL) {
203     ABORTCOUNT(ObjToBeLocked);
204   }
205
206   return hardabort;
207 }
208
209 /**
210  * getReadAbortCount : Tells the number of aborts caused by objects that are read by
211  *                    visiting the read array
212  * params: int start, int stop are indexes to readLocked array
213  *         void  *oidrdlocked = readLocked array
214  *         int *oidrdversion = version array
215  *        : oidrdage : array of ages of objects read ina transaction cache
216  *        : ObjSeqId : sequence Id/age to start the comparision with
217  **/
218 int getReadAbortCount(int start, int stop, void *oidrdlocked, int *oidrdversion, 
219     int *oidrdage, int ObjSeqId, objheader_t *header, int *isObjTypeTraverse) {
220   int i;
221   int hardabort=0;
222   objheader_t *ObjToBeLocked=header;
223
224   /* Go through oids read that are locked */
225   for(i = start; i < stop; i++) {
226     objheader_t *header = ((void **)oidrdlocked)[i];
227     unsigned int version = oidrdversion[i];
228     int OidAge = oidrdage[i];
229     if(version != header->version) { /* versions do not match */
230 #ifdef STMSTATS
231       header->abortCount++;
232       if(ObjSeqId > OidAge) {
233         ObjSeqId = OidAge;
234         ObjToBeLocked = header;
235       }
236       getTransSize(header, isObjTypeTraverse);
237 #endif
238       hardabort=1;
239     }
240   }
241
242   if(ObjToBeLocked != NULL) {
243     ABORTCOUNT(ObjToBeLocked);
244   }
245
246   return hardabort;
247 }
248
249
250 /**
251  * needLock
252  * params: Object header, ptr to garbage collector
253  * Locks an object that causes aborts
254  **/
255 objheader_t * needLock(objheader_t *header, void *gl) {
256   int lockstatus;
257   threadrec_t *ptr;
258   while((lockstatus = pthread_mutex_trylock(header->objlock)) 
259       && ((ptr = header->trec) == NULL)) { //retry
260     ;
261   }
262   if(lockstatus==0) { //acquired lock
263     /* Set trec */
264     header->trec = trec;
265   } else { //failed to get lock
266     trec->blocked=1;
267     //memory barrier
268     CFENCE;
269     //see if other thread is blocked
270     if(ptr->blocked == 1) {
271       //it might be block, so ignore lock and clear our blocked flag
272       trec->blocked=0;
273       return;
274     } else { 
275 #ifdef PRECISE_GC
276       INTPTR ptrarray[]={1, (INTPTR)gl, (INTPTR) header};
277       void *lockptr=header->objlock;
278       stopforgc((struct garbagelist *)ptrarray);
279       //grab lock and wait our turn
280       pthread_mutex_lock(lockptr);
281       restartaftergc();
282       header=(objheader_t *) ptrarray[2];
283 #else
284       pthread_mutex_lock(header->objptr);
285 #endif
286       /* we have lock, so we are not blocked anymore */
287       trec->blocked = 0;
288       /* Set our trec */
289       header->trec = trec;
290     }
291   }
292   //trec->blocked is zero now
293
294   /* Save the locked object */
295   if (lockedobjs->offset<MAXOBJLIST) {
296     lockedobjs->objs[lockedobjs->offset++]=header;
297   } else {
298     struct objlist *tmp=malloc(sizeof(struct objlist));
299     tmp->next=lockedobjs;
300     tmp->objs[0]=header;
301     tmp->offset=1;
302     lockedobjs=tmp;
303   }
304   return header;
305 }
306
307 /**
308  * Inline fuction to get Transaction size per object type for those
309  * objects that cause 
310  *
311  **/
312 /*
313 INLINE void getTransSize(objheader_t *header , int *isObjTypeTraverse) {
314   (typesCausingAbort[TYPE(header)]).numabort++;
315   if(isObjTypeTraverse[TYPE(header)] != 1)
316     (typesCausingAbort[TYPE(header)]).numaccess+=c_numelements;
317   isObjTypeTraverse[TYPE(header)]=1;
318 }
319 */
320
321 #endif