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