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