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   ompt_team_info_t *info;
223   if (team_size) {
224     info = __ompt_get_teaminfo(ancestor_level, team_size);
225   } else {
226     info = __ompt_get_teaminfo(ancestor_level, NULL);
227   }
228   if (parallel_data) {
229     *parallel_data = info ? &(info->parallel_data) : NULL;
230   }
231   return info ? 2 : 0;
232 }
233 
234 //----------------------------------------------------------
235 // lightweight task team support
236 //----------------------------------------------------------
237 
238 void __ompt_lw_taskteam_init(ompt_lw_taskteam_t *lwt, kmp_info_t *thr, int gtid,
239                              ompt_data_t *ompt_pid, void *codeptr) {
240   // initialize parallel_data with input, return address to parallel_data on
241   // exit
242   lwt->ompt_team_info.parallel_data = *ompt_pid;
243   lwt->ompt_team_info.master_return_address = codeptr;
244   lwt->ompt_task_info.task_data.value = 0;
245   lwt->ompt_task_info.frame.enter_frame = NULL;
246   lwt->ompt_task_info.frame.exit_frame = NULL;
247   lwt->ompt_task_info.scheduling_parent = NULL;
248   lwt->ompt_task_info.deps = NULL;
249   lwt->ompt_task_info.ndeps = 0;
250   lwt->heap = 0;
251   lwt->parent = 0;
252 }
253 
254 void __ompt_lw_taskteam_link(ompt_lw_taskteam_t *lwt, kmp_info_t *thr,
255                              int on_heap) {
256   ompt_lw_taskteam_t *link_lwt = lwt;
257   if (thr->th.th_team->t.t_serialized >
258       1) { // we already have a team, so link the new team and swap values
259     if (on_heap) { // the lw_taskteam cannot stay on stack, allocate it on heap
260       link_lwt =
261           (ompt_lw_taskteam_t *)__kmp_allocate(sizeof(ompt_lw_taskteam_t));
262     }
263     link_lwt->heap = on_heap;
264 
265     // would be swap in the (on_stack) case.
266     ompt_team_info_t tmp_team = lwt->ompt_team_info;
267     link_lwt->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr);
268     *OMPT_CUR_TEAM_INFO(thr) = tmp_team;
269 
270     ompt_task_info_t tmp_task = lwt->ompt_task_info;
271     link_lwt->ompt_task_info = *OMPT_CUR_TASK_INFO(thr);
272     *OMPT_CUR_TASK_INFO(thr) = tmp_task;
273 
274     // link the taskteam into the list of taskteams:
275     ompt_lw_taskteam_t *my_parent =
276         thr->th.th_team->t.ompt_serialized_team_info;
277     link_lwt->parent = my_parent;
278     thr->th.th_team->t.ompt_serialized_team_info = link_lwt;
279   } else {
280     // this is the first serialized team, so we just store the values in the
281     // team and drop the taskteam-object
282     *OMPT_CUR_TEAM_INFO(thr) = lwt->ompt_team_info;
283     *OMPT_CUR_TASK_INFO(thr) = lwt->ompt_task_info;
284   }
285 }
286 
287 void __ompt_lw_taskteam_unlink(kmp_info_t *thr) {
288   ompt_lw_taskteam_t *lwtask = thr->th.th_team->t.ompt_serialized_team_info;
289   if (lwtask) {
290     thr->th.th_team->t.ompt_serialized_team_info = lwtask->parent;
291 
292     ompt_team_info_t tmp_team = lwtask->ompt_team_info;
293     lwtask->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr);
294     *OMPT_CUR_TEAM_INFO(thr) = tmp_team;
295 
296     ompt_task_info_t tmp_task = lwtask->ompt_task_info;
297     lwtask->ompt_task_info = *OMPT_CUR_TASK_INFO(thr);
298     *OMPT_CUR_TASK_INFO(thr) = tmp_task;
299 
300     if (lwtask->heap) {
301       __kmp_free(lwtask);
302       lwtask = NULL;
303     }
304   }
305   //    return lwtask;
306 }
307 
308 //----------------------------------------------------------
309 // task support
310 //----------------------------------------------------------
311 
312 int __ompt_get_task_info_internal(int ancestor_level, int *type,
313                                   ompt_data_t **task_data,
314                                   ompt_frame_t **task_frame,
315                                   ompt_data_t **parallel_data,
316                                   int *thread_num) {
317   if (ancestor_level < 0)
318     return 0;
319 
320   // copied from __ompt_get_scheduling_taskinfo
321   ompt_task_info_t *info = NULL;
322   ompt_team_info_t *team_info = NULL;
323   kmp_info_t *thr = ompt_get_thread();
324 
325   if (thr) {
326     kmp_taskdata_t *taskdata = thr->th.th_current_task;
327     if (taskdata == NULL)
328       return 0;
329     kmp_team *team = thr->th.th_team;
330     if (team == NULL)
331       return 0;
332     ompt_lw_taskteam_t *lwt = NULL,
333                        *next_lwt = LWT_FROM_TEAM(taskdata->td_team);
334 
335     while (ancestor_level > 0) {
336       // next lightweight team (if any)
337       if (lwt)
338         lwt = lwt->parent;
339 
340       // next heavyweight team (if any) after
341       // lightweight teams are exhausted
342       if (!lwt && taskdata) {
343         // first try scheduling parent (for explicit task scheduling)
344         if (taskdata->ompt_task_info.scheduling_parent) {
345           taskdata = taskdata->ompt_task_info.scheduling_parent;
346         } else if (next_lwt) {
347           lwt = next_lwt;
348           next_lwt = NULL;
349         } else {
350           // then go for implicit tasks
351           taskdata = taskdata->td_parent;
352           if (team == NULL)
353             return 0;
354           team = team->t.t_parent;
355           if (taskdata) {
356             next_lwt = LWT_FROM_TEAM(taskdata->td_team);
357           }
358         }
359       }
360       ancestor_level--;
361     }
362 
363     if (lwt) {
364       info = &lwt->ompt_task_info;
365       team_info = &lwt->ompt_team_info;
366       if (type) {
367         *type = ompt_task_implicit;
368       }
369     } else if (taskdata) {
370       info = &taskdata->ompt_task_info;
371       team_info = &team->t.ompt_team_info;
372       if (type) {
373         if (taskdata->td_parent) {
374           *type = (taskdata->td_flags.tasktype ? ompt_task_explicit
375                                                : ompt_task_implicit) |
376                   TASK_TYPE_DETAILS_FORMAT(taskdata);
377         } else {
378           *type = ompt_task_initial;
379         }
380       }
381     }
382     if (task_data) {
383       *task_data = info ? &info->task_data : NULL;
384     }
385     if (task_frame) {
386       // OpenMP spec asks for the scheduling task to be returned.
387       *task_frame = info ? &info->frame : NULL;
388     }
389     if (parallel_data) {
390       *parallel_data = team_info ? &(team_info->parallel_data) : NULL;
391     }
392     return info ? 2 : 0;
393   }
394   return 0;
395 }
396 
397 //----------------------------------------------------------
398 // team support
399 //----------------------------------------------------------
400 
401 void __ompt_team_assign_id(kmp_team_t *team, ompt_data_t ompt_pid) {
402   team->t.ompt_team_info.parallel_data = ompt_pid;
403 }
404 
405 //----------------------------------------------------------
406 // misc
407 //----------------------------------------------------------
408 
409 static uint64_t __ompt_get_unique_id_internal() {
410   static uint64_t thread = 1;
411   static THREAD_LOCAL uint64_t ID = 0;
412   if (ID == 0) {
413     uint64_t new_thread = KMP_TEST_THEN_INC64((kmp_int64 *)&thread);
414     ID = new_thread << (sizeof(uint64_t) * 8 - OMPT_THREAD_ID_BITS);
415   }
416   return ++ID;
417 }
418