1 #ifndef _BSD_SOURCE
2 #define _BSD_SOURCE
3 #endif
4 #define _DEFAULT_SOURCE
5 #include <stdio.h>
6 #ifndef __STDC_FORMAT_MACROS
7 #define __STDC_FORMAT_MACROS
8 #endif
9 #include <inttypes.h>
10 #include <omp.h>
11 #include <ompt.h>
12 #include "ompt-signal.h"
13 
14 // Used to detect architecture
15 #include "../../src/kmp_platform.h"
16 
17 static const char* ompt_thread_t_values[] = {
18   NULL,
19   "ompt_thread_initial",
20   "ompt_thread_worker",
21   "ompt_thread_other"
22 };
23 
24 static const char* ompt_task_status_t_values[] = {
25   NULL,
26   "ompt_task_complete",
27   "ompt_task_yield",
28   "ompt_task_cancel",
29   "ompt_task_others"
30 };
31 static const char* ompt_cancel_flag_t_values[] = {
32   "ompt_cancel_parallel",
33   "ompt_cancel_sections",
34   "ompt_cancel_loop",
35   "ompt_cancel_taskgroup",
36   "ompt_cancel_activated",
37   "ompt_cancel_detected",
38   "ompt_cancel_discarded_task"
39 };
40 
41 static void format_task_type(int type, char *buffer) {
42   char *progress = buffer;
43   if (type & ompt_task_initial)
44     progress += sprintf(progress, "ompt_task_initial");
45   if (type & ompt_task_implicit)
46     progress += sprintf(progress, "ompt_task_implicit");
47   if (type & ompt_task_explicit)
48     progress += sprintf(progress, "ompt_task_explicit");
49   if (type & ompt_task_target)
50     progress += sprintf(progress, "ompt_task_target");
51   if (type & ompt_task_undeferred)
52     progress += sprintf(progress, "|ompt_task_undeferred");
53   if (type & ompt_task_untied)
54     progress += sprintf(progress, "|ompt_task_untied");
55   if (type & ompt_task_final)
56     progress += sprintf(progress, "|ompt_task_final");
57   if (type & ompt_task_mergeable)
58     progress += sprintf(progress, "|ompt_task_mergeable");
59   if (type & ompt_task_merged)
60     progress += sprintf(progress, "|ompt_task_merged");
61 }
62 
63 static ompt_set_callback_t ompt_set_callback;
64 static ompt_get_callback_t ompt_get_callback;
65 static ompt_get_state_t ompt_get_state;
66 static ompt_get_task_info_t ompt_get_task_info;
67 static ompt_get_thread_data_t ompt_get_thread_data;
68 static ompt_get_parallel_info_t ompt_get_parallel_info;
69 static ompt_get_unique_id_t ompt_get_unique_id;
70 static ompt_get_num_procs_t ompt_get_num_procs;
71 static ompt_get_num_places_t ompt_get_num_places;
72 static ompt_get_place_proc_ids_t ompt_get_place_proc_ids;
73 static ompt_get_place_num_t ompt_get_place_num;
74 static ompt_get_partition_place_nums_t ompt_get_partition_place_nums;
75 static ompt_get_proc_id_t ompt_get_proc_id;
76 static ompt_enumerate_states_t ompt_enumerate_states;
77 static ompt_enumerate_mutex_impls_t ompt_enumerate_mutex_impls;
78 
79 static void print_ids(int level)
80 {
81   int task_type, thread_num;
82   ompt_frame_t *frame;
83   ompt_data_t *task_parallel_data;
84   ompt_data_t *task_data;
85   int exists_task = ompt_get_task_info(level, &task_type, &task_data, &frame,
86                                        &task_parallel_data, &thread_num);
87   char buffer[2048];
88   format_task_type(task_type, buffer);
89   if (frame)
90     printf("%" PRIu64 ": task level %d: parallel_id=%" PRIu64
91            ", task_id=%" PRIu64 ", exit_frame=%p, reenter_frame=%p, "
92            "task_type=%s=%d, thread_num=%d\n",
93            ompt_get_thread_data()->value, level,
94            exists_task ? task_parallel_data->value : 0,
95            exists_task ? task_data->value : 0, frame->exit_frame.ptr,
96            frame->enter_frame.ptr, buffer, task_type, thread_num);
97 }
98 
99 #define get_frame_address(level) __builtin_frame_address(level)
100 
101 #define print_frame(level)                                                     \
102   printf("%" PRIu64 ": __builtin_frame_address(%d)=%p\n",                      \
103          ompt_get_thread_data()->value, level, get_frame_address(level))
104 
105 // clang (version 5.0 and above) adds an intermediate function call with debug flag (-g)
106 #if defined(TEST_NEED_PRINT_FRAME_FROM_OUTLINED_FN)
107   #if defined(DEBUG) && defined(__clang__) && __clang_major__ >= 5
108     #define print_frame_from_outlined_fn(level) print_frame(level+1)
109   #else
110     #define print_frame_from_outlined_fn(level) print_frame(level)
111   #endif
112 
113   #if defined(__clang__) && __clang_major__ >= 5
114     #warning "Clang 5.0 and later add an additional wrapper for outlined functions when compiling with debug information."
115     #warning "Please define -DDEBUG iff you manually pass in -g to make the tests succeed!"
116   #endif
117 #endif
118 
119 // This macro helps to define a label at the current position that can be used
120 // to get the current address in the code.
121 //
122 // For print_current_address():
123 //   To reliably determine the offset between the address of the label and the
124 //   actual return address, we insert a NOP instruction as a jump target as the
125 //   compiler would otherwise insert an instruction that we can't control. The
126 //   instruction length is target dependent and is explained below.
127 //
128 // (The empty block between "#pragma omp ..." and the __asm__ statement is a
129 // workaround for a bug in the Intel Compiler.)
130 #define define_ompt_label(id) \
131   {} \
132   __asm__("nop"); \
133 ompt_label_##id:
134 
135 // This macro helps to get the address of a label that is inserted by the above
136 // macro define_ompt_label(). The address is obtained with a GNU extension
137 // (&&label) that has been tested with gcc, clang and icc.
138 #define get_ompt_label_address(id) (&& ompt_label_##id)
139 
140 // This macro prints the exact address that a previously called runtime function
141 // returns to.
142 #define print_current_address(id) \
143   define_ompt_label(id) \
144   print_possible_return_addresses(get_ompt_label_address(id))
145 
146 #if KMP_ARCH_X86 || KMP_ARCH_X86_64
147 // On X86 the NOP instruction is 1 byte long. In addition, the comiler inserts
148 // a MOV instruction for non-void runtime functions which is 3 bytes long.
149 #define print_possible_return_addresses(addr) \
150   printf("%" PRIu64 ": current_address=%p or %p for non-void functions\n", \
151          ompt_get_thread_data()->value, ((char *)addr) - 1, ((char *)addr) - 4)
152 #elif KMP_ARCH_PPC64
153 // On Power the NOP instruction is 4 bytes long. In addition, the compiler
154 // inserts an LD instruction which accounts for another 4 bytes. In contrast to
155 // X86 this instruction is always there, even for void runtime functions.
156 #define print_possible_return_addresses(addr) \
157   printf("%" PRIu64 ": current_address=%p\n", ompt_get_thread_data()->value, \
158          ((char *)addr) - 8)
159 #elif KMP_ARCH_AARCH64
160 // On AArch64 the NOP instruction is 4 bytes long, can be followed by inserted
161 // store instruction (another 4 bytes long).
162 #define print_possible_return_addresses(addr) \
163   printf("%" PRIu64 ": current_address=%p or %p\n", ompt_get_thread_data()->value, \
164          ((char *)addr) - 4, ((char *)addr) - 8)
165 #else
166 #error Unsupported target architecture, cannot determine address offset!
167 #endif
168 
169 
170 // This macro performs a somewhat similar job to print_current_address(), except
171 // that it discards a certain number of nibbles from the address and only prints
172 // the most significant bits / nibbles. This can be used for cases where the
173 // return address can only be approximated.
174 //
175 // To account for overflows (ie the most significant bits / nibbles have just
176 // changed as we are a few bytes above the relevant power of two) the addresses
177 // of the "current" and of the "previous block" are printed.
178 #define print_fuzzy_address(id) \
179   define_ompt_label(id) \
180   print_fuzzy_address_blocks(get_ompt_label_address(id))
181 
182 // If you change this define you need to adapt all capture patterns in the tests
183 // to include or discard the new number of nibbles!
184 #define FUZZY_ADDRESS_DISCARD_NIBBLES 2
185 #define FUZZY_ADDRESS_DISCARD_BYTES (1 << ((FUZZY_ADDRESS_DISCARD_NIBBLES) * 4))
186 #define print_fuzzy_address_blocks(addr)                                       \
187   printf("%" PRIu64 ": fuzzy_address=0x%" PRIx64 " or 0x%" PRIx64              \
188          " or 0x%" PRIx64 " or 0x%" PRIx64 " (%p)\n",                          \
189          ompt_get_thread_data()->value,                                        \
190          ((uint64_t)addr) / FUZZY_ADDRESS_DISCARD_BYTES - 1,                   \
191          ((uint64_t)addr) / FUZZY_ADDRESS_DISCARD_BYTES,                       \
192          ((uint64_t)addr) / FUZZY_ADDRESS_DISCARD_BYTES + 1,                   \
193          ((uint64_t)addr) / FUZZY_ADDRESS_DISCARD_BYTES + 2, addr)
194 
195 static void
196 on_ompt_callback_mutex_acquire(
197   ompt_mutex_t kind,
198   unsigned int hint,
199   unsigned int impl,
200   ompt_wait_id_t wait_id,
201   const void *codeptr_ra)
202 {
203   switch(kind)
204   {
205     case ompt_mutex_lock:
206       printf("%" PRIu64 ": ompt_event_wait_lock: wait_id=%" PRIu64 ", hint=%" PRIu32 ", impl=%" PRIu32 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, hint, impl, codeptr_ra);
207       break;
208     case ompt_mutex_nest_lock:
209       printf("%" PRIu64 ": ompt_event_wait_nest_lock: wait_id=%" PRIu64 ", hint=%" PRIu32 ", impl=%" PRIu32 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, hint, impl, codeptr_ra);
210       break;
211     case ompt_mutex_critical:
212       printf("%" PRIu64 ": ompt_event_wait_critical: wait_id=%" PRIu64 ", hint=%" PRIu32 ", impl=%" PRIu32 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, hint, impl, codeptr_ra);
213       break;
214     case ompt_mutex_atomic:
215       printf("%" PRIu64 ": ompt_event_wait_atomic: wait_id=%" PRIu64 ", hint=%" PRIu32 ", impl=%" PRIu32 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, hint, impl, codeptr_ra);
216       break;
217     case ompt_mutex_ordered:
218       printf("%" PRIu64 ": ompt_event_wait_ordered: wait_id=%" PRIu64 ", hint=%" PRIu32 ", impl=%" PRIu32 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, hint, impl, codeptr_ra);
219       break;
220     default:
221       break;
222   }
223 }
224 
225 static void
226 on_ompt_callback_mutex_acquired(
227   ompt_mutex_t kind,
228   ompt_wait_id_t wait_id,
229   const void *codeptr_ra)
230 {
231   switch(kind)
232   {
233     case ompt_mutex_lock:
234       printf("%" PRIu64 ": ompt_event_acquired_lock: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
235       break;
236     case ompt_mutex_nest_lock:
237       printf("%" PRIu64 ": ompt_event_acquired_nest_lock_first: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
238       break;
239     case ompt_mutex_critical:
240       printf("%" PRIu64 ": ompt_event_acquired_critical: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
241       break;
242     case ompt_mutex_atomic:
243       printf("%" PRIu64 ": ompt_event_acquired_atomic: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
244       break;
245     case ompt_mutex_ordered:
246       printf("%" PRIu64 ": ompt_event_acquired_ordered: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
247       break;
248     default:
249       break;
250   }
251 }
252 
253 static void
254 on_ompt_callback_mutex_released(
255   ompt_mutex_t kind,
256   ompt_wait_id_t wait_id,
257   const void *codeptr_ra)
258 {
259   switch(kind)
260   {
261     case ompt_mutex_lock:
262       printf("%" PRIu64 ": ompt_event_release_lock: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
263       break;
264     case ompt_mutex_nest_lock:
265       printf("%" PRIu64 ": ompt_event_release_nest_lock_last: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
266       break;
267     case ompt_mutex_critical:
268       printf("%" PRIu64 ": ompt_event_release_critical: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
269       break;
270     case ompt_mutex_atomic:
271       printf("%" PRIu64 ": ompt_event_release_atomic: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
272       break;
273     case ompt_mutex_ordered:
274       printf("%" PRIu64 ": ompt_event_release_ordered: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
275       break;
276     default:
277       break;
278   }
279 }
280 
281 static void
282 on_ompt_callback_nest_lock(
283     ompt_scope_endpoint_t endpoint,
284     ompt_wait_id_t wait_id,
285     const void *codeptr_ra)
286 {
287   switch(endpoint)
288   {
289     case ompt_scope_begin:
290       printf("%" PRIu64 ": ompt_event_acquired_nest_lock_next: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
291       break;
292     case ompt_scope_end:
293       printf("%" PRIu64 ": ompt_event_release_nest_lock_prev: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
294       break;
295   }
296 }
297 
298 static void
299 on_ompt_callback_sync_region(
300   ompt_sync_region_t kind,
301   ompt_scope_endpoint_t endpoint,
302   ompt_data_t *parallel_data,
303   ompt_data_t *task_data,
304   const void *codeptr_ra)
305 {
306   switch(endpoint)
307   {
308     case ompt_scope_begin:
309       switch(kind)
310       {
311         case ompt_sync_region_barrier:
312         case ompt_sync_region_barrier_implicit:
313         case ompt_sync_region_barrier_explicit:
314         case ompt_sync_region_barrier_implementation:
315           printf("%" PRIu64 ": ompt_event_barrier_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
316           print_ids(0);
317           break;
318         case ompt_sync_region_taskwait:
319           printf("%" PRIu64 ": ompt_event_taskwait_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
320           break;
321         case ompt_sync_region_taskgroup:
322           printf("%" PRIu64 ": ompt_event_taskgroup_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
323           break;
324         case ompt_sync_region_reduction:
325           break;
326       }
327       break;
328     case ompt_scope_end:
329       switch(kind)
330       {
331         case ompt_sync_region_barrier:
332         case ompt_sync_region_barrier_implicit:
333         case ompt_sync_region_barrier_explicit:
334         case ompt_sync_region_barrier_implementation:
335           printf("%" PRIu64 ": ompt_event_barrier_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, (parallel_data)?parallel_data->value:0, task_data->value, codeptr_ra);
336           break;
337         case ompt_sync_region_taskwait:
338           printf("%" PRIu64 ": ompt_event_taskwait_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, (parallel_data)?parallel_data->value:0, task_data->value, codeptr_ra);
339           break;
340         case ompt_sync_region_taskgroup:
341           printf("%" PRIu64 ": ompt_event_taskgroup_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, (parallel_data)?parallel_data->value:0, task_data->value, codeptr_ra);
342           break;
343         case ompt_sync_region_reduction:
344           break;
345       }
346       break;
347   }
348 }
349 
350 static void
351 on_ompt_callback_sync_region_wait(
352   ompt_sync_region_t kind,
353   ompt_scope_endpoint_t endpoint,
354   ompt_data_t *parallel_data,
355   ompt_data_t *task_data,
356   const void *codeptr_ra)
357 {
358   switch(endpoint)
359   {
360     case ompt_scope_begin:
361       switch(kind)
362       {
363         case ompt_sync_region_barrier:
364         case ompt_sync_region_barrier_implicit:
365         case ompt_sync_region_barrier_explicit:
366         case ompt_sync_region_barrier_implementation:
367           printf("%" PRIu64 ": ompt_event_wait_barrier_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
368           break;
369         case ompt_sync_region_taskwait:
370           printf("%" PRIu64 ": ompt_event_wait_taskwait_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
371           break;
372         case ompt_sync_region_taskgroup:
373           printf("%" PRIu64 ": ompt_event_wait_taskgroup_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
374           break;
375         case ompt_sync_region_reduction:
376           break;
377       }
378       break;
379     case ompt_scope_end:
380       switch(kind)
381       {
382         case ompt_sync_region_barrier:
383         case ompt_sync_region_barrier_implicit:
384         case ompt_sync_region_barrier_explicit:
385         case ompt_sync_region_barrier_implementation:
386           printf("%" PRIu64 ": ompt_event_wait_barrier_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, (parallel_data)?parallel_data->value:0, task_data->value, codeptr_ra);
387           break;
388         case ompt_sync_region_taskwait:
389           printf("%" PRIu64 ": ompt_event_wait_taskwait_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, (parallel_data)?parallel_data->value:0, task_data->value, codeptr_ra);
390           break;
391         case ompt_sync_region_taskgroup:
392           printf("%" PRIu64 ": ompt_event_wait_taskgroup_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, (parallel_data)?parallel_data->value:0, task_data->value, codeptr_ra);
393           break;
394         case ompt_sync_region_reduction:
395           break;
396       }
397       break;
398   }
399 }
400 
401 static void
402 on_ompt_callback_flush(
403     ompt_data_t *thread_data,
404     const void *codeptr_ra)
405 {
406   printf("%" PRIu64 ": ompt_event_flush: codeptr_ra=%p\n", thread_data->value, codeptr_ra);
407 }
408 
409 static void
410 on_ompt_callback_cancel(
411     ompt_data_t *task_data,
412     int flags,
413     const void *codeptr_ra)
414 {
415   const char* first_flag_value;
416   const char* second_flag_value;
417   if(flags & ompt_cancel_parallel)
418     first_flag_value = ompt_cancel_flag_t_values[0];
419   else if(flags & ompt_cancel_sections)
420     first_flag_value = ompt_cancel_flag_t_values[1];
421   else if(flags & ompt_cancel_loop)
422     first_flag_value = ompt_cancel_flag_t_values[2];
423   else if(flags & ompt_cancel_taskgroup)
424     first_flag_value = ompt_cancel_flag_t_values[3];
425 
426   if(flags & ompt_cancel_activated)
427     second_flag_value = ompt_cancel_flag_t_values[4];
428   else if(flags & ompt_cancel_detected)
429     second_flag_value = ompt_cancel_flag_t_values[5];
430   else if(flags & ompt_cancel_discarded_task)
431     second_flag_value = ompt_cancel_flag_t_values[6];
432 
433   printf("%" PRIu64 ": ompt_event_cancel: task_data=%" PRIu64 ", flags=%s|%s=%" PRIu32 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, task_data->value, first_flag_value, second_flag_value, flags,  codeptr_ra);
434 }
435 
436 static void
437 on_ompt_callback_implicit_task(
438     ompt_scope_endpoint_t endpoint,
439     ompt_data_t *parallel_data,
440     ompt_data_t *task_data,
441     unsigned int team_size,
442     unsigned int thread_num)
443 {
444   switch(endpoint)
445   {
446     case ompt_scope_begin:
447       if(task_data->ptr)
448         printf("%s\n", "0: task_data initially not null");
449       task_data->value = ompt_get_unique_id();
450       printf("%" PRIu64 ": ompt_event_implicit_task_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", team_size=%" PRIu32 ", thread_num=%" PRIu32 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, team_size, thread_num);
451       break;
452     case ompt_scope_end:
453       printf("%" PRIu64 ": ompt_event_implicit_task_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", team_size=%" PRIu32 ", thread_num=%" PRIu32 "\n", ompt_get_thread_data()->value, (parallel_data)?parallel_data->value:0, task_data->value, team_size, thread_num);
454       break;
455   }
456 }
457 
458 static void
459 on_ompt_callback_lock_init(
460   ompt_mutex_t kind,
461   unsigned int hint,
462   unsigned int impl,
463   ompt_wait_id_t wait_id,
464   const void *codeptr_ra)
465 {
466   switch(kind)
467   {
468     case ompt_mutex_lock:
469       printf("%" PRIu64 ": ompt_event_init_lock: wait_id=%" PRIu64 ", hint=%" PRIu32 ", impl=%" PRIu32 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, hint, impl, codeptr_ra);
470       break;
471     case ompt_mutex_nest_lock:
472       printf("%" PRIu64 ": ompt_event_init_nest_lock: wait_id=%" PRIu64 ", hint=%" PRIu32 ", impl=%" PRIu32 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, hint, impl, codeptr_ra);
473       break;
474     default:
475       break;
476   }
477 }
478 
479 static void
480 on_ompt_callback_lock_destroy(
481   ompt_mutex_t kind,
482   ompt_wait_id_t wait_id,
483   const void *codeptr_ra)
484 {
485   switch(kind)
486   {
487     case ompt_mutex_lock:
488       printf("%" PRIu64 ": ompt_event_destroy_lock: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
489       break;
490     case ompt_mutex_nest_lock:
491       printf("%" PRIu64 ": ompt_event_destroy_nest_lock: wait_id=%" PRIu64 ", codeptr_ra=%p \n", ompt_get_thread_data()->value, wait_id, codeptr_ra);
492       break;
493     default:
494       break;
495   }
496 }
497 
498 static void
499 on_ompt_callback_work(
500   ompt_work_t wstype,
501   ompt_scope_endpoint_t endpoint,
502   ompt_data_t *parallel_data,
503   ompt_data_t *task_data,
504   uint64_t count,
505   const void *codeptr_ra)
506 {
507   switch(endpoint)
508   {
509     case ompt_scope_begin:
510       switch(wstype)
511       {
512         case ompt_work_loop:
513           printf("%" PRIu64 ": ompt_event_loop_begin: parallel_id=%" PRIu64 ", parent_task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
514           break;
515         case ompt_work_sections:
516           printf("%" PRIu64 ": ompt_event_sections_begin: parallel_id=%" PRIu64 ", parent_task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
517           break;
518         case ompt_work_single_executor:
519           printf("%" PRIu64 ": ompt_event_single_in_block_begin: parallel_id=%" PRIu64 ", parent_task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
520           break;
521         case ompt_work_single_other:
522           printf("%" PRIu64 ": ompt_event_single_others_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
523           break;
524         case ompt_work_workshare:
525           //impl
526           break;
527         case ompt_work_distribute:
528           printf("%" PRIu64 ": ompt_event_distribute_begin: parallel_id=%" PRIu64 ", parent_task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
529           break;
530         case ompt_work_taskloop:
531           //impl
532           printf("%" PRIu64 ": ompt_event_taskloop_begin: parallel_id=%" PRIu64 ", parent_task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
533           break;
534       }
535       break;
536     case ompt_scope_end:
537       switch(wstype)
538       {
539         case ompt_work_loop:
540           printf("%" PRIu64 ": ompt_event_loop_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
541           break;
542         case ompt_work_sections:
543           printf("%" PRIu64 ": ompt_event_sections_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
544           break;
545         case ompt_work_single_executor:
546           printf("%" PRIu64 ": ompt_event_single_in_block_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
547           break;
548         case ompt_work_single_other:
549           printf("%" PRIu64 ": ompt_event_single_others_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
550           break;
551         case ompt_work_workshare:
552           //impl
553           break;
554         case ompt_work_distribute:
555           printf("%" PRIu64 ": ompt_event_distribute_end: parallel_id=%" PRIu64 ", parent_task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
556           break;
557         case ompt_work_taskloop:
558           //impl
559           printf("%" PRIu64 ": ompt_event_taskloop_end: parallel_id=%" PRIu64 ", parent_task_id=%" PRIu64 ", codeptr_ra=%p, count=%" PRIu64 "\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra, count);
560           break;
561       }
562       break;
563   }
564 }
565 
566 static void
567 on_ompt_callback_master(
568   ompt_scope_endpoint_t endpoint,
569   ompt_data_t *parallel_data,
570   ompt_data_t *task_data,
571   const void *codeptr_ra)
572 {
573   switch(endpoint)
574   {
575     case ompt_scope_begin:
576       printf("%" PRIu64 ": ompt_event_master_begin: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
577       break;
578     case ompt_scope_end:
579       printf("%" PRIu64 ": ompt_event_master_end: parallel_id=%" PRIu64 ", task_id=%" PRIu64 ", codeptr_ra=%p\n", ompt_get_thread_data()->value, parallel_data->value, task_data->value, codeptr_ra);
580       break;
581   }
582 }
583 
584 static void on_ompt_callback_parallel_begin(
585     ompt_data_t *encountering_task_data,
586     const ompt_frame_t *encountering_task_frame, ompt_data_t *parallel_data,
587     uint32_t requested_team_size, int flag, const void *codeptr_ra) {
588   if(parallel_data->ptr)
589     printf("0: parallel_data initially not null\n");
590   parallel_data->value = ompt_get_unique_id();
591   printf("%" PRIu64 ": ompt_event_parallel_begin: parent_task_id=%" PRIu64
592          ", parent_task_frame.exit=%p, parent_task_frame.reenter=%p, "
593          "parallel_id=%" PRIu64 ", requested_team_size=%" PRIu32
594          ", codeptr_ra=%p, invoker=%d\n",
595          ompt_get_thread_data()->value, encountering_task_data->value,
596          encountering_task_frame->exit_frame.ptr,
597          encountering_task_frame->enter_frame.ptr, parallel_data->value,
598          requested_team_size, codeptr_ra, flag);
599 }
600 
601 static void on_ompt_callback_parallel_end(ompt_data_t *parallel_data,
602                                           ompt_data_t *encountering_task_data,
603                                           int flag, const void *codeptr_ra) {
604   printf("%" PRIu64 ": ompt_event_parallel_end: parallel_id=%" PRIu64
605          ", task_id=%" PRIu64 ", invoker=%d, codeptr_ra=%p\n",
606          ompt_get_thread_data()->value, parallel_data->value,
607          encountering_task_data->value, flag, codeptr_ra);
608 }
609 
610 static void
611 on_ompt_callback_task_create(
612     ompt_data_t *encountering_task_data,
613     const ompt_frame_t *encountering_task_frame,
614     ompt_data_t* new_task_data,
615     int type,
616     int has_dependences,
617     const void *codeptr_ra)
618 {
619   if(new_task_data->ptr)
620     printf("0: new_task_data initially not null\n");
621   new_task_data->value = ompt_get_unique_id();
622   char buffer[2048];
623 
624   format_task_type(type, buffer);
625 
626   //there is no parallel_begin callback for implicit parallel region
627   //thus it is initialized in initial task
628   if(type & ompt_task_initial)
629   {
630     ompt_data_t *parallel_data;
631     ompt_get_parallel_info(0, &parallel_data, NULL);
632     if(parallel_data->ptr)
633       printf("%s\n", "0: parallel_data initially not null");
634     parallel_data->value = ompt_get_unique_id();
635   }
636 
637   printf("%" PRIu64 ": ompt_event_task_create: parent_task_id=%" PRIu64 ", parent_task_frame.exit=%p, parent_task_frame.reenter=%p, new_task_id=%" PRIu64 ", codeptr_ra=%p, task_type=%s=%d, has_dependences=%s\n", ompt_get_thread_data()->value, encountering_task_data ? encountering_task_data->value : 0, encountering_task_frame ? encountering_task_frame->exit_frame.ptr : NULL, encountering_task_frame ? encountering_task_frame->enter_frame.ptr : NULL, new_task_data->value, codeptr_ra, buffer, type, has_dependences ? "yes" : "no");
638 }
639 
640 static void
641 on_ompt_callback_task_schedule(
642     ompt_data_t *first_task_data,
643     ompt_task_status_t prior_task_status,
644     ompt_data_t *second_task_data)
645 {
646   printf("%" PRIu64 ": ompt_event_task_schedule: first_task_id=%" PRIu64 ", second_task_id=%" PRIu64 ", prior_task_status=%s=%d\n", ompt_get_thread_data()->value, first_task_data->value, second_task_data->value, ompt_task_status_t_values[prior_task_status], prior_task_status);
647   if(prior_task_status == ompt_task_complete)
648   {
649     printf("%" PRIu64 ": ompt_event_task_end: task_id=%" PRIu64 "\n", ompt_get_thread_data()->value, first_task_data->value);
650   }
651 }
652 
653 static void
654 on_ompt_callback_task_dependences(
655   ompt_data_t *task_data,
656   const ompt_task_dependence_t *deps,
657   int ndeps)
658 {
659   printf("%" PRIu64 ": ompt_event_task_dependences: task_id=%" PRIu64 ", deps=%p, ndeps=%d\n", ompt_get_thread_data()->value, task_data->value, (void *)deps, ndeps);
660 }
661 
662 static void
663 on_ompt_callback_task_dependence(
664   ompt_data_t *first_task_data,
665   ompt_data_t *second_task_data)
666 {
667   printf("%" PRIu64 ": ompt_event_task_dependence_pair: first_task_id=%" PRIu64 ", second_task_id=%" PRIu64 "\n", ompt_get_thread_data()->value, first_task_data->value, second_task_data->value);
668 }
669 
670 static void
671 on_ompt_callback_thread_begin(
672   ompt_thread_t thread_type,
673   ompt_data_t *thread_data)
674 {
675   if(thread_data->ptr)
676     printf("%s\n", "0: thread_data initially not null");
677   thread_data->value = ompt_get_unique_id();
678   printf("%" PRIu64 ": ompt_event_thread_begin: thread_type=%s=%d, thread_id=%" PRIu64 "\n", ompt_get_thread_data()->value, ompt_thread_t_values[thread_type], thread_type, thread_data->value);
679 }
680 
681 static void
682 on_ompt_callback_thread_end(
683   ompt_data_t *thread_data)
684 {
685   printf("%" PRIu64 ": ompt_event_thread_end: thread_id=%" PRIu64 "\n", ompt_get_thread_data()->value, thread_data->value);
686 }
687 
688 static int
689 on_ompt_callback_control_tool(
690   uint64_t command,
691   uint64_t modifier,
692   void *arg,
693   const void *codeptr_ra)
694 {
695   ompt_frame_t* omptTaskFrame;
696   ompt_get_task_info(0, NULL, (ompt_data_t**) NULL, &omptTaskFrame, NULL, NULL);
697   printf("%" PRIu64 ": ompt_event_control_tool: command=%" PRIu64 ", modifier=%" PRIu64 ", arg=%p, codeptr_ra=%p, current_task_frame.exit=%p, current_task_frame.reenter=%p \n", ompt_get_thread_data()->value, command, modifier, arg, codeptr_ra, omptTaskFrame->exit_frame.ptr, omptTaskFrame->enter_frame.ptr);
698   return 0; //success
699 }
700 
701 #define register_callback_t(name, type)                       \
702 do{                                                           \
703   type f_##name = &on_##name;                                 \
704   if (ompt_set_callback(name, (ompt_callback_t)f_##name) ==   \
705       ompt_set_never)                                         \
706     printf("0: Could not register callback '" #name "'\n");   \
707 }while(0)
708 
709 #define register_callback(name) register_callback_t(name, name##_t)
710 
711 int ompt_initialize(
712   ompt_function_lookup_t lookup,
713   ompt_data_t *tool_data)
714 {
715   ompt_set_callback = (ompt_set_callback_t) lookup("ompt_set_callback");
716   ompt_get_callback = (ompt_get_callback_t) lookup("ompt_get_callback");
717   ompt_get_state = (ompt_get_state_t) lookup("ompt_get_state");
718   ompt_get_task_info = (ompt_get_task_info_t) lookup("ompt_get_task_info");
719   ompt_get_thread_data = (ompt_get_thread_data_t) lookup("ompt_get_thread_data");
720   ompt_get_parallel_info = (ompt_get_parallel_info_t) lookup("ompt_get_parallel_info");
721   ompt_get_unique_id = (ompt_get_unique_id_t) lookup("ompt_get_unique_id");
722 
723   ompt_get_num_procs = (ompt_get_num_procs_t) lookup("ompt_get_num_procs");
724   ompt_get_num_places = (ompt_get_num_places_t) lookup("ompt_get_num_places");
725   ompt_get_place_proc_ids = (ompt_get_place_proc_ids_t) lookup("ompt_get_place_proc_ids");
726   ompt_get_place_num = (ompt_get_place_num_t) lookup("ompt_get_place_num");
727   ompt_get_partition_place_nums = (ompt_get_partition_place_nums_t) lookup("ompt_get_partition_place_nums");
728   ompt_get_proc_id = (ompt_get_proc_id_t) lookup("ompt_get_proc_id");
729   ompt_enumerate_states = (ompt_enumerate_states_t) lookup("ompt_enumerate_states");
730   ompt_enumerate_mutex_impls = (ompt_enumerate_mutex_impls_t) lookup("ompt_enumerate_mutex_impls");
731 
732   register_callback(ompt_callback_mutex_acquire);
733   register_callback_t(ompt_callback_mutex_acquired, ompt_callback_mutex_t);
734   register_callback_t(ompt_callback_mutex_released, ompt_callback_mutex_t);
735   register_callback(ompt_callback_nest_lock);
736   register_callback(ompt_callback_sync_region);
737   register_callback_t(ompt_callback_sync_region_wait, ompt_callback_sync_region_t);
738   register_callback(ompt_callback_control_tool);
739   register_callback(ompt_callback_flush);
740   register_callback(ompt_callback_cancel);
741   register_callback(ompt_callback_implicit_task);
742   register_callback_t(ompt_callback_lock_init, ompt_callback_mutex_acquire_t);
743   register_callback_t(ompt_callback_lock_destroy, ompt_callback_mutex_t);
744   register_callback(ompt_callback_work);
745   register_callback(ompt_callback_master);
746   register_callback(ompt_callback_parallel_begin);
747   register_callback(ompt_callback_parallel_end);
748   register_callback(ompt_callback_task_create);
749   register_callback(ompt_callback_task_schedule);
750   register_callback(ompt_callback_task_dependences);
751   register_callback(ompt_callback_task_dependence);
752   register_callback(ompt_callback_thread_begin);
753   register_callback(ompt_callback_thread_end);
754   printf("0: NULL_POINTER=%p\n", (void*)NULL);
755   return 1; //success
756 }
757 
758 void ompt_finalize(ompt_data_t *tool_data)
759 {
760   printf("0: ompt_event_runtime_shutdown\n");
761 }
762 
763 ompt_start_tool_result_t* ompt_start_tool(
764   unsigned int omp_version,
765   const char *runtime_version)
766 {
767   static ompt_start_tool_result_t ompt_start_tool_result = {&ompt_initialize,&ompt_finalize, 0};
768   return &ompt_start_tool_result;
769 }
770