470 lines · python
1from __future__ import print_function2import ompdModule3from ompd_handles import ompd_thread, ompd_task, ompd_parallel4import gdb5import sys6import traceback7from enum import Enum8 9 10class ompd_scope(Enum):11 ompd_scope_global = 112 ompd_scope_address_space = 213 ompd_scope_thread = 314 ompd_scope_parallel = 415 ompd_scope_implicit_task = 516 ompd_scope_task = 617 18 19class ompd_address_space(object):20 def __init__(self):21 """Initializes an ompd_address_space object by calling ompd_initialize22 in ompdModule.c23 """24 self.addr_space = ompdModule.call_ompd_initialize()25 # maps thread_num (thread id given by gdb) to ompd_thread object with thread handle26 self.threads = {}27 self.states = None28 self.icv_map = None29 self.ompd_tool_test_bp = None30 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=True42 )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 OpenMP49 thread is created.50 """51 if isinstance(event, gdb.BreakpointEvent):52 # check if breakpoint has already been hit53 if self.new_thread_breakpoint in event.breakpoints:54 self.add_thread()55 gdb.execute("continue")56 return57 elif (58 self.ompd_tool_test_bp is not None59 and self.ompd_tool_test_bp in event.breakpoints60 ):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 pass69 else:70 # TODO: probably not possible?71 pass72 73 def get_icv_map(self):74 """Fills ICV map."""75 self.icv_map = {}76 current = 077 more = 178 while more > 0:79 tup = ompdModule.call_ompd_enumerate_icvs(self.addr_space, current)80 (current, next_icv, next_scope, more) = tup81 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 set87 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 return97 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 values106 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 values118 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 id128 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 data142 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_handle146 )[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 threads154 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 level168 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 level182 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 data196 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 0203 ]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 threads211 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_parallel243 # NOTE: omp_parallel = true if active-levels-var > 0244 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 == 1253 and icv_value <= 0254 or ompt_parallel == 0255 and icv_value > 0256 ):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_final263 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_dynamic278 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_levels292 if (293 "omp_max_active_levels" in field_names294 and "max-active-levels-var" in self.icv_map295 ):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 modifier309 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_modifier324 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 = 0336 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_bind342 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 frames374 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 data389 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 of456 'ompd threads'.457 """458 if self.states is None:459 self.states = {}460 current = int("0x102", 0)461 count = 0462 more = 1463 464 while more > 0:465 tup = ompdModule.call_ompd_enumerate_states(self.addr_space, current)466 (next_state, next_state_name, more) = tup467 468 self.states[next_state] = next_state_name469 current = next_state470