blob: 9f6b914402fbd61636591e04ac5ef05b19561e40 [file] [log] [blame]
import gdb
import ompdModule
import itertools
from gdb.FrameDecorator import FrameDecorator
import ompd
from ompd_handles import ompd_task, ompd_parallel, ompd_thread
import traceback
from tempfile import NamedTemporaryFile
class OmpdFrameDecorator(FrameDecorator):
def __init__(self, fobj, curr_task_handle):
"""Initializes a FrameDecorator with the given GDB Frame object. The global OMPD address space defined in
ompd.py is set as well.
"""
super(OmpdFrameDecorator, self).__init__(fobj)
self.addr_space = ompd.addr_space
self.fobj = None
if isinstance(fobj, gdb.Frame):
self.fobj = fobj
elif isinstance(fobj, FrameDecorator):
self.fobj = fobj.inferior_frame()
self.curr_task_handle = curr_task_handle
def function(self):
"""This appends the name of a frame that is printed with the information whether the task started in the frame
is implicit or explicit. The ICVs are evaluated to determine that.
"""
name = str(self.fobj.name())
if self.curr_task_handle is None:
return name
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])
if icv_value == 0:
name = '@thread %i: %s "#pragma omp task"' % (gdb.selected_thread().num, name)
elif icv_value == 1:
name = '@thread %i: %s "#pragma omp parallel"' % (gdb.selected_thread().num, name)
else:
name = '@thread %i: %s' % (gdb.selected_thread().num, name)
return name
class OmpdFrameDecoratorThread(FrameDecorator):
def __init__(self, fobj):
"""Initializes a FrameDecorator with the given GDB Frame object."""
super(OmpdFrameDecoratorThread, self).__init__(fobj)
if isinstance(fobj, gdb.Frame):
self.fobj = fobj
elif isinstance(fobj, FrameDecorator):
self.fobj = fobj.inferior_frame()
def function(self):
name = str(self.fobj.name())
return '@thread %i: %s' % (gdb.selected_thread().num, name)
class FrameFilter():
def __init__(self, addr_space):
"""Initializes the FrameFilter, registers is in the GDB runtime and saves the given OMPD address space capsule.
"""
self.addr_space = addr_space
self.name = "Filter"
self.priority = 100
self.enabled = True
gdb.frame_filters[self.name] = self
self.switched_on = False
self.continue_to_master = False
def set_switch(self, on_off):
"""Prints output when executing 'ompd bt on' or 'ompd bt off'.
"""
self.switched_on = on_off
if self.switched_on:
print('Enabled filter for "bt" output successfully.')
else:
print('Disabled filter for "bt" output successfully.')
def set_switch_continue(self, on_off):
"""Prints output when executing 'ompd bt on continued'."
"""
self.continue_to_master = on_off
if self.continue_to_master:
print('Enabled "bt" mode that continues backtrace on to master thread for worker threads.')
else:
print('Disabled "bt" mode that continues onto master thread.')
def get_master_frames_for_worker(self, past_thread_num, latest_sp):
"""Prints master frames for worker thread with id past_thread_num.
"""
gdb.execute('t 1')
gdb.execute('ompd bt on')
gdb.execute('bt')
frame = gdb.newest_frame()
while frame.older() is not None:
print('master frame sp:', str(frame.read_register('sp')))
yield OmpdFrameDecorator(frame)
frame = frame.older()
print('latest sp:', str(latest_sp))
gdb.execute('ompd bt on continued')
gdb.execute('t %d' % int(past_thread_num))
def filter_frames(self, frame_iter):
"""Iterates through frames and only returns those that are relevant to the application
being debugged. The OmpdFrameDecorator is applied automatically.
"""
curr_thread_num = gdb.selected_thread().num
is_no_omp_thread = False
if curr_thread_num in self.addr_space.threads:
curr_thread_obj = self.addr_space.threads[curr_thread_num]
self.curr_task = curr_thread_obj.get_current_task()
self.frames = self.curr_task.get_task_frame()
else:
is_no_omp_thread = True
print('Thread %d is no OpenMP thread, printing all frames:' % curr_thread_num)
stop_iter = False
for x in frame_iter:
if is_no_omp_thread:
yield OmpdFrameDecoratorThread(x)
continue
if x.inferior_frame().older() is None:
continue
if self.curr_task.task_handle is None:
continue
gdb_sp = int(str(x.inferior_frame().read_register('sp')), 16)
gdb_sp_next_new = int(str(x.inferior_frame()).split(",")[0].split("=")[1], 16)
if x.inferior_frame().older():
gdb_sp_next = int(str(x.inferior_frame().older().read_register('sp')), 16)
else:
gdb_sp_next = int(str(x.inferior_frame().read_register('sp')), 16)
while(1):
(ompd_enter_frame, ompd_exit_frame) = self.frames
if (ompd_enter_frame != 0 and gdb_sp_next_new < ompd_enter_frame):
break
if (ompd_exit_frame != 0 and gdb_sp_next_new < ompd_exit_frame):
if x.inferior_frame().older().older() and int(str(x.inferior_frame().older().older().read_register('sp')), 16) < ompd_exit_frame:
if self.continue_to_master:
yield OmpdFrameDecoratorThread(x)
else:
yield OmpdFrameDecorator(x, self.curr_task.task_handle)
else:
yield OmpdFrameDecorator(x, self.curr_task.task_handle)
break
sched_task_handle = self.curr_task.get_scheduling_task_handle()
if(sched_task_handle is None):
stop_iter = True
break
self.curr_task = self.curr_task.get_scheduling_task()
self.frames = self.curr_task.get_task_frame()
if stop_iter:
break
# implementation of "ompd bt continued"
if self.continue_to_master:
orig_thread = gdb.selected_thread().num
gdb_threads = dict([(t.num, t) for t in gdb.selected_inferior().threads()])
# iterate through generating tasks until outermost task is reached
while(1):
# get OMPD thread id for master thread (systag in GDB output)
try:
master_num = self.curr_task.get_task_parallel().get_thread_in_parallel(0).get_thread_id()
except:
break
# search for thread id without the "l" for long via "thread find" and get GDB thread num from output
hex_str = str(hex(master_num))
thread_output = gdb.execute('thread find %s' % hex_str[0:len(hex_str)-1], to_string=True).split(" ")
if thread_output[0] == "No":
raise ValueError('Master thread num could not be found!')
gdb_master_num = int(thread_output[1])
# get task that generated last task of worker thread
try:
self.curr_task = self.curr_task.get_task_parallel().get_task_in_parallel(0).get_generating_task()
except:
break;
self.frames = self.curr_task.get_task_frame()
(enter_frame, exit_frame) = self.frames
if exit_frame == 0:
print('outermost generating task was reached')
break
# save GDB num for worker thread to change back to it later
worker_thread = gdb.selected_thread().num
# use InferiorThread.switch()
gdb_threads = dict([(t.num, t) for t in gdb.selected_inferior().threads()])
gdb_threads[gdb_master_num].switch()
print('#### switching to thread %i ####' % gdb_master_num)
frame = gdb.newest_frame()
stop_iter = False
while(not stop_iter):
if self.curr_task.task_handle is None:
break
self.frames = self.curr_task.get_task_frame()
while frame:
if self.curr_task.task_handle is None:
break
gdb_sp_next_new = int(str(frame).split(",")[0].split("=")[1], 16)
if frame.older():
gdb_sp_next = int(str(frame.older().read_register('sp')), 16)
else:
gdb_sp_next = int(str(frame.read_register('sp')), 16)
while(1):
(ompd_enter_frame, ompd_exit_frame) = self.frames
if (ompd_enter_frame != 0 and gdb_sp_next_new < ompd_enter_frame):
break
if (ompd_exit_frame == 0 or gdb_sp_next_new < ompd_exit_frame):
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:
yield OmpdFrameDecoratorThread(frame)
else:
yield OmpdFrameDecorator(frame, self.curr_task.task_handle)
break
sched_task_handle = ompdModule.call_ompd_get_scheduling_task_handle(self.curr_task.task_handle)
if(sched_task_handle is None):
stop_iter = True
break
self.curr_task = self.curr_task.get_generating_task()
self.frames = self.curr_task.get_task_frame()
frame = frame.older()
break
gdb_threads[worker_thread].switch()
gdb_threads[orig_thread].switch()
def filter(self, frame_iter):
"""Function is called automatically with every 'bt' executed. If switched on, this will only let revelant frames be printed
or all frames otherwise. If switched on, a FrameDecorator will be applied to state whether '.ompd_task_entry.' refers to an
explicit or implicit task.
"""
if self.switched_on:
return self.filter_frames(frame_iter)
else:
return frame_iter