1 1.1 mrg /* OpenACC Profiling Interface 2 1.1 mrg 3 1.1.1.2 mrg Copyright (C) 2019-2022 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