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