Merge remote-tracking branch 'private/master'
[model-checker.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                         computeCV(list);
149                 }
150                 //add action to end
151                 sclist->push_back(act);
152         }
153         return sclist;
154 }
155
156 void SCAnalysis::buildVectors(action_list_t *list) {
157         maxthreads = 0;
158         for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
159                 ModelAction *act = *it;
160                 int threadid = id_to_int(act->get_tid());
161                 if (threadid > maxthreads) {
162                         threadlists.resize(threadid + 1);
163                         maxthreads = threadid;
164                 }
165                 threadlists[threadid].push_back(act);
166         }
167 }
168
169 bool SCAnalysis::updateConstraints(ModelAction *act) {
170         bool changed = false;
171         for (int i = 0; i <= maxthreads; i++) {
172                 thread_id_t tid = int_to_id(i);
173                 if (tid == act->get_tid())
174                         continue;
175
176                 action_list_t *list = &threadlists[id_to_int(tid)];
177                 for (action_list_t::iterator rit = list->begin(); rit != list->end(); rit++) {
178                         ModelAction *write = *rit;
179                         if (!write->is_write())
180                                 continue;
181                         ClockVector *writecv = cvmap.get(write);
182                         if (writecv->synchronized_since(act))
183                                 break;
184                         if (write->get_location() == act->get_location()) {
185                                 //write is sc after act
186                                 merge(writecv, write, act);
187                                 changed = true;
188                                 break;
189                         }
190                 }
191         }
192         return changed;
193 }
194
195 bool SCAnalysis::processRead(ModelAction *read, ClockVector *cv) {
196         bool changed = false;
197
198         /* Merge in the clock vector from the write */
199         const ModelAction *write = read->get_reads_from();
200         ClockVector *writecv = cvmap.get(write);
201         changed |= merge(cv, read, write) && (*read < *write);
202
203         for (int i = 0; i <= maxthreads; i++) {
204                 thread_id_t tid = int_to_id(i);
205                 if (tid == read->get_tid())
206                         continue;
207                 if (tid == write->get_tid())
208                         continue;
209                 action_list_t *list = execution->get_actions_on_obj(read->get_location(), tid);
210                 if (list == NULL)
211                         continue;
212                 for (action_list_t::reverse_iterator rit = list->rbegin(); rit != list->rend(); rit++) {
213                         ModelAction *write2 = *rit;
214                         if (!write2->is_write())
215                                 continue;
216
217                         ClockVector *write2cv = cvmap.get(write2);
218                         if (write2cv == NULL)
219                                 continue;
220
221                         /* write -sc-> write2 &&
222                                  write -rf-> R =>
223                                  R -sc-> write2 */
224                         if (write2cv->synchronized_since(write)) {
225                                 changed |= merge(write2cv, write2, read);
226                         }
227
228                         //looking for earliest write2 in iteration to satisfy this
229                         /* write2 -sc-> R &&
230                                  write -rf-> R =>
231                                  write2 -sc-> write */
232                         if (cv->synchronized_since(write2)) {
233                                 changed |= writecv==NULL || merge(writecv, write, write2);
234                                 break;
235                         }
236                 }
237         }
238         return changed;
239 }
240
241 void SCAnalysis::computeCV(action_list_t *list) {
242         bool changed = true;
243         bool firsttime = true;
244         ModelAction **last_act = (ModelAction **)model_calloc(1, (maxthreads + 1) * sizeof(ModelAction *));
245         while (changed) {
246                 changed = changed&firsttime;
247                 firsttime = false;
248
249                 for (action_list_t::iterator it = list->begin(); it != list->end(); it++) {
250                         ModelAction *act = *it;
251                         ModelAction *lastact = last_act[id_to_int(act->get_tid())];
252                         if (act->is_thread_start())
253                                 lastact = execution->get_thread(act)->get_creation();
254                         last_act[id_to_int(act->get_tid())] = act;
255                         ClockVector *cv = cvmap.get(act);
256                         if (cv == NULL) {
257                                 cv = new ClockVector(NULL, act);
258                                 cvmap.put(act, cv);
259                         }
260                         if (lastact != NULL) {
261                                 merge(cv, act, lastact);
262                         }
263                         if (act->is_thread_join()) {
264                                 Thread *joinedthr = act->get_thread_operand();
265                                 ModelAction *finish = execution->get_last_action(joinedthr->get_id());
266                                 changed |= merge(cv, act, finish);
267                         }
268                         if (act->is_read()) {
269                                 changed |= processRead(act, cv);
270                         }
271                 }
272                 /* Reset the last action array */
273                 if (changed) {
274                         bzero(last_act, (maxthreads + 1) * sizeof(ModelAction *));
275                 }
276         }
277         model_free(last_act);
278 }