|
| 1 | +import gdb |
| 2 | +import ompdModule |
| 3 | +import itertools |
| 4 | +from gdb.FrameDecorator import FrameDecorator |
| 5 | +import ompd |
| 6 | +from ompd_handles import ompd_task, ompd_parallel, ompd_thread |
| 7 | +import traceback |
| 8 | +from tempfile import NamedTemporaryFile |
| 9 | + |
| 10 | + |
| 11 | +class OmpdFrameDecorator(FrameDecorator): |
| 12 | + |
| 13 | + def __init__(self, fobj, curr_task_handle): |
| 14 | + """Initializes a FrameDecorator with the given GDB Frame object. The global OMPD address space defined in |
| 15 | + ompd.py is set as well. |
| 16 | + """ |
| 17 | + super(OmpdFrameDecorator, self).__init__(fobj) |
| 18 | + self.addr_space = ompd.addr_space |
| 19 | + self.fobj = None |
| 20 | + if isinstance(fobj, gdb.Frame): |
| 21 | + self.fobj = fobj |
| 22 | + elif isinstance(fobj, FrameDecorator): |
| 23 | + self.fobj = fobj.inferior_frame() |
| 24 | + self.curr_task_handle = curr_task_handle |
| 25 | + |
| 26 | + def function(self): |
| 27 | + """This appends the name of a frame that is printed with the information whether the task started in the frame |
| 28 | + is implicit or explicit. The ICVs are evaluated to determine that. |
| 29 | + """ |
| 30 | + name = str(self.fobj.name()) |
| 31 | + |
| 32 | + if self.curr_task_handle is None: |
| 33 | + return name |
| 34 | + |
| 35 | + icv_value = ompdModule.call_ompd_get_icv_from_scope(self.curr_task_handle, ompd.icv_map['implicit-task-var'][1], ompd.icv_map['implicit-task-var'][0]) |
| 36 | + if icv_value == 0: |
| 37 | + name = '@thread %i: %s "#pragma omp task"' % (gdb.selected_thread().num, name) |
| 38 | + elif icv_value == 1: |
| 39 | + name = '@thread %i: %s "#pragma omp parallel"' % (gdb.selected_thread().num, name) |
| 40 | + else: |
| 41 | + name = '@thread %i: %s' % (gdb.selected_thread().num, name) |
| 42 | + return name |
| 43 | + |
| 44 | +class OmpdFrameDecoratorThread(FrameDecorator): |
| 45 | + |
| 46 | + def __init__(self, fobj): |
| 47 | + """Initializes a FrameDecorator with the given GDB Frame object.""" |
| 48 | + super(OmpdFrameDecoratorThread, self).__init__(fobj) |
| 49 | + if isinstance(fobj, gdb.Frame): |
| 50 | + self.fobj = fobj |
| 51 | + elif isinstance(fobj, FrameDecorator): |
| 52 | + self.fobj = fobj.inferior_frame() |
| 53 | + |
| 54 | + def function(self): |
| 55 | + name = str(self.fobj.name()) |
| 56 | + return '@thread %i: %s' % (gdb.selected_thread().num, name) |
| 57 | + |
| 58 | +class FrameFilter(): |
| 59 | + |
| 60 | + def __init__(self, addr_space): |
| 61 | + """Initializes the FrameFilter, registers is in the GDB runtime and saves the given OMPD address space capsule. |
| 62 | + """ |
| 63 | + self.addr_space = addr_space |
| 64 | + self.name = "Filter" |
| 65 | + self.priority = 100 |
| 66 | + self.enabled = True |
| 67 | + gdb.frame_filters[self.name] = self |
| 68 | + self.switched_on = False |
| 69 | + self.continue_to_master = False |
| 70 | + |
| 71 | + def set_switch(self, on_off): |
| 72 | + """Prints output when executing 'ompd bt on' or 'ompd bt off'. |
| 73 | + """ |
| 74 | + self.switched_on = on_off |
| 75 | + if self.switched_on: |
| 76 | + print('Enabled filter for "bt" output successfully.') |
| 77 | + else: |
| 78 | + print('Disabled filter for "bt" output successfully.') |
| 79 | + |
| 80 | + def set_switch_continue(self, on_off): |
| 81 | + """Prints output when executing 'ompd bt on continued'." |
| 82 | + """ |
| 83 | + self.continue_to_master = on_off |
| 84 | + if self.continue_to_master: |
| 85 | + print('Enabled "bt" mode that continues backtrace on to master thread for worker threads.') |
| 86 | + else: |
| 87 | + print('Disabled "bt" mode that continues onto master thread.') |
| 88 | + |
| 89 | + def get_master_frames_for_worker(self, past_thread_num, latest_sp): |
| 90 | + """Prints master frames for worker thread with id past_thread_num. |
| 91 | + """ |
| 92 | + gdb.execute('t 1') |
| 93 | + gdb.execute('ompd bt on') |
| 94 | + gdb.execute('bt') |
| 95 | + |
| 96 | + frame = gdb.newest_frame() |
| 97 | + |
| 98 | + while frame.older() is not None: |
| 99 | + print('master frame sp:', str(frame.read_register('sp'))) |
| 100 | + yield OmpdFrameDecorator(frame) |
| 101 | + frame = frame.older() |
| 102 | + print('latest sp:', str(latest_sp)) |
| 103 | + |
| 104 | + gdb.execute('ompd bt on continued') |
| 105 | + gdb.execute('t %d' % int(past_thread_num)) |
| 106 | + |
| 107 | + |
| 108 | + def filter_frames(self, frame_iter): |
| 109 | + """Iterates through frames and only returns those that are relevant to the application |
| 110 | + being debugged. The OmpdFrameDecorator is applied automatically. |
| 111 | + """ |
| 112 | + curr_thread_num = gdb.selected_thread().num |
| 113 | + is_no_omp_thread = False |
| 114 | + if curr_thread_num in self.addr_space.threads: |
| 115 | + curr_thread_obj = self.addr_space.threads[curr_thread_num] |
| 116 | + self.curr_task = curr_thread_obj.get_current_task() |
| 117 | + self.frames = self.curr_task.get_task_frame() |
| 118 | + else: |
| 119 | + is_no_omp_thread = True |
| 120 | + print('Thread %d is no OpenMP thread, printing all frames:' % curr_thread_num) |
| 121 | + |
| 122 | + stop_iter = False |
| 123 | + for x in frame_iter: |
| 124 | + if is_no_omp_thread: |
| 125 | + yield OmpdFrameDecoratorThread(x) |
| 126 | + continue |
| 127 | + |
| 128 | + if x.inferior_frame().older() is None: |
| 129 | + continue |
| 130 | + if self.curr_task.task_handle is None: |
| 131 | + continue |
| 132 | + |
| 133 | + gdb_sp = int(str(x.inferior_frame().read_register('sp')), 16) |
| 134 | + gdb_sp_next_new = int(str(x.inferior_frame()).split(",")[0].split("=")[1], 16) |
| 135 | + if x.inferior_frame().older(): |
| 136 | + gdb_sp_next = int(str(x.inferior_frame().older().read_register('sp')), 16) |
| 137 | + else: |
| 138 | + gdb_sp_next = int(str(x.inferior_frame().read_register('sp')), 16) |
| 139 | + while(1): |
| 140 | + (ompd_enter_frame, ompd_exit_frame) = self.frames |
| 141 | + |
| 142 | + if (ompd_enter_frame != 0 and gdb_sp_next_new < ompd_enter_frame): |
| 143 | + break |
| 144 | + if (ompd_exit_frame != 0 and gdb_sp_next_new < ompd_exit_frame): |
| 145 | + if x.inferior_frame().older().older() and int(str(x.inferior_frame().older().older().read_register('sp')), 16) < ompd_exit_frame: |
| 146 | + if self.continue_to_master: |
| 147 | + yield OmpdFrameDecoratorThread(x) |
| 148 | + else: |
| 149 | + yield OmpdFrameDecorator(x, self.curr_task.task_handle) |
| 150 | + else: |
| 151 | + yield OmpdFrameDecorator(x, self.curr_task.task_handle) |
| 152 | + break |
| 153 | + sched_task_handle = self.curr_task.get_scheduling_task_handle() |
| 154 | + |
| 155 | + if(sched_task_handle is None): |
| 156 | + stop_iter = True |
| 157 | + break |
| 158 | + |
| 159 | + self.curr_task = self.curr_task.get_scheduling_task() |
| 160 | + self.frames = self.curr_task.get_task_frame() |
| 161 | + if stop_iter: |
| 162 | + break |
| 163 | + |
| 164 | + # implementation of "ompd bt continued" |
| 165 | + if self.continue_to_master: |
| 166 | + |
| 167 | + orig_thread = gdb.selected_thread().num |
| 168 | + gdb_threads = dict([(t.num, t) for t in gdb.selected_inferior().threads()]) |
| 169 | + |
| 170 | + # iterate through generating tasks until outermost task is reached |
| 171 | + while(1): |
| 172 | + # get OMPD thread id for master thread (systag in GDB output) |
| 173 | + try: |
| 174 | + master_num = self.curr_task.get_task_parallel().get_thread_in_parallel(0).get_thread_id() |
| 175 | + except: |
| 176 | + break |
| 177 | + # search for thread id without the "l" for long via "thread find" and get GDB thread num from output |
| 178 | + hex_str = str(hex(master_num)) |
| 179 | + thread_output = gdb.execute('thread find %s' % hex_str[0:len(hex_str)-1], to_string=True).split(" ") |
| 180 | + if thread_output[0] == "No": |
| 181 | + raise ValueError('Master thread num could not be found!') |
| 182 | + gdb_master_num = int(thread_output[1]) |
| 183 | + # get task that generated last task of worker thread |
| 184 | + try: |
| 185 | + self.curr_task = self.curr_task.get_task_parallel().get_task_in_parallel(0).get_generating_task() |
| 186 | + except: |
| 187 | + break; |
| 188 | + self.frames = self.curr_task.get_task_frame() |
| 189 | + (enter_frame, exit_frame) = self.frames |
| 190 | + if exit_frame == 0: |
| 191 | + print('outermost generating task was reached') |
| 192 | + break |
| 193 | + |
| 194 | + # save GDB num for worker thread to change back to it later |
| 195 | + worker_thread = gdb.selected_thread().num |
| 196 | + |
| 197 | + # use InferiorThread.switch() |
| 198 | + gdb_threads = dict([(t.num, t) for t in gdb.selected_inferior().threads()]) |
| 199 | + gdb_threads[gdb_master_num].switch() |
| 200 | + print('#### switching to thread %i ####' % gdb_master_num) |
| 201 | + |
| 202 | + frame = gdb.newest_frame() |
| 203 | + stop_iter = False |
| 204 | + |
| 205 | + while(not stop_iter): |
| 206 | + if self.curr_task.task_handle is None: |
| 207 | + break |
| 208 | + self.frames = self.curr_task.get_task_frame() |
| 209 | + |
| 210 | + while frame: |
| 211 | + if self.curr_task.task_handle is None: |
| 212 | + break |
| 213 | + |
| 214 | + gdb_sp_next_new = int(str(frame).split(",")[0].split("=")[1], 16) |
| 215 | + |
| 216 | + if frame.older(): |
| 217 | + gdb_sp_next = int(str(frame.older().read_register('sp')), 16) |
| 218 | + else: |
| 219 | + gdb_sp_next = int(str(frame.read_register('sp')), 16) |
| 220 | + |
| 221 | + while(1): |
| 222 | + (ompd_enter_frame, ompd_exit_frame) = self.frames |
| 223 | + |
| 224 | + if (ompd_enter_frame != 0 and gdb_sp_next_new < ompd_enter_frame): |
| 225 | + break |
| 226 | + if (ompd_exit_frame == 0 or gdb_sp_next_new < ompd_exit_frame): |
| 227 | + if ompd_exit_frame == 0 or frame.older() and frame.older().older() and int(str(frame.older().older().read_register('sp')), 16) < ompd_exit_frame: |
| 228 | + yield OmpdFrameDecoratorThread(frame) |
| 229 | + else: |
| 230 | + yield OmpdFrameDecorator(frame, self.curr_task.task_handle) |
| 231 | + break |
| 232 | + sched_task_handle = ompdModule.call_ompd_get_scheduling_task_handle(self.curr_task.task_handle) |
| 233 | + |
| 234 | + if(sched_task_handle is None): |
| 235 | + stop_iter = True |
| 236 | + break |
| 237 | + self.curr_task = self.curr_task.get_generating_task() |
| 238 | + self.frames = self.curr_task.get_task_frame() |
| 239 | + |
| 240 | + frame = frame.older() |
| 241 | + break |
| 242 | + |
| 243 | + gdb_threads[worker_thread].switch() |
| 244 | + |
| 245 | + gdb_threads[orig_thread].switch() |
| 246 | + |
| 247 | + |
| 248 | + def filter(self, frame_iter): |
| 249 | + """Function is called automatically with every 'bt' executed. If switched on, this will only let revelant frames be printed |
| 250 | + or all frames otherwise. If switched on, a FrameDecorator will be applied to state whether '.ompd_task_entry.' refers to an |
| 251 | + explicit or implicit task. |
| 252 | + """ |
| 253 | + if self.switched_on: |
| 254 | + return self.filter_frames(frame_iter) |
| 255 | + else: |
| 256 | + return frame_iter |
0 commit comments