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

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

added $assert statement and implemented its semantics; updated examples/libraries according to the new syntax of $assert.

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

  • Property mode set to 100644
File size: 11.3 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
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
22typedef enum __OMP_loop_policy_{
23 ROUND_ROBIN, // partition by round robin order
24 RANDOM, // a random partition
25 ALL // all possible partitions
26} $omp_loop_policy;
27
28/* global shared object, containing a reference to a shared variable.
29 * A handle type.
30 */
31typedef struct OMP_gshared {
32 _Bool init[]; // which threads have joined
33 void * original; // pointer to original variable
34} * $omp_gshared;
35
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.
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
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 */
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?
64 //$domain loop_domain; // full loop domain; null if not loop
65 $domain subdomain; // tasks this thread must do
66 // reduction operation?
67} $omp_work_record;
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
72 * be stored. This includes a global barrier, and a worksharing
73 * queue for every thread.
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 */
84 $omp_work_record work[][];
85 /* the shared object data. */
86 $omp_gshared shared[];
87 $gbarrier gbarrier;
88} * $omp_gteam;
89
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 */
94typedef struct OMP_team {
95 $omp_gteam gteam;
96 $scope scope;
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) {
111 $omp_work_record empty[0];
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;
154 result->scope = scope;
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
174 * object corresponds to is given.
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));
180 _Bool f = $false;
181
182 $seq_init(result->init, gteam->nthreads, &f);
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
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. */
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
205 $assert !gshared->init[team->tid] :
206 "Thread %d has already created its local copy for %p.\n",
207 team->tid, gshared;
208 result->gshared = gshared;
209 result->tid = team->tid;
210 result->local = local;
211 result->status = status;
212 $seq_append(&team->shared, &result, 1);
213 return result;
214}
215
216/* destroys the local shared object */
217void $omp_shared_destroy($omp_shared shared) {
218 $free(shared);
219}
220
221/* called by a thread to read a shared object.
222 * ref is a pointer into the local copy of the shared variable.
223 * The result of the read is stored in the
224 * memory unit pointed to by result.
225 * assumes ref is a pointer to a scalar.
226 */
227void $omp_read($omp_shared shared, void *result, void *ref) {
228 int tid = shared->tid;
229 int *status_ref = (int*)$translate_ptr(ref, shared->status);
230 int status = *status_ref;
231
232 if(status == EMPTY){
233 void *local = $translate_ptr(ref, shared->local);
234
235 $copy(local, ref); // copy shared to local
236 *status_ref = FULL; // set status to FULL
237 }
238 // read local
239 $copy(result, ref);
240}
241
242/* called by a thread to write to the shared object.
243 * ref is a pointer into the local copy of the shared variable.
244 * The value to be written is taken
245 * from the memory unit pointed to by value.
246 * assumes ref is a pointer to a scalar.
247 */
248void $omp_write($omp_shared shared, void *ref, void *value) {
249 int tid = shared->tid;
250 int *status_ref = (int*)$translate_ptr(ref, shared->status);
251
252 $copy(ref, value);
253 *status_ref = MODIFIED;
254}
255
256/* applies the associative operator
257 * specified by op to the local copy and the corresponding shared copy,
258 * and writes the result back to the shared copy.
259 * This happens in one atomic step. Example: you can
260 * use this to add some value to a shared variable,
261 * using CIVL_SUM for op.
262 * assumes local is a pointer to a scalar.
263 */
264void $omp_apply_assoc($omp_shared shared,
265 $operation op,
266 void *local){
267 $atomic{
268 void *shared_ref = $translate_ptr(local, shared->gshared->original);
269
270 $apply(shared_ref, op, local, shared_ref);
271 }
272}
273
274/* performs an OpenMP flush operation on the shared object
275 */
276void $omp_flush($omp_shared shared, void *ref) {
277 // need to drill down into all leaf nodes of the object
278 // being flushed...
279 // also, it should be ok to flush a memory unit if you are not
280 // the owner but you also have no reads or writes to that variable
281
282 $omp_gshared gshared = shared->gshared;
283 int tid = shared->tid;
284 void *refs[];
285 int numRefs;
286
287 // get all leaf node pointers
288 $leaf_node_ptrs(&refs, ref);
289 numRefs = $seq_length(&refs);
290 for(int i = 0; i < numRefs; i++){
291 void *leaf = refs[i];
292 int *leaf_status = (int *)$translate_ptr(leaf, shared->status);
293 void *leaf_local = (int *)$translate_ptr(leaf, shared->local);
294 void *leaf_shared = (int *)$translate_ptr(leaf, gshared->original);
295
296 switch(*leaf_status){
297 case EMPTY:
298 break;
299 case MODIFIED:
300 $copy(leaf_shared, leaf_local);
301 case FULL:
302 *leaf_status = EMPTY;
303 $set_default(leaf_local);
304 break;
305 }
306 }
307}
308
309/* performs an OpenMP flush operation on all shared
310 * objects. This is the default in OpenMP if no argument
311 * is specified for a flush construct.
312 */
313void $omp_flush_all($omp_team team) {
314 int num_shared = $seq_length(team->shared);
315
316 for (int i=0; i<num_shared; i++) {
317 $omp_shared shared = team->shared[i];
318
319 $omp_flush(shared, shared->local);
320 }
321}
322
323/* performs a barrier only. Note however that usually
324 * (always?) a barrier is accompanied by a flush-all,
325 * so $omp_barrier_and_flush should be used instead.
326 */
327void $omp_barrier($omp_team team){
328 $barrier_call(team->barrier);
329}
330
331/* combines a barrier and a flush on all shared objects
332 * owned by the team. Implicit in many OpenMP worksharing
333 * constructs.
334 */
335void $omp_barrier_and_flush($omp_team team) {
336 // this is a collective operation: all members of team call
337 $barrier_call(team->barrier);
338 $omp_flush_all(team);
339 $barrier_call(team->barrier);
340}
341
342// To be continued: needs a way to specify non-rectangular
343// domains.
344/* called by a thread when it reaches an omp for loop,
345 * this function returns the subset of the loop domain
346 * specifying the iterations that this thread will execute,
347 * according to the given policy.
348 * The dimension of the domain returned equals the
349 * dimension of the given domain loop_dom.
350 */
351$domain $omp_arrive_loop($omp_team, $domain loop_dom, int policy);
352
353/* called by a thread when it reaches an omp sections
354 * construct, this function returns the subset of the
355 * integers 0..numSections-1 specifying the indexes of
356 * the sections that this thread will execute. The sections
357 * are numbered from 0 in increasing order.
358 */
359$domain(1) $omp_arrive_sections($omp_team team, int numSections){
360 int low = team->tid, high = numSections - 1, step = team->gteam->nthreads;
361 $range range = low .. high # step;
362 $domain(1) dom = ($domain(1)) {range};
363
364 return dom;
365}
366
367/* called by a thread when it reaches on omp single
368 * construct, returns the thread ID of the thread that
369 * will execute the single construct.
370 */
371int $omp_arrive_single($omp_team team){
372 return 0;
373}
374
375#endif
Note: See TracBrowser for help on using the repository browser.