From 157f7e40141ee429081007d865b35cf8ae915e57 Mon Sep 17 00:00:00 2001 From: timv Date: Fri, 14 Jun 2013 18:30:40 -0400 Subject: [PATCH] Pickling Interpreter state seems to work. --- src/Dyna/Backend/Python/defn.py | 4 +- src/Dyna/Backend/Python/interpreter.py | 106 ++++++++++--------------- src/Dyna/Backend/Python/term.py | 8 +- src/Dyna/Backend/Python/utils.py | 22 +++++ 4 files changed, 68 insertions(+), 72 deletions(-) diff --git a/src/Dyna/Backend/Python/defn.py b/src/Dyna/Backend/Python/defn.py index a014199..e48d28f 100644 --- a/src/Dyna/Backend/Python/defn.py +++ b/src/Dyna/Backend/Python/defn.py @@ -17,8 +17,8 @@ class Aggregator(object): class BAggregator(Counter, Aggregator): - def __init__(self): - super(BAggregator, self).__init__() +# def __init__(self): +# super(BAggregator, self).__init__() def inc(self, val, ruleix, variables): self[val] += 1 def dec(self, val, ruleix, variables): diff --git a/src/Dyna/Backend/Python/interpreter.py b/src/Dyna/Backend/Python/interpreter.py index a577af4..b358493 100644 --- a/src/Dyna/Backend/Python/interpreter.py +++ b/src/Dyna/Backend/Python/interpreter.py @@ -251,11 +251,15 @@ class foo(dict): return c +def none(): + return None + + class Interpreter(object): def __init__(self): # declarations - self.agg_name = defaultdict(lambda: None) + self.agg_name = defaultdict(none) self.edges = defaultdict(set) # TODO: finding HG should be a post-processor self.updaters = defaultdict(list) # data structures @@ -266,21 +270,20 @@ class Interpreter(object): self.rules = ddict(Rule) self.errors = {} -# def __getstate__(self): -# return ((self.chart, -# self.agenda, -# self.agenda, -# self.errors, -# self.agg_name, -# self.parser_state), -# '\n'.join(self.rules[i].src for i in sorted(self.rules))) - -# def __setstate__(self, state): -# ((self.chart, self.agenda, self.agenda, self.errors, self.agg_name, self.parser_state), code) = state -# self.edges = defaultdict(set) -# self.updaters = defaultdict(list) -# self.rules = ddict(Rule) -# self.do(self.dynac_code(code)) + def __getstate__(self): + return ((self.chart, + self.agenda, + self.errors, + self.agg_name, + self.parser_state), + '\n'.join(self.rules[i].src for i in sorted(self.rules))) + + def __setstate__(self, state): + ((self.chart, self.agenda, self.errors, self.agg_name, self.parser_state), code) = state + self.edges = defaultdict(set) + self.updaters = defaultdict(list) + self.rules = ddict(Rule) + self.do(self.dynac_code(code), initialize=False) def new_fn(self, fn, agg): # check for aggregator conflict. @@ -346,7 +349,7 @@ class Interpreter(object): def dump_rules(self): for i in sorted(self.rules): print '%3s: %s' % (i, self.rules[i].src) -# + # def query(self, q): # if q.endswith('.'): # print "Queries don't end with a dot." @@ -367,7 +370,6 @@ class Interpreter(object): # print ' ', val, 'when', bindings # print - def build(self, fn, *args): # TODO: codegen should handle true/0 is True and false/0 is False if fn == "true/0": @@ -415,13 +417,10 @@ class Interpreter(object): return # Step 1: remove update handlers for u in rule.updaters: - for hs in self.updaters.values(): - for i, h in enumerate(hs): - if u is h: - del hs[i] - break - else: - assert False, "failed to find updater." + for xs in self.updaters.values(): + if u in xs: + xs.remove(u) + assert u not in xs, 'Several occurrences of u in xs' # Step 2: run initializer in delete mode rule.init(emit=self.delete_emit) # Step 3; go! @@ -430,7 +429,7 @@ class Interpreter(object): def go(self): try: return self._go() - except KeyboardInterrupt: # TODO: need to be safer in some parts of the code. + except KeyboardInterrupt: print '^C' self.dump_charts() @@ -521,7 +520,7 @@ class Interpreter(object): import repl repl.REPL(self, hist).cmdloop() - def do(self, filename): + def do(self, filename, initialize=True): """ Compile, load, and execute new dyna rules. @@ -533,16 +532,6 @@ class Interpreter(object): """ assert os.path.exists(filename) - # TODO: need a new tracing tool - # for debuggging -# with file(filename) as h: -# print >> self.trace, magenta % 'Loading new code' -# print >> self.trace, yellow % h.read() - - - # load generated code. -# execfile(filename, env) - env = imp.load_source('module.name', filename) for k,v in [('chart', self.chart), @@ -560,9 +549,10 @@ class Interpreter(object): self.new_fn(k, v) try: - # only run new initializers - for _, init in env.initializers: - init(emit=_emit) + if initialize: + # only run new initializers + for _, init in env.initializers: + init(emit=_emit) except (TypeError, ZeroDivisionError) as e: raise DynaInitializerException(e, init) @@ -603,9 +593,7 @@ class Interpreter(object): x.update(code) dyna = dotdynadir / 'tmp' / ('%s.dyna' % x.hexdigest()) - - # make necessary directories - dyna.dirname().mkdir_p() + dyna.dirname().mkdir_p() # make necessary directories out = '%s.plan.py' % dyna @@ -648,18 +636,18 @@ def main(): parser.add_argument('-o', dest='output', help='Output chart.') parser.add_argument('--draw', action='store_true', help='Output html page with hypergraph and chart.') - parser.add_argument('--postprocess', help='run post-processing script.') + parser.add_argument('--post-process', help='run post-processing script.') parser.add_argument('--profile', action='store_true', help='run profiler.') args = parser.parse_args() - if args.postprocess is not None: + if args.post_process is not None: try: - pp = __import__(args.postprocess) + pp = __import__(args.post_process) except ImportError: - print ('ERROR: No postprocessor named %r' % args.postprocess) + print ('ERROR: No postprocessor named %r' % args.post_process) return interp = Interpreter() @@ -679,26 +667,20 @@ def main(): # reason the garbage collector overhead is lowered in this # situation. Giving in a counterintuitive result. - import cProfile + from cProfile import Profile - cmd = 'interp.do(plan)' plan = '%s.plan.py' % args.source - dynac(args.source, plan) - p = cProfile.Profile() - - # redirect stdout - #sys.stdout = file(args.source + '.stdout', 'wb') - - p.runctx(cmd, globals(), locals()) + p = Profile() + p.runctx('interp.do(plan)', globals(), locals()) p.dump_stats('prof') interp.dump_charts() # call graph os.system('gprof2dot.py -f pstats prof | dot -Tsvg -o prof.svg && eog prof.svg &') - os.system('snakeviz prof &') + os.system('pkill snakeviz; snakeviz prof &') return @@ -735,15 +717,7 @@ def main(): if args.draw: interp.draw() -# interp.query('phrase(X,I,K)') - -# import cPickle -# out = cPickle.dumps(interp) # XXX: -# interp2 = cPickle.loads(out) # XXX: -# interp2.repl() - - if args.postprocess is not None: - # TODO: import and call main method instead. + if args.post_process is not None: pp.main(interp) diff --git a/src/Dyna/Backend/Python/term.py b/src/Dyna/Backend/Python/term.py index 441d143..dd88c0c 100644 --- a/src/Dyna/Backend/Python/term.py +++ b/src/Dyna/Backend/Python/term.py @@ -29,11 +29,11 @@ class Term(object): return fn return '%s(%s)' % (fn, ','.join(map(_repr, self.args))) -# def __getstate__(self): -# return (self.fn, self.args, self.value, self.aggregator) + def __getstate__(self): + return (self.fn, self.args, self.value, self.aggregator) -# def __setstate__(self, state): -# (self.fn, self.args, self.value, self.aggregator) = state + def __setstate__(self, state): + (self.fn, self.args, self.value, self.aggregator) = state __add__ = __sub__ = __mul__ = notimplemented diff --git a/src/Dyna/Backend/Python/utils.py b/src/Dyna/Backend/Python/utils.py index e2d1250..5f24ede 100644 --- a/src/Dyna/Backend/Python/utils.py +++ b/src/Dyna/Backend/Python/utils.py @@ -3,6 +3,8 @@ from subprocess import Popen, PIPE from IPython.frontend.terminal.embed import InteractiveShellEmbed from IPython.core.ultratb import VerboseTB from config import dynahome, dotdynadir +import signal +from contextlib import contextmanager # interactive IPython shell @@ -85,6 +87,26 @@ def enable_crash_handler(): sys.excepthook = exception_handler +@contextmanager +def interrupt_after(): + + def handler(signum, frame): + sys.stderr.write('^C') + handler.interrupted = True + return signal.SIG_IGN + + handler.interrupted = False + signal.signal(signal.SIGINT, handler) + + yield + + signal.signal(signal.SIGINT, signal.default_int_handler) + + if handler.interrupted: + raise KeyboardInterrupt + + + def notimplemented(*_,**__): raise NotImplementedError -- 2.50.1