import logging; log = logging.getLogger(__name__)
log_user = logging.getLogger("mcgdb.log.user.step")
import gdb
from mcgdb.toolbox import my_gdb, aspect
from mcgdb.interaction import push_stop_request
representation = None
OPM_ZONES = ("single", "parallel", "critical", "task", "sections", "barrier", "master")
current_worker = None
@my_gdb.internal
[docs]def initialize():
global representation, current_worker
from .. import representation
current_worker = representation.Worker.get_current_worker
@my_gdb.internal
[docs]def activate():
aspect.register("step", aspects)
cmd_omp_step()
cmd_omp_next()
######################
[docs]class cmd_omp_next (gdb.Command):
""" Stops the execution before the next OPM zone
[.] --> stop only on the current thread, anythread otherwise
[{}] --> stop at the next [where] zone.
""".format(",".join(OPM_ZONES))
def __init__ (self):
gdb.Command.__init__(self, "omp next", gdb.COMMAND_OBSCURE)
[docs] def invoke (self, arg, from_tty):
args = gdb.string_to_argv(arg)
# by default apply to any thread,
# if args[0] is . apply to current thread
apply_to = None
if args and args[0] == ".":
apply_to = current_worker()
args.pop(0)
where = args[0] if args and args[0] in OPM_ZONES else None
if where is None and arg:
print("Could not recognize 'where' argument '{}'".format(arg))
print("It should be one of {}".format(",".join(OPM_ZONES)))
return
step._nexting[apply_to] = where
my_gdb.start_or_continue()
###
[docs]class cmd_omp_step (gdb.Command):
"""Steps inside the next OPM zone.
Usage:
(default) -> stop the first thread entering the zone
all -> stop all the threads entering the zone
out -> stop the end of the (inner most) zone
"""
def __init__ (self):
gdb.Command.__init__(self, "omp step", gdb.COMMAND_OBSCURE)
[docs] def invoke (self, args, from_tty):
step._stepping = True
if "out" in args:
step._step_out = True
step._stepping = False
my_gdb.start_or_continue()
#####################################
[docs]class step:
_nexting = {} # worker -> (where|None)
_stepping = False
_step_out = False
@staticmethod
[docs] def nexting(current_where):
cw = current_worker()
if None in step._nexting.keys():
cw = None
else:
cw = current_worker()
if cw not in step._nexting.keys():
return False
target_where = step._nexting[cw]
if target_where is not None and \
current_where != target_where:
return False
del step._nexting[cw]
return True
@staticmethod
[docs] def stepping():
ret = step._stepping
step._stepping = False
return ret
@staticmethod
[docs] def stepping_out():
ret = step._step_out
step._step_out = False
return ret
[docs]def check_nexting(where, what=None):
assert where in OPM_ZONES
if what is None:
what = "{} zone".format(where.title())
if step.nexting(where):
push_stop_request("[OpenMP next] reached {}".format(what))
return True
return False
[docs]def check_stepping(evt):
if step.stepping():
push_stop_request("[OpenMP step] inside {}".format(evt))
return True
return False
[docs]def check_stepping_out(evt):
if step.stepping_out():
push_stop_request("[OpenMP step out] outside {}".format(evt))
return True
return False
#######################
# Aspect for stepping #
#######################
[docs]def aspects(Tracks):
@Tracks(representation.Worker)
class WorkerTracker:
def __init__(this):
pass
@Tracks(representation.ParallelJob)
class ParallelJobTracker:
def __init__(this):
this.args.num_workers, this.args.parent_worker = this.meth_args
check_nexting("parallel")
def start_working(this):
check_stepping("Worker #{} in parallel zone".format(this.args.worker.number))
def stop_working(this):
pass
def completed(this):
check_stepping_out("Parallel zone")
def start_section_zone(this):
check_nexting("sections")
def stop_section_zone(this):
check_stepping_out("Section zone")
@Tracks(representation.SingleJob)
class SingleTracker:
def __init__(this):
this.args.worker, this.args.parallel_job = this.meth_args
def enter(this):
check_nexting("single")
if this.args.inside:
check_stepping("Worker #{} in single zone".format(this.args.worker.number))
def finished(this):
pass
def completed(this):
check_stepping_out("Single zone")
@Tracks(representation.TaskJob)
class TaskJobTracker:
def __init__(this):
this.args.worker, = this.meth_args
log_user.info("New task: {}".format(this.self))
if check_nexting("task", "Task #{} creation".format(this.self.number)):
my_gdb.up_before_prompt()
def start(this):
check_stepping("Worker #{} on the task".format(this.args.worker.number))
def finish(this):
check_stepping_out("Task")
@Tracks(representation.CriticalJob)
class CriticalJobTracker:
def __init__(this):
this.args.worker,this. args.parallel_job = this.meth_args
def try_enter(this):
if check_nexting("critical"):
my_gdb.up_before_prompt()
def entered(this):
check_stepping("Worker #{} in critical zone".format(this.args.worker.number))
def left(this):
pass
def completed(this):
check_stepping_out("Critical zone")
@Tracks(representation.Barrier)
class BarrierTracker:
def __init__(this):
#if this.self.internal: return
this.args.parallel_job, this.args.worker,= this.meth_args
def reach_barrier(this):
#if this.self.internal: return
if check_nexting("barrier", "Barrier"):
my_gdb.up_before_prompt()
if gdb.parameter("scheduler-locking") == "on":
log_user.warning("gdb scheduler-locking is active,")
log_user.warning("OpenMP won't be able to pass the barrier")
log_user.warning("Run `omp schedule all` if necessary.")
def leave_barrier(this):
if this.self.internal: return
check_stepping_out("Barrier")
@Tracks(representation.SectionJob)
class SectionJobTracker:
def __init__(this):
this.args.parallel_job, this.args.worker, this.args.count = this.meth_args
def work_on_section(this):
if (this.args.section_id != 0):
check_stepping("inside Section #{}".format(this.args.section_id))
def ended(this):
pass
def completed(this):
pass