Fix bug that prevents graph generation from compiling.
[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         /* Find the model action with the earliest sequence number in case of a cycle.
96          */
97
98         for (int i = 0; i <= maxthreads; i++) {
99                 action_list_t *threadlist = &threadlists[i];
100                 if (threadlist->empty())
101                         continue;
102                 ModelAction *first = threadlist->front();
103                 ClockVector *cvfirst = cvmap.get(first);
104                 if (first->get_seq_number()<act->get_seq_number()) {
105                         bool candidate=true;
106                         for (int j = 0; j <= maxthreads; j++) {
107                                 action_list_t *threadlist2 = &threadlists[j];
108                                 if (threadlist2->empty())
109                                         continue;
110                                 ModelAction *check = threadlist2->front();
111                                 if ((check!=first) &&
112                                                 cvfirst->synchronized_since(check)) {
113                                         candidate=false;
114                                         break;
115                                 }
116                         }
117                         if (candidate)
118                                 act=first;
119                 }
120         }
121
122         /* See if hb demands an earlier action. */
123         for (int i = 0; i <= maxthreads; i++) {
124                 action_list_t *threadlist = &threadlists[i];
125                 if (threadlist->empty())
126                         continue;
127                 ModelAction *first = threadlist->front();
128                 ClockVector *cv = act->get_cv();
129                 if (cv->synchronized_since(first)) {
130                         act = first;
131                 }
132         }
133         return act;
134 }
135
136 action_list_t * SCAnalysis::generateSC(action_list_t *list) {
137         action_list_t *sclist = new action_list_t();
138         while (true) {
139                 ModelAction *act = getNextAction();
140                 if (act == NULL)
141                         break;
142                 thread_id_t tid = act->get_tid();
143                 //remove action
144                 threadlists[id_to_int(tid)].pop_front();
145                 //add ordering constraints from this choice
146                 if (updateConstraints(act)) {
147                         //propagate changes if we have them
148                         bool oc=cyclic;
149                         computeCV(list);
150                         if (!oc && cyclic)
151                                 model_print("XXXXXXXXXXXXXX\n");
152                 }
153                 //add action to end
154                 sclist->push_back(act);
155         }
156         return sclist;
157 }
158
159 void SCAnalysis::buildVectors(action_list_t *list) {
160         maxthreads = 0;
161         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
162                 ModelAction *act = *it;
163                 int threadid = id_to_int(act->get_tid());
164                 if (threadid > maxthreads) {
165                         threadlists.resize(threadid + 1);
166                         maxthreads = threadid;
167                 }
168                 threadlists[threadid].push_back(act);
169         }
170 }
171
172 bool SCAnalysis::updateConstraints(ModelAction *act) {
173         bool changed = false;
174         for (int i = 0; i <= maxthreads; i++) {
175                 thread_id_t tid = int_to_id(i);
176                 if (tid == act->get_tid())
177                         continue;
178
179                 action_list_t *list = &threadlists[id_to_int(tid)];
180                 for (action_list_t::iterator rit = list->begin(); rit != list->end(); rit++) {
181                         ModelAction *write = *rit;
182                         if (!write->is_write())
183                                 continue;
184                         ClockVector *writecv = cvmap.get(write);
185                         if (writecv->synchronized_since(act))
186                                 break;
187                         if (write->get_location() == act->get_location()) {
188                                 //write is sc after act
189                                 merge(writecv, write, act);
190                                 changed = true;
191                                 break;
192                         }
193                 }
194         }
195         return changed;
196 }
197
198 bool SCAnalysis::processRead(ModelAction *read, ClockVector *cv) {
199         bool changed = false;
200
201         /* Merge in the clock vector from the write */
202         const ModelAction *write = read->get_reads_from();
203         ClockVector *writecv = cvmap.get(write);
204         changed |= merge(cv, read, write) && (*read < *write);
205
206         for (int i = 0; i <= maxthreads; i++) {
207                 thread_id_t tid = int_to_id(i);
208                 if (tid == read->get_tid())
209                         continue;
210                 if (tid == write->get_tid())
211                         continue;
212                 action_list_t *list = execution->get_actions_on_obj(read->get_location(), tid);
213                 if (list == NULL)
214                         continue;
215                 for (action_list_t::reverse_iterator rit = list->rbegin(); rit != list->rend(); rit++) {
216                         ModelAction *write2 = *rit;
217                         if (!write2->is_write())
218                                 continue;
219
220                         ClockVector *write2cv = cvmap.get(write2);
221                         if (write2cv == NULL)
222                                 continue;
223
224                         /* write -sc-> write2 &&
225                                  write -rf-> R =>
226                                  R -sc-> write2 */
227                         if (write2cv->synchronized_since(write)) {
228                                 changed |= merge(write2cv, write2, read);
229                         }
230
231                         //looking for earliest write2 in iteration to satisfy this
232                         /* write2 -sc-> R &&
233                                  write -rf-> R =>
234                                  write2 -sc-> write */
235                         if (cv->synchronized_since(write2)) {
236                                 changed |= writecv==NULL || merge(writecv, write, write2);
237                                 break;
238                         }
239                 }
240         }
241         return changed;
242 }
243
244 void SCAnalysis::computeCV(action_list_t *list) {
245         bool changed = true;
246         bool firsttime = true;
247         ModelAction **last_act = (ModelAction **)model_calloc(1, (maxthreads + 1) * sizeof(ModelAction *));
248         while (changed) {
249                 changed = changed&firsttime;
250                 firsttime = false;
251
252                 for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
253                         ModelAction *act = *it;
254                         ModelAction *lastact = last_act[id_to_int(act->get_tid())];
255                         if (act->is_thread_start())
256                                 lastact = execution->get_thread(act)->get_creation();
257                         last_act[id_to_int(act->get_tid())] = act;
258                         ClockVector *cv = cvmap.get(act);
259                         if (cv == NULL) {
260                                 cv = new ClockVector(NULL, act);
261                                 cvmap.put(act, cv);
262                         }
263                         if (lastact != NULL) {
264                                 merge(cv, act, lastact);
265                         }
266                         if (act->is_thread_join()) {
267                                 Thread *joinedthr = act->get_thread_operand();
268                                 ModelAction *finish = execution->get_last_action(joinedthr->get_id());
269                                 changed |= merge(cv, act, finish);
270                         }
271                         if (act->is_read()) {
272                                 changed |= processRead(act, cv);
273                         }
274                 }
275                 /* Reset the last action array */
276                 if (changed) {
277                         bzero(last_act, (maxthreads + 1) * sizeof(ModelAction *));
278                 }
279         }
280         model_free(last_act);
281 }