source: CIVL/text/include/civlc-omp.cvl@ 85b7e48

1.23 2.0 main test-branch
Last change on this file since 85b7e48 was 06518e3, checked in by Manchun Zheng <zmanchun@…>, 12 years ago

added the checking of changes of loop domain for OpenMP support functions.

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

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