source: CIVL/text/include/omp.cvl@ 8a50139

1.23 2.0 main test-branch
Last change on this file since 8a50139 was 9f139d7, checked in by Stephen Siegel <siegel@…>, 12 years ago

Improved printing methods to handle cases where certain fields are null (sources), though further analysis is needed to determine why they are allowed to be null.

Fixed bug in omp.cvl dealing with initialization of an empty sequence.

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

  • Property mode set to 100644
File size: 12.5 KB
Line 
1/* This header file defines standard types and provides
2 * function prototypes used in the OpenMP to CIVLC transformation.
3 */
4
5#ifdef __CIVLC_OMP__
6#else
7#define __CIVLC_OMP__
8
9#include<civlc.cvh>
10#include<pointer.cvh>
11#include<seq.cvh>
12#include<concurrency.cvh>
13#include<domain.cvh>
14
15/* *********************** Types *********************** */
16
17typedef enum __OMP_var_status_{
18 EMPTY, // local is empty
19 FULL, // local is occupied, no writes to it have been made
20 MODIFIED // local is occupied, writes have been made to it
21} $omp_var_status;
22
23typedef enum __OMP_worksharing_kind {
24 LOOP,
25 BARRIER,
26 SECTIONS,
27 SINGLE
28} $omp_worksharing_kind;
29
30/*
31typedef enum __OMP_loop_policy_{
32 ROUND_ROBIN, // partition by round robin order
33 RANDOM, // a random partition
34 ALL // all possible partitions
35} $omp_loop_policy;*/
36
37/* global shared object, containing a reference to a shared variable.
38 * A handle type.
39 */
40typedef struct OMP_gshared {
41 _Bool init[]; // which threads have joined
42 void * original; // pointer to original variable
43} * $omp_gshared;
44
45/* local view of a shared object, belonging to a single
46 * thread, with reference to the global object, and
47 * a local copy and a status of the shared object.
48 * The type of the status variable is obtained from
49 * the type of the original variable by replacing
50 * all leaf nodes in the type tree with "int".
51 * A handle type.
52 */
53typedef struct OMP_shared {
54 $omp_gshared gshared;
55 // The thread id
56 int tid;
57 // Pointer to the local copy of the shared variable.
58 // This provides the thread's "private view" of the variable.
59 void * local;
60 // Pointer to the local status variable
61 void * status;
62} * $omp_shared;
63
64/* the worksharing information that a thread needs for executing
65 * a worksharing region. It contains the kind of the worksharing
66 * region, the location of the region, the status of the region
67 * and the subdomain (iterations/sections/task assigned to the thread).
68 */
69typedef struct OMP_work_record {
70 int kind; // loop, barrier, sections, or single
71 int location; // location in model of construct
72 _Bool arrived; // has this thread arrived yet?
73 //$domain loop_domain; // full loop domain; null if not loop
74 $domain subdomain; // tasks this thread must do
75 // reduction operation?
76} $omp_work_record;
77
78/* global team object, represents a team of threads executing
79 * in a parallel region. A handle type. This is where all the
80 * state needed to correctly execute a parallel region will
81 * be stored. This includes a global barrier, and a worksharing
82 * queue for every thread.
83 */
84typedef struct OMP_gteam {
85 /* scope in which data is allocated in heap */
86 $scope scope;
87 /* number of threads in team */
88 int nthreads;
89 /* which threads have joined this gteam */
90 _Bool init[];
91 /* work queues. Length nthreads. For each thread,
92 * a FIFO queue of work records */
93 $omp_work_record work[][];
94 /* the shared object data. */
95 $omp_gshared shared[];
96 $gbarrier gbarrier;
97} * $omp_gteam;
98
99/*
100 * local object belonging to a single thread and referencing the global team object.
101 * A handle type. It also includes the local views of all shared data and a local barrier.
102 */
103typedef struct OMP_team {
104 $omp_gteam gteam;
105 $scope scope;
106 int tid;
107 $omp_shared shared[];
108 $barrier barrier;
109} * $omp_team;
110
111
112
113/* *********************** Functions *********************** */
114
115/* creates new global team object, allocating object in heap
116 * in specified scope. Number of threads that will be in the
117 * team is nthreads.
118 */
119$omp_gteam $omp_gteam_create($scope scope, int nthreads) {
120 $omp_work_record empty[];
121 $omp_gteam result = ($omp_gteam)$malloc(scope, sizeof(struct OMP_gteam));
122 _Bool f = $false;
123
124 $seq_init(&empty, 0, NULL);
125 result->scope = scope;
126 result->nthreads = nthreads;
127 $seq_init(&result->init, nthreads, &f);
128 $seq_init(&result->work, nthreads, &empty);
129 $seq_init(&result->shared, 0, NULL);
130 result->gbarrier = $gbarrier_create(scope, nthreads);
131 return result;
132}
133
134/* destroys the global team object. All shared objects
135 * associated to the team must have been destroyed before
136 * calling this function.
137 */
138void $omp_gteam_destroy($omp_gteam gteam) {
139 int nthreads = gteam->nthreads;
140
141 //$assert $seq_length(&gteam->shared)==0 :
142 //"shared objects must be deallocated before freeing gteam";
143 for (int i=0; i<nthreads; i++) {
144 int numRecords = $seq_length(&gteam->work[i]);
145
146 $assert numRecords == 0 :
147 "Thread %d still has %d queued worksharing events",
148 i, numRecords;
149 }
150 $free(gteam->gbarrier);
151 $free(gteam);
152}
153
154
155/* creates new local team object for a specific thread. */
156$omp_team $omp_team_create($scope scope, $omp_gteam gteam, int tid) {
157 $omp_team result = ($omp_team)$malloc(scope, sizeof(struct OMP_team));
158
159 $assert !gteam->init[tid] :
160 "Thread %d has already joined gteam",
161 tid;
162 gteam->init[tid] = $true;
163 result->gteam = gteam;
164 result->scope = scope;
165 result->tid = tid;
166 $seq_init(result->shared, 0, NULL);
167 result->barrier = $barrier_create(scope, gteam->gbarrier, tid);
168 return result;
169}
170
171/* destroys the local team object */
172void $omp_team_destroy($omp_team team) {
173 int numShared = $seq_length(team->shared);
174
175 for(int i = 0; i < numShared; i++){
176 $free(team->shared[i]);
177 }
178 $free(team->barrier);
179 $free(team);
180}
181
182/* creates new global shared object, associated to the given
183 * global team. A pointer to the shared variable that this
184 * object corresponds to is given.
185 */
186$omp_gshared $omp_gshared_create($omp_gteam gteam,
187 void *original) {
188 $omp_gshared result =
189 ($omp_gshared)$malloc(gteam->scope, sizeof(struct OMP_gshared));
190 _Bool f = $false;
191
192 $seq_init(result->init, gteam->nthreads, &f);
193 result->original = original;
194 //result->status = status;
195 return result;
196}
197
198/* destroys the global shared object, copying the content
199 * to the original variable.
200 */
201void $omp_gshared_destroy($omp_gshared gshared) {
202 $free(gshared);
203}
204
205/* creates a local shared object, returning handle to it.
206 * The local copy of the shared object is initialized
207 * by copying the values from the original variable referenced to
208 * by the gshared object. The created shared object is appended
209 * to the shared queue of the $omp_team object. */
210$omp_shared $omp_shared_create($omp_team team,
211 $omp_gshared gshared, void *local, void *status) {
212 $omp_shared result =
213 ($omp_shared)$malloc(team->scope, sizeof(struct OMP_shared));
214
215 $assert !gshared->init[team->tid] :
216 "Thread %d has already created its local copy for %p.\n",
217 team->tid, gshared;
218 result->gshared = gshared;
219 result->tid = team->tid;
220 result->local = local;
221 result->status = status;
222 $seq_append(&team->shared, &result, 1);
223 return result;
224}
225
226/* destroys the local shared object */
227void $omp_shared_destroy($omp_shared shared) {
228 $free(shared);
229}
230
231/* called by a thread to read a shared object.
232 * ref is a pointer into the local copy of the shared variable.
233 * The result of the read is stored in the
234 * memory unit pointed to by result.
235 * assumes ref is a pointer to a scalar.
236 */
237void $omp_read($omp_shared shared, void *result, void *ref) {
238 int tid = shared->tid;
239 int *status_ref = (int*)$translate_ptr(ref, shared->status);
240 int status = *status_ref;
241
242 if(status == EMPTY){
243 void *local = $translate_ptr(ref, shared->local);
244
245 $copy(local, ref); // copy shared to local
246 *status_ref = FULL; // set status to FULL
247 }
248 // read local
249 $copy(result, ref);
250}
251
252/* called by a thread to write to the shared object.
253 * ref is a pointer into the local copy of the shared variable.
254 * The value to be written is taken
255 * from the memory unit pointed to by value.
256 * assumes ref is a pointer to a scalar.
257 */
258void $omp_write($omp_shared shared, void *ref, void *value) {
259 int tid = shared->tid;
260 int *status_ref = (int*)$translate_ptr(ref, shared->status);
261
262 $copy(ref, value);
263 *status_ref = MODIFIED;
264}
265
266/* applies the associative operator
267 * specified by op to the local copy and the corresponding shared copy,
268 * and writes the result back to the shared copy.
269 * This happens in one atomic step. Example: you can
270 * use this to add some value to a shared variable,
271 * using CIVL_SUM for op.
272 * assumes local is a pointer to a scalar.
273 */
274void $omp_apply_assoc($omp_shared shared,
275 $operation op,
276 void *local){
277 $atomic{
278 void *shared_ref = $translate_ptr(local, shared->gshared->original);
279
280 $apply(shared_ref, op, local, shared_ref);
281 }
282}
283
284/* performs an OpenMP flush operation on the shared object
285 */
286void $omp_flush($omp_shared shared, void *ref) {
287 // need to drill down into all leaf nodes of the object
288 // being flushed...
289 // also, it should be ok to flush a memory unit if you are not
290 // the owner but you also have no reads or writes to that variable
291
292 $omp_gshared gshared = shared->gshared;
293 int tid = shared->tid;
294 void *refs[];
295 int numRefs;
296
297 // get all leaf node pointers
298 $leaf_node_ptrs(&refs, ref);
299 numRefs = $seq_length(&refs);
300 for(int i = 0; i < numRefs; i++){
301 void *leaf = refs[i];
302 int *leaf_status = (int *)$translate_ptr(leaf, shared->status);
303 void *leaf_local = (int *)$translate_ptr(leaf, shared->local);
304 void *leaf_shared = (int *)$translate_ptr(leaf, gshared->original);
305
306 switch(*leaf_status){
307 case EMPTY:
308 break;
309 case MODIFIED:
310 $copy(leaf_shared, leaf_local);
311 case FULL:
312 *leaf_status = EMPTY;
313 $set_default(leaf_local);
314 break;
315 }
316 }
317}
318
319/* performs an OpenMP flush operation on all shared
320 * objects. This is the default in OpenMP if no argument
321 * is specified for a flush construct.
322 */
323void $omp_flush_all($omp_team team) {
324 int num_shared = $seq_length(team->shared);
325
326 for (int i=0; i<num_shared; i++) {
327 $omp_shared shared = team->shared[i];
328
329 $omp_flush(shared, shared->local);
330 }
331}
332
333/* performs a barrier only. Note however that usually
334 * (always?) a barrier is accompanied by a flush-all,
335 * so $omp_barrier_and_flush should be used instead.
336 */
337void $omp_barrier($omp_team team){
338 $barrier_call(team->barrier);
339}
340
341/* combines a barrier and a flush on all shared objects
342 * owned by the team. Implicit in many OpenMP worksharing
343 * constructs.
344 */
345void $omp_barrier_and_flush($omp_team team) {
346 // this is a collective operation: all members of team call
347 $barrier_call(team->barrier);
348 $omp_flush_all(team);
349 $barrier_call(team->barrier);
350}
351
352// To be continued: needs a way to specify non-rectangular
353// domains.
354/* called by a thread when it reaches an omp for loop,
355 * this function returns the subset of the loop domain
356 * specifying the iterations that this thread will execute,
357 * according to the given policy.
358 * The dimension of the domain returned equals the
359 * dimension of the given domain loop_dom.
360 */
361$domain $omp_arrive_loop($omp_team team, $domain loop_dom,
362 $DecompositionStrategy strategy){
363 $omp_gteam gteam = team->gteam;
364 int tid = team->tid;
365 int numWorkrecords, nthreads = gteam->nthreads;
366 $domain_decomposition decomposition;
367 $domain result;
368
369 $assert gteam->init[tid] : "The current thread %d has not joined the gteam!", tid;
370 numWorkrecords = $seq_length(&gteam->work[tid]);
371 for(int i = 0; i < numWorkrecords; i++){
372 $omp_work_record workrecord = gteam->work[tid][i];
373
374 if(!workrecord.arrived)
375 return workrecord.subdomain;
376 }
377 decomposition = $domain_partition(loop_dom, strategy, nthreads);
378 for(int i = 0; i< nthreads; i++){
379 $omp_work_record workrecord;
380
381 workrecord.kind = LOOP;
382 workrecord.location = 0; // TODO: how to specify the location?
383 if(i != tid){
384 workrecord.arrived = $false;
385 }else{
386 workrecord.arrived = $true;
387 result = decomposition.subdomains[i];
388 }
389 workrecord.subdomain = decomposition.subdomains[i];
390 $seq_append(&gteam->work[i], &workrecord, 1);
391 }
392 return result;
393}
394
395/* called by a thread when it reaches an omp sections
396 * construct, this function returns the subset of the
397 * integers 0..numSections-1 specifying the indexes of
398 * the sections that this thread will execute. The sections
399 * are numbered from 0 in increasing order.
400 */
401$domain(1) $omp_arrive_sections($omp_team team, int numSections){
402 int low = team->tid, high = numSections - 1, step = team->gteam->nthreads;
403 $range range = low .. high # step;
404 $domain(1) dom = ($domain(1)) {range};
405
406 return dom;
407}
408
409/* called by a thread when it reaches on omp single
410 * construct, returns the thread ID of the thread that
411 * will execute the single construct.
412 */
413int $omp_arrive_single($omp_team team){
414 return 0;
415}
416
417#endif
Note: See TracBrowser for help on using the repository browser.