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

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

reverted the OpenMP tests to be un-ignored; implemented arrive_loop for omp.cvl.

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

  • Property mode set to 100644
File size: 12.4 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[0];
121 $omp_gteam result = ($omp_gteam)$malloc(scope, sizeof(struct OMP_gteam));
122 _Bool f = $false;
123
124 result->scope = scope;
125 result->nthreads = nthreads;
126 $seq_init(&result->init, nthreads, &f);
127 $seq_init(&result->work, nthreads, &empty);
128 $seq_init(&result->shared, 0, NULL);
129 result->gbarrier = $gbarrier_create(scope, nthreads);
130 return result;
131}
132
133/* destroys the global team object. All shared objects
134 * associated to the team must have been destroyed before
135 * calling this function.
136 */
137void $omp_gteam_destroy($omp_gteam gteam) {
138 int nthreads = gteam->nthreads;
139
140 //$assert $seq_length(&gteam->shared)==0 :
141 //"shared objects must be deallocated before freeing gteam";
142 for (int i=0; i<nthreads; i++) {
143 int numRecords = $seq_length(&gteam->work[i]);
144
145 $assert numRecords == 0 :
146 "Thread %d still has %d queued worksharing events",
147 i, numRecords;
148 }
149 $free(gteam->gbarrier);
150 $free(gteam);
151}
152
153
154/* creates new local team object for a specific thread. */
155$omp_team $omp_team_create($scope scope, $omp_gteam gteam, int tid) {
156 $omp_team result = ($omp_team)$malloc(scope, sizeof(struct OMP_team));
157
158 $assert !gteam->init[tid] :
159 "Thread %d has already joined gteam",
160 tid;
161 gteam->init[tid] = $true;
162 result->gteam = gteam;
163 result->scope = scope;
164 result->tid = tid;
165 $seq_init(result->shared, 0, NULL);
166 result->barrier = $barrier_create(scope, gteam->gbarrier, tid);
167 return result;
168}
169
170/* destroys the local team object */
171void $omp_team_destroy($omp_team team) {
172 int numShared = $seq_length(team->shared);
173
174 for(int i = 0; i < numShared; i++){
175 $free(team->shared[i]);
176 }
177 $free(team->barrier);
178 $free(team);
179}
180
181/* creates new global shared object, associated to the given
182 * global team. A pointer to the shared variable that this
183 * object corresponds to is given.
184 */
185$omp_gshared $omp_gshared_create($omp_gteam gteam,
186 void *original) {
187 $omp_gshared result =
188 ($omp_gshared)$malloc(gteam->scope, sizeof(struct OMP_gshared));
189 _Bool f = $false;
190
191 $seq_init(result->init, gteam->nthreads, &f);
192 result->original = original;
193 //result->status = status;
194 return result;
195}
196
197/* destroys the global shared object, copying the content
198 * to the original variable.
199 */
200void $omp_gshared_destroy($omp_gshared gshared) {
201 $free(gshared);
202}
203
204/* creates a local shared object, returning handle to it.
205 * The local copy of the shared object is initialized
206 * by copying the values from the original variable referenced to
207 * by the gshared object. The created shared object is appended
208 * to the shared queue of the $omp_team object. */
209$omp_shared $omp_shared_create($omp_team team,
210 $omp_gshared gshared, void *local, void *status) {
211 $omp_shared result =
212 ($omp_shared)$malloc(team->scope, sizeof(struct OMP_shared));
213
214 $assert !gshared->init[team->tid] :
215 "Thread %d has already created its local copy for %p.\n",
216 team->tid, gshared;
217 result->gshared = gshared;
218 result->tid = team->tid;
219 result->local = local;
220 result->status = status;
221 $seq_append(&team->shared, &result, 1);
222 return result;
223}
224
225/* destroys the local shared object */
226void $omp_shared_destroy($omp_shared shared) {
227 $free(shared);
228}
229
230/* called by a thread to read a shared object.
231 * ref is a pointer into the local copy of the shared variable.
232 * The result of the read is stored in the
233 * memory unit pointed to by result.
234 * assumes ref is a pointer to a scalar.
235 */
236void $omp_read($omp_shared shared, void *result, void *ref) {
237 int tid = shared->tid;
238 int *status_ref = (int*)$translate_ptr(ref, shared->status);
239 int status = *status_ref;
240
241 if(status == EMPTY){
242 void *local = $translate_ptr(ref, shared->local);
243
244 $copy(local, ref); // copy shared to local
245 *status_ref = FULL; // set status to FULL
246 }
247 // read local
248 $copy(result, ref);
249}
250
251/* called by a thread to write to the shared object.
252 * ref is a pointer into the local copy of the shared variable.
253 * The value to be written is taken
254 * from the memory unit pointed to by value.
255 * assumes ref is a pointer to a scalar.
256 */
257void $omp_write($omp_shared shared, void *ref, void *value) {
258 int tid = shared->tid;
259 int *status_ref = (int*)$translate_ptr(ref, shared->status);
260
261 $copy(ref, value);
262 *status_ref = MODIFIED;
263}
264
265/* applies the associative operator
266 * specified by op to the local copy and the corresponding shared copy,
267 * and writes the result back to the shared copy.
268 * This happens in one atomic step. Example: you can
269 * use this to add some value to a shared variable,
270 * using CIVL_SUM for op.
271 * assumes local is a pointer to a scalar.
272 */
273void $omp_apply_assoc($omp_shared shared,
274 $operation op,
275 void *local){
276 $atomic{
277 void *shared_ref = $translate_ptr(local, shared->gshared->original);
278
279 $apply(shared_ref, op, local, shared_ref);
280 }
281}
282
283/* performs an OpenMP flush operation on the shared object
284 */
285void $omp_flush($omp_shared shared, void *ref) {
286 // need to drill down into all leaf nodes of the object
287 // being flushed...
288 // also, it should be ok to flush a memory unit if you are not
289 // the owner but you also have no reads or writes to that variable
290
291 $omp_gshared gshared = shared->gshared;
292 int tid = shared->tid;
293 void *refs[];
294 int numRefs;
295
296 // get all leaf node pointers
297 $leaf_node_ptrs(&refs, ref);
298 numRefs = $seq_length(&refs);
299 for(int i = 0; i < numRefs; i++){
300 void *leaf = refs[i];
301 int *leaf_status = (int *)$translate_ptr(leaf, shared->status);
302 void *leaf_local = (int *)$translate_ptr(leaf, shared->local);
303 void *leaf_shared = (int *)$translate_ptr(leaf, gshared->original);
304
305 switch(*leaf_status){
306 case EMPTY:
307 break;
308 case MODIFIED:
309 $copy(leaf_shared, leaf_local);
310 case FULL:
311 *leaf_status = EMPTY;
312 $set_default(leaf_local);
313 break;
314 }
315 }
316}
317
318/* performs an OpenMP flush operation on all shared
319 * objects. This is the default in OpenMP if no argument
320 * is specified for a flush construct.
321 */
322void $omp_flush_all($omp_team team) {
323 int num_shared = $seq_length(team->shared);
324
325 for (int i=0; i<num_shared; i++) {
326 $omp_shared shared = team->shared[i];
327
328 $omp_flush(shared, shared->local);
329 }
330}
331
332/* performs a barrier only. Note however that usually
333 * (always?) a barrier is accompanied by a flush-all,
334 * so $omp_barrier_and_flush should be used instead.
335 */
336void $omp_barrier($omp_team team){
337 $barrier_call(team->barrier);
338}
339
340/* combines a barrier and a flush on all shared objects
341 * owned by the team. Implicit in many OpenMP worksharing
342 * constructs.
343 */
344void $omp_barrier_and_flush($omp_team team) {
345 // this is a collective operation: all members of team call
346 $barrier_call(team->barrier);
347 $omp_flush_all(team);
348 $barrier_call(team->barrier);
349}
350
351// To be continued: needs a way to specify non-rectangular
352// domains.
353/* called by a thread when it reaches an omp for loop,
354 * this function returns the subset of the loop domain
355 * specifying the iterations that this thread will execute,
356 * according to the given policy.
357 * The dimension of the domain returned equals the
358 * dimension of the given domain loop_dom.
359 */
360$domain $omp_arrive_loop($omp_team team, $domain loop_dom,
361 $DecompositionStrategy strategy){
362 $omp_gteam gteam = team->gteam;
363 int tid = team->tid;
364 int numWorkrecords, nthreads = gteam->nthreads;
365 $domain_decomposition decomposition;
366 $domain result;
367
368 $assert gteam->init[tid] : "The current thread %d has not joined the gteam!", tid;
369 numWorkrecords = $seq_length(&gteam->work[tid]);
370 for(int i = 0; i < numWorkrecords; i++){
371 $omp_work_record workrecord = gteam->work[tid][i];
372
373 if(!workrecord.arrived)
374 return workrecord.subdomain;
375 }
376 decomposition = $domain_partition(loop_dom, strategy, nthreads);
377 for(int i = 0; i< nthreads; i++){
378 $omp_work_record workrecord;
379
380 workrecord.kind = LOOP;
381 workrecord.location = 0; // TODO: how to specify the location?
382 if(i != tid){
383 workrecord.arrived = $false;
384 }else{
385 workrecord.arrived = $true;
386 result = decomposition.subdomains[i];
387 }
388 workrecord.subdomain = decomposition.subdomains[i];
389 $seq_append(&gteam->work[i], &workrecord, 1);
390 }
391 return result;
392}
393
394/* called by a thread when it reaches an omp sections
395 * construct, this function returns the subset of the
396 * integers 0..numSections-1 specifying the indexes of
397 * the sections that this thread will execute. The sections
398 * are numbered from 0 in increasing order.
399 */
400$domain(1) $omp_arrive_sections($omp_team team, int numSections){
401 int low = team->tid, high = numSections - 1, step = team->gteam->nthreads;
402 $range range = low .. high # step;
403 $domain(1) dom = ($domain(1)) {range};
404
405 return dom;
406}
407
408/* called by a thread when it reaches on omp single
409 * construct, returns the thread ID of the thread that
410 * will execute the single construct.
411 */
412int $omp_arrive_single($omp_team team){
413 return 0;
414}
415
416#endif
Note: See TracBrowser for help on using the repository browser.