| from __future__ import print_function |
| import ompdModule |
| from ompd_handles import ompd_thread, ompd_task, ompd_parallel |
| import gdb |
| import sys |
| import traceback |
| from enum import Enum |
| |
| |
| class ompd_scope(Enum): |
| ompd_scope_global = 1 |
| ompd_scope_address_space = 2 |
| ompd_scope_thread = 3 |
| ompd_scope_parallel = 4 |
| ompd_scope_implicit_task = 5 |
| ompd_scope_task = 6 |
| |
| |
| class ompd_address_space(object): |
| def __init__(self): |
| """Initializes an ompd_address_space object by calling ompd_initialize |
| in ompdModule.c |
| """ |
| self.addr_space = ompdModule.call_ompd_initialize() |
| # maps thread_num (thread id given by gdb) to ompd_thread object with thread handle |
| self.threads = {} |
| self.states = None |
| self.icv_map = None |
| self.ompd_tool_test_bp = None |
| self.scope_map = { |
| 1: "global", |
| 2: "address_space", |
| 3: "thread", |
| 4: "parallel", |
| 5: "implicit_task", |
| 6: "task", |
| } |
| self.sched_map = {1: "static", 2: "dynamic", 3: "guided", 4: "auto"} |
| gdb.events.stop.connect(self.handle_stop_event) |
| self.new_thread_breakpoint = gdb.Breakpoint( |
| "ompd_bp_thread_begin", internal=True |
| ) |
| tool_break_symbol = gdb.lookup_global_symbol("ompd_tool_break") |
| if tool_break_symbol is not None: |
| self.ompd_tool_test_bp = gdb.Breakpoint("ompd_tool_break", internal=True) |
| |
| def handle_stop_event(self, event): |
| """Sets a breakpoint at different events, e.g. when a new OpenMP |
| thread is created. |
| """ |
| if isinstance(event, gdb.BreakpointEvent): |
| # check if breakpoint has already been hit |
| if self.new_thread_breakpoint in event.breakpoints: |
| self.add_thread() |
| gdb.execute("continue") |
| return |
| elif ( |
| self.ompd_tool_test_bp is not None |
| and self.ompd_tool_test_bp in event.breakpoints |
| ): |
| try: |
| self.compare_ompt_data() |
| gdb.execute("continue") |
| except (): |
| traceback.print_exc() |
| elif isinstance(event, gdb.SignalEvent): |
| # TODO: what do we need to do on SIGNALS? |
| pass |
| else: |
| # TODO: probably not possible? |
| pass |
| |
| def get_icv_map(self): |
| """Fills ICV map.""" |
| self.icv_map = {} |
| current = 0 |
| more = 1 |
| while more > 0: |
| tup = ompdModule.call_ompd_enumerate_icvs(self.addr_space, current) |
| (current, next_icv, next_scope, more) = tup |
| self.icv_map[next_icv] = (current, next_scope, self.scope_map[next_scope]) |
| print("Initialized ICV map successfully for checking OMP API values.") |
| |
| def compare_ompt_data(self): |
| """Compares OMPT tool data about parallel region to data returned by OMPD functions.""" |
| # make sure all threads and states are set |
| self.list_threads(False) |
| |
| thread_id = gdb.selected_thread().ptid[1] |
| curr_thread = self.get_curr_thread() |
| |
| # check if current thread is LWP thread; return if "ompd_rc_unavailable" |
| thread_handle = ompdModule.get_thread_handle(thread_id, self.addr_space) |
| if thread_handle == -1: |
| print("Skipping OMPT-OMPD checks for non-LWP thread.") |
| return |
| |
| print("Comparing OMPT data to OMPD data...") |
| field_names = [i.name for i in gdb.parse_and_eval("thread_data").type.fields()] |
| thread_data = gdb.parse_and_eval("thread_data") |
| |
| if self.icv_map is None: |
| self.get_icv_map() |
| |
| # compare state values |
| if "ompt_state" in field_names: |
| if self.states is None: |
| self.enumerate_states() |
| ompt_state = str(thread_data["ompt_state"]) |
| ompd_state = str(self.states[curr_thread.get_state()[0]]) |
| if ompt_state != ompd_state: |
| print( |
| "OMPT-OMPD mismatch: ompt_state (%s) does not match OMPD state (%s)!" |
| % (ompt_state, ompd_state) |
| ) |
| |
| # compare wait_id values |
| if "ompt_wait_id" in field_names: |
| ompt_wait_id = thread_data["ompt_wait_id"] |
| ompd_wait_id = curr_thread.get_state()[1] |
| if ompt_wait_id != ompd_wait_id: |
| print( |
| "OMPT-OMPD mismatch: ompt_wait_id (%d) does not match OMPD wait id (%d)!" |
| % (ompt_wait_id, ompd_wait_id) |
| ) |
| |
| # compare thread id |
| if "omp_thread_num" in field_names and "thread-num-var" in self.icv_map: |
| ompt_thread_num = thread_data["omp_thread_num"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.thread_handle, |
| self.icv_map["thread-num-var"][1], |
| self.icv_map["thread-num-var"][0], |
| ) |
| if ompt_thread_num != icv_value: |
| print( |
| "OMPT-OMPD mismatch: omp_thread_num (%d) does not match OMPD thread num according to ICVs (%d)!" |
| % (ompt_thread_num, icv_value) |
| ) |
| |
| # compare thread data |
| if "ompt_thread_data" in field_names: |
| ompt_thread_data = thread_data["ompt_thread_data"].dereference()["value"] |
| ompd_value = ompdModule.call_ompd_get_tool_data( |
| 3, curr_thread.thread_handle |
| )[0] |
| if ompt_thread_data != ompd_value: |
| print( |
| "OMPT-OMPD mismatch: value of ompt_thread_data (%d) does not match that of OMPD data union (%d)!" |
| % (ompt_thread_data, ompd_value) |
| ) |
| |
| # compare number of threads |
| if "omp_num_threads" in field_names and "team-size-var" in self.icv_map: |
| ompt_num_threads = thread_data["omp_num_threads"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.get_current_parallel_handle(), |
| self.icv_map["team-size-var"][1], |
| self.icv_map["team-size-var"][0], |
| ) |
| if ompt_num_threads != icv_value: |
| print( |
| "OMPT-OMPD mismatch: omp_num_threads (%d) does not match OMPD num threads according to ICVs (%d)!" |
| % (ompt_num_threads, icv_value) |
| ) |
| |
| # compare omp level |
| if "omp_level" in field_names and "levels-var" in self.icv_map: |
| ompt_levels = thread_data["omp_level"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.get_current_parallel_handle(), |
| self.icv_map["levels-var"][1], |
| self.icv_map["levels-var"][0], |
| ) |
| if ompt_levels != icv_value: |
| print( |
| "OMPT-OMPD mismatch: omp_level (%d) does not match OMPD levels according to ICVs (%d)!" |
| % (ompt_levels, icv_value) |
| ) |
| |
| # compare active level |
| if "omp_active_level" in field_names and "active-levels-var" in self.icv_map: |
| ompt_active_levels = thread_data["omp_active_level"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.get_current_parallel_handle(), |
| self.icv_map["active-levels-var"][1], |
| self.icv_map["active-levels-var"][0], |
| ) |
| if ompt_active_levels != icv_value: |
| print( |
| "OMPT-OMPD mismatch: active levels (%d) do not match active levels according to ICVs (%d)!" |
| % (ompt_active_levels, icv_value) |
| ) |
| |
| # compare parallel data |
| if "ompt_parallel_data" in field_names: |
| ompt_parallel_data = thread_data["ompt_parallel_data"].dereference()[ |
| "value" |
| ] |
| current_parallel_handle = curr_thread.get_current_parallel_handle() |
| ompd_value = ompdModule.call_ompd_get_tool_data(4, current_parallel_handle)[ |
| 0 |
| ] |
| if ompt_parallel_data != ompd_value: |
| print( |
| "OMPT-OMPD mismatch: value of ompt_parallel_data (%d) does not match that of OMPD data union (%d)!" |
| % (ompt_parallel_data, ompd_value) |
| ) |
| |
| # compare max threads |
| if "omp_max_threads" in field_names and "nthreads-var" in self.icv_map: |
| ompt_max_threads = thread_data["omp_max_threads"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.thread_handle, |
| self.icv_map["nthreads-var"][1], |
| self.icv_map["nthreads-var"][0], |
| ) |
| if icv_value is None: |
| icv_string = ompdModule.call_ompd_get_icv_string_from_scope( |
| curr_thread.thread_handle, |
| self.icv_map["nthreads-var"][1], |
| self.icv_map["nthreads-var"][0], |
| ) |
| if icv_string is None: |
| print( |
| "OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (None Object)" |
| % (ompt_max_threads) |
| ) |
| else: |
| if ompt_max_threads != int(icv_string.split(",")[0]): |
| print( |
| "OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (%d)!" |
| % (ompt_max_threads, int(icv_string.split(",")[0])) |
| ) |
| else: |
| if ompt_max_threads != icv_value: |
| print( |
| "OMPT-OMPD mismatch: omp_max_threads (%d) does not match OMPD thread limit according to ICVs (%d)!" |
| % (ompt_max_threads, icv_value) |
| ) |
| |
| # compare omp_parallel |
| # NOTE: omp_parallel = true if active-levels-var > 0 |
| if "omp_parallel" in field_names: |
| ompt_parallel = thread_data["omp_parallel"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.get_current_parallel_handle(), |
| self.icv_map["active-levels-var"][1], |
| self.icv_map["active-levels-var"][0], |
| ) |
| if ( |
| ompt_parallel == 1 |
| and icv_value <= 0 |
| or ompt_parallel == 0 |
| and icv_value > 0 |
| ): |
| print( |
| "OMPT-OMPD mismatch: ompt_parallel (%d) does not match OMPD parallel according to ICVs (%d)!" |
| % (ompt_parallel, icv_value) |
| ) |
| |
| # compare omp_final |
| if "omp_final" in field_names and "final-task-var" in self.icv_map: |
| ompt_final = thread_data["omp_final"] |
| current_task_handle = curr_thread.get_current_task_handle() |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| current_task_handle, |
| self.icv_map["final-task-var"][1], |
| self.icv_map["final-task-var"][0], |
| ) |
| if icv_value != ompt_final: |
| print( |
| "OMPT-OMPD mismatch: omp_final (%d) does not match OMPD final according to ICVs (%d)!" |
| % (ompt_final, icv_value) |
| ) |
| |
| # compare omp_dynamic |
| if "omp_dynamic" in field_names and "dyn-var" in self.icv_map: |
| ompt_dynamic = thread_data["omp_dynamic"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.thread_handle, |
| self.icv_map["dyn-var"][1], |
| self.icv_map["dyn-var"][0], |
| ) |
| if icv_value != ompt_dynamic: |
| print( |
| "OMPT-OMPD mismatch: omp_dynamic (%d) does not match OMPD dynamic according to ICVs (%d)!" |
| % (ompt_dynamic, icv_value) |
| ) |
| |
| # compare omp_max_active_levels |
| if ( |
| "omp_max_active_levels" in field_names |
| and "max-active-levels-var" in self.icv_map |
| ): |
| ompt_max_active_levels = thread_data["omp_max_active_levels"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.get_current_task_handle(), |
| self.icv_map["max-active-levels-var"][1], |
| self.icv_map["max-active-levels-var"][0], |
| ) |
| if ompt_max_active_levels != icv_value: |
| print( |
| "OMPT-OMPD mismatch: omp_max_active_levels (%d) does not match OMPD max active levels (%d)!" |
| % (ompt_max_active_levels, icv_value) |
| ) |
| |
| # compare omp_kind: TODO: Add the test for monotonic/nonmonotonic modifier |
| if "omp_kind" in field_names and "run-sched-var" in self.icv_map: |
| ompt_sched_kind = thread_data["omp_kind"] |
| icv_value = ompdModule.call_ompd_get_icv_string_from_scope( |
| curr_thread.get_current_task_handle(), |
| self.icv_map["run-sched-var"][1], |
| self.icv_map["run-sched-var"][0], |
| ) |
| ompd_sched_kind = icv_value.split(",")[0] |
| if self.sched_map.get(int(ompt_sched_kind)) != ompd_sched_kind: |
| print( |
| "OMPT-OMPD mismatch: omp_kind kind (%s) does not match OMPD schedule kind according to ICVs (%s)!" |
| % (self.sched_map.get(int(ompt_sched_kind)), ompd_sched_kind) |
| ) |
| |
| # compare omp_modifier |
| if "omp_modifier" in field_names and "run-sched-var" in self.icv_map: |
| ompt_sched_mod = thread_data["omp_modifier"] |
| icv_value = ompdModule.call_ompd_get_icv_string_from_scope( |
| curr_thread.get_current_task_handle(), |
| self.icv_map["run-sched-var"][1], |
| self.icv_map["run-sched-var"][0], |
| ) |
| token = icv_value.split(",")[1] |
| if token is not None: |
| ompd_sched_mod = int(token) |
| else: |
| ompd_sched_mod = 0 |
| if ompt_sched_mod != ompd_sched_mod: |
| print( |
| "OMPT-OMPD mismatch: omp_kind modifier does not match OMPD schedule modifier according to ICVs!" |
| ) |
| |
| # compare omp_proc_bind |
| if "omp_proc_bind" in field_names and "bind-var" in self.icv_map: |
| ompt_proc_bind = thread_data["omp_proc_bind"] |
| icv_value = ompdModule.call_ompd_get_icv_from_scope( |
| curr_thread.get_current_task_handle(), |
| self.icv_map["bind-var"][1], |
| self.icv_map["bind-var"][0], |
| ) |
| if icv_value is None: |
| icv_string = ompdModule.call_ompd_get_icv_string_from_scope( |
| curr_thread.get_current_task_handle(), |
| self.icv_map["bind-var"][1], |
| self.icv_map["bind-var"][0], |
| ) |
| if icv_string is None: |
| print( |
| "OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (None Object)" |
| % (ompt_proc_bind) |
| ) |
| else: |
| if ompt_proc_bind != int(icv_string.split(",")[0]): |
| print( |
| "OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (%d)!" |
| % (ompt_proc_bind, int(icv_string.split(",")[0])) |
| ) |
| else: |
| if ompt_proc_bind != icv_value: |
| print( |
| "OMPT-OMPD mismatch: omp_proc_bind (%d) does not match OMPD proc bind according to ICVs (%d)!" |
| % (ompt_proc_bind, icv_value) |
| ) |
| |
| # compare enter and exit frames |
| if "ompt_frame_list" in field_names: |
| ompt_task_frame_dict = thread_data["ompt_frame_list"].dereference() |
| ompt_task_frames = ( |
| int(ompt_task_frame_dict["enter_frame"].cast(gdb.lookup_type("long"))), |
| int(ompt_task_frame_dict["exit_frame"].cast(gdb.lookup_type("long"))), |
| ) |
| current_task = curr_thread.get_current_task() |
| ompd_task_frames = current_task.get_task_frame() |
| if ompt_task_frames != ompd_task_frames: |
| print( |
| "OMPT-OMPD mismatch: ompt_task_frames (%s) do not match OMPD task frames (%s)!" |
| % (ompt_task_frames, ompd_task_frames) |
| ) |
| |
| # compare task data |
| if "ompt_task_data" in field_names: |
| ompt_task_data = thread_data["ompt_task_data"].dereference()["value"] |
| current_task_handle = curr_thread.get_current_task_handle() |
| ompd_value = ompdModule.call_ompd_get_tool_data(6, current_task_handle)[0] |
| if ompt_task_data != ompd_value: |
| print( |
| "OMPT-OMPD mismatch: value of ompt_task_data (%d) does not match that of OMPD data union (%d)!" |
| % (ompt_task_data, ompd_value) |
| ) |
| |
| def save_thread_object(self, thread_num, thread_id, addr_space): |
| """Saves thread object for thread_num inside threads dictionary.""" |
| thread_handle = ompdModule.get_thread_handle(thread_id, addr_space) |
| self.threads[int(thread_num)] = ompd_thread(thread_handle) |
| |
| def get_thread(self, thread_num): |
| """Get thread object from map.""" |
| return self.threads[int(thread_num)] |
| |
| def get_curr_thread(self): |
| """Get current thread object from map or add new one to map, if missing.""" |
| thread_num = int(gdb.selected_thread().num) |
| if thread_num not in self.threads: |
| self.add_thread() |
| return self.threads[thread_num] |
| |
| def add_thread(self): |
| """Add currently selected (*) thread to dictionary threads.""" |
| inf_thread = gdb.selected_thread() |
| try: |
| self.save_thread_object(inf_thread.num, inf_thread.ptid[1], self.addr_space) |
| except: |
| traceback.print_exc() |
| |
| def list_threads(self, verbose): |
| """Prints OpenMP threads only that are being tracking inside the "threads" dictionary. |
| See handle_stop_event and add_thread. |
| """ |
| list_tids = [] |
| curr_inferior = gdb.selected_inferior() |
| |
| for inf_thread in curr_inferior.threads(): |
| list_tids.append((inf_thread.num, inf_thread.ptid)) |
| if verbose: |
| if self.states is None: |
| self.enumerate_states() |
| for (thread_num, thread_ptid) in sorted(list_tids): |
| if thread_num in self.threads: |
| try: |
| print( |
| "Thread %i (%i) is an OpenMP thread; state: %s" |
| % ( |
| thread_num, |
| thread_ptid[1], |
| self.states[self.threads[thread_num].get_state()[0]], |
| ) |
| ) |
| except: |
| traceback.print_exc() |
| else: |
| print( |
| "Thread %i (%i) is no OpenMP thread" |
| % (thread_num, thread_ptid[1]) |
| ) |
| |
| def enumerate_states(self): |
| """Helper function for list_threads: initializes map of OMPD states for output of |
| 'ompd threads'. |
| """ |
| if self.states is None: |
| self.states = {} |
| current = int("0x102", 0) |
| count = 0 |
| more = 1 |
| |
| while more > 0: |
| tup = ompdModule.call_ompd_enumerate_states(self.addr_space, current) |
| (next_state, next_state_name, more) = tup |
| |
| self.states[next_state] = next_state_name |
| current = next_state |