Intel® OpenMP* Runtime Library
 All Classes Functions Variables Typedefs Enumerations Enumerator Groups Pages
ompt-specific.c
1 /*
2  * ompt-specific.c -- OMPT specific file.
3  */
4 
5 /* <copyright>
6  Copyright (c) 1997-2015 Intel Corporation. All Rights Reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions
10  are met:
11 
12  * Redistributions of source code must retain the above copyright
13  notice, this list of conditions and the following disclaimer.
14  * Redistributions in binary form must reproduce the above copyright
15  notice, this list of conditions and the following disclaimer in the
16  documentation and/or other materials provided with the distribution.
17  * Neither the name of Intel Corporation nor the names of its
18  contributors may be used to endorse or promote products derived
19  from this software without specific prior written permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 </copyright> */
34 
35 //******************************************************************************
36 // include files
37 //******************************************************************************
38 
39 #include "kmp.h"
40 #include "ompt-internal.h"
41 #include "ompt-specific.h"
42 
43 //******************************************************************************
44 // macros
45 //******************************************************************************
46 
47 #define GTID_TO_OMPT_THREAD_ID(id) ((ompt_thread_id_t) (id >=0) ? id + 1: 0)
48 
49 #define LWT_FROM_TEAM(team) (team)->t.ompt_serialized_team_info;
50 
51 #define OMPT_THREAD_ID_BITS 16
52 
53 // 2013 08 24 - John Mellor-Crummey
54 // ideally, a thread should assign its own ids based on thread private data.
55 // however, the way the intel runtime reinitializes thread data structures
56 // when it creates teams makes it difficult to maintain persistent thread
57 // data. using a shared variable instead is simple. I leave it to intel to
58 // sort out how to implement a higher performance version in their runtime.
59 
60 // when using fetch_and_add to generate the IDs, there isn't any reason to waste
61 // bits for thread id.
62 #define NEXT_ID(id_ptr,tid) (KMP_TEST_THEN_INC64((volatile kmp_int64 *)id_ptr))
63 
64 //******************************************************************************
65 // private operations
66 //******************************************************************************
67 
68 //----------------------------------------------------------
69 // traverse the team and task hierarchy
70 // note: __ompt_get_teaminfo and __ompt_get_taskinfo
71 // traverse the hierarchy similarly and need to be
72 // kept consistent
73 //----------------------------------------------------------
74 
75 ompt_team_info_t *
76 __ompt_get_teaminfo(int depth, int *size)
77 {
78  kmp_info_t *thr = ompt_get_thread();
79 
80  if (thr) {
81  kmp_team *team = thr->th.th_team;
82  ompt_lw_taskteam_t *lwt = LWT_FROM_TEAM(team);
83 
84  while(depth > 0) {
85  // next lightweight team (if any)
86  if (lwt) lwt = lwt->parent;
87 
88  // next heavyweight team (if any) after
89  // lightweight teams are exhausted
90  if (!lwt && team) team=team->t.t_parent;
91 
92  depth--;
93  }
94 
95  if (lwt) {
96  // lightweight teams have one task
97  if (size) *size = 1;
98 
99  // return team info for lightweight team
100  return &lwt->ompt_team_info;
101  } else if (team) {
102  // extract size from heavyweight team
103  if (size) *size = team->t.t_nproc;
104 
105  // return team info for heavyweight team
106  return &team->t.ompt_team_info;
107  }
108  }
109 
110  return NULL;
111 }
112 
113 
114 ompt_task_info_t *
115 __ompt_get_taskinfo(int depth)
116 {
117  ompt_task_info_t *info = NULL;
118  kmp_info_t *thr = ompt_get_thread();
119 
120  if (thr) {
121  kmp_taskdata_t *taskdata = thr->th.th_current_task;
122  ompt_lw_taskteam_t *lwt = LWT_FROM_TEAM(taskdata->td_team);
123 
124  while (depth > 0) {
125  // next lightweight team (if any)
126  if (lwt) lwt = lwt->parent;
127 
128  // next heavyweight team (if any) after
129  // lightweight teams are exhausted
130  if (!lwt && taskdata) {
131  taskdata = taskdata->td_parent;
132  if (taskdata) {
133  lwt = LWT_FROM_TEAM(taskdata->td_team);
134  }
135  }
136  depth--;
137  }
138 
139  if (lwt) {
140  info = &lwt->ompt_task_info;
141  } else if (taskdata) {
142  info = &taskdata->ompt_task_info;
143  }
144  }
145 
146  return info;
147 }
148 
149 
150 
151 //******************************************************************************
152 // interface operations
153 //******************************************************************************
154 
155 //----------------------------------------------------------
156 // initialization support
157 //----------------------------------------------------------
158 
159 void
160 __ompt_init_internal()
161 {
162  if (ompt_status & ompt_status_track) {
163  // initialize initial thread for OMPT
164  kmp_info_t *root_thread = ompt_get_thread();
165  __kmp_task_init_ompt(
166  root_thread->th.th_team->t.t_implicit_task_taskdata, 0);
167  __kmp_task_init_ompt(
168  root_thread->th.th_serial_team->t.t_implicit_task_taskdata, 0);
169 
170  // make mandatory callback for creation of initial thread
171  // this needs to occur here rather than in __kmp_register_root because
172  // __kmp_register_root is called before ompt_initialize
173  int gtid = __kmp_get_gtid();
174  if (KMP_UBER_GTID(gtid)) {
175  // initialize the initial thread's idle frame and state
176  root_thread->th.ompt_thread_info.idle_frame = 0;
177  root_thread->th.ompt_thread_info.state = ompt_state_overhead;
178  if ((ompt_status == ompt_status_track_callback) &&
179  ompt_callbacks.ompt_callback(ompt_event_thread_begin)) {
180  __ompt_thread_begin(ompt_thread_initial, gtid);
181  }
182  root_thread->th.ompt_thread_info.state = ompt_state_work_serial;
183  }
184  }
185 }
186 
187 
188 //----------------------------------------------------------
189 // thread support
190 //----------------------------------------------------------
191 
192 ompt_parallel_id_t
193 __ompt_thread_id_new()
194 {
195  static uint64_t ompt_thread_id = 1;
196  return NEXT_ID(&ompt_thread_id, 0);
197 }
198 
199 void
200 __ompt_thread_begin(ompt_thread_type_t thread_type, int gtid)
201 {
202  ompt_callbacks.ompt_callback(ompt_event_thread_begin)(
203  thread_type, GTID_TO_OMPT_THREAD_ID(gtid));
204 }
205 
206 
207 void
208 __ompt_thread_end(ompt_thread_type_t thread_type, int gtid)
209 {
210  ompt_callbacks.ompt_callback(ompt_event_thread_end)(
211  thread_type, GTID_TO_OMPT_THREAD_ID(gtid));
212 }
213 
214 
215 ompt_thread_id_t
216 __ompt_get_thread_id_internal()
217 {
218  // FIXME
219  // until we have a better way of assigning ids, use __kmp_get_gtid
220  // since the return value might be negative, we need to test that before
221  // assigning it to an ompt_thread_id_t, which is unsigned.
222  int id = __kmp_get_gtid();
223  assert(id >= 0);
224 
225  return GTID_TO_OMPT_THREAD_ID(id);
226 }
227 
228 //----------------------------------------------------------
229 // state support
230 //----------------------------------------------------------
231 
232 void
233 __ompt_thread_assign_wait_id(void *variable)
234 {
235  int gtid = __kmp_gtid_get_specific();
236  kmp_info_t *ti = ompt_get_thread_gtid(gtid);
237 
238  ti->th.ompt_thread_info.wait_id = (ompt_wait_id_t) variable;
239 }
240 
241 ompt_state_t
242 __ompt_get_state_internal(ompt_wait_id_t *ompt_wait_id)
243 {
244  kmp_info_t *ti = ompt_get_thread();
245 
246  if (ti) {
247  if (ompt_wait_id)
248  *ompt_wait_id = ti->th.ompt_thread_info.wait_id;
249  return ti->th.ompt_thread_info.state;
250  }
251  return ompt_state_undefined;
252 }
253 
254 //----------------------------------------------------------
255 // idle frame support
256 //----------------------------------------------------------
257 
258 void *
259 __ompt_get_idle_frame_internal(void)
260 {
261  kmp_info_t *ti = ompt_get_thread();
262  return ti ? ti->th.ompt_thread_info.idle_frame : NULL;
263 }
264 
265 
266 //----------------------------------------------------------
267 // parallel region support
268 //----------------------------------------------------------
269 
270 ompt_parallel_id_t
271 __ompt_parallel_id_new(int gtid)
272 {
273  static uint64_t ompt_parallel_id = 1;
274  return gtid >= 0 ? NEXT_ID(&ompt_parallel_id, gtid) : 0;
275 }
276 
277 
278 void *
279 __ompt_get_parallel_function_internal(int depth)
280 {
281  ompt_team_info_t *info = __ompt_get_teaminfo(depth, NULL);
282  void *function = info ? info->microtask : NULL;
283  return function;
284 }
285 
286 
287 ompt_parallel_id_t
288 __ompt_get_parallel_id_internal(int depth)
289 {
290  ompt_team_info_t *info = __ompt_get_teaminfo(depth, NULL);
291  ompt_parallel_id_t id = info ? info->parallel_id : 0;
292  return id;
293 }
294 
295 
296 int
297 __ompt_get_parallel_team_size_internal(int depth)
298 {
299  // initialize the return value with the error value.
300  // if there is a team at the specified depth, the default
301  // value will be overwritten the size of that team.
302  int size = -1;
303  (void) __ompt_get_teaminfo(depth, &size);
304  return size;
305 }
306 
307 
308 //----------------------------------------------------------
309 // lightweight task team support
310 //----------------------------------------------------------
311 
312 void
313 __ompt_lw_taskteam_init(ompt_lw_taskteam_t *lwt, kmp_info_t *thr,
314  int gtid, void *microtask,
315  ompt_parallel_id_t ompt_pid)
316 {
317  lwt->ompt_team_info.parallel_id = ompt_pid;
318  lwt->ompt_team_info.microtask = microtask;
319  lwt->ompt_task_info.task_id = 0;
320  lwt->ompt_task_info.frame.reenter_runtime_frame = 0;
321  lwt->ompt_task_info.frame.exit_runtime_frame = 0;
322  lwt->ompt_task_info.function = NULL;
323  lwt->parent = 0;
324 }
325 
326 
327 void
328 __ompt_lw_taskteam_link(ompt_lw_taskteam_t *lwt, kmp_info_t *thr)
329 {
330  ompt_lw_taskteam_t *my_parent = thr->th.th_team->t.ompt_serialized_team_info;
331  lwt->parent = my_parent;
332  thr->th.th_team->t.ompt_serialized_team_info = lwt;
333 }
334 
335 
336 ompt_lw_taskteam_t *
337 __ompt_lw_taskteam_unlink(kmp_info_t *thr)
338 {
339  ompt_lw_taskteam_t *lwtask = thr->th.th_team->t.ompt_serialized_team_info;
340  if (lwtask) thr->th.th_team->t.ompt_serialized_team_info = lwtask->parent;
341  return lwtask;
342 }
343 
344 
345 //----------------------------------------------------------
346 // task support
347 //----------------------------------------------------------
348 
349 ompt_task_id_t
350 __ompt_task_id_new(int gtid)
351 {
352  static uint64_t ompt_task_id = 1;
353  return NEXT_ID(&ompt_task_id, gtid);
354 }
355 
356 
357 ompt_task_id_t
358 __ompt_get_task_id_internal(int depth)
359 {
360  ompt_task_info_t *info = __ompt_get_taskinfo(depth);
361  ompt_task_id_t task_id = info ? info->task_id : 0;
362  return task_id;
363 }
364 
365 
366 void *
367 __ompt_get_task_function_internal(int depth)
368 {
369  ompt_task_info_t *info = __ompt_get_taskinfo(depth);
370  void *function = info ? info->function : NULL;
371  return function;
372 }
373 
374 
375 ompt_frame_t *
376 __ompt_get_task_frame_internal(int depth)
377 {
378  ompt_task_info_t *info = __ompt_get_taskinfo(depth);
379  ompt_frame_t *frame = info ? frame = &info->frame : NULL;
380  return frame;
381 }
382 
383 
384 //----------------------------------------------------------
385 // team support
386 //----------------------------------------------------------
387 
388 void
389 __ompt_team_assign_id(kmp_team_t *team, ompt_parallel_id_t ompt_pid)
390 {
391  team->t.ompt_team_info.parallel_id = ompt_pid;
392 }
393 
394 
395 //----------------------------------------------------------
396 // runtime version support
397 //----------------------------------------------------------
398 
399 const char *
400 __ompt_get_runtime_version_internal()
401 {
402  return &__kmp_version_lib_ver[KMP_VERSION_MAGIC_LEN];
403 }