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

1.23 2.0 main test-branch
Last change on this file since a9d2603 was 43c7a35, checked in by Ziqing Luo <ziqing@…>, 12 years ago

fixed the "$seq_init()" little mistake

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@1547 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.