source: CIVL/include/impls/civl-omp2.cvl@ 1aaefd4

main test-branch
Last change on this file since 1aaefd4 was ea777aa, checked in by Alex Wilton <awilton@…>, 3 years ago

Moved examples, include, build_default.properties, common.xml, and README out from dev.civl.com into the root of the repo.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@5704 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 16.4 KB
Line 
1// civlc-omp.cvl: implementations of functions and types in civlc-omp.cvh
2#include<civl-omp.cvh>
3#include<civlc.cvh>
4#include<pointer.cvh>
5#include<seq.cvh>
6#include<concurrency.cvh>
7#include<domain.cvh>
8
9/* Completes the definition of struct OMP_gshared given in civlc-omp.cvh.
10 */
11struct OMP_gshared {
12 int nthreads;
13 _Bool init[]; // which threads have joined
14 $omp_shared shares[];
15 void * original; // pointer to original variable
16};
17
18/* Completes the definition of struct OMP_shared given in civlc-omp.cvh.
19 */
20struct OMP_shared {
21 $omp_gshared gshared;
22 /* The thread id */
23 int tid;
24 /* Pointer to the local copy of the shared variable.
25 * This provides the thread's "private view" of the variable. */
26 void * local;
27 /* Pointer to the local status variable */
28 void * status;
29};
30
31/* Completes the definition of struct OMP_work_record
32 * given in civlc-omp.cvh. */
33struct OMP_work_record {
34 int kind; // loop, barrier, sections, or single
35 int location; // location in model of construct
36 _Bool arrived; // has this thread arrived yet?
37 $domain loop_domain; // full loop domain; null if not loop
38 $domain subdomain; // tasks this thread must do
39 // reduction operation?
40};
41
42struct OMP_gteam {
43 /* scope in which data is allocated in heap */
44 $scope scope;
45 /* number of threads in team */
46 int nthreads;
47 /* which threads have joined this gteam */
48 _Bool init[];
49 /* work queues. Length nthreads. For each thread,
50 * a FIFO queue of work records */
51 /* work queues. Width nthreads. For each worksharing region,
52 * one entry of size nthreads is added. */
53 $omp_work_record work[][];
54 /* the shared object data. */
55 $omp_gshared shared[];
56 $gbarrier gbarrier;
57};
58
59struct OMP_team {
60 $omp_gteam gteam;
61 $scope scope;
62 int tid;
63 $omp_shared shared[];
64 $barrier barrier;
65};
66
67
68/* *********************** Functions *********************** */
69
70$atomic $omp_gteam $omp_gteam_create($scope scope, int nthreads)
71$depends {$nothing}
72$reads {$nothing}
73{
74 //$omp_work_record empty[];
75 $omp_gteam result = ($omp_gteam)$malloc(scope, sizeof(struct OMP_gteam));
76 _Bool f = $false;
77
78 //$seq_init(&empty, 0, NULL);
79 result->scope = scope;
80 result->nthreads = nthreads;
81 $seq_init(&result->init, nthreads, &f);
82 $seq_init(&result->work, 0, NULL);
83 $seq_init(&result->shared, 0, NULL);
84 result->gbarrier = $gbarrier_create(scope, nthreads);
85 return result;
86}
87
88
89$fatomic void $omp_gteam_destroy($omp_gteam gteam)
90$depends {$access(*gteam)}
91$assigns {*gteam}
92{
93 int length = $seq_length(&gteam->work);
94
95 $assert(length == 0, "There are still %d queued worksharing events.", length);
96 $free(gteam->gbarrier);
97 $free(gteam);
98}
99
100/* creates new local team object for a specific thread. */
101$fatomic $omp_team $omp_team_create($scope scope, $omp_gteam gteam, int tid)
102$depends {$nothing}
103{
104 $omp_team result = ($omp_team)$malloc(scope, sizeof(struct OMP_team));
105
106 $assert(!gteam->init[tid], "Thread %d has already joined gteam",
107 tid);
108 gteam->init[tid] = $true;
109 result->gteam = gteam;
110 result->scope = scope;
111 result->tid = tid;
112 $seq_init(&result->shared, 0, NULL);
113 result->barrier = $barrier_create(scope, gteam->gbarrier, tid);
114 $read_set_push();
115 $write_set_push();
116 return result;
117}
118
119/* destroys the local team object */
120$fatomic void $omp_team_destroy($omp_team team)
121$depends {$access(*team)}
122$assigns {*team}
123{
124 $read_set_pop();
125 $write_set_pop();
126 /*int numShared = $seq_length(&team->shared);
127
128 for(int i = 0; i < numShared; i++){
129 $free(team->shared[i]);
130 }*/
131 $free(team->barrier);
132 $free(team);
133}
134
135/* creates new global shared object, associated to the given
136 * global team. A pointer to the shared variable that this
137 * object corresponds to is given.
138 */
139$fatomic $omp_gshared $omp_gshared_create($omp_gteam gteam,
140 void *original)
141$depends {$nothing}
142$reads {$nothing}
143{
144 $omp_gshared result =
145 ($omp_gshared)$malloc(gteam->scope, sizeof(struct OMP_gshared));
146 _Bool f = $false;
147 $omp_shared null = NULL;
148
149 result->nthreads = gteam->nthreads;
150 $seq_init(&result->init, gteam->nthreads, &f);
151 result->original = original;
152 $seq_init(&result->shares, gteam->nthreads, &null);
153 //result->status = status;
154 return result;
155}
156
157/* destroys the global shared object, copying the content
158 * to the original variable.
159 */
160$fatomic void $omp_gshared_destroy($omp_gshared gshared)
161$depends {$access(*gshared)}
162$assigns {*gshared}
163{
164 $free(gshared);
165}
166
167$fatomic $omp_shared $omp_shared_create($omp_team team,
168 $omp_gshared gshared, void *local, void *status)
169$depends {$nothing}
170$reads {$nothing}
171{
172 $omp_shared result =
173 ($omp_shared)$malloc(team->scope, sizeof(struct OMP_shared));
174 //void *statusRefs[];
175 //int numStatusRefs;
176 int sharedLength;
177
178 $assert(!gshared->init[team->tid], "Thread %d has already created its local copy for %p.\n",
179 team->tid, gshared);
180 result->gshared = gshared;
181 result->tid = team->tid;
182 result->local = local;
183 // copies the shared data to the local copy
184 $copy(local, gshared->original);
185 result->status = status;
186 // set all leaf nodes of status to FULL
187 $set_leaf_nodes(status, FULL);
188 //$leaf_node_ptrs(&statusRefs, status);
189 //numStatusRefs = $seq_length(&statusRefs);
190 //for(int i = 0; i < numStatusRefs; i++)
191 //*((int*)(statusRefs[i])) = FULL;
192 sharedLength = $seq_length(&team->shared);
193 $seq_insert(&team->shared, sharedLength, &result, 1);
194 //$seq_append(&team->shared, &result, 1);
195 gshared->shares[team->tid] = result;
196 return result;
197}
198
199$fatomic void $omp_shared_destroy($omp_shared shared)
200$depends {$access(*shared)}
201$assigns {*shared}
202{
203 $free(shared);
204}
205
206// returns the id of the thread that has some unflushed modification to
207// the shared object
208// shared->gshared->shares[*]->status(ref): only the specific reference matters
209int $omp_modified_tid($omp_shared shared, void *ref)
210 $reads {shared->tid, shared->gshared->shares[*]->status}
211{
212 int tid = shared->tid;
213 $omp_gshared gshared = shared->gshared;
214 int nthreads = gshared->nthreads;
215 _Bool isIdentityRef = $is_identity_ref(ref);
216
217 for(int i=0; i < nthreads;i++){
218 if(i == tid)
219 continue;
220 else{
221 $omp_shared other = gshared->shares[i];
222 $omp_var_status other_status;
223 _Bool hasModified = $false;
224
225 if(!$is_valid_pointer(other))
226 continue;
227 if(isIdentityRef){
228 hasModified = $has_leaf_node_equal_to(other->status, MODIFIED);
229 }else{
230 int *other_status_ref = (int*)$translate_ptr(ref, other->status);
231
232 hasModified = ((*other_status_ref) == MODIFIED);
233 }
234 if(hasModified)
235 return i;
236 }
237 }
238 return -1;
239}
240
241$fatomic void $omp_read($omp_shared shared, void *result, void *ref)
242$depends {$access(*result), $access(*ref), $write(*(shared->status), *(shared->gshared->original))}
243$assigns {*result, *ref}//over-approximation, possibly assigns *ref.
244$reads {*(shared->status), *(shared->gshared->original)}
245{
246 int otherTid = $omp_modified_tid(shared, ref);
247
248 $assert(otherTid < 0,
249 "Thread %d can't perform $omp_read because thread %d has written to the same variable and hasn't flushed yet.\n",
250 shared->tid, otherTid);
251 if($is_identity_ref(ref)){
252 if($leaf_nodes_equal_to(shared->status, EMPTY)){
253 $copy(ref, shared->gshared->original); // copy shared to local
254 $set_leaf_nodes(shared->status, FULL);
255 }
256 }else{
257 int *status_ref = (int*)$translate_ptr(ref, shared->status);
258 int status = *status_ref;
259
260 if(status == EMPTY){
261 void *global = $translate_ptr(ref, shared->gshared->original);
262
263 $copy(ref, global); // copy shared to local
264 *status_ref = FULL; // set status to FULL
265 }
266 }
267 // read local
268 $copy(result, ref);
269}
270
271$fatomic void $omp_write($omp_shared shared, void *ref, void *value)
272$depends
273{
274 int otherTid = $omp_modified_tid(shared, ref);
275
276 $assert(otherTid < 0, "Thread %d can't perform $omp_write because thread %d has written to the same variable and hasn't flushed yet.\n",
277 shared->tid, otherTid);
278 $copy(ref, value);
279 if($is_identity_ref(ref)){
280 $set_leaf_nodes(shared->status, MODIFIED);
281 }else{
282 int *status_ref = (int*)$translate_ptr(ref, shared->status);
283 *status_ref = MODIFIED;
284 }
285}
286
287/* Only applicable to scalar type? */
288void $omp_apply_assoc($omp_shared shared,
289 $operation op,
290 void *local){
291 $atomic {
292 void *shared_ref = $translate_ptr(local, shared->gshared->original);
293
294 $apply(shared_ref, op, local, shared_ref);
295 }
296}
297
298void $omp_flush($omp_shared shared, void *ref) {
299 // need to drill down into all leaf nodes of the object
300 // being flushed...
301 // also, it should be ok to flush a memory unit if you are not
302 // the owner but you also have no reads or writes to that variable
303 // TODO: assert there is at most one thread for which this memory unit has status MODIFIED;
304 $omp_gshared gshared = shared->gshared;
305 int tid = shared->tid;
306 void *refs[];
307 int numRefs;
308
309 // get all leaf node pointers
310 $leaf_node_ptrs(&refs, ref);
311 numRefs = $seq_length(&refs);
312 for(int i = 0; i < numRefs; i++){
313 void *leaf = refs[i];
314 int *leaf_status = (int *)$translate_ptr(leaf, shared->status);
315 //void *leaf_local = (int *)$translate_ptr(leaf, shared->local);
316 void *leaf_shared = (int *)$translate_ptr(leaf, gshared->original);
317
318 switch(*leaf_status){
319 case EMPTY:
320 break;
321 case MODIFIED:
322 $copy(leaf_shared, leaf);
323 case FULL:
324 *leaf_status = EMPTY;
325 $set_default(leaf);
326 break;
327 }
328 }
329}
330
331void $omp_flush_all($omp_team team) {
332 int num_shared = $seq_length(&team->shared);
333
334 for (int i=0; i<num_shared; i++) {
335 $omp_shared shared = team->shared[i];
336
337 $omp_flush(shared, shared->local);
338 }
339}
340
341void $omp_barrier($omp_team team){
342 $barrier_call(team->barrier);
343}
344
345void $omp_barrier_and_flush($omp_team team) {
346 $read_set_pop();
347 $write_set_pop();
348 // this is a collective operation: all members of team call
349 $barrier_call(team->barrier);
350 $omp_flush_all(team);
351 $barrier_call(team->barrier);
352 $read_set_push();
353 $write_set_push();
354}
355
356/**
357 * performs the checking of workrecords when the last thread arrives the workshared region,
358 * including:
359 * number of workrecords in the entry should be nthreads
360 * all workrecords are arrived
361 * all workrecords have the same location as specified
362 * all workrecords are of the same kind
363 */
364void $omp_check_workrecords($omp_gteam gteam, int location, $omp_worksharing_kind kind, int index){
365 int nthreads = gteam->nthreads;
366 int numWorkrecords;
367
368 numWorkrecords = $seq_length(&gteam->work[index]);
369 $assert(numWorkrecords == nthreads, "The %d-th workshared entry has length %d while the expected length should be %d.", index, numWorkrecords, nthreads);
370 for(int i = 0; i < nthreads; i++){
371 $omp_work_record workrecord = gteam->work[index][i];
372
373 $assert(workrecord.arrived, "The workshared event of location %d for thread %d hasn't been arrived yet.",
374 location, i);
375 $assert(workrecord.location == location, "Wrong workshared location of thread %d: expected %d, but saw %d.",
376 i, location, workrecord.location);
377 $assert(workrecord.kind == kind, "Wrong workshared kind of thread %d: expected %d but saw %d",
378 i, kind, workrecord.kind);
379 }
380}
381
382/* finds the workrecord of the given location for a certain thread in a team,
383 * stores the workrecord in the buffer provided,
384 * returns the index of the workrecod entry in the work queue
385 * or -1 if the workrecord is absent.
386 *
387 * gteam: the global team object
388 * tid: the id of the thread
389 * location: the location of the workrecord being searched for
390 * result: the buffer for store the workrecord found
391 */
392int find_work_record($omp_gteam gteam, int tid, int location, $omp_work_record *result){
393 int numEntires = $seq_length(&gteam->work);
394
395 for(int i = 0; i < numEntires; i++){
396 $omp_work_record workrecord = gteam->work[i][tid];
397
398 if(workrecord.location == location){
399 *result = workrecord;
400 return i;
401 }
402 }
403 return -1;
404}
405
406/* checks if all threads have arrived the workrecord at the given index */
407_Bool all_arrived($omp_gteam gteam, int index){
408 for(int tid = 0; tid < gteam->nthreads; tid++){
409 if(!gteam->work[index][tid].arrived)
410 return $false;
411 }
412 return $true;
413}
414
415void arrive($omp_gteam gteam, int tid, int index,
416$omp_work_record workrecord, $omp_worksharing_kind kind, int location){
417 $assert(!workrecord.arrived, "The loop at location %d has been arrived before by thread %d!",
418 location, tid);
419 $assert(workrecord.kind == kind, "Wrong workshare kind of thread %d: expected LOOP",
420 tid);
421 (gteam->work[index][tid]).arrived = $true;
422 if(all_arrived(gteam, index)){//this is the last thread
423 $assert(index == 0, "Inconsistent order or worksharing events.");
424 $omp_check_workrecords(gteam, location, kind, index);
425 $seq_remove(&gteam->work, index, NULL, 1);
426 }
427}
428
429/* TODO: checks if loop_dom gets changed if the current thread is NOT the
430 * first thread entering the loop.
431 */
432$domain $omp_arrive_loop($omp_team team, int location, $domain loop_dom,
433 $domain_strategy strategy){
434 $atomic{
435 $omp_gteam gteam = team->gteam;
436 int tid = team->tid;
437 int nthreads = gteam->nthreads;
438 int index;
439 $omp_work_record workrecord;
440
441 $assert(gteam->init[tid], "The current thread %d has not joined the gteam!", tid);
442 if(nthreads == 1)
443 return loop_dom;
444 index = find_work_record(gteam, tid, location, &workrecord);
445 if(index >= 0){//workrecord found
446 $assert($equals(&gteam->work[index][0].loop_domain, &loop_dom), "The loop domain at location %d is changed when thread %d arrives it. \n Expected %s but saw %s.",
447 location,
448 tid,
449 gteam->work[index][0].loop_domain,
450 loop_dom);
451 arrive(gteam, tid, index, workrecord, LOOP, location);
452 return workrecord.subdomain;
453 }else{//workrecord not found, this should be the first thread
454 $omp_work_record workrecords[nthreads];
455 $domain_decomposition decomposition;
456 int numEntries = $seq_length(&gteam->work);
457
458 decomposition = $domain_partition(loop_dom, strategy, nthreads);
459 workrecords[0].loop_domain = loop_dom;
460 for(int i = 0; i< nthreads; i++){
461 workrecords[i].kind = LOOP;
462 workrecords[i].location = location;
463 workrecords[i].arrived = (i == tid);
464 workrecords[i].subdomain = decomposition.subdomains[i];
465 }
466 $seq_insert(&gteam->work, numEntries, &workrecords, 1);
467 return workrecords[tid].subdomain;
468 }
469 }
470}
471
472/* TODO: need strategies? */
473$domain(1) $omp_arrive_sections($omp_team team, int location, int numSections){
474 $atomic{
475 $omp_gteam gteam = team->gteam;
476 int tid = team->tid;
477 int nthreads = gteam->nthreads;
478 int index;
479 $omp_work_record workrecord;
480
481 $assert(gteam->init[tid], "The current thread %d has not joined the gteam!", tid);
482 if(nthreads == 1)
483 return ($domain(1)) {0 .. numSections - 1 # 1};
484 index = find_work_record(gteam, tid, location, &workrecord);
485 if(index >= 0){//workrecord found
486 arrive(gteam, tid, index, workrecord, SECTIONS, location);
487 return workrecord.subdomain;
488 }else{//workrecord not found, this should be the first thread
489 $omp_work_record workrecords[nthreads];
490 int numEntries = $seq_length(&gteam->work);
491
492 for(int i = 0; i < nthreads; i++){
493 int low = i, high = numSections - 1, step = nthreads;
494 $range range = low .. high # step;
495 $domain(1) dom = ($domain(1)) {range};
496
497 workrecords[i].kind = SECTIONS;
498 workrecords[i].location = location;
499 workrecords[i].arrived = (i == tid);
500 workrecords[i].subdomain = dom;
501 }
502 $seq_insert(&gteam->work, numEntries, &workrecords, 1);
503 return workrecords[tid].subdomain;
504 }
505 }
506}
507
508/* TODO: need strategies? */
509 int $omp_arrive_single($omp_team team, int location){
510 $atomic{
511 $omp_gteam gteam = team->gteam;
512 int tid = team->tid;
513 int nthreads = gteam->nthreads;
514 int index;
515 $omp_work_record workrecord;
516
517 $assert(gteam->init[tid], "The current thread %d has not joined the gteam!", tid);
518 if(nthreads == 1)
519 return tid;
520 index = find_work_record(gteam, tid, location, &workrecord);
521 if(index >= 0){//workrecord found
522 arrive(gteam, tid, index, workrecord, SINGLE, location);
523 }else{//workrecord not found, this should be the first thread
524 $omp_work_record workrecords[nthreads];
525 int numEntries = $seq_length(&gteam->work);
526
527 for(int i = 0; i < nthreads; i++){
528 workrecords[i].kind = SINGLE;
529 workrecords[i].location = location;
530 workrecords[i].arrived = (i == tid);
531 }
532 $seq_insert(&gteam->work, numEntries, &workrecords, 1);
533 }
534 return 0;
535 }
536}
537
Note: See TracBrowser for help on using the repository browser.