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 }
467