[pypy-commit] lang-smalltalk storage: Refactored command line flags a little to be more precise and give more controll over what happens.

anton_gulenko noreply at buildbot.pypy.org
Thu Jul 10 12:56:52 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage
Changeset: r875:f9f21debba52
Date: 2014-07-07 17:36 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/f9f21debba52/

Log:	Refactored command line flags a little to be more precise and give
	more controll over what happens. Added descriptions to the usage-
	string.

diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -10,201 +10,114 @@
 from spyvm.tool.analyseimage import create_image
 from spyvm.interpreter_proxy import VirtualMachine
 
-def print_result(w_result):
-    # This will also print contents of strings/symbols/numbers
-    print w_result.as_repr_string().replace('\r', '\n')
-
-def _run_benchmark(interp, number, benchmark, arg):
-    from spyvm.plugins.vmdebugging import stop_ui_process
-    stop_ui_process()
-
-    space = interp.space
-    scheduler = wrapper.scheduler(space)
-    w_hpp = scheduler.active_process()
-    if space.unwrap_int(scheduler.active_process().fetch(space, 2)) > space.unwrap_int(w_hpp.fetch(space, 2)):
-        w_hpp = scheduler.active_process()
-    assert isinstance(w_hpp, model.W_PointersObject)
-    w_benchmark_proc = model.W_PointersObject(
-        space,
-        w_hpp.getclass(space),
-        w_hpp.size()
-    )
-
-    s_frame = context_for(interp, number, benchmark, arg)
-    # second variable is suspended context
-    w_benchmark_proc.store(space, 1, s_frame.w_self())
-
-    # third variable is priority
-    priority = space.unwrap_int(w_hpp.fetch(space, 2)) / 2 + 1
-    # Priorities below 10 are not allowed in newer versions of Squeak.
-    if interp.image.version.has_closures:
-        priority = max(11, priority)
-    else:
-        priority = 7
-    w_benchmark_proc.store(space, 2, space.wrap_int(priority))
-
-    # make process eligible for scheduling
-    wrapper.ProcessWrapper(space, w_benchmark_proc).put_to_sleep()
-
-    t1 = time.time()
-    w_result = _run_image(interp)
-    t2 = time.time()
-    if w_result:
-        print_result(w_result)
-        print "took %s seconds" % (t2 - t1)
-        return 0
-    return -1
-
-def _run_image(interp):
-    space = interp.space
-    ap = wrapper.ProcessWrapper(space, wrapper.scheduler(space).active_process())
-    w_ctx = ap.suspended_context()
-    assert isinstance(w_ctx, model.W_PointersObject)
-    ap.store_suspended_context(space.w_nil)
-    try:
-        return interp.interpret_toplevel(w_ctx)
-    except error.Exit, e:
-        print e.msg
-
-def _run_code(interp, code, as_benchmark=False):
-    import time
-    selector = "DoIt%d" % int(time.time())
-    space = interp.space
-    w_receiver = space.w_nil
-    w_receiver_class = w_receiver.getclass(space)
-    try:
-        w_result = interp.perform(
-            w_receiver_class,
-            "compile:classified:notifying:",
-            space.wrap_string("%s\r\n%s" % (selector, code)),
-            space.wrap_string("spy-run-code"),
-            space.w_nil
-        )
-        w_receiver_class.as_class_get_shadow(space).s_methoddict().sync_method_cache()
-    except interpreter.ReturnFromTopLevel, e:
-        print e.object
-        return 1
-    except error.Exit, e:
-        print e.msg
-        return 1
-    
-    if not as_benchmark:
-        try:
-            w_result = interp.perform(w_receiver, selector)
-        except interpreter.ReturnFromTopLevel, e:
-            print e.object
-            return 1
-        except error.Exit, e:
-            print e.msg
-            return 1
-        if w_result:
-            print_result(w_result)
-        return 0
-    else:
-        return _run_benchmark(interp, 0, selector, "")
-
-def context_for(interp, number, benchmark, stringarg):
-    w_receiver = interp.space.wrap_int(number)
-    if stringarg:
-        return interp.create_toplevel_context(w_receiver, benchmark, interp.space.wrap_string(stringarg))
-    else:
-        return interp.create_toplevel_context(w_receiver, benchmark)
-
 def _usage(argv):
     print """
-    Usage: %s
-          -j|--jit [jitargs]
-          -n|--number [smallint, default: 0]
-          -m|--method [benchmark on smallint]
-          -a|--arg [string argument to #method]
-          -r|--run [code string]
-          -b|--benchmark [code string]
-          -p|--poll_events
-          -ni|--no-interrupts
-          -d|--max-stack-depth [number, default %d, <= 0 disables stack protection]
-          -l|--storage-log
-          -L|--storage-log-aggregate
-          -E|--storage-log-elements
-          [image path, default: Squeak.image]
+    Usage: %s <path> [-r|-m] [-naH] [-jpis] [-tlLE]
+            <path> - image path (default: Squeak.image)
+          
+          Execution mode:
+            (no flags)             - Image will be normally opened.
+            -r|--run <code>        - Code will be compiled and executed, result printed.
+            -m|--method <selector> - Selector will be sent to a SmallInteger, result printed.
+            -h|--help              - Output this and exit.
+            
+          Execution parameters:
+            -n|--num <int> - Only with -m or -r, SmallInteger to be used as receiver (default: nil).
+            -a|--arg <arg> - Only with -m, will be used as single String argument.
+            -H|--headless  - Only with -m or -r, run in headless mode.
+                             Execute the context directly, ignoring the active context in the image.
+                             The execution will 'hijack' the active process.
+                             Image window will probably not open. Good for benchmarking.
+                             By default, a high-priority process will be created for the context, then the image
+                             will be started normally.
+            -u             - Only with -m or -r, try to stop UI-process at startup. Can help with -H.
+            
+          Other parameters:
+            -j|--jit <jitargs> - jitargs will be passed to the jit configuration.
+            -p|--poll          - Actively poll for events. Try this if the image is not responding well.
+            -i|--no-interrupts - Disable timer interrupt. Disables non-cooperative scheduling.
+            -s <num>           - After num stack frames, the entire stack will be dumped to the heap.
+                                 This breaks performance, but protects agains stack overflow.
+                                 num <= 0 disables stack protection (default: %d)
+            
+          Logging parameters:
+            -t|--trace                 - Output a trace of each message, primitive, return value and process switch.
+            -l|--storage-log           - Output a log of storage operations.
+            -L|--storage-log-aggregate - Output an aggregated storage log at the end of execution.
+            -E|--storage-log-elements  - Include classnames of elements into the storage log.
+            
     """ % (argv[0], constants.MAX_LOOP_DEPTH)
 
