1from __future__ import print_function 2import ompdModule 3from ompd_handles import ompd_thread, ompd_task, ompd_parallel 4import gdb 5import sys 6import traceback 7from enum import Enum 8 9 10class ompd_scope(Enum): 11 ompd_scope_global = 1 12 ompd_scope_address_space = 2 13 ompd_scope_thread = 3 14 ompd_scope_parallel = 4 15 ompd_scope_implicit_task = 5 16 ompd_scope_task = 6 17 18 19class ompd_address_space(object): 20 def __init__(self): 21 """Initializes an ompd_address_space object by calling ompd_initialize 22 in ompdModule.c 23 """ 24 self.addr_space = ompdModule.call_ompd_initialize() 25 # maps thread_num (thread id given by gdb) to ompd_thread object with thread handle 26 self.threads = {} 27 self.states = None 28 self.icv_map = None 29 self.ompd_tool_test_bp = None 30 self.scope_map = { 31 1: "global", 32 2: "address_space", 33 3: "thread", 34 4: "parallel", 35 5: "implicit_task", 36 6: "task", 37 } 38 self.sched_map = {1: "static", 2: "dynamic", 3: "guided", 4: "auto"} 39 gdb.events.stop.connect(self.handle_stop_event) 40 self.new_thread_breakpoint = gdb.Breakpoint( 41 "ompd_bp_thread_begin", internal=True 42 ) 43 tool_break_symbol = gdb.lookup_global_symbol("ompd_tool_break") 44 if tool_break_symbol is not None: 45 self.ompd_tool_test_bp = gdb.Breakpoint("ompd_tool_break", internal=True) 46 47 def handle_stop_event(self, event): 48 """Sets a breakpoint at different events, e.g. when a new OpenMP 49 thread is created. 50 """ 51 if isinstance(event, gdb.BreakpointEvent): 52 # check if breakpoint has already been hit 53 if self.new_thread_breakpoint in event.breakpoints: 54 self.add_thread() 55 gdb.execute("continue") 56 return 57 elif ( 58 self.ompd_tool_test_bp is not None 59 and self.ompd_tool_test_bp in event.breakpoints 60 ): 61 try: 62 self.compare_ompt_data() 63 gdb.execute("continue") 64 except (): 65 traceback.print_exc() 66 elif isinstance(event, gdb.SignalEvent): 67 # TODO: what do we need to do on SIGNALS? 68 pass 69 else: 70 # TODO: probably not possible? 71 pass 72 73 def get_icv_map(self): 74 """Fills ICV map.""" 75 self.icv_map = {} 76 current = 0 77 more = 1 78 while more > 0: 79 tup = ompdModule.call_ompd_enumerate_icvs(self.addr_space, current) 80 (current, next_icv, next_scope, more) = tup 81 self.icv_map[next_icv] = (current, next_scope, self.scope_map[next_scope]) 82 print("Initialized ICV map successfully for checking OMP API values.") 83 84 def compare_ompt_data(self): 85 """Compares OMPT tool data about parallel region to data returned by OMPD functions.""" 86 # make sure all threads and states are set 87 self.list_threads(False) 88 89 thread_id = gdb.selected_thread().ptid[1] 90 curr_thread = self.get_curr_thread() 91 92 # check if current thread is LWP thread; return if "ompd_rc_unavailable" 93 thread_handle = ompdModule.get_thread_handle(thread_id, self.addr_space) 94 if thread_handle == -1: 95 print("Skipping OMPT-OMPD checks for non-LWP thread.") 96 return 97 98 print("Comparing OMPT data to OMPD data...") 99 field_names = [i.name for i in gdb.parse_and_eval("thread_data").type.fields()] 100 thread_data = gdb.parse_and_eval("thread_data") 101 102 if self.icv_map is None: 103 self.get_icv_map() 104 105 # compare state values 106 if "ompt_state" in field_names: 107 if self.states is None: 108 self.enumerate_states() 109 ompt_state = str(thread_data["ompt_state"]) 110 ompd_state = str(self.states[curr_thread.get_state()[0]]) 111 if ompt_state != ompd_state: 112 print( 113 "OMPT-OMPD mismatch: ompt_state (%s) does not match OMPD state (%s)!" 114 % (ompt_state, ompd_state) 115 ) 116 117 # compare wait_id values 118 if "ompt_wait_id" in field_names: 119 ompt_wait_id = thread_data["ompt_wait_id"] 120 ompd_wait_id = curr_thread.get_state()[1] 121 if ompt_wait_id != ompd_wait_id: 122 print( 123 "OMPT-OMPD mismatch: ompt_wait_id (%d) does not match OMPD wait id (%d)!" 124 % (ompt_wait_id, ompd_wait_id) 125 ) 126 127 # compare thread id 128 if "omp_thread_num" in field_names and "thread-num-var" in self.icv_map: 129 ompt_thread_num = thread_data["omp_thread_num"] 130 icv_value = ompdModule.call_ompd_get_icv_from_scope( 131 curr_thread.thread_handle, 132 self.icv_map["thread-num-var"][1], 133 self.icv_map["thread-num-var"][0], 134 ) 135 if ompt_thread_num != icv_value: 136 print( 137 "OMPT-OMPD mismatch: omp_thread_num (%d) does not match OMPD thread num according to ICVs (%d)!" 138 % (ompt_thread_num, icv_value) 139 ) 140 141 # compare thread data 142 if "ompt_thread_data" in field_names: 143 ompt_thread_data = thread_data["ompt_thread_data"].dereference()["value"] 144 ompd_value = ompdModule.call_ompd_get_tool_data( 145 3, curr_thread.thread_handle 146 )[0] 147 if ompt_thread_data != ompd_value: 148 print( 149 "OMPT-OMPD mismatch: value of ompt_thread_data (%d) does not match that of OMPD data union (%d)!" 150 % (ompt_thread_data, ompd_value) 151 ) 152 153 # compare number of threads 154 if "omp_num_threads" in field_names and "team-size-var" in self.icv_map: 155 ompt_num_threads = thread_data["omp_num_threads"] 156 icv_value = ompdModule.call_ompd_get_icv_from_scope( 157 curr_thread.get_current_parallel_handle(), 158 self.icv_map["team-size-var"][1], 159 self.icv_map["team-size-var"][0], 160 ) 161 if ompt_num_threads != icv_value: 162 print( 163 "OMPT-OMPD mismatch: omp_num_threads (%d) does not match OMPD num threads according to ICVs (%d)!" 164 % (ompt_num_threads, icv_value) 165 ) 166 167 # compare omp level 168 if "omp_level" in field_names and "levels-var" in self.icv_map: 169 ompt_levels = thread_data["omp_level"] 170 icv_value = ompdModule.call_ompd_get_icv_from_scope( 171 curr_thread.get_current_parallel_handle(), 172 self.icv_map["levels-var"][1], 173 self.icv_map["levels-var"][0], 174 ) 175 if ompt_levels != icv_value: 176 print( 177 "OMPT-OMPD mismatch: omp_level (%d) does not match OMPD levels according to ICVs (%d)!" 178 % (ompt_levels, icv_value) 179 ) 180 181 # compare active level 182 if "omp_active_level" in field_names and "active-levels-var" in self.icv_map: 183 ompt_active_levels = thread_data["omp_active_level"] 184 icv_value = ompdModule.call_ompd_get_icv_from_scope( 185 curr_thread.get_current_parallel_handle(), 186 self.icv_map["active-levels-var"][1], 187 self.icv_map["active-levels-var"][0], 188 ) 189 if ompt_active_levels != icv_value: 190 print( 191 "OMPT-OMPD mismatch: active levels (%d) do not match active levels according to ICVs (%d)!" 192 % (ompt_active_levels, icv_value) 193 ) 194 195 # compare parallel data 196 if "ompt_parallel_data" in field_names: 197 ompt_parallel_data = thread_data["ompt_parallel_data"].dereference()[ 198 "value" 199 ] 200 current_parallel_handle = curr_thread.get_current_parallel_handle() 201 ompd_value = ompdModule.call_ompd_get_tool_data(4, current_parallel_handle)[ 202 0 203 ] 204 if ompt_parallel_data != ompd_value: 205 print( 206 "OMPT-OMPD mismatch: value of ompt_parallel_data (%d) does not match that of OMPD data union (%d)!" 207 % (ompt_parallel_data, ompd_value) 208 ) 209 210 # compare max threads 211 if "omp_max_threads" in field_names and "nthreads-var" in self.icv_map: 212 ompt_max_threads = thread_data["omp_max_threads"] 213 icv_value = ompdModule.call_ompd_get_icv_from_scope( 214 curr_thread.thread_handle, 215 self.icv_map["nthreads-var"][1], 216 self.icv_map["nthreads-var"][0], 217 ) 218 if icv_value is None: 219 icv_string = ompdModule.call_ompd_get_icv_string_from_scope( 220 curr_thread.thread_handle, 221 self.icv_map["nthreads-var"][1], 222 self.icv_map["nthreads-var"][0], 223 ) 224 if icv_string is None: 225 print( 226 "OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (None Object)" 227 % (ompt_max_threads) 228 ) 229 else: 230 if ompt_max_threads != int(icv_string.split(",")[0]): 231 print( 232 "OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (%d)!" 233 % (ompt_max_threads, int(icv_string.split(",")[0])) 234 ) 235 else: 236 if ompt_max_threads != icv_value: 237 print( 238 "OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (%d)!" 239 % (ompt_max_threads, icv_value) 240 ) 241 242 # compare omp_parallel 243 # NOTE: omp_parallel = true if active-levels-var > 0 244 if "omp_parallel" in field_names: 245 ompt_parallel = thread_data["omp_parallel"] 246 icv_value = ompdModule.call_ompd_get_icv_from_scope( 247 curr_thread.get_current_parallel_handle(), 248 self.icv_map["active-levels-var"][1], 249 self.icv_map["active-levels-var"][0], 250 ) 251 if ( 252 ompt_parallel == 1 253 and icv_value <= 0 254 or ompt_parallel == 0 255 and icv_value > 0 256 ): 257 print( 258 "OMPT-OMPD mismatch: ompt_parallel (%d) does not match OMPD parallel according to ICVs (%d)!" 259 % (ompt_parallel, icv_value) 260 ) 261 262 # compare omp_final 263 if "omp_final" in field_names and "final-task-var" in self.icv_map: 264 ompt_final = thread_data["omp_final"] 265 current_task_handle = curr_thread.get_current_task_handle() 266 icv_value = ompdModule.call_ompd_get_icv_from_scope( 267 current_task_handle, 268 self.icv_map["final-task-var"][1], 269 self.icv_map["final-task-var"][0], 270 ) 271 if icv_value != ompt_final: 272 print( 273 "OMPT-OMPD mismatch: omp_final (%d) does not match OMPD final according to ICVs (%d)!" 274 % (ompt_final, icv_value) 275 ) 276 277 # compare omp_dynamic 278 if "omp_dynamic" in field_names and "dyn-var" in self.icv_map: 279 ompt_dynamic = thread_data["omp_dynamic"] 280 icv_value = ompdModule.call_ompd_get_icv_from_scope( 281 curr_thread.thread_handle, 282 self.icv_map["dyn-var"][1], 283 self.icv_map["dyn-var"][0], 284 ) 285 if icv_value != ompt_dynamic: 286 print( 287 "OMPT-OMPD mismatch: omp_dynamic (%d) does not match OMPD dynamic according to ICVs (%d)!" 288 % (ompt_dynamic, icv_value) 289 ) 290 291 # compare omp_max_active_levels 292 if ( 293 "omp_max_active_levels" in field_names 294 and "max-active-levels-var" in self.icv_map 295 ): 296 ompt_max_active_levels = thread_data["omp_max_active_levels"] 297 icv_value = ompdModule.call_ompd_get_icv_from_scope( 298 curr_thread.get_current_task_handle(), 299 self.icv_map["max-active-levels-var"][1], 300 self.icv_map["max-active-levels-var"][0], 301 ) 302 if ompt_max_active_levels != icv_value: 303 print( 304 "OMPT-OMPD mismatch: omp_max_active_levels (%d) does not match OMPD max active levels (%d)!" 305 % (ompt_max_active_levels, icv_value) 306 ) 307 308 # compare omp_kind: TODO: Add the test for monotonic/nonmonotonic modifier 309 if "omp_kind" in field_names and "run-sched-var" in self.icv_map: 310 ompt_sched_kind = thread_data["omp_kind"] 311 icv_value = ompdModule.call_ompd_get_icv_string_from_scope( 312 curr_thread.get_current_task_handle(), 313 self.icv_map["run-sched-var"][1], 314 self.icv_map["run-sched-var"][0], 315 ) 316 ompd_sched_kind = icv_value.split(",")[0] 317 if self.sched_map.get(int(ompt_sched_kind)) != ompd_sched_kind: 318 print( 319 "OMPT-OMPD mismatch: omp_kind kind (%s) does not match OMPD schedule kind according to ICVs (%s)!" 320 % (self.sched_map.get(int(ompt_sched_kind)), ompd_sched_kind) 321 ) 322 323 # compare omp_modifier 324 if "omp_modifier" in field_names and "run-sched-var" in self.icv_map: 325 ompt_sched_mod = thread_data["omp_modifier"] 326 icv_value = ompdModule.call_ompd_get_icv_string_from_scope( 327 curr_thread.get_current_task_handle(), 328 self.icv_map["run-sched-var"][1], 329 self.icv_map["run-sched-var"][0], 330 ) 331 token = icv_value.split(",")[1] 332 if token is not None: 333 ompd_sched_mod = int(token) 334 else: 335 ompd_sched_mod = 0 336 if ompt_sched_mod != ompd_sched_mod: 337 print( 338 "OMPT-OMPD mismatch: omp_kind modifier does not match OMPD schedule modifier according to ICVs!" 339 ) 340 341 # compare omp_proc_bind 342 if "omp_proc_bind" in field_names and "bind-var" in self.icv_map: 343 ompt_proc_bind = thread_data["omp_proc_bind"] 344 icv_value = ompdModule.call_ompd_get_icv_from_scope( 345 curr_thread.get_current_task_handle(), 346 self.icv_map["bind-var"][1], 347 self.icv_map["bind-var"][0], 348 ) 349 if icv_value is None: 350 icv_string = ompdModule.call_ompd_get_icv_string_from_scope( 351 curr_thread.get_current_task_handle(), 352 self.icv_map["bind-var"][1], 353 self.icv_map["bind-var"][0], 354 ) 355 if icv_string is None: 356 print( 357 "OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (None Object)" 358 % (ompt_proc_bind) 359 ) 360 else: 361 if ompt_proc_bind != int(icv_string.split(",")[0]): 362 print( 363 "OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (%d)!" 364 % (ompt_proc_bind, int(icv_string.split(",")[0])) 365 ) 366 else: 367 if ompt_proc_bind != icv_value: 368 print( 369 "OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (%d)!" 370 % (ompt_proc_bind, icv_value) 371 ) 372 373 # compare enter and exit frames 374 if "ompt_frame_list" in field_names: 375 ompt_task_frame_dict = thread_data["ompt_frame_list"].dereference() 376 ompt_task_frames = ( 377 int(ompt_task_frame_dict["enter_frame"].cast(gdb.lookup_type("long"))), 378 int(ompt_task_frame_dict["exit_frame"].cast(gdb.lookup_type("long"))), 379 ) 380 current_task = curr_thread.get_current_task() 381 ompd_task_frames = current_task.get_task_frame() 382 if ompt_task_frames != ompd_task_frames: 383 print( 384 "OMPT-OMPD mismatch: ompt_task_frames (%s) do not match OMPD task frames (%s)!" 385 % (ompt_task_frames, ompd_task_frames) 386 ) 387 388 # compare task data 389 if "ompt_task_data" in field_names: 390 ompt_task_data = thread_data["ompt_task_data"].dereference()["value"] 391 current_task_handle = curr_thread.get_current_task_handle() 392 ompd_value = ompdModule.call_ompd_get_tool_data(6, current_task_handle)[0] 393 if ompt_task_data != ompd_value: 394 print( 395 "OMPT-OMPD mismatch: value of ompt_task_data (%d) does not match that of OMPD data union (%d)!" 396 % (ompt_task_data, ompd_value) 397 ) 398 399 def save_thread_object(self, thread_num, thread_id, addr_space): 400 """Saves thread object for thread_num inside threads dictionary.""" 401 thread_handle = ompdModule.get_thread_handle(thread_id, addr_space) 402 self.threads[int(thread_num)] = ompd_thread(thread_handle) 403 404 def get_thread(self, thread_num): 405 """Get thread object from map.""" 406 return self.threads[int(thread_num)] 407 408 def get_curr_thread(self): 409 """Get current thread object from map or add new one to map, if missing.""" 410 thread_num = int(gdb.selected_thread().num) 411 if thread_num not in self.threads: 412 self.add_thread() 413 return self.threads[thread_num] 414 415 def add_thread(self): 416 """Add currently selected (*) thread to dictionary threads.""" 417 inf_thread = gdb.selected_thread() 418 try: 419 self.save_thread_object(inf_thread.num, inf_thread.ptid[1], self.addr_space) 420 except: 421 traceback.print_exc() 422 423 def list_threads(self, verbose): 424 """Prints OpenMP threads only that are being tracking inside the "threads" dictionary. 425 See handle_stop_event and add_thread. 426 """ 427 list_tids = [] 428 curr_inferior = gdb.selected_inferior() 429 430 for inf_thread in curr_inferior.threads(): 431 list_tids.append((inf_thread.num, inf_thread.ptid)) 432 if verbose: 433 if self.states is None: 434 self.enumerate_states() 435 for (thread_num, thread_ptid) in sorted(list_tids): 436 if thread_num in self.threads: 437 try: 438 print( 439 "Thread %i (%i) is an OpenMP thread; state: %s" 440 % ( 441 thread_num, 442 thread_ptid[1], 443 self.states[self.threads[thread_num].get_state()[0]], 444 ) 445 ) 446 except: 447 traceback.print_exc() 448 else: 449 print( 450 "Thread %i (%i) is no OpenMP thread" 451 % (thread_num, thread_ptid[1]) 452 ) 453 454 def enumerate_states(self): 455 """Helper function for list_threads: initializes map of OMPD states for output of 456 'ompd threads'. 457 """ 458 if self.states is None: 459 self.states = {} 460 current = int("0x102", 0) 461 count = 0 462 more = 1 463 464 while more > 0: 465 tup = ompdModule.call_ompd_enumerate_states(self.addr_space, current) 466 (next_state, next_state_name, more) = tup 467 468 self.states[next_state] = next_state_name 469 current = next_state 470