oacc-profiling.c revision 1.1 1 1.1 mrg /* OpenACC Profiling Interface
2 1.1 mrg
3 1.1 mrg Copyright (C) 2019-2020 Free Software Foundation, Inc.
4 1.1 mrg
5 1.1 mrg Contributed by Mentor, a Siemens Business.
6 1.1 mrg
7 1.1 mrg This file is part of the GNU Offloading and Multi Processing Library
8 1.1 mrg (libgomp).
9 1.1 mrg
10 1.1 mrg Libgomp is free software; you can redistribute it and/or modify it
11 1.1 mrg under the terms of the GNU General Public License as published by
12 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
13 1.1 mrg any later version.
14 1.1 mrg
15 1.1 mrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
16 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 1.1 mrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 1.1 mrg more details.
19 1.1 mrg
20 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
21 1.1 mrg permissions described in the GCC Runtime Library Exception, version
22 1.1 mrg 3.1, as published by the Free Software Foundation.
23 1.1 mrg
24 1.1 mrg You should have received a copy of the GNU General Public License and
25 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
26 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 1.1 mrg <http://www.gnu.org/licenses/>. */
28 1.1 mrg
29 1.1 mrg #define _GNU_SOURCE
30 1.1 mrg #include "libgomp.h"
31 1.1 mrg #include "oacc-int.h"
32 1.1 mrg #include "secure_getenv.h"
33 1.1 mrg #include "acc_prof.h"
34 1.1 mrg #include <assert.h>
35 1.1 mrg #ifdef HAVE_STRING_H
36 1.1 mrg # include <string.h>
37 1.1 mrg #endif
38 1.1 mrg #ifdef PLUGIN_SUPPORT
39 1.1 mrg # include <dlfcn.h>
40 1.1 mrg #endif
41 1.1 mrg
42 1.1 mrg #define STATIC_ASSERT(expr) _Static_assert (expr, "!(" #expr ")")
43 1.1 mrg
44 1.1 mrg /* Statically assert that the layout of the common fields in the
45 1.1 mrg 'acc_event_info' variants matches. */
46 1.1 mrg /* 'event_type' */
47 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, event_type)
48 1.1 mrg == offsetof (acc_event_info, data_event.event_type));
49 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.event_type)
50 1.1 mrg == offsetof (acc_event_info, launch_event.event_type));
51 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.event_type)
52 1.1 mrg == offsetof (acc_event_info, other_event.event_type));
53 1.1 mrg /* 'valid_bytes' */
54 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.valid_bytes)
55 1.1 mrg == offsetof (acc_event_info, launch_event.valid_bytes));
56 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.valid_bytes)
57 1.1 mrg == offsetof (acc_event_info, other_event.valid_bytes));
58 1.1 mrg /* 'parent_construct' */
59 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.parent_construct)
60 1.1 mrg == offsetof (acc_event_info, launch_event.parent_construct));
61 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.parent_construct)
62 1.1 mrg == offsetof (acc_event_info, other_event.parent_construct));
63 1.1 mrg /* 'implicit' */
64 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.implicit)
65 1.1 mrg == offsetof (acc_event_info, launch_event.implicit));
66 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.implicit)
67 1.1 mrg == offsetof (acc_event_info, other_event.implicit));
68 1.1 mrg /* 'tool_info' */
69 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.tool_info)
70 1.1 mrg == offsetof (acc_event_info, launch_event.tool_info));
71 1.1 mrg STATIC_ASSERT (offsetof (acc_event_info, data_event.tool_info)
72 1.1 mrg == offsetof (acc_event_info, other_event.tool_info));
73 1.1 mrg
74 1.1 mrg struct goacc_prof_callback_entry
75 1.1 mrg {
76 1.1 mrg acc_prof_callback cb;
77 1.1 mrg int ref;
78 1.1 mrg bool enabled;
79 1.1 mrg struct goacc_prof_callback_entry *next;
80 1.1 mrg };
81 1.1 mrg
82 1.1 mrg /* Use a separate flag to minimize run-time performance impact for the (very
83 1.1 mrg common) case that profiling is not enabled.
84 1.1 mrg
85 1.1 mrg Once enabled, we're not going to disable this anymore, anywhere. We
86 1.1 mrg probably could, by adding appropriate logic to 'acc_prof_register',
87 1.1 mrg 'acc_prof_unregister'. */
88 1.1 mrg bool goacc_prof_enabled = false;
89 1.1 mrg
90 1.1 mrg /* Global state for registered callbacks.
91 1.1 mrg 'goacc_prof_callbacks_enabled[acc_ev_none]' acts as a global toggle. */
92 1.1 mrg static bool goacc_prof_callbacks_enabled[acc_ev_last];
93 1.1 mrg static struct goacc_prof_callback_entry *goacc_prof_callback_entries[acc_ev_last];
94 1.1 mrg /* Lock used to protect access to 'goacc_prof_callbacks_enabled', and
95 1.1 mrg 'goacc_prof_callback_entries'. */
96 1.1 mrg static gomp_mutex_t goacc_prof_lock;
97 1.1 mrg
98 1.1 mrg void
99 1.1 mrg goacc_profiling_initialize (void)
100 1.1 mrg {
101 1.1 mrg gomp_mutex_init (&goacc_prof_lock);
102 1.1 mrg
103 1.1 mrg /* Initially, all callbacks for all events are enabled. */
104 1.1 mrg for (int i = 0; i < acc_ev_last; ++i)
105 1.1 mrg goacc_prof_callbacks_enabled[i] = true;
106 1.1 mrg
107 1.1 mrg
108 1.1 mrg #ifdef PLUGIN_SUPPORT
109 1.1 mrg char *acc_proflibs = secure_getenv ("ACC_PROFLIB");
110 1.1 mrg while (acc_proflibs != NULL && acc_proflibs[0] != '\0')
111 1.1 mrg {
112 1.1 mrg char *acc_proflibs_sep = strchr (acc_proflibs, ';');
113 1.1 mrg char *acc_proflib;
114 1.1 mrg if (acc_proflibs_sep == acc_proflibs)
115 1.1 mrg {
116 1.1 mrg /* Stray ';' separator: make sure we don't 'dlopen' the main
117 1.1 mrg program. */
118 1.1 mrg acc_proflib = NULL;
119 1.1 mrg }
120 1.1 mrg else
121 1.1 mrg {
122 1.1 mrg if (acc_proflibs_sep != NULL)
123 1.1 mrg {
124 1.1 mrg /* Single out the first library. */
125 1.1 mrg acc_proflib = gomp_malloc (acc_proflibs_sep - acc_proflibs + 1);
126 1.1 mrg memcpy (acc_proflib, acc_proflibs,
127 1.1 mrg acc_proflibs_sep - acc_proflibs);
128 1.1 mrg acc_proflib[acc_proflibs_sep - acc_proflibs] = '\0';
129 1.1 mrg }
130 1.1 mrg else
131 1.1 mrg {
132 1.1 mrg /* No ';' separator, so only one library. */
133 1.1 mrg acc_proflib = acc_proflibs;
134 1.1 mrg }
135 1.1 mrg
136 1.1 mrg gomp_debug (0, "%s: dlopen (\"%s\")\n", __FUNCTION__, acc_proflib);
137 1.1 mrg void *dl_handle = dlopen (acc_proflib, RTLD_LAZY);
138 1.1 mrg if (dl_handle != NULL)
139 1.1 mrg {
140 1.1 mrg typeof (&acc_register_library) a_r_l
141 1.1 mrg = dlsym (dl_handle, "acc_register_library");
142 1.1 mrg if (a_r_l == NULL)
143 1.1 mrg goto dl_fail;
144 1.1 mrg gomp_debug (0, " %s: calling %s:acc_register_library\n",
145 1.1 mrg __FUNCTION__, acc_proflib);
146 1.1 mrg a_r_l (acc_prof_register, acc_prof_unregister,
147 1.1 mrg acc_prof_lookup);
148 1.1 mrg }
149 1.1 mrg else
150 1.1 mrg {
151 1.1 mrg dl_fail:
152 1.1 mrg gomp_error ("while loading ACC_PROFLIB \"%s\": %s",
153 1.1 mrg acc_proflib, dlerror ());
154 1.1 mrg if (dl_handle != NULL)
155 1.1 mrg {
156 1.1 mrg int err = dlclose (dl_handle);
157 1.1 mrg dl_handle = NULL;
158 1.1 mrg if (err != 0)
159 1.1 mrg goto dl_fail;
160 1.1 mrg }
161 1.1 mrg }
162 1.1 mrg }
163 1.1 mrg
164 1.1 mrg if (acc_proflib != acc_proflibs)
165 1.1 mrg {
166 1.1 mrg free (acc_proflib);
167 1.1 mrg
168 1.1 mrg acc_proflibs = acc_proflibs_sep + 1;
169 1.1 mrg }
170 1.1 mrg else
171 1.1 mrg acc_proflibs = NULL;
172 1.1 mrg }
173 1.1 mrg #endif /* PLUGIN_SUPPORT */
174 1.1 mrg }
175 1.1 mrg
176 1.1 mrg void
177 1.1 mrg acc_prof_register (acc_event_t ev, acc_prof_callback cb, acc_register_t reg)
178 1.1 mrg {
179 1.1 mrg gomp_debug (0, "%s: ev=%d, cb=%p, reg=%d\n",
180 1.1 mrg __FUNCTION__, (int) ev, (void *) cb, (int) reg);
181 1.1 mrg
182 1.1 mrg
183 1.1 mrg /* For any events to be dispatched, the user first has to register a
184 1.1 mrg callback, which makes this here a good place for enabling the whole
185 1.1 mrg machinery. */
186 1.1 mrg if (!GOACC_PROF_ENABLED)
187 1.1 mrg __atomic_store_n (&goacc_prof_enabled, true, MEMMODEL_RELEASE);
188 1.1 mrg
189 1.1 mrg
190 1.1 mrg enum
191 1.1 mrg {
192 1.1 mrg EVENT_KIND_BOGUS,
193 1.1 mrg EVENT_KIND_NORMAL,
194 1.1 mrg /* As end events invoke callbacks in the reverse order, we register these
195 1.1 mrg in the reverse order here. */
196 1.1 mrg EVENT_KIND_END,
197 1.1 mrg } event_kind = EVENT_KIND_BOGUS;
198 1.1 mrg switch (ev)
199 1.1 mrg {
200 1.1 mrg case acc_ev_none:
201 1.1 mrg case acc_ev_device_init_start:
202 1.1 mrg case acc_ev_device_shutdown_start:
203 1.1 mrg case acc_ev_runtime_shutdown:
204 1.1 mrg case acc_ev_create:
205 1.1 mrg case acc_ev_delete:
206 1.1 mrg case acc_ev_alloc:
207 1.1 mrg case acc_ev_free:
208 1.1 mrg case acc_ev_enter_data_start:
209 1.1 mrg case acc_ev_exit_data_start:
210 1.1 mrg case acc_ev_update_start:
211 1.1 mrg case acc_ev_compute_construct_start:
212 1.1 mrg case acc_ev_enqueue_launch_start:
213 1.1 mrg case acc_ev_enqueue_upload_start:
214 1.1 mrg case acc_ev_enqueue_download_start:
215 1.1 mrg case acc_ev_wait_start:
216 1.1 mrg event_kind = EVENT_KIND_NORMAL;
217 1.1 mrg break;
218 1.1 mrg case acc_ev_device_init_end:
219 1.1 mrg case acc_ev_device_shutdown_end:
220 1.1 mrg case acc_ev_enter_data_end:
221 1.1 mrg case acc_ev_exit_data_end:
222 1.1 mrg case acc_ev_update_end:
223 1.1 mrg case acc_ev_compute_construct_end:
224 1.1 mrg case acc_ev_enqueue_launch_end:
225 1.1 mrg case acc_ev_enqueue_upload_end:
226 1.1 mrg case acc_ev_enqueue_download_end:
227 1.1 mrg case acc_ev_wait_end:
228 1.1 mrg event_kind = EVENT_KIND_END;
229 1.1 mrg break;
230 1.1 mrg case acc_ev_last:
231 1.1 mrg break;
232 1.1 mrg }
233 1.1 mrg if (event_kind == EVENT_KIND_BOGUS)
234 1.1 mrg {
235 1.1 mrg /* Silently ignore. */
236 1.1 mrg gomp_debug (0, " ignoring request for bogus 'acc_event_t'\n");
237 1.1 mrg return;
238 1.1 mrg }
239 1.1 mrg
240 1.1 mrg bool bogus = true;
241 1.1 mrg switch (reg)
242 1.1 mrg {
243 1.1 mrg case acc_reg:
244 1.1 mrg case acc_toggle:
245 1.1 mrg case acc_toggle_per_thread:
246 1.1 mrg bogus = false;
247 1.1 mrg break;
248 1.1 mrg }
249 1.1 mrg if (bogus)
250 1.1 mrg {
251 1.1 mrg /* Silently ignore. */
252 1.1 mrg gomp_debug (0, " ignoring request with bogus 'acc_register_t'\n");
253 1.1 mrg return;
254 1.1 mrg }
255 1.1 mrg
256 1.1 mrg /* Special cases. */
257 1.1 mrg if (reg == acc_toggle)
258 1.1 mrg {
259 1.1 mrg if (cb == NULL)
260 1.1 mrg {
261 1.1 mrg gomp_debug (0, " globally enabling callbacks\n");
262 1.1 mrg gomp_mutex_lock (&goacc_prof_lock);
263 1.1 mrg /* For 'acc_ev_none', this acts as a global toggle. */
264 1.1 mrg goacc_prof_callbacks_enabled[ev] = true;
265 1.1 mrg gomp_mutex_unlock (&goacc_prof_lock);
266 1.1 mrg return;
267 1.1 mrg }
268 1.1 mrg else if (ev == acc_ev_none && cb != NULL)
269 1.1 mrg {
270 1.1 mrg gomp_debug (0, " ignoring request\n");
271 1.1 mrg return;
272 1.1 mrg }
273 1.1 mrg }
274 1.1 mrg else if (reg == acc_toggle_per_thread)
275 1.1 mrg {
276 1.1 mrg if (ev == acc_ev_none && cb == NULL)
277 1.1 mrg {
278 1.1 mrg gomp_debug (0, " thread: enabling callbacks\n");
279 1.1 mrg goacc_lazy_initialize ();
280 1.1 mrg struct goacc_thread *thr = goacc_thread ();
281 1.1 mrg thr->prof_callbacks_enabled = true;
282 1.1 mrg return;
283 1.1 mrg }
284 1.1 mrg /* Silently ignore. */
285 1.1 mrg gomp_debug (0, " ignoring bogus request\n");
286 1.1 mrg return;
287 1.1 mrg }
288 1.1 mrg
289 1.1 mrg gomp_mutex_lock (&goacc_prof_lock);
290 1.1 mrg
291 1.1 mrg struct goacc_prof_callback_entry *it, *it_p;
292 1.1 mrg it = goacc_prof_callback_entries[ev];
293 1.1 mrg it_p = NULL;
294 1.1 mrg while (it)
295 1.1 mrg {
296 1.1 mrg if (it->cb == cb)
297 1.1 mrg break;
298 1.1 mrg it_p = it;
299 1.1 mrg it = it->next;
300 1.1 mrg }
301 1.1 mrg
302 1.1 mrg switch (reg)
303 1.1 mrg {
304 1.1 mrg case acc_reg:
305 1.1 mrg /* If we already have this callback registered, just increment its
306 1.1 mrg reference count. */
307 1.1 mrg if (it != NULL)
308 1.1 mrg {
309 1.1 mrg it->ref++;
310 1.1 mrg gomp_debug (0, " already registered;"
311 1.1 mrg " incrementing reference count to: %d\n", it->ref);
312 1.1 mrg }
313 1.1 mrg else
314 1.1 mrg {
315 1.1 mrg struct goacc_prof_callback_entry *e
316 1.1 mrg = gomp_malloc (sizeof (struct goacc_prof_callback_entry));
317 1.1 mrg e->cb = cb;
318 1.1 mrg e->ref = 1;
319 1.1 mrg e->enabled = true;
320 1.1 mrg bool prepend = (event_kind == EVENT_KIND_END);
321 1.1 mrg /* If we don't have any callback registered yet, also use the
322 1.1 mrg 'prepend' code path. */
323 1.1 mrg if (it_p == NULL)
324 1.1 mrg prepend = true;
325 1.1 mrg if (prepend)
326 1.1 mrg {
327 1.1 mrg gomp_debug (0, " prepending\n");
328 1.1 mrg e->next = goacc_prof_callback_entries[ev];
329 1.1 mrg goacc_prof_callback_entries[ev] = e;
330 1.1 mrg }
331 1.1 mrg else
332 1.1 mrg {
333 1.1 mrg gomp_debug (0, " appending\n");
334 1.1 mrg e->next = NULL;
335 1.1 mrg it_p->next = e;
336 1.1 mrg }
337 1.1 mrg }
338 1.1 mrg break;
339 1.1 mrg
340 1.1 mrg case acc_toggle:
341 1.1 mrg if (it == NULL)
342 1.1 mrg {
343 1.1 mrg gomp_debug (0, " ignoring request: is not registered\n");
344 1.1 mrg break;
345 1.1 mrg }
346 1.1 mrg else
347 1.1 mrg {
348 1.1 mrg gomp_debug (0, " enabling\n");
349 1.1 mrg it->enabled = true;
350 1.1 mrg }
351 1.1 mrg break;
352 1.1 mrg
353 1.1 mrg case acc_toggle_per_thread:
354 1.1 mrg __builtin_unreachable ();
355 1.1 mrg }
356 1.1 mrg
357 1.1 mrg gomp_mutex_unlock (&goacc_prof_lock);
358 1.1 mrg }
359 1.1 mrg
360 1.1 mrg void
361 1.1 mrg acc_prof_unregister (acc_event_t ev, acc_prof_callback cb, acc_register_t reg)
362 1.1 mrg {
363 1.1 mrg gomp_debug (0, "%s: ev=%d, cb=%p, reg=%d\n",
364 1.1 mrg __FUNCTION__, (int) ev, (void *) cb, (int) reg);
365 1.1 mrg
366 1.1 mrg /* If profiling is not enabled, there cannot be anything to unregister. */
367 1.1 mrg if (!GOACC_PROF_ENABLED)
368 1.1 mrg return;
369 1.1 mrg
370 1.1 mrg if (ev < acc_ev_none
371 1.1 mrg || ev >= acc_ev_last)
372 1.1 mrg {
373 1.1 mrg /* Silently ignore. */
374 1.1 mrg gomp_debug (0, " ignoring request for bogus 'acc_event_t'\n");
375 1.1 mrg return;
376 1.1 mrg }
377 1.1 mrg
378 1.1 mrg bool bogus = true;
379 1.1 mrg switch (reg)
380 1.1 mrg {
381 1.1 mrg case acc_reg:
382 1.1 mrg case acc_toggle:
383 1.1 mrg case acc_toggle_per_thread:
384 1.1 mrg bogus = false;
385 1.1 mrg break;
386 1.1 mrg }
387 1.1 mrg if (bogus)
388 1.1 mrg {
389 1.1 mrg /* Silently ignore. */
390 1.1 mrg gomp_debug (0, " ignoring request with bogus 'acc_register_t'\n");
391 1.1 mrg return;
392 1.1 mrg }
393 1.1 mrg
394 1.1 mrg /* Special cases. */
395 1.1 mrg if (reg == acc_toggle)
396 1.1 mrg {
397 1.1 mrg if (cb == NULL)
398 1.1 mrg {
399 1.1 mrg gomp_debug (0, " globally disabling callbacks\n");
400 1.1 mrg gomp_mutex_lock (&goacc_prof_lock);
401 1.1 mrg /* For 'acc_ev_none', this acts as a global toggle. */
402 1.1 mrg goacc_prof_callbacks_enabled[ev] = false;
403 1.1 mrg gomp_mutex_unlock (&goacc_prof_lock);
404 1.1 mrg return;
405 1.1 mrg }
406 1.1 mrg else if (ev == acc_ev_none && cb != NULL)
407 1.1 mrg {
408 1.1 mrg gomp_debug (0, " ignoring request\n");
409 1.1 mrg return;
410 1.1 mrg }
411 1.1 mrg }
412 1.1 mrg else if (reg == acc_toggle_per_thread)
413 1.1 mrg {
414 1.1 mrg if (ev == acc_ev_none && cb == NULL)
415 1.1 mrg {
416 1.1 mrg gomp_debug (0, " thread: disabling callbacks\n");
417 1.1 mrg goacc_lazy_initialize ();
418 1.1 mrg struct goacc_thread *thr = goacc_thread ();
419 1.1 mrg thr->prof_callbacks_enabled = false;
420 1.1 mrg return;
421 1.1 mrg }
422 1.1 mrg /* Silently ignore. */
423 1.1 mrg gomp_debug (0, " ignoring bogus request\n");
424 1.1 mrg return;
425 1.1 mrg }
426 1.1 mrg
427 1.1 mrg gomp_mutex_lock (&goacc_prof_lock);
428 1.1 mrg
429 1.1 mrg struct goacc_prof_callback_entry *it, *it_p;
430 1.1 mrg it = goacc_prof_callback_entries[ev];
431 1.1 mrg it_p = NULL;
432 1.1 mrg while (it)
433 1.1 mrg {
434 1.1 mrg if (it->cb == cb)
435 1.1 mrg break;
436 1.1 mrg it_p = it;
437 1.1 mrg it = it->next;
438 1.1 mrg }
439 1.1 mrg
440 1.1 mrg switch (reg)
441 1.1 mrg {
442 1.1 mrg case acc_reg:
443 1.1 mrg if (it == NULL)
444 1.1 mrg {
445 1.1 mrg /* Silently ignore. */
446 1.1 mrg gomp_debug (0, " ignoring bogus request: is not registered\n");
447 1.1 mrg break;
448 1.1 mrg }
449 1.1 mrg it->ref--;
450 1.1 mrg gomp_debug (0, " decrementing reference count to: %d\n", it->ref);
451 1.1 mrg if (it->ref == 0)
452 1.1 mrg {
453 1.1 mrg if (it_p == NULL)
454 1.1 mrg goacc_prof_callback_entries[ev] = it->next;
455 1.1 mrg else
456 1.1 mrg it_p->next = it->next;
457 1.1 mrg free (it);
458 1.1 mrg }
459 1.1 mrg break;
460 1.1 mrg
461 1.1 mrg case acc_toggle:
462 1.1 mrg if (it == NULL)
463 1.1 mrg {
464 1.1 mrg gomp_debug (0, " ignoring request: is not registered\n");
465 1.1 mrg break;
466 1.1 mrg }
467 1.1 mrg else
468 1.1 mrg {
469 1.1 mrg gomp_debug (0, " disabling\n");
470 1.1 mrg it->enabled = false;
471 1.1 mrg }
472 1.1 mrg break;
473 1.1 mrg
474 1.1 mrg case acc_toggle_per_thread:
475 1.1 mrg __builtin_unreachable ();
476 1.1 mrg }
477 1.1 mrg
478 1.1 mrg gomp_mutex_unlock (&goacc_prof_lock);
479 1.1 mrg }
480 1.1 mrg
481 1.1 mrg acc_query_fn
482 1.1 mrg acc_prof_lookup (const char *name)
483 1.1 mrg {
484 1.1 mrg gomp_debug (0, "%s (%s)\n",
485 1.1 mrg __FUNCTION__, name ?: "NULL");
486 1.1 mrg
487 1.1 mrg return NULL;
488 1.1 mrg }
489 1.1 mrg
490 1.1 mrg void
491 1.1 mrg acc_register_library (acc_prof_reg reg, acc_prof_reg unreg,
492 1.1 mrg acc_prof_lookup_func lookup)
493 1.1 mrg {
494 1.1 mrg gomp_fatal ("TODO");
495 1.1 mrg }
496 1.1 mrg
497 1.1 mrg /* Prepare to dispatch events? */
498 1.1 mrg
499 1.1 mrg bool
500 1.1 mrg _goacc_profiling_dispatch_p (bool check_not_nested_p)
501 1.1 mrg {
502 1.1 mrg gomp_debug (0, "%s\n", __FUNCTION__);
503 1.1 mrg
504 1.1 mrg bool ret;
505 1.1 mrg
506 1.1 mrg struct goacc_thread *thr = goacc_thread ();
507 1.1 mrg if (__builtin_expect (thr == NULL, false))
508 1.1 mrg {
509 1.1 mrg /* If we don't have any per-thread state yet, that means that per-thread
510 1.1 mrg callback dispatch has not been explicitly disabled (which only a call
511 1.1 mrg to 'acc_prof_unregister' with 'acc_toggle_per_thread' would do, and
512 1.1 mrg that would have allocated per-thread state via
513 1.1 mrg 'goacc_lazy_initialize'); initially, all callbacks for all events are
514 1.1 mrg enabled. */
515 1.1 mrg gomp_debug (0, " %s: don't have any per-thread state yet\n", __FUNCTION__);
516 1.1 mrg }
517 1.1 mrg else
518 1.1 mrg {
519 1.1 mrg if (check_not_nested_p)
520 1.1 mrg {
521 1.1 mrg /* No nesting. */
522 1.1 mrg assert (thr->prof_info == NULL);
523 1.1 mrg assert (thr->api_info == NULL);
524 1.1 mrg }
525 1.1 mrg
526 1.1 mrg if (__builtin_expect (!thr->prof_callbacks_enabled, true))
527 1.1 mrg {
528 1.1 mrg gomp_debug (0, " %s: disabled for this thread\n", __FUNCTION__);
529 1.1 mrg ret = false;
530 1.1 mrg goto out;
531 1.1 mrg }
532 1.1 mrg }
533 1.1 mrg
534 1.1 mrg gomp_mutex_lock (&goacc_prof_lock);
535 1.1 mrg
536 1.1 mrg /* 'goacc_prof_callbacks_enabled[acc_ev_none]' acts as a global toggle. */
537 1.1 mrg if (__builtin_expect (!goacc_prof_callbacks_enabled[acc_ev_none], true))
538 1.1 mrg {
539 1.1 mrg gomp_debug (0, " %s: disabled globally\n", __FUNCTION__);
540 1.1 mrg ret = false;
541 1.1 mrg goto out_unlock;
542 1.1 mrg }
543 1.1 mrg else
544 1.1 mrg ret = true;
545 1.1 mrg
546 1.1 mrg out_unlock:
547 1.1 mrg gomp_mutex_unlock (&goacc_prof_lock);
548 1.1 mrg
549 1.1 mrg out:
550 1.1 mrg return ret;
551 1.1 mrg }
552 1.1 mrg
553 1.1 mrg /* Set up to dispatch events? */
554 1.1 mrg
555 1.1 mrg bool
556 1.1 mrg _goacc_profiling_setup_p (struct goacc_thread *thr,
557 1.1 mrg acc_prof_info *prof_info, acc_api_info *api_info)
558 1.1 mrg {
559 1.1 mrg gomp_debug (0, "%s (%p)\n", __FUNCTION__, thr);
560 1.1 mrg
561 1.1 mrg /* If we don't have any per-thread state yet, we can't register 'prof_info'
562 1.1 mrg and 'api_info'. */
563 1.1 mrg if (__builtin_expect (thr == NULL, false))
564 1.1 mrg {
565 1.1 mrg gomp_debug (0, "Can't dispatch OpenACC Profiling Interface events for"
566 1.1 mrg " the current call, construct, or directive\n");
567 1.1 mrg return false;
568 1.1 mrg }
569 1.1 mrg
570 1.1 mrg if (thr->prof_info != NULL)
571 1.1 mrg {
572 1.1 mrg /* Profiling has already been set up for an outer construct. In this
573 1.1 mrg case, we continue to use the existing information, and thus return
574 1.1 mrg 'false' here.
575 1.1 mrg
576 1.1 mrg This can happen, for example, for an 'enter data' directive, which
577 1.1 mrg sets up profiling, then calls into 'acc_copyin', which should not
578 1.1 mrg again set up profiling, should not overwrite the existing
579 1.1 mrg information. */
580 1.1 mrg return false;
581 1.1 mrg }
582 1.1 mrg
583 1.1 mrg thr->prof_info = prof_info;
584 1.1 mrg thr->api_info = api_info;
585 1.1 mrg
586 1.1 mrg /* Fill in some defaults. */
587 1.1 mrg
588 1.1 mrg prof_info->event_type = -1; /* Must be set later. */
589 1.1 mrg prof_info->valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
590 1.1 mrg prof_info->version = _ACC_PROF_INFO_VERSION;
591 1.1 mrg if (thr->dev)
592 1.1 mrg {
593 1.1 mrg prof_info->device_type = acc_device_type (thr->dev->type);
594 1.1 mrg prof_info->device_number = thr->dev->target_id;
595 1.1 mrg }
596 1.1 mrg else
597 1.1 mrg {
598 1.1 mrg prof_info->device_type = -1;
599 1.1 mrg prof_info->device_number = -1;
600 1.1 mrg }
601 1.1 mrg prof_info->thread_id = -1;
602 1.1 mrg prof_info->async = acc_async_sync;
603 1.1 mrg prof_info->async_queue = prof_info->async;
604 1.1 mrg prof_info->src_file = NULL;
605 1.1 mrg prof_info->func_name = NULL;
606 1.1 mrg prof_info->line_no = -1;
607 1.1 mrg prof_info->end_line_no = -1;
608 1.1 mrg prof_info->func_line_no = -1;
609 1.1 mrg prof_info->func_end_line_no = -1;
610 1.1 mrg
611 1.1 mrg api_info->device_api = acc_device_api_none;
612 1.1 mrg api_info->valid_bytes = _ACC_API_INFO_VALID_BYTES;
613 1.1 mrg api_info->device_type = prof_info->device_type;
614 1.1 mrg api_info->vendor = -1;
615 1.1 mrg api_info->device_handle = NULL;
616 1.1 mrg api_info->context_handle = NULL;
617 1.1 mrg api_info->async_handle = NULL;
618 1.1 mrg
619 1.1 mrg return true;
620 1.1 mrg }
621 1.1 mrg
622 1.1 mrg /* Dispatch events.
623 1.1 mrg
624 1.1 mrg This must only be called if 'GOACC_PROFILING_DISPATCH_P' or
625 1.1 mrg 'GOACC_PROFILING_SETUP_P' returned a true result. */
626 1.1 mrg
627 1.1 mrg void
628 1.1 mrg goacc_profiling_dispatch (acc_prof_info *prof_info, acc_event_info *event_info,
629 1.1 mrg acc_api_info *apt_info)
630 1.1 mrg {
631 1.1 mrg acc_event_t event_type = event_info->event_type;
632 1.1 mrg gomp_debug (0, "%s: event_type=%d\n", __FUNCTION__, (int) event_type);
633 1.1 mrg assert (event_type > acc_ev_none
634 1.1 mrg && event_type < acc_ev_last);
635 1.1 mrg
636 1.1 mrg gomp_mutex_lock (&goacc_prof_lock);
637 1.1 mrg
638 1.1 mrg if (!goacc_prof_callbacks_enabled[event_type])
639 1.1 mrg {
640 1.1 mrg gomp_debug (0, " disabled for this event type\n");
641 1.1 mrg
642 1.1 mrg goto out_unlock;
643 1.1 mrg }
644 1.1 mrg
645 1.1 mrg for (struct goacc_prof_callback_entry *e
646 1.1 mrg = goacc_prof_callback_entries[event_type];
647 1.1 mrg e != NULL;
648 1.1 mrg e = e->next)
649 1.1 mrg {
650 1.1 mrg if (!e->enabled)
651 1.1 mrg {
652 1.1 mrg gomp_debug (0, " disabled for callback %p\n", e->cb);
653 1.1 mrg continue;
654 1.1 mrg }
655 1.1 mrg
656 1.1 mrg gomp_debug (0, " calling callback %p\n", e->cb);
657 1.1 mrg e->cb (prof_info, event_info, apt_info);
658 1.1 mrg }
659 1.1 mrg
660 1.1 mrg out_unlock:
661 1.1 mrg gomp_mutex_unlock (&goacc_prof_lock);
662 1.1 mrg }
663