-def _arg_missing(argv, idx, arg):
-    if len(argv) == idx + 1:
+def get_parameter(argv, idx, arg):
+    if len(argv) < idx + 1:
         raise RuntimeError("Error: missing argument after %s" % arg)
-
+    return argv[idx], idx + 1
+    
 prebuilt_space = objspace.ObjSpace()
 
 def entry_point(argv):
-    idx = 1
-    path = None
+    # == Main execution parameters
+    selector = None
+    code = ""
     number = 0
-    benchmark = None
+    have_number = False
+    stringarg = None
+    headless = False
+    # == Other parameters
+    poll = False
+    interrupts = True
+    max_stack_depth = constants.MAX_LOOP_DEPTH
     trace = False
-    evented = True
-    stringarg = ""
-    code = None
-    as_benchmark = False
-    max_stack_depth = constants.MAX_LOOP_DEPTH
-    interrupts = True
+    
+    path = argv[1] if len(argv) > 1 else "Squeak.image"
+    idx = 2
     
     while idx < len(argv):
         arg = argv[idx]
+        idx += 1
         if arg in ["-h", "--help"]:
             _usage(argv)
             return 0
         elif arg in ["-j", "--jit"]:
-            _arg_missing(argv, idx, arg)
-            jitarg = argv[idx + 1]
-            idx += 1
+            jitarg, idx = get_parameter(argv, idx, arg)
             jit.set_user_param(interpreter.Interpreter.jit_driver, jitarg)
         elif arg in ["-n", "--number"]:
