LLVM OpenMP* Runtime Library
ompt-general.cpp
1 /*****************************************************************************
2  * system include files
3  ****************************************************************************/
4 
5 #include <assert.h>
6 
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 /*****************************************************************************
13  * ompt include files
14  ****************************************************************************/
15 
16 #include "ompt-specific.cpp"
17 
18 /*****************************************************************************
19  * macros
20  ****************************************************************************/
21 
22 #define ompt_get_callback_success 1
23 #define ompt_get_callback_failure 0
24 
25 #define no_tool_present 0
26 
27 #define OMPT_API_ROUTINE static
28 
29 #ifndef OMPT_STR_MATCH
30 #define OMPT_STR_MATCH(haystack, needle) (!strcasecmp(haystack, needle))
31 #endif
32 
33 /*****************************************************************************
34  * types
35  ****************************************************************************/
36 
37 typedef struct {
38  const char *state_name;
39  ompt_state_t state_id;
40 } ompt_state_info_t;
41 
42 enum tool_setting_e {
43  omp_tool_error,
44  omp_tool_unset,
45  omp_tool_disabled,
46  omp_tool_enabled
47 };
48 
49 typedef void (*ompt_initialize_t)(ompt_function_lookup_t ompt_fn_lookup,
50  const char *version,
51  unsigned int ompt_version);
52 
53 /*****************************************************************************
54  * global variables
55  ****************************************************************************/
56 
57 int ompt_enabled = 0;
58 
59 ompt_state_info_t ompt_state_info[] = {
60 #define ompt_state_macro(state, code) {#state, state},
61  FOREACH_OMPT_STATE(ompt_state_macro)
62 #undef ompt_state_macro
63 };
64 
65 ompt_callbacks_t ompt_callbacks;
66 
67 static ompt_initialize_t ompt_initialize_fn = NULL;
68 
69 /*****************************************************************************
70  * forward declarations
71  ****************************************************************************/
72 
73 static ompt_interface_fn_t ompt_fn_lookup(const char *s);
74 
75 OMPT_API_ROUTINE ompt_thread_id_t ompt_get_thread_id(void);
76 
77 /*****************************************************************************
78  * initialization and finalization (private operations)
79  ****************************************************************************/
80 
81 /* On Unix-like systems that support weak symbols the following implementation
82  * of ompt_tool() will be used in case no tool-supplied implementation of
83  * this function is present in the address space of a process.
84  *
85  * On Windows, the ompt_tool_windows function is used to find the
86  * ompt_tool symbol across all modules loaded by a process. If ompt_tool is
87  * found, ompt_tool's return value is used to initialize the tool. Otherwise,
88  * NULL is returned and OMPT won't be enabled */
89 #if OMPT_HAVE_WEAK_ATTRIBUTE
90 _OMP_EXTERN
91 __attribute__((weak)) ompt_initialize_t ompt_tool() {
92 #if OMPT_DEBUG
93  printf("ompt_tool() is called from the RTL\n");
94 #endif
95  return NULL;
96 }
97 
98 #elif OMPT_HAVE_PSAPI
99 
100 #include <psapi.h>
101 #pragma comment(lib, "psapi.lib")
102 #define ompt_tool ompt_tool_windows
103 
104 // The number of loaded modules to start enumeration with EnumProcessModules()
105 #define NUM_MODULES 128
106 
107 static ompt_initialize_t ompt_tool_windows() {
108  int i;
109  DWORD needed, new_size;
110  HMODULE *modules;
111  HANDLE process = GetCurrentProcess();
112  modules = (HMODULE *)malloc(NUM_MODULES * sizeof(HMODULE));
113  ompt_initialize_t (*ompt_tool_p)() = NULL;
114 
115 #if OMPT_DEBUG
116  printf("ompt_tool_windows(): looking for ompt_tool\n");
117 #endif
118  if (!EnumProcessModules(process, modules, NUM_MODULES * sizeof(HMODULE),
119  &needed)) {
120  // Regardless of the error reason use the stub initialization function
121  free(modules);
122  return NULL;
123  }
124  // Check if NUM_MODULES is enough to list all modules
125  new_size = needed / sizeof(HMODULE);
126  if (new_size > NUM_MODULES) {
127 #if OMPT_DEBUG
128  printf("ompt_tool_windows(): resize buffer to %d bytes\n", needed);
129 #endif
130  modules = (HMODULE *)realloc(modules, needed);
131  // If resizing failed use the stub function.
132  if (!EnumProcessModules(process, modules, needed, &needed)) {
133  free(modules);
134  return NULL;
135  }
136  }
137  for (i = 0; i < new_size; ++i) {
138  (FARPROC &)ompt_tool_p = GetProcAddress(modules[i], "ompt_tool");
139  if (ompt_tool_p) {
140 #if OMPT_DEBUG
141  TCHAR modName[MAX_PATH];
142  if (GetModuleFileName(modules[i], modName, MAX_PATH))
143  printf("ompt_tool_windows(): ompt_tool found in module %s\n", modName);
144 #endif
145  free(modules);
146  return ompt_tool_p();
147  }
148 #if OMPT_DEBUG
149  else {
150  TCHAR modName[MAX_PATH];
151  if (GetModuleFileName(modules[i], modName, MAX_PATH))
152  printf("ompt_tool_windows(): ompt_tool not found in module %s\n",
153  modName);
154  }
155 #endif
156  }
157  free(modules);
158  return NULL;
159 }
160 #else
161 #error Either __attribute__((weak)) or psapi.dll are required for OMPT support
162 #endif // OMPT_HAVE_WEAK_ATTRIBUTE
163 
164 void ompt_pre_init() {
165  //--------------------------------------------------
166  // Execute the pre-initialization logic only once.
167  //--------------------------------------------------
168  static int ompt_pre_initialized = 0;
169 
170  if (ompt_pre_initialized)
171  return;
172 
173  ompt_pre_initialized = 1;
174 
175  //--------------------------------------------------
176  // Use a tool iff a tool is enabled and available.
177  //--------------------------------------------------
178  const char *ompt_env_var = getenv("OMP_TOOL");
179  tool_setting_e tool_setting = omp_tool_error;
180 
181  if (!ompt_env_var || !strcmp(ompt_env_var, ""))
182  tool_setting = omp_tool_unset;
183  else if (OMPT_STR_MATCH(ompt_env_var, "disabled"))
184  tool_setting = omp_tool_disabled;
185  else if (OMPT_STR_MATCH(ompt_env_var, "enabled"))
186  tool_setting = omp_tool_enabled;
187 
188 #if OMPT_DEBUG
189  printf("ompt_pre_init(): tool_setting = %d\n", tool_setting);
190 #endif
191  switch (tool_setting) {
192  case omp_tool_disabled:
193  break;
194 
195  case omp_tool_unset:
196  case omp_tool_enabled:
197  ompt_initialize_fn = ompt_tool();
198  if (ompt_initialize_fn) {
199  ompt_enabled = 1;
200  }
201  break;
202 
203  case omp_tool_error:
204  fprintf(stderr, "Warning: OMP_TOOL has invalid value \"%s\".\n"
205  " legal values are (NULL,\"\",\"disabled\","
206  "\"enabled\").\n",
207  ompt_env_var);
208  break;
209  }
210 #if OMPT_DEBUG
211  printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled);
212 #endif
213 }
214 
215 void ompt_post_init() {
216  //--------------------------------------------------
217  // Execute the post-initialization logic only once.
218  //--------------------------------------------------
219  static int ompt_post_initialized = 0;
220 
221  if (ompt_post_initialized)
222  return;
223 
224  ompt_post_initialized = 1;
225 
226  //--------------------------------------------------
227  // Initialize the tool if so indicated.
228  //--------------------------------------------------
229  if (ompt_enabled) {
230  ompt_initialize_fn(ompt_fn_lookup, ompt_get_runtime_version(),
231  OMPT_VERSION);
232 
233  ompt_thread_t *root_thread = ompt_get_thread();
234 
235  ompt_set_thread_state(root_thread, ompt_state_overhead);
236 
237  if (ompt_callbacks.ompt_callback(ompt_event_thread_begin)) {
238  ompt_callbacks.ompt_callback(ompt_event_thread_begin)(
239  ompt_thread_initial, ompt_get_thread_id());
240  }
241 
242  ompt_set_thread_state(root_thread, ompt_state_work_serial);
243  }
244 }
245 
246 void ompt_fini() {
247  if (ompt_enabled) {
248  if (ompt_callbacks.ompt_callback(ompt_event_runtime_shutdown)) {
249  ompt_callbacks.ompt_callback(ompt_event_runtime_shutdown)();
250  }
251  }
252 
253  ompt_enabled = 0;
254 }
255 
256 /*****************************************************************************
257  * interface operations
258  ****************************************************************************/
259 
260 /*****************************************************************************
261  * state
262  ****************************************************************************/
263 
264 OMPT_API_ROUTINE int ompt_enumerate_state(int current_state, int *next_state,
265  const char **next_state_name) {
266  const static int len = sizeof(ompt_state_info) / sizeof(ompt_state_info_t);
267  int i = 0;
268 
269  for (i = 0; i < len - 1; i++) {
270  if (ompt_state_info[i].state_id == current_state) {
271  *next_state = ompt_state_info[i + 1].state_id;
272  *next_state_name = ompt_state_info[i + 1].state_name;
273  return 1;
274  }
275  }
276 
277  return 0;
278 }
279 
280 /*****************************************************************************
281  * callbacks
282  ****************************************************************************/
283 
284 OMPT_API_ROUTINE int ompt_set_callback(ompt_event_t evid, ompt_callback_t cb) {
285  switch (evid) {
286 
287 #define ompt_event_macro(event_name, callback_type, event_id) \
288  case event_name: \
289  if (ompt_event_implementation_status(event_name)) { \
290  ompt_callbacks.ompt_callback(event_name) = (callback_type)cb; \
291  } \
292  return ompt_event_implementation_status(event_name);
293 
294  FOREACH_OMPT_EVENT(ompt_event_macro)
295 
296 #undef ompt_event_macro
297 
298  default:
299  return ompt_set_result_registration_error;
300  }
301 }
302 
303 OMPT_API_ROUTINE int ompt_get_callback(ompt_event_t evid, ompt_callback_t *cb) {
304  switch (evid) {
305 
306 #define ompt_event_macro(event_name, callback_type, event_id) \
307  case event_name: \
308  if (ompt_event_implementation_status(event_name)) { \
309  ompt_callback_t mycb = \
310  (ompt_callback_t)ompt_callbacks.ompt_callback(event_name); \
311  if (mycb) { \
312  *cb = mycb; \
313  return ompt_get_callback_success; \
314  } \
315  } \
316  return ompt_get_callback_failure;
317 
318  FOREACH_OMPT_EVENT(ompt_event_macro)
319 
320 #undef ompt_event_macro
321 
322  default:
323  return ompt_get_callback_failure;
324  }
325 }
326 
327 /*****************************************************************************
328  * parallel regions
329  ****************************************************************************/
330 
331 OMPT_API_ROUTINE ompt_parallel_id_t ompt_get_parallel_id(int ancestor_level) {
332  return __ompt_get_parallel_id_internal(ancestor_level);
333 }
334 
335 OMPT_API_ROUTINE int ompt_get_parallel_team_size(int ancestor_level) {
336  return __ompt_get_parallel_team_size_internal(ancestor_level);
337 }
338 
339 OMPT_API_ROUTINE void *ompt_get_parallel_function(int ancestor_level) {
340  return __ompt_get_parallel_function_internal(ancestor_level);
341 }
342 
343 OMPT_API_ROUTINE ompt_state_t ompt_get_state(ompt_wait_id_t *ompt_wait_id) {
344  ompt_state_t thread_state = __ompt_get_state_internal(ompt_wait_id);
345 
346  if (thread_state == ompt_state_undefined) {
347  thread_state = ompt_state_work_serial;
348  }
349 
350  return thread_state;
351 }
352 
353 /*****************************************************************************
354  * threads
355  ****************************************************************************/
356 
357 OMPT_API_ROUTINE void *ompt_get_idle_frame() {
358  return __ompt_get_idle_frame_internal();
359 }
360 
361 /*****************************************************************************
362  * tasks
363  ****************************************************************************/
364 
365 OMPT_API_ROUTINE ompt_thread_id_t ompt_get_thread_id(void) {
366  return __ompt_get_thread_id_internal();
367 }
368 
369 OMPT_API_ROUTINE ompt_task_id_t ompt_get_task_id(int depth) {
370  return __ompt_get_task_id_internal(depth);
371 }
372 
373 OMPT_API_ROUTINE ompt_frame_t *ompt_get_task_frame(int depth) {
374  return __ompt_get_task_frame_internal(depth);
375 }
376 
377 OMPT_API_ROUTINE void *ompt_get_task_function(int depth) {
378  return __ompt_get_task_function_internal(depth);
379 }
380 
381 /*****************************************************************************
382  * placeholders
383  ****************************************************************************/
384 
385 // Don't define this as static. The loader may choose to eliminate the symbol
386 // even though it is needed by tools.
387 #define OMPT_API_PLACEHOLDER
388 
389 // Ensure that placeholders don't have mangled names in the symbol table.
390 #ifdef __cplusplus
391 extern "C" {
392 #endif
393 
394 OMPT_API_PLACEHOLDER void ompt_idle(void) {
395  // This function is a placeholder used to represent the calling context of
396  // idle OpenMP worker threads. It is not meant to be invoked.
397  assert(0);
398 }
399 
400 OMPT_API_PLACEHOLDER void ompt_overhead(void) {
401  // This function is a placeholder used to represent the OpenMP context of
402  // threads working in the OpenMP runtime. It is not meant to be invoked.
403  assert(0);
404 }
405 
406 OMPT_API_PLACEHOLDER void ompt_barrier_wait(void) {
407  // This function is a placeholder used to represent the OpenMP context of
408  // threads waiting for a barrier in the OpenMP runtime. It is not meant
409  // to be invoked.
410  assert(0);
411 }
412 
413 OMPT_API_PLACEHOLDER void ompt_task_wait(void) {
414  // This function is a placeholder used to represent the OpenMP context of
415  // threads waiting for a task in the OpenMP runtime. It is not meant
416  // to be invoked.
417  assert(0);
418 }
419 
420 OMPT_API_PLACEHOLDER void ompt_mutex_wait(void) {
421  // This function is a placeholder used to represent the OpenMP context of
422  // threads waiting for a mutex in the OpenMP runtime. It is not meant
423  // to be invoked.
424  assert(0);
425 }
426 
427 #ifdef __cplusplus
428 };
429 #endif
430 
431 /*****************************************************************************
432  * compatability
433  ****************************************************************************/
434 
435 OMPT_API_ROUTINE int ompt_get_ompt_version() { return OMPT_VERSION; }
436 
437 /*****************************************************************************
438  * application-facing API
439  ****************************************************************************/
440 
441 /*----------------------------------------------------------------------------
442  | control
443  ---------------------------------------------------------------------------*/
444 
445 _OMP_EXTERN void ompt_control(uint64_t command, uint64_t modifier) {
446  if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_control)) {
447  ompt_callbacks.ompt_callback(ompt_event_control)(command, modifier);
448  }
449 }
450 
451 /*****************************************************************************
452  * API inquiry for tool
453  ****************************************************************************/
454 
455 static ompt_interface_fn_t ompt_fn_lookup(const char *s) {
456 
457 #define ompt_interface_fn(fn) \
458  if (strcmp(s, #fn) == 0) \
459  return (ompt_interface_fn_t)fn;
460 
461  FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn)
462 
463  FOREACH_OMPT_PLACEHOLDER_FN(ompt_interface_fn)
464 
465  return (ompt_interface_fn_t)0;
466 }