265c84cd4fdf3e937ea48adfbc7e145b14efcb15
[cdsspec-compiler.git] / scanalysis.cc
1 #include "scanalysis.h"
2 #include "action.h"
3 #include "threads-model.h"
4 #include "clockvector.h"
5 #include "execution.h"
6
7 SCAnalysis::SCAnalysis() :
8         cvmap(),
9         cyclic(false),
10         badrfset(),
11         lastwrmap(),
12         threadlists(1),
13         execution(NULL)
14 {
15 }
16
17 SCAnalysis::~SCAnalysis() {
18 }
19
20 void SCAnalysis::setExecution(ModelExecution * execution) {
21         this->execution=execution;
22 }
23
24 char * SCAnalysis::name() {
25         char * name = "SC";
26         return name;
27 }
28
29 void SCAnalysis::print_list(action_list_t *list) {
30         model_print("---------------------------------------------------------------------\n");
31         if (cyclic)
32                 model_print("Not SC\n");
33         unsigned int hash = 0;
34
35         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
36                 const ModelAction *act = *it;
37                 if (act->get_seq_number() > 0) {
38                         if (badrfset.contains(act))
39                                 model_print("BRF ");
40                         act->print();
41                         if (badrfset.contains(act)) {
42                                 model_print("Desired Rf: %u \n", badrfset.get(act)->get_seq_number());
43                         }
44                 }
45                 hash = hash ^ (hash << 3) ^ ((*it)->hash());
46         }
47         model_print("HASH %u\n", hash);
48         model_print("---------------------------------------------------------------------\n");
49 }
50
51 void SCAnalysis::analyze(action_list_t *actions) {
52         action_list_t *list = generateSC(actions);
53         check_rf(list);
54         print_list(list);
55 }
56
57 void SCAnalysis::check_rf(action_list_t *list) {
58         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
59                 const ModelAction *act = *it;
60                 if (act->is_read()) {
61                         if (act->get_reads_from() != lastwrmap.get(act->get_location()))
62                                 badrfset.put(act, lastwrmap.get(act->get_location()));
63                 }
64                 if (act->is_write())
65                         lastwrmap.put(act->get_location(), act);
66         }
67 }
68
69 bool SCAnalysis::merge(ClockVector *cv, const ModelAction *act, const ModelAction *act2) {
70         ClockVector *cv2 = cvmap.get(act2);
71         if (cv2 == NULL)
72                 return true;
73         if (cv2->getClock(act->get_tid()) >= act->get_seq_number() && act->get_seq_number() != 0) {
74                 cyclic = true;
75                 //refuse to introduce cycles into clock vectors
76                 return false;
77         }
78
79         return cv->merge(cv2);
80 }
81
82 int SCAnalysis::getNextActions(ModelAction ** array) {
83         int count=0;
84
85         for (int t = 0; t <= maxthreads; t++) {
86                 action_list_t *tlt = &threadlists[t];
87                 if (tlt->empty())
88                         continue;
89                 ModelAction *act = tlt->front();
90                 ClockVector *cv = cvmap.get(act);
91                 
92                 /* Find the earliest in SC ordering */
93                 for (int i = 0; i <= maxthreads; i++) {
94                         if ( i == t )
95                                 continue;
96                         action_list_t *threadlist = &threadlists[i];
97                         if (threadlist->empty())
98                                 continue;
99                         ModelAction *first = threadlist->front();
100                         if (cv->synchronized_since(first)) {
101                                 act = NULL;
102                                 break;
103                         }
104                 }
105                 if (act != NULL) {
106                         array[count++]=act;
107                 }
108         }
109         if (count != 0)
110                 return count;
111         for (int t = 0; t <= maxthreads; t++) {
112                 action_list_t *tlt = &threadlists[t];
113                 if (tlt->empty())
114                         continue;
115                 ModelAction *act = tlt->front();
116                 ClockVector *cv = act->get_cv();
117                 
118                 /* Find the earliest in SC ordering */
119                 for (int i = 0; i <= maxthreads; i++) {
120                         if ( i == t )
121                                 continue;
122                         action_list_t *threadlist = &threadlists[i];
123                         if (threadlist->empty())
124                                 continue;
125                         ModelAction *first = threadlist->front();
126                         if (cv->synchronized_since(first)) {
127                                 act = NULL;
128                                 break;
129                         }
130                 }
131                 if (act != NULL) {
132                         array[count++]=act;
133                 }
134         }
135
136         ASSERT(count==0 || cyclic);
137
138         return count;
139 }
140
141 ModelAction * SCAnalysis::pruneArray(ModelAction **array,int count) {
142         /* No choice */
143         if (count == 1)
144                 return array[0];
145
146         /* Choose first non-write action */
147         ModelAction *nonwrite=NULL;
148         for(int i=0;i<count;i++) {
149                 if (!array[i]->is_write())
150                         if (nonwrite==NULL || nonwrite->get_seq_number() > array[i]->get_seq_number())
151                                 nonwrite = array[i];
152         }
153         if (nonwrite != NULL)
154                 return nonwrite;
155         
156         /* Look for non-conflicting action */
157         ModelAction *nonconflict=NULL;
158         for(int a=0;a<count;a++) {
159                 ModelAction *act=array[a];
160                 for (int i = 0; i <= maxthreads && act != NULL; i++) {
161                         thread_id_t tid = int_to_id(i);
162                         if (tid == act->get_tid())
163                                 continue;
164                         
165                         action_list_t *list = &threadlists[id_to_int(tid)];
166                         for (action_list_t::iterator rit = list->begin(); rit != list->end(); rit++) {
167                                 ModelAction *write = *rit;
168                                 if (!write->is_write())
169                                         continue;
170                                 ClockVector *writecv = cvmap.get(write);
171                                 if (writecv->synchronized_since(act))
172                                         break;
173                                 if (write->get_location() == act->get_location()) {
174                                         //write is sc after act
175                                         act = NULL;
176                                         break;
177                                 }
178                         }
179                 }
180                 if (act != NULL) {
181                         if (nonconflict == NULL || nonconflict->get_seq_number() > act->get_seq_number())
182                                 nonconflict=act;
183                 }
184         }
185         return nonconflict;
186 }
187
188 action_list_t * SCAnalysis::generateSC(action_list_t *list) {
189         int numactions=buildVectors(list);
190         computeCV(list);
191
192         action_list_t *sclist = new action_list_t();
193         ModelAction **array = (ModelAction **)model_calloc(1, (maxthreads + 1) * sizeof(ModelAction *));
194         int * choices = (int *) model_calloc(1, sizeof(int)*numactions);
195         int endchoice = 0;
196         int currchoice = 0;
197         int lastchoice = -1;
198         while (true) {
199                 int numActions = getNextActions(array);
200                 if (numActions == 0)
201                         break;
202                 ModelAction * act=pruneArray(array, numActions);
203                 if (act == NULL) {
204                         if (currchoice < endchoice) {
205                                 act = array[choices[currchoice]];
206                                 //check whether there is still another option
207                                 if ((choices[currchoice]+1)<numActions)
208                                         lastchoice=currchoice;
209                                 currchoice++;
210                         } else {
211                                 act = array[0];
212                                 choices[currchoice]=0;
213                                 if (numActions>1)
214                                         lastchoice=currchoice;
215                                 currchoice++;
216                         }
217                 }
218                 thread_id_t tid = act->get_tid();
219                 //remove action
220                 threadlists[id_to_int(tid)].pop_front();
221                 //add ordering constraints from this choice
222                 if (updateConstraints(act)) {
223                         //propagate changes if we have them
224                         bool prevc=cyclic;
225                         computeCV(list);
226                         if (!prevc && cyclic) {
227                                 model_print("ROLLBACK in SC\n");
228                                 //check whether we have another choice
229                                 if (lastchoice != -1) {
230                                         //have to reset everything
231                                         choices[lastchoice]++;
232                                         endchoice=lastchoice+1;
233                                         currchoice=0;
234                                         lastchoice=-1;
235                                         reset(list);
236                                         buildVectors(list);
237                                         computeCV(list);
238                                         sclist->clear();
239                                         continue;
240                                 }
241                         }
242                 }
243                 //add action to end
244                 sclist->push_back(act);
245         }
246         model_free(array);
247         return sclist;
248 }
249
250 int SCAnalysis::buildVectors(action_list_t *list) {
251         maxthreads = 0;
252         int numactions = 0;
253         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
254                 ModelAction *act = *it;
255                 numactions++;
256                 int threadid = id_to_int(act->get_tid());
257                 if (threadid > maxthreads) {
258                         threadlists.resize(threadid + 1);
259                         maxthreads = threadid;
260                 }
261                 threadlists[threadid].push_back(act);
262         }
263         return numactions;
264 }
265
266 void SCAnalysis::reset(action_list_t *list) {
267         for (int t = 0; t <= maxthreads; t++) {
268                 action_list_t *tlt = &threadlists[t];
269                 tlt->clear();
270         }
271         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
272                 ModelAction *act = *it;
273                 delete cvmap.get(act);
274                 cvmap.put(act, NULL);
275         }
276
277         cyclic=false;   
278 }
279
280 bool SCAnalysis::updateConstraints(ModelAction *act) {
281         bool changed = false;
282         for (int i = 0; i <= maxthreads; i++) {
283                 thread_id_t tid = int_to_id(i);
284                 if (tid == act->get_tid())
285                         continue;
286
287                 action_list_t *list = &threadlists[id_to_int(tid)];
288                 for (action_list_t::iterator rit = list->begin(); rit != list->end(); rit++) {
289                         ModelAction *write = *rit;
290                         if (!write->is_write())
291                                 continue;
292                         ClockVector *writecv = cvmap.get(write);
293                         if (writecv->synchronized_since(act))
294                                 break;
295                         if (write->get_location() == act->get_location()) {
296                                 //write is sc after act
297                                 merge(writecv, write, act);
298                                 changed = true;
299                                 break;
300                         }
301                 }
302         }
303         return changed;
304 }
305
306 bool SCAnalysis::processRead(ModelAction *read, ClockVector *cv) {
307         bool changed = false;
308
309         /* Merge in the clock vector from the write */
310         const ModelAction *write = read->get_reads_from();
311         ClockVector *writecv = cvmap.get(write);
312         changed |= merge(cv, read, write) && (*read < *write);
313
314         for (int i = 0; i <= maxthreads; i++) {
315                 thread_id_t tid = int_to_id(i);
316                 if (tid == read->get_tid())
317                         continue;
318                 if (tid == write->get_tid())
319                         continue;
320                 action_list_t *list = execution->get_actions_on_obj(read->get_location(), tid);
321                 if (list == NULL)
322                         continue;
323                 for (action_list_t::reverse_iterator rit = list->rbegin(); rit != list->rend(); rit++) {
324                         ModelAction *write2 = *rit;
325                         if (!write2->is_write())
326                                 continue;
327
328                         ClockVector *write2cv = cvmap.get(write2);
329                         if (write2cv == NULL)
330                                 continue;
331
332                         /* write -sc-> write2 &&
333                                  write -rf-> R =>
334                                  R -sc-> write2 */
335                         if (write2cv->synchronized_since(write)) {
336                                 changed |= merge(write2cv, write2, read);
337                         }
338
339                         //looking for earliest write2 in iteration to satisfy this
340                         /* write2 -sc-> R &&
341                                  write -rf-> R =>
342                                  write2 -sc-> write */
343                         if (cv->synchronized_since(write2)) {
344                                 changed |= writecv == NULL || merge(writecv, write, write2);
345                                 break;
346                         }
347                 }
348         }
349         return changed;
350 }
351
352 void SCAnalysis::computeCV(action_list_t *list) {
353         bool changed = true;
354         bool firsttime = true;
355         ModelAction **last_act = (ModelAction **)model_calloc(1, (maxthreads + 1) * sizeof(ModelAction *));
356         while (changed) {
357                 changed = changed&firsttime;
358                 firsttime = false;
359
360                 for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
361                         ModelAction *act = *it;
362                         ModelAction *lastact = last_act[id_to_int(act->get_tid())];
363                         if (act->is_thread_start())
364                                 lastact = execution->get_thread(act)->get_creation();
365                         last_act[id_to_int(act->get_tid())] = act;
366                         ClockVector *cv = cvmap.get(act);
367                         if (cv == NULL) {
368                                 cv = new ClockVector(NULL, act);
369                                 cvmap.put(act, cv);
370                         }
371                         if (lastact != NULL) {
372                                 merge(cv, act, lastact);
373                         }
374                         if (act->is_thread_join()) {
375                                 Thread *joinedthr = act->get_thread_operand();
376                                 ModelAction *finish = execution->get_last_action(joinedthr->get_id());
377                                 changed |= merge(cv, act, finish);
378                         }
379                         if (act->is_read()) {
380                                 changed |= processRead(act, cv);
381                         }
382                 }
383                 /* Reset the last action array */
384                 if (changed) {
385                         bzero(last_act, (maxthreads + 1) * sizeof(ModelAction *));
386                 }
387         }
388         model_free(last_act);
389 }