-            _arg_missing(argv, idx, arg)
-            number = int(argv[idx + 1])
-            idx += 1
+            numarg, idx = get_parameter(argv, idx, arg)
+            number = int(numarg)
+            have_number = True
         elif arg in ["-m", "--method"]:
-            _arg_missing(argv, idx, arg)
-            benchmark = argv[idx + 1]
-            idx += 1
+            selector, idx = get_parameter(argv, idx, arg)
         elif arg in ["-t", "--trace"]:
             trace = True
-        elif arg in ["-p", "--poll_events"]:
-            evented = False
+        elif arg in ["-p", "--poll"]:
+            poll = True
         elif arg in ["-a", "--arg"]:
-            _arg_missing(argv, idx, arg)
-            stringarg = argv[idx + 1]
-            idx += 1
+            stringarg, idx = get_parameter(argv, idx, arg)
         elif arg in ["-r", "--run"]:
-            _arg_missing(argv, idx, arg)
-            code = argv[idx + 1]
-            as_benchmark = False
-            idx += 1
-        elif arg in ["-b", "--benchmark"]:
-            _arg_missing(argv, idx, arg)
-            code = argv[idx + 1]
-            as_benchmark = True
-            idx += 1
-        elif arg in ["-ni", "--no-interrupts"]:
+            code, idx = get_parameter(argv, idx, arg)
+        elif arg in ["-i", "--no-interrupts"]:
             interrupts = False
-        elif arg in ["-d", "--max-stack-depth"]:
-            _arg_missing(argv, idx, arg)
-            max_stack_depth = int(argv[idx + 1])
-            idx += 1
+        elif arg in ["-s"]:
+            arg, idx = get_parameter(argv, idx, arg)
+            max_stack_depth = int(arg)
+        elif arg in ["-H", "--headless"]:
+            headless = True
+        elif arg in ["-u"]:
+            from spyvm.plugins.vmdebugging import stop_ui_process
+            stop_ui_process()
         elif arg in ["-l", "--storage-log"]:
             storage_logger.activate()
         elif arg in ["-L", "--storage-log-aggregate"]:
             storage_logger.activate(aggregate=True)
         elif arg in ["-E", "--storage-log-elements"]:
             storage_logger.activate(elements=True)
-        elif path is None:
-            path = argv[idx]
         else:
             _usage(argv)
             return -1
-        idx += 1
-
-    if path is None:
-        path = "Squeak.image"
-
+    
+    if code and selector:
+        raise RuntimeError("Cannot handle both -r and -m.")
+    
     path = rpath.rabspath(path)
     try:
         f = open_file_as_stream(path, mode="rb", buffering=0)
@@ -216,27 +129,108 @@
         os.write(2, "%s -- %s (LoadError)\n" % (os.strerror(e.errno), path))
         return 1
     
+    # Load & prepare image and environment
     space = prebuilt_space
     image_reader = squeakimage.reader_for_image(space, squeakimage.Stream(data=imagedata))
     image = create_image(space, image_reader)
     interp = interpreter.Interpreter(space, image, image_name=path,
-                trace=trace, evented=evented,
+                trace=trace, evented=not poll,
                 interrupts=interrupts, max_stack_depth=max_stack_depth)
     space.runtime_setup(argv[0])
