LLVM OpenMP* Runtime Library
ompt-specific.cpp
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 }