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