import ompdModule import gdb import re import traceback from ompd_address_space import ompd_address_space from ompd_handles import ompd_thread, ompd_task, ompd_parallel from frame_filter import FrameFilter from enum import Enum addr_space = None ff = None icv_map = None ompd_scope_map = { 1: "global", 2: "address_space", 3: "thread", 4: "parallel", 5: "implicit_task", 6: "task", } in_task_function = False class ompd(gdb.Command): def __init__(self): super(ompd, self).__init__("ompd", gdb.COMMAND_STATUS, gdb.COMPLETE_NONE, True) class ompd_init(gdb.Command): """Find and initialize ompd library""" # first parameter is command-line input, second parameter is gdb-specific data def __init__(self): self.__doc__ = "Find and initialize OMPD library\n usage: ompd init" super(ompd_init, self).__init__("ompd init", gdb.COMMAND_DATA) def invoke(self, arg, from_tty): global addr_space global ff try: try: print(gdb.newest_frame()) except: gdb.execute("start") try: lib_list = gdb.parse_and_eval("(char**)ompd_dll_locations") except gdb.error: raise ValueError( "No ompd_dll_locations symbol in execution, make sure to have an OMPD enabled OpenMP runtime" ) while not gdb.parse_and_eval("(char**)ompd_dll_locations"): gdb.execute("tbreak ompd_dll_locations_valid") gdb.execute("continue") lib_list = gdb.parse_and_eval("(char**)ompd_dll_locations") i = 0 while lib_list[i]: ret = ompdModule.ompd_open(lib_list[i].string()) if ret == -1: raise ValueError("Handle of OMPD library is not a valid string!") if ret == -2: print("ret == -2") pass # It's ok to fail on dlopen if ret == -3: print("ret == -3") pass # It's ok to fail on dlsym if ret < -10: raise ValueError("OMPD error code %i!" % (-10 - ret)) if ret > 0: print("Loaded OMPD lib successfully!") try: addr_space = ompd_address_space() ff = FrameFilter(addr_space) except: traceback.print_exc() return i = i + 1 raise ValueError("OMPD library could not be loaded!") except: traceback.print_exc() class ompd_threads(gdb.Command): """Register thread ids of current context""" def __init__(self): self.__doc__ = ( "Provide information on threads of current context.\n usage: ompd threads" ) super(ompd_threads, self).__init__("ompd threads", gdb.COMMAND_STATUS) def invoke(self, arg, from_tty): global addr_space if init_error(): return addr_space.list_threads(True) def print_parallel_region(curr_parallel, team_size): """Helper function for ompd_parallel_region. To print out the details of the parallel region.""" for omp_thr in range(team_size): thread = curr_parallel.get_thread_in_parallel(omp_thr) ompd_state = str(addr_space.states[thread.get_state()[0]]) ompd_wait_id = thread.get_state()[1] task = curr_parallel.get_task_in_parallel(omp_thr) task_func_addr = task.get_task_function() # Get the function this addr belongs to sal = gdb.find_pc_line(task_func_addr) block = gdb.block_for_pc(task_func_addr) while block and not block.function: block = block.superblock if omp_thr == 0: print( "%6d (master) %-37s %ld 0x%lx %-25s %-17s:%d" % ( omp_thr, ompd_state, ompd_wait_id, task_func_addr, block.function.print_name, sal.symtab.filename, sal.line, ) ) else: print( "%6d %-37s %ld 0x%lx %-25s %-17s:%d" % ( omp_thr, ompd_state, ompd_wait_id, task_func_addr, block.function.print_name, sal.symtab.filename, sal.line, ) ) class ompd_parallel_region(gdb.Command): """Parallel Region Details""" def __init__(self): self.__doc__ = "Display the details of the current and enclosing parallel regions.\n usage: ompd parallel" super(ompd_parallel_region, self).__init__("ompd parallel", gdb.COMMAND_STATUS) def invoke(self, arg, from_tty): global addr_space if init_error(): return if addr_space.icv_map is None: addr_space.get_icv_map() if addr_space.states is None: addr_space.enumerate_states() curr_thread_handle = addr_space.get_curr_thread() curr_parallel_handle = curr_thread_handle.get_current_parallel_handle() curr_parallel = ompd_parallel(curr_parallel_handle) while curr_parallel_handle is not None and curr_parallel is not None: nest_level = ompdModule.call_ompd_get_icv_from_scope( curr_parallel_handle, addr_space.icv_map["levels-var"][1], addr_space.icv_map["levels-var"][0], ) if nest_level == 0: break team_size = ompdModule.call_ompd_get_icv_from_scope( curr_parallel_handle, addr_space.icv_map["team-size-var"][1], addr_space.icv_map["team-size-var"][0], ) print("") print( "Parallel Region: Nesting Level %d: Team Size: %d" % (nest_level, team_size) ) print("================================================") print("") print( "OMP Thread Nbr Thread State Wait Id EntryAddr FuncName File:Line" ) print( "======================================================================================================" ) print_parallel_region(curr_parallel, team_size) enclosing_parallel = curr_parallel.get_enclosing_parallel() enclosing_parallel_handle = curr_parallel.get_enclosing_parallel_handle() curr_parallel = enclosing_parallel curr_parallel_handle = enclosing_parallel_handle class ompd_icvs(gdb.Command): """ICVs""" def __init__(self): self.__doc__ = ( "Display the values of the Internal Control Variables.\n usage: ompd icvs" ) super(ompd_icvs, self).__init__("ompd icvs", gdb.COMMAND_STATUS) def invoke(self, arg, from_tty): global addr_space global ompd_scope_map if init_error(): return curr_thread_handle = addr_space.get_curr_thread() if addr_space.icv_map is None: addr_space.get_icv_map() print("ICV Name Scope Value") print("===============================================================") try: for icv_name in addr_space.icv_map: scope = addr_space.icv_map[icv_name][1] # {1:'global', 2:'address_space', 3:'thread', 4:'parallel', 5:'implicit_task', 6:'task'} if scope == 2: handle = addr_space.addr_space elif scope == 3: handle = curr_thread_handle.thread_handle elif scope == 4: handle = curr_thread_handle.get_current_parallel_handle() elif scope == 6: handle = curr_thread_handle.get_current_task_handle() else: raise ValueError("Invalid scope") if icv_name == "nthreads-var" or icv_name == "bind-var": icv_value = ompdModule.call_ompd_get_icv_from_scope( handle, scope, addr_space.icv_map[icv_name][0] ) if icv_value is None: icv_string = ompdModule.call_ompd_get_icv_string_from_scope( handle, scope, addr_space.icv_map[icv_name][0] ) print( "%-31s %-26s %s" % (icv_name, ompd_scope_map[scope], icv_string) ) else: print( "%-31s %-26s %d" % (icv_name, ompd_scope_map[scope], icv_value) ) elif ( icv_name == "affinity-format-var" or icv_name == "run-sched-var" or icv_name == "tool-libraries-var" or icv_name == "tool-verbose-init-var" ): icv_string = ompdModule.call_ompd_get_icv_string_from_scope( handle, scope, addr_space.icv_map[icv_name][0] ) print( "%-31s %-26s %s" % (icv_name, ompd_scope_map[scope], icv_string) ) else: icv_value = ompdModule.call_ompd_get_icv_from_scope( handle, scope, addr_space.icv_map[icv_name][0] ) print( "%-31s %-26s %d" % (icv_name, ompd_scope_map[scope], icv_value) ) except: traceback.print_exc() def curr_thread(): """Helper function for ompd_step. Returns the thread object for the current thread number.""" global addr_space if addr_space is not None: return addr_space.threads[int(gdb.selected_thread().num)] return None class ompd_test(gdb.Command): """Test area""" def __init__(self): self.__doc__ = "Test functionalities for correctness\n usage: ompd test" super(ompd_test, self).__init__("ompd test", gdb.COMMAND_OBSCURE) def invoke(self, arg, from_tty): global addr_space if init_error(): return # get task function for current task of current thread try: current_thread = int(gdb.selected_thread().num) current_thread_obj = addr_space.threads[current_thread] task_function = current_thread_obj.get_current_task().get_task_function() print("bt value:", int("0x0000000000400b6c", 0)) print("get_task_function value:", task_function) # get task function of implicit task in current parallel region for current thread current_parallel_obj = current_thread_obj.get_current_parallel() task_in_parallel = current_parallel_obj.get_task_in_parallel(current_thread) task_function_in_parallel = task_in_parallel.get_task_function() print("task_function_in_parallel:", task_function_in_parallel) except: print("Task function value not found for this thread") class ompdtestapi(gdb.Command): """To test API's return code""" def __init__(self): self.__doc__ = "Test OMPD tool Interface APIs.\nUsage: ompdtestapi " super(ompdtestapi, self).__init__("ompdtestapi", gdb.COMMAND_OBSCURE) def invoke(self, arg, from_tty): global addr_space if init_error(): print("Error in Initialization.") return if not arg: print("No API provided to test, eg: ompdtestapi ompd_initialize") if arg == "ompd_get_thread_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] ompdModule.test_ompd_get_thread_handle(addr_handle, threadId) elif arg == "ompd_get_curr_parallel_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) ompdModule.test_ompd_get_curr_parallel_handle(thread_handle) elif arg == "ompd_get_thread_in_parallel": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle( thread_handle ) ompdModule.test_ompd_get_thread_in_parallel(parallel_handle) elif arg == "ompd_thread_handle_compare": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle( thread_handle ) thread_handle1 = ompdModule.call_ompd_get_thread_in_parallel( parallel_handle, 1 ) thread_handle2 = ompdModule.call_ompd_get_thread_in_parallel( parallel_handle, 2 ) ompdModule.test_ompd_thread_handle_compare(thread_handle1, thread_handle1) ompdModule.test_ompd_thread_handle_compare(thread_handle1, thread_handle2) elif arg == "ompd_get_thread_id": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) ompdModule.test_ompd_get_thread_id(thread_handle) elif arg == "ompd_rel_thread_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) ompdModule.test_ompd_rel_thread_handle(thread_handle) elif arg == "ompd_get_enclosing_parallel_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle( thread_handle ) ompdModule.test_ompd_get_enclosing_parallel_handle(parallel_handle) elif arg == "ompd_parallel_handle_compare": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) parallel_handle1 = ompdModule.call_ompd_get_curr_parallel_handle( thread_handle ) parallel_handle2 = ompdModule.call_ompd_get_enclosing_parallel_handle( parallel_handle1 ) ompdModule.test_ompd_parallel_handle_compare( parallel_handle1, parallel_handle1 ) ompdModule.test_ompd_parallel_handle_compare( parallel_handle1, parallel_handle2 ) elif arg == "ompd_rel_parallel_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle( thread_handle ) ompdModule.test_ompd_rel_parallel_handle(parallel_handle) elif arg == "ompd_initialize": ompdModule.test_ompd_initialize() elif arg == "ompd_get_api_version": ompdModule.test_ompd_get_api_version() elif arg == "ompd_get_version_string": ompdModule.test_ompd_get_version_string() elif arg == "ompd_finalize": ompdModule.test_ompd_finalize() elif arg == "ompd_process_initialize": ompdModule.call_ompd_initialize() ompdModule.test_ompd_process_initialize() elif arg == "ompd_device_initialize": ompdModule.test_ompd_device_initialize() elif arg == "ompd_rel_address_space_handle": ompdModule.test_ompd_rel_address_space_handle() elif arg == "ompd_get_omp_version": addr_handle = addr_space.addr_space ompdModule.test_ompd_get_omp_version(addr_handle) elif arg == "ompd_get_omp_version_string": addr_handle = addr_space.addr_space ompdModule.test_ompd_get_omp_version_string(addr_handle) elif arg == "ompd_get_curr_task_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) ompdModule.test_ompd_get_curr_task_handle(thread_handle) elif arg == "ompd_get_task_parallel_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle) ompdModule.test_ompd_get_task_parallel_handle(task_handle) elif arg == "ompd_get_generating_task_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle) ompdModule.test_ompd_get_generating_task_handle(task_handle) elif arg == "ompd_get_scheduling_task_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle) ompdModule.test_ompd_get_scheduling_task_handle(task_handle) elif arg == "ompd_get_task_in_parallel": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle( thread_handle ) ompdModule.test_ompd_get_task_in_parallel(parallel_handle) elif arg == "ompd_rel_task_handle": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle) ompdModule.test_ompd_rel_task_handle(task_handle) elif arg == "ompd_task_handle_compare": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) task_handle1 = ompdModule.call_ompd_get_curr_task_handle(thread_handle) task_handle2 = ompdModule.call_ompd_get_generating_task_handle(task_handle1) ompdModule.test_ompd_task_handle_compare(task_handle1, task_handle2) ompdModule.test_ompd_task_handle_compare(task_handle2, task_handle1) elif arg == "ompd_get_task_function": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle) ompdModule.test_ompd_get_task_function(task_handle) elif arg == "ompd_get_task_frame": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle) ompdModule.test_ompd_get_task_frame(task_handle) elif arg == "ompd_get_state": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) ompdModule.test_ompd_get_state(thread_handle) elif arg == "ompd_get_display_control_vars": addr_handle = addr_space.addr_space ompdModule.test_ompd_get_display_control_vars(addr_handle) elif arg == "ompd_rel_display_control_vars": ompdModule.test_ompd_rel_display_control_vars() elif arg == "ompd_enumerate_icvs": addr_handle = addr_space.addr_space ompdModule.test_ompd_enumerate_icvs(addr_handle) elif arg == "ompd_get_icv_from_scope": addr_handle = addr_space.addr_space threadId = gdb.selected_thread().ptid[1] thread_handle = ompdModule.get_thread_handle(threadId, addr_handle) parallel_handle = ompdModule.call_ompd_get_curr_parallel_handle( thread_handle ) task_handle = ompdModule.call_ompd_get_curr_task_handle(thread_handle) ompdModule.test_ompd_get_icv_from_scope_with_addr_handle(addr_handle) ompdModule.test_ompd_get_icv_from_scope_with_thread_handle(thread_handle) ompdModule.test_ompd_get_icv_from_scope_with_parallel_handle( parallel_handle ) ompdModule.test_ompd_get_icv_from_scope_with_task_handle(task_handle) elif arg == "ompd_get_icv_string_from_scope": addr_handle = addr_space.addr_space ompdModule.test_ompd_get_icv_string_from_scope(addr_handle) elif arg == "ompd_get_tool_data": ompdModule.test_ompd_get_tool_data() elif arg == "ompd_enumerate_states": ompdModule.test_ompd_enumerate_states() else: print("Invalid API.") class ompd_bt(gdb.Command): """Turn filter for 'bt' on/off for output to only contain frames relevant to the application or all frames.""" def __init__(self): self.__doc__ = 'Turn filter for "bt" output on or off. Specify "on continued" option to trace worker threads back to master threads.\n usage: ompd bt on|on continued|off' super(ompd_bt, self).__init__("ompd bt", gdb.COMMAND_STACK) def invoke(self, arg, from_tty): global ff global addr_space global icv_map global ompd_scope_map if init_error(): return if icv_map is None: icv_map = {} current = 0 more = 1 while more > 0: tup = ompdModule.call_ompd_enumerate_icvs( addr_space.addr_space, current ) (current, next_icv, next_scope, more) = tup icv_map[next_icv] = (current, next_scope, ompd_scope_map[next_scope]) print('Initialized ICV map successfully for filtering "bt".') arg_list = gdb.string_to_argv(arg) if len(arg_list) == 0: print( 'When calling "ompd bt", you must either specify "on", "on continued" or "off". Check "help ompd".' ) elif len(arg_list) == 1 and arg_list[0] == "on": addr_space.list_threads(False) ff.set_switch(True) ff.set_switch_continue(False) elif arg_list[0] == "on" and arg_list[1] == "continued": ff.set_switch(True) ff.set_switch_continue(True) elif len(arg_list) == 1 and arg_list[0] == "off": ff.set_switch(False) ff.set_switch_continue(False) else: print( 'When calling "ompd bt", you must either specify "on", "on continued" or "off". Check "help ompd".' ) # TODO: remove class ompd_taskframes(gdb.Command): """Prints task handles for relevant task frames. Meant for debugging.""" def __init__(self): self.__doc__ = "Prints list of tasks.\nUsage: ompd taskframes" super(ompd_taskframes, self).__init__("ompd taskframes", gdb.COMMAND_STACK) def invoke(self, arg, from_tty): global addr_space if init_error(): return frame = gdb.newest_frame() while frame: print(frame.read_register("sp")) frame = frame.older() curr_task_handle = None if addr_space.threads and addr_space.threads.get(gdb.selected_thread().num): curr_thread_handle = curr_thread().thread_handle curr_task_handle = ompdModule.call_ompd_get_curr_task_handle( curr_thread_handle ) if not curr_task_handle: return None prev_frames = None try: while 1: frames_with_flags = ompdModule.call_ompd_get_task_frame( curr_task_handle ) frames = (frames_with_flags[0], frames_with_flags[3]) if prev_frames == frames: break if not isinstance(frames, tuple): break (ompd_enter_frame, ompd_exit_frame) = frames print(hex(ompd_enter_frame), hex(ompd_exit_frame)) curr_task_handle = ompdModule.call_ompd_get_scheduling_task_handle( curr_task_handle ) prev_frames = frames if not curr_task_handle: break except: traceback.print_exc() def print_and_exec(string): """Helper function for ompd_step. Executes the given command in GDB and prints it.""" print(string) gdb.execute(string) class TempFrameFunctionBp(gdb.Breakpoint): """Helper class for ompd_step. Defines stop function for breakpoint on frame function.""" def stop(self): global in_task_function in_task_function = True self.enabled = False class ompd_step(gdb.Command): """Executes 'step' and skips frames irrelevant to the application / the ones without debug information.""" def __init__(self): self.__doc__ = 'Executes "step" and skips runtime frames as much as possible.' super(ompd_step, self).__init__("ompd step", gdb.COMMAND_STACK) class TaskBeginBp(gdb.Breakpoint): """Helper class. Defines stop function for breakpoint ompd_bp_task_begin.""" def stop(self): try: code_line = curr_thread().get_current_task().get_task_function() frame_fct_bp = TempFrameFunctionBp( ("*%i" % code_line), temporary=True, internal=True ) frame_fct_bp.thread = self.thread return False except: return False def invoke(self, arg, from_tty): global in_task_function if init_error(): return tbp = self.TaskBeginBp("ompd_bp_task_begin", temporary=True, internal=True) tbp.thread = int(gdb.selected_thread().num) print_and_exec("step") while gdb.selected_frame().find_sal().symtab is None: if not in_task_function: print_and_exec("finish") else: print_and_exec("si") def init_error(): global addr_space if (gdb.selected_thread() is None) or (addr_space is None) or (not addr_space): print("Run 'ompd init' before running any of the ompd commands") return True return False def main(): ompd() ompd_init() ompd_threads() ompd_icvs() ompd_parallel_region() ompd_test() ompdtestapi() ompd_taskframes() ompd_bt() ompd_step() if __name__ == "__main__": try: main() except: traceback.print_exc() # NOTE: test code using: # OMP_NUM_THREADS=... gdb a.out -x ../../projects/gdb_plugin/gdb-ompd/__init__.py # ompd init # ompd threads