1 //******************************************************************************
2 // include files
3 //******************************************************************************
4 
5 #include "kmp.h"
6 #include "ompt-specific.h"
7 
8 #if KMP_OS_UNIX
9 #include <dlfcn.h>
10 #endif
11 
12 #if KMP_OS_WINDOWS
13 #define THREAD_LOCAL __declspec(thread)
14 #else
15 #define THREAD_LOCAL __thread
16 #endif
17 
18 #define OMPT_WEAK_ATTRIBUTE KMP_WEAK_ATTRIBUTE
19 
20 //******************************************************************************
21 // macros
22 //******************************************************************************
23 
24 #define LWT_FROM_TEAM(team) (team)->t.ompt_serialized_team_info
25 
26 #define OMPT_THREAD_ID_BITS 16
27 
28 //******************************************************************************
29 // private operations
30 //******************************************************************************
31 
32 //----------------------------------------------------------
33 // traverse the team and task hierarchy
34 // note: __ompt_get_teaminfo and __ompt_get_task_info_object
35 //       traverse the hierarchy similarly and need to be
36 //       kept consistent
37 //----------------------------------------------------------
38 
39 ompt_team_info_t *__ompt_get_teaminfo(int depth, int *size) {
40   kmp_info_t *thr = ompt_get_thread();
41 
42   if (thr) {
43     kmp_team *team = thr->th.th_team;
44     if (team == NULL)
45       return NULL;
46 
47     ompt_lw_taskteam_t *next_lwt = LWT_FROM_TEAM(team), *lwt = NULL;
48 
49     while (depth > 0) {
50       // next lightweight team (if any)
51       if (lwt)
52         lwt = lwt->parent;
53 
54       // next heavyweight team (if any) after
55       // lightweight teams are exhausted
56       if (!lwt && team) {
57         if (next_lwt) {
58           lwt = next_lwt;
59           next_lwt = NULL;
60         } else {
61           team = team->t.t_parent;
62           if (team) {
63             next_lwt = LWT_FROM_TEAM(team);
64           }
65         }
66       }
67 
68       depth--;
69     }
70 
71     if (lwt) {
72       // lightweight teams have one task
73       if (size)
74         *size = 1;
75 
76       // return team info for lightweight team
77       return &lwt->ompt_team_info;
78     } else if (team) {
79       // extract size from heavyweight team
80       if (size)
81         *size = team->t.t_nproc;
82 
83       // return team info for heavyweight team
84       return &team->t.ompt_team_info;
85     }
86   }
87 
88   return NULL;
89 }
90 
91 ompt_task_info_t *__ompt_get_task_info_object(int depth) {
92   ompt_task_info_t *info = NULL;
93   kmp_info_t *thr = ompt_get_thread();
94 
95   if (thr) {
96     kmp_taskdata_t *taskdata = thr->th.th_current_task;
97     ompt_lw_taskteam_t *lwt = NULL,
98                        *next_lwt = LWT_FROM_TEAM(taskdata->td_team);
99 
100     while (depth > 0) {
101       // next lightweight team (if any)
102       if (lwt)
103         lwt = lwt->parent;
104 
105       // next heavyweight team (if any) after
106       // lightweight teams are exhausted
107       if (!lwt && taskdata) {
108         if (next_lwt) {
109           lwt = next_lwt;
110           next_lwt = NULL;
111         } else {
112           taskdata = taskdata->td_parent;
113           if (taskdata) {
114             next_lwt = LWT_FROM_TEAM(taskdata->td_team);
115           }
116         }
117       }
118       depth--;
119     }
120 
121     if (lwt) {
122       info = &lwt->ompt_task_info;
123     } else if (taskdata) {
124       info = &taskdata->ompt_task_info;
125     }
126   }
127 
128   return info;
129 }
130 
131 ompt_task_info_t *__ompt_get_scheduling_taskinfo(int depth) {
132   ompt_task_info_t *info = NULL;
133   kmp_info_t *thr = ompt_get_thread();
134 
135   if (thr) {
136     kmp_taskdata_t *taskdata = thr->th.th_current_task;
137 
138     ompt_lw_taskteam_t *lwt = NULL,
139                        *next_lwt = LWT_FROM_TEAM(taskdata->td_team);
140 
141     while (depth > 0) {
142       // next lightweight team (if any)
143       if (lwt)
144         lwt = lwt->parent;
145 
146       // next heavyweight team (if any) after
147       // lightweight teams are exhausted
148       if (!lwt && taskdata) {
149         // first try scheduling parent (for explicit task scheduling)
150         if (taskdata->ompt_task_info.scheduling_parent) {
151           taskdata = taskdata->ompt_task_info.scheduling_parent;
152         } else if (next_lwt) {
153           lwt = next_lwt;
154           next_lwt = NULL;
155         } else {
156           // then go for implicit tasks
157           taskdata = taskdata->td_parent;
158           if (taskdata) {
159             next_lwt = LWT_FROM_TEAM(taskdata->td_team);
160           }
161         }
162       }
163       depth--;
164     }
165 
166     if (lwt) {
167       info = &lwt->ompt_task_info;
168     } else if (taskdata) {
169       info = &taskdata->ompt_task_info;
170     }
171   }
172 
173   return info;
174 }
175 
176 //******************************************************************************
177 // interface operations
178 //******************************************************************************
179 
180 //----------------------------------------------------------
181 // thread support
182 //----------------------------------------------------------
183 
184 ompt_data_t *__ompt_get_thread_data_internal() {
185   if (__kmp_get_gtid() >= 0) {
186     kmp_info_t *thread = ompt_get_thread();
187     if (thread == NULL)
188       return NULL;
189     return &(thread->th.ompt_thread_info.thread_data);
190   }
191   return NULL;
192 }
193 
194 //----------------------------------------------------------
195 // state support
196 //----------------------------------------------------------
197 
198 void __ompt_thread_assign_wait_id(void *variable) {
199   kmp_info_t *ti = ompt_get_thread();
200 
201   ti->th.ompt_thread_info.wait_id = (ompt_wait_id_t)variable;
202 }
203 
204 omp_state_t __ompt_get_state_internal(ompt_wait_id_t *ompt_wait_id) {
205   kmp_info_t *ti = ompt_get_thread();
206 
207   if (ti) {
208     if (ompt_wait_id)
209       *ompt_wait_id = ti->th.ompt_thread_info.wait_id;
210     return ti->th.ompt_thread_info.state;
211   }
212   return omp_state_undefined;
213 }
214 
215 //----------------------------------------------------------
216 // parallel region support
217 //----------------------------------------------------------
218 
219 int __ompt_get_parallel_info_internal(int ancestor_level,
220                                       ompt_data_t **parallel_data,
221                                       int *team_size) {
222   if (__kmp_get_gtid() >= 0) {
223     ompt_team_info_t *info;
224     if (team_size) {
225       info = __ompt_get_teaminfo(ancestor_level, team_size);
226     } else {
227       info = __ompt_get_teaminfo(ancestor_level, NULL);
228     }
229     if (parallel_data) {
230       *parallel_data = info ? &(info->parallel_data) : NULL;
231     }
232     return info ? 2 : 0;
233   } else {
234     return 0;
235   }
236 }
237 
238 //----------------------------------------------------------
239 // lightweight task team support
240 //----------------------------------------------------------
241 
242 void __ompt_lw_taskteam_init(ompt_lw_taskteam_t *lwt, kmp_info_t *thr, int gtid,
243                              ompt_data_t *ompt_pid, void *codeptr) {
244   // initialize parallel_data with input, return address to parallel_data on
245   // exit
246   lwt->ompt_team_info.parallel_data = *ompt_pid;
247   lwt->ompt_team_info.master_return_address = codeptr;
248   lwt->ompt_task_info.task_data.value = 0;
249   lwt->ompt_task_info.frame.enter_frame = NULL;
250   lwt->ompt_task_info.frame.exit_frame = NULL;
251   lwt->ompt_task_info.scheduling_parent = NULL;
252   lwt->ompt_task_info.deps = NULL;
253   lwt->ompt_task_info.ndeps = 0;
254   lwt->heap = 0;
255   lwt->parent = 0;
256 }
257 
258 void __ompt_lw_taskteam_link(ompt_lw_taskteam_t *lwt, kmp_info_t *thr,
259                              int on_heap) {
260   ompt_lw_taskteam_t *link_lwt = lwt;
261   if (thr->th.th_team->t.t_serialized >
262       1) { // we already have a team, so link the new team and swap values
263     if (on_heap) { // the lw_taskteam cannot stay on stack, allocate it on heap
264       link_lwt =
265           (ompt_lw_taskteam_t *)__kmp_allocate(sizeof(ompt_lw_taskteam_t));
266     }
267     link_lwt->heap = on_heap;
268 
269     // would be swap in the (on_stack) case.
270     ompt_team_info_t tmp_team = lwt->ompt_team_info;
271     link_lwt->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr);
272     *OMPT_CUR_TEAM_INFO(thr) = tmp_team;
273 
274     ompt_task_info_t tmp_task = lwt->ompt_task_info;
275     link_lwt->ompt_task_info = *OMPT_CUR_TASK_INFO(thr);
276     *OMPT_CUR_TASK_INFO(thr) = tmp_task;
277 
278     // link the taskteam into the list of taskteams:
279     ompt_lw_taskteam_t *my_parent =
280         thr->th.th_team->t.ompt_serialized_team_info;
281     link_lwt->parent = my_parent;
282     thr->th.th_team->t.ompt_serialized_team_info = link_lwt;
283   } else {
284     // this is the first serialized team, so we just store the values in the
285     // team and drop the taskteam-object
286     *OMPT_CUR_TEAM_INFO(thr) = lwt->ompt_team_info;
287     *OMPT_CUR_TASK_INFO(thr) = lwt->ompt_task_info;
288   }
289 }
290 
291 void __ompt_lw_taskteam_unlink(kmp_info_t *thr) {
292   ompt_lw_taskteam_t *lwtask = thr->th.th_team->t.ompt_serialized_team_info;
293   if (lwtask) {
294     thr->th.th_team->t.ompt_serialized_team_info = lwtask->parent;
295 
296     ompt_team_info_t tmp_team = lwtask->ompt_team_info;
297     lwtask->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr);
298     *OMPT_CUR_TEAM_INFO(thr) = tmp_team;
299 
300     ompt_task_info_t tmp_task = lwtask->ompt_task_info;
301     lwtask->ompt_task_info = *OMPT_CUR_TASK_INFO(thr);
302     *OMPT_CUR_TASK_INFO(thr) = tmp_task;
303 
304     if (lwtask->heap) {
305       __kmp_free(lwtask);
306       lwtask = NULL;
307     }
308   }
309   //    return lwtask;
310 }
311 
312 //----------------------------------------------------------
313 // task support
314 //----------------------------------------------------------
315 
316 int __ompt_get_task_info_internal(int ancestor_level, int *type,
317                                   ompt_data_t **task_data,
318                                   ompt_frame_t **task_frame,
319                                   ompt_data_t **parallel_data,
320                                   int *thread_num) {
321   if (__kmp_get_gtid() < 0)
322     return 0;
323 
324   if (ancestor_level < 0)
325     return 0;
326 
327   // copied from __ompt_get_scheduling_taskinfo
328   ompt_task_info_t *info = NULL;
329   ompt_team_info_t *team_info = NULL;
330   kmp_info_t *thr = ompt_get_thread();
331 
332   if (thr) {
333     kmp_taskdata_t *taskdata = thr->th.th_current_task;
334     if (taskdata == NULL)
335       return 0;
336     kmp_team *team = thr->th.th_team;
337     if (team == NULL)
338       return 0;
339     ompt_lw_taskteam_t *lwt = NULL,
340                        *next_lwt = LWT_FROM_TEAM(taskdata->td_team);
341 
342     while (ancestor_level > 0) {
343       // next lightweight team (if any)
344       if (lwt)
345         lwt = lwt->parent;
346 
347       // next heavyweight team (if any) after
348       // lightweight teams are exhausted
349       if (!lwt && taskdata) {
350         // first try scheduling parent (for explicit task scheduling)
351         if (taskdata->ompt_task_info.scheduling_parent) {
352           taskdata = taskdata->ompt_task_info.scheduling_parent;
353         } else if (next_lwt) {
354           lwt = next_lwt;
355           next_lwt = NULL;
356         } else {
357           // then go for implicit tasks
358           taskdata = taskdata->td_parent;
359           if (team == NULL)
360             return 0;
361           team = team->t.t_parent;
362           if (taskdata) {
363             next_lwt = LWT_FROM_TEAM(taskdata->td_team);
364           }
365         }
366       }
367       ancestor_level--;
368     }
369 
370     if (lwt) {
371       info = &lwt->ompt_task_info;
372       team_info = &lwt->ompt_team_info;
373       if (type) {
374         *type = ompt_task_implicit;
375       }
376     } else if (taskdata) {
377       info = &taskdata->ompt_task_info;
378       team_info = &team->t.ompt_team_info;
379       if (type) {
380         if (taskdata->td_parent) {
381           *type = (taskdata->td_flags.tasktype ? ompt_task_explicit
382                                                : ompt_task_implicit) |
383                   TASK_TYPE_DETAILS_FORMAT(taskdata);
384         } else {
385           *type = ompt_task_initial;
386         }
387       }
388     }
389     if (task_data) {
390       *task_data = info ? &info->task_data : NULL;
391     }
392     if (task_frame) {
393       // OpenMP spec asks for the scheduling task to be returned.
394       *task_frame = info ? &info->frame : NULL;
395     }
396     if (parallel_data) {
397       *parallel_data = team_info ? &(team_info->parallel_data) : NULL;
398     }
399     return info ? 2 : 0;
400   }
401   return 0;
402 }
403 
404 //----------------------------------------------------------
405 // team support
406 //----------------------------------------------------------
407 
408 void __ompt_team_assign_id(kmp_team_t *team, ompt_data_t ompt_pid) {
409   team->t.ompt_team_info.parallel_data = ompt_pid;
410 }
411 
412 //----------------------------------------------------------
413 // misc
414 //----------------------------------------------------------
415 
416 static uint64_t __ompt_get_unique_id_internal() {
417   static uint64_t thread = 1;
418   static THREAD_LOCAL uint64_t ID = 0;
419   if (ID == 0) {
420     uint64_t new_thread = KMP_TEST_THEN_INC64((kmp_int64 *)&thread);
421     ID = new_thread << (sizeof(uint64_t) * 8 - OMPT_THREAD_ID_BITS);
422   }
423   return ++ID;
424 }
425