-    result = 0
-    if benchmark is not None:
-        result = _run_benchmark(interp, number, benchmark, stringarg)
-    elif code is not None:
-        result = _run_code(interp, code, as_benchmark=as_benchmark)
+    
+    # Create context to be executed
+    if code or selector:
+        if not have_number:
+            w_receiver = interp.space.w_nil
+        else:
+            w_receiver = interp.space.wrap_int(number)
+        if code:
+            selector = compile_code(interp, w_receiver, code)
+            if selector is None:
+                return -1 # Compilation failed, message is printed.
+        s_frame = create_context(interp, w_receiver, selector, stringarg)
+        if headless:
+            context = s_frame
+        else:
+            create_process(interp, s_frame)
+            context = active_context(interp.space)
     else:
-        _run_image(interp)
-        result = 0
+        context = active_context(interp.space)
+    
+    w_result = execute_context(interp, context)
+    print result_string(w_result)
     storage_logger.print_aggregated_log()
-    return result
+    return 0
 
+def result_string(w_result):
+    # This will also print contents of strings/symbols/numbers
+    return w_result.as_repr_string().replace('\r', '\n')
 
-# _____ Define and setup target ___
+def compile_code(interp, w_receiver, code):
+    import time
+    selector = "DoIt%d" % int(time.time())
+    space = interp.space
+    w_receiver_class = w_receiver.getclass(space)
+    try:
+        w_result = interp.perform(
+            w_receiver_class,
+            "compile:classified:notifying:",
+            w_arguments = [space.wrap_string("%s\r\n%s" % (selector, code)),
+            space.wrap_string("spy-run-code"),
+            space.w_nil]
+        )
+        # TODO - is this expected in every image?
+        if not isinstance(w_result, model.W_BytesObject) or w_result.as_string() != selector:
+            print "Compilation failed, unexpected result: %s" % result_string(w_result)
+            return None
+    except error.Exit, e:
+        print "Exited while compiling code: %s" % e.msg
+        return None
+    w_receiver_class.as_class_get_shadow(space).s_methoddict().sync_method_cache()
+    return selector
+    
+def create_context(interp, w_receiver, selector, stringarg):
+    args = []
+    if stringarg:
+        args.append(interp.space.wrap_string(stringarg))
+    return interp.create_toplevel_context(w_receiver, selector, w_arguments = args)
+    
+def create_process(interp, s_frame):
+    space = interp.space
+    w_active_process = wrapper.scheduler(space).active_process()
+    assert isinstance(w_active_process, model.W_PointersObject)
+    w_benchmark_proc = model.W_PointersObject(
+        space, w_active_process.getclass(space), w_active_process.size()
+    )
+    if interp.image.version.has_closures:
+        # Priorities below 10 are not allowed in newer versions of Squeak.
+        active_priority = space.unwrap_int(w_active_process.fetch(space, 2))
+        priority = active_priority / 2 + 1
+        priority = max(11, priority)
+    else:
+        priority = 7
+    w_benchmark_proc.store(space, 1, s_frame.w_self())
+    w_benchmark_proc.store(space, 2, space.wrap_int(priority))
+    
+    # Make process eligible for scheduling
+    wrapper.ProcessWrapper(space, w_benchmark_proc).put_to_sleep()
+    
+def active_context(space):
+    w_active_process = wrapper.scheduler(space).active_process()
+    active_process = wrapper.ProcessWrapper(space, w_active_process)
+    w_active_context = active_process.suspended_context()
+    assert isinstance(w_active_context, model.W_PointersObject)
+    active_process.store_suspended_context(space.w_nil)
+    return w_active_context.as_context_get_shadow(space)
 
+def execute_context(interp, s_frame, measure=False):
+    try:
+        return interp.interpret_toplevel(s_frame.w_self())
+    except error.Exit, e:
+        print "Exited: %s" % e.msg
+        return None
+    
+# _____ Target and Main _____
 
 def target(driver, *args):
     # driver.config.translation.gc = "stmgc"
@@ -247,11 +241,9 @@
         driver.config.translation.thread = True
     return entry_point, None
 
-
 def jitpolicy(self):
     from rpython.jit.codewriter.policy import JitPolicy
     return JitPolicy()
 
-
 if __name__ == "__main__":
     entry_point(sys.argv)


More information about the pypy-commit mailing list