cleanup printing
[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(const ModelExecution *execution) :
8         cvmap(),
9         cyclic(false),
10         badrfset(),
11         lastwrmap(),
12         threadlists(1),
13         execution(execution)
14 {
15 }
16
17 SCAnalysis::~SCAnalysis() {
18 }
19
20 void SCAnalysis::print_list(action_list_t *list) {
21         model_print("---------------------------------------------------------------------\n");
22         if (cyclic)
23                 model_print("Not SC\n");
24         unsigned int hash = 0;
25
26         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
27                 const ModelAction *act = *it;
28                 if (act->get_seq_number() > 0) {
29                         if (badrfset.contains(act))
30                                 model_print("BRF ");
31                         act->print();
32                         if (badrfset.contains(act)) {
33                                 model_print("Desired Rf: %u \n",badrfset.get(act)->get_seq_number());
34                         }
35                 }
36                 hash = hash ^ (hash << 3) ^ ((*it)->hash());
37         }
38         model_print("HASH %u\n", hash);
39         model_print("---------------------------------------------------------------------\n");
40 }
41
42 void SCAnalysis::analyze(action_list_t *actions) {
43         buildVectors(actions);
44         computeCV(actions);
45         action_list_t *list = generateSC(actions);
46         check_rf(list);
47         print_list(list);
48 }
49
50 void SCAnalysis::check_rf(action_list_t *list) {
51         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
52                 const ModelAction *act = *it;
53                 if (act->is_read()) {
54                         if (act->get_reads_from()!=lastwrmap.get(act->get_location()))
55                                 badrfset.put(act,lastwrmap.get(act->get_location()));
56                 }
57                 if (act->is_write())
58                         lastwrmap.put(act->get_location(), act);
59         }
60 }
61
62 bool SCAnalysis::merge(ClockVector *cv, const ModelAction *act, const ModelAction *act2) {
63         ClockVector * cv2=cvmap.get(act2);
64         if (cv2==NULL)
65                 return true;
66         if (cv2->getClock(act->get_tid()) >= act->get_seq_number() && act->get_seq_number() != 0) {
67                 cyclic=true;
68                 //refuse to introduce cycles into clock vectors
69                 return false;
70         }
71
72         return cv->merge(cv2);
73 }
74
75 ModelAction * SCAnalysis::getNextAction() {
76         ModelAction *act = NULL;
77         /* Find the earliest in SC ordering */
78         for (int i = 0; i <= maxthreads; i++) {
79                 action_list_t *threadlist = &threadlists[i];
80                 if (threadlist->empty())
81                         continue;
82                 ModelAction *first = threadlist->front();
83                 if (act==NULL) {
84                         act=first;
85                         continue;
86                 }
87                 ClockVector *cv = cvmap.get(act);
88                 if (cv->synchronized_since(first)) {
89                         act = first;
90                 }
91         }
92         if (act == NULL)
93                 return act;
94
95
96         /* Find the model action with the earliest sequence number in case of a cycle.
97          */
98
99         for (int i = 0; i <= maxthreads; i++) {
100                 action_list_t *threadlist = &threadlists[i];
101                 if (threadlist->empty())
102                         continue;
103                 ModelAction *first = threadlist->front();
104                 ClockVector *cv = cvmap.get(act);
105                 ClockVector *cvfirst = cvmap.get(first);
106                 if (first->get_seq_number()<act->get_seq_number()&&
107                                 (cv->synchronized_since(first)||!cvfirst->synchronized_since(act))) {
108                         act=first;
109                 }
110         }
111
112         /* See if hb demands an earlier action. */
113         for (int i = 0; i <= maxthreads; i++) {
114                 action_list_t *threadlist = &threadlists[i];
115                 if (threadlist->empty())
116                         continue;
117                 ModelAction *first = threadlist->front();
118                 ClockVector *cv = act->get_cv();
119                 if (cv->synchronized_since(first)) {
120                         act = first;
121                 }
122         }
123         return act;
124 }
125
126 action_list_t * SCAnalysis::generateSC(action_list_t *list) {
127         action_list_t *sclist = new action_list_t();
128         while (true) {
129                 ModelAction *act = getNextAction();
130                 if (act == NULL)
131                         break;
132                 thread_id_t tid = act->get_tid();
133                 //remove action
134                 threadlists[id_to_int(tid)].pop_front();
135                 //add ordering constraints from this choice
136                 if (updateConstraints(act)) {
137                         //propagate changes if we have them
138                         computeCV(list);
139                 }
140                 //add action to end
141                 sclist->push_back(act);
142         }
143         return sclist;
144 }
145
146 void SCAnalysis::buildVectors(action_list_t *list) {
147         maxthreads = 0;
148         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
149                 ModelAction *act = *it;
150                 int threadid = id_to_int(act->get_tid());
151                 if (threadid > maxthreads) {
152                         threadlists.resize(threadid + 1);
153                         maxthreads = threadid;
154                 }
155                 threadlists[threadid].push_back(act);
156         }
157 }
158
159 bool SCAnalysis::updateConstraints(ModelAction *act) {
160         bool changed = false;
161         for (int i = 0; i <= maxthreads; i++) {
162                 thread_id_t tid = int_to_id(i);
163                 if (tid == act->get_tid())
164                         continue;
165
166                 action_list_t *list = &threadlists[id_to_int(tid)];
167                 for (action_list_t::iterator rit = list->begin(); rit != list->end(); rit++) {
168                         ModelAction *write = *rit;
169                         if (!write->is_write())
170                                 continue;
171                         ClockVector *writecv = cvmap.get(write);
172                         if (writecv->synchronized_since(act))
173                                 break;
174                         if (write->get_location() == act->get_location()) {
175                                 //write is sc after act
176                                 merge(writecv, write, act);
177                                 changed = true;
178                                 break;
179                         }
180                 }
181         }
182         return changed;
183 }
184
185 bool SCAnalysis::processRead(ModelAction *read, ClockVector *cv) {
186         bool changed = false;
187
188         /* Merge in the clock vector from the write */
189         const ModelAction *write = read->get_reads_from();
190         ClockVector *writecv = cvmap.get(write);
191         changed |= merge(cv, read, write) && (*read < *write);
192
193         for (int i = 0; i <= maxthreads; i++) {
194                 thread_id_t tid = int_to_id(i);
195                 if (tid == read->get_tid())
196                         continue;
197                 if (tid == write->get_tid())
198                         continue;
199                 action_list_t *list = execution->get_actions_on_obj(read->get_location(), tid);
200                 if (list == NULL)
201                         continue;
202                 for (action_list_t::reverse_iterator rit = list->rbegin(); rit != list->rend(); rit++) {
203                         ModelAction *write2 = *rit;
204                         if (!write2->is_write())
205                                 continue;
206
207                         ClockVector *write2cv = cvmap.get(write2);
208                         if (write2cv == NULL)
209                                 continue;
210
211                         /* write -sc-> write2 &&
212                                  write -rf-> R =>
213                                  R -sc-> write2 */
214                         if (write2cv->synchronized_since(write)) {
215                                 changed |= merge(write2cv, write2, read);
216                         }
217
218                         //looking for earliest write2 in iteration to satisfy this
219                         /* write2 -sc-> R &&
220                                  write -rf-> R =>
221                                  write2 -sc-> write */
222                         if (cv->synchronized_since(write2)) {
223                                 changed |= writecv==NULL || merge(writecv, write, write2);
224                                 break;
225                         }
226                 }
227         }
228         return changed;
229 }
230
231 void SCAnalysis::computeCV(action_list_t *list) {
232         bool changed = true;
233         bool firsttime = true;
234         ModelAction **last_act = (ModelAction **)model_calloc(1, (maxthreads + 1) * sizeof(ModelAction *));
235         while (changed) {
236                 changed = changed&firsttime;
237                 firsttime = false;
238
239                 for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
240                         ModelAction *act = *it;
241                         ModelAction *lastact = last_act[id_to_int(act->get_tid())];
242                         if (act->is_thread_start())
243                                 lastact = execution->get_thread(act)->get_creation();
244                         last_act[id_to_int(act->get_tid())] = act;
245                         ClockVector *cv = cvmap.get(act);
246                         if (cv == NULL) {
247                                 cv = new ClockVector(NULL, act);
248                                 cvmap.put(act, cv);
249                         }
250                         if (lastact != NULL) {
251                                 merge(cv, act, lastact);
252                         }
253                         if (act->is_thread_join()) {
254                                 Thread *joinedthr = act->get_thread_operand();
255                                 ModelAction *finish = execution->get_last_action(joinedthr->get_id());
256                                 changed |= merge(cv, act, finish);
257                         }
258                         if (act->is_read()) {
259                                 changed |= processRead(act, cv);
260                         }
261                 }
262                 /* Reset the last action array */
263                 if (changed) {
264                         bzero(last_act, (maxthreads + 1) * sizeof(ModelAction *));
265                 }
266         }
267         model_free(last_act);
268 }