source: CIVL/text/include/omp.cvl@ c2a3f74

1.23 2.0 main test-branch
Last change on this file since c2a3f74 was 36eabcc, checked in by Manchun Zheng <zmanchun@…>, 12 years ago

minor correction of duplicated enumerator: FULL.

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

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