浏览代码

Create a utils.py for performance tests

jonathanvdc 8 年之前
父节点
当前提交
5eeb9801fe
共有 1 个文件被更改,包括 204 次插入0 次删除
  1. 204 0
      performance/utils.py

+ 204 - 0
performance/utils.py

@@ -0,0 +1,204 @@
+import unittest
+import sys
+import os
+
+import sys
+import time
+import json
+import urllib
+import urllib2
+import subprocess
+import signal
+import random
+
+sys.path.append("interface/HUTN")
+sys.path.append("scripts")
+from hutn_compiler.compiler import main as do_compile
+from check_objects import to_recompile
+
+USERNAME = "test_user"
+PARALLEL_PUSH = True
+
+BOOTSTRAP_FOLDER_NAME = "bootstrap"
+CURRENT_FOLDER_NAME = "performance"
+
+PORTS = set()
+
+class ModelverseTerminated(Exception):
+    """An exception that tells the user that the Modelverse has terminated."""
+    pass
+
+def get_code_folder_name():
+    """Gets the name of the code folder."""
+    return '%s/code' % CURRENT_FOLDER_NAME
+
+def get_free_port():
+    """Gets a unique new port."""
+    while 1:
+        port = random.randint(10000, 20000)
+        # Check if this port is in the set of ports.
+        if port not in PORTS:
+            # We have found a unique port. Add it to the set and return.
+            PORTS.add(port)
+            return port
+
+def execute(scriptname, parameters=None, wait=False):
+    """Runs a script."""
+    if os.name not in ["nt", "posix"]:
+        # Stop now, as we would have no clue on how to kill its subtree
+        raise Exception("Unknown OS version: " + str(os.name))
+
+    command = [sys.executable, "scripts/%s.py" % scriptname] + (
+        [] if parameters is None else parameters)
+
+    if wait:
+        return subprocess.call(command, shell=False)
+    else:
+        return subprocess.Popen(command, shell=False)
+
+def kill(process):
+    """Kills the given process."""
+    if os.name == "nt":
+        subprocess.call(["taskkill", "/F", "/T", "/PID", "%i" % process.pid])
+    elif os.name == "posix":
+        subprocess.call(["pkill", "-P", "%i" % process.pid])
+
+def set_input_data(address, data):
+    """Sets the Modelverse program's input data."""
+    if data is not None:
+        urllib2.urlopen(
+            urllib2.Request(
+                address,
+                urllib.urlencode(
+                    {"op": "set_input", "data": json.dumps(data), "username": USERNAME})),
+            timeout=10).read()
+    else:
+        return []
+
+def compile_file(address, mod_filename, filename, mode, proc):
+    """Compiles the given file."""
+    # Load in the file required
+    try:
+        timeout_val = 240
+        username = str(random.random())
+        while 1:
+            proc2 = execute(
+                "compile", [address, mod_filename, username, filename, mode], wait=False)
+
+            if proc.returncode is not None:
+                # Modelverse has already terminated, which isn't a good sign!
+                raise Exception("Modelverse died!")
+
+            while proc2.returncode is None:
+                time.sleep(0.01)
+                proc2.poll()
+                timeout_val -= 0.01
+                if timeout_val < 0:
+                    kill(proc2)
+                    print("Compilation timeout expired!")
+                    return False
+
+            if proc2.returncode != 2:
+                break
+
+        # Make sure everything stopped correctly
+        assert proc2.returncode == 0
+        if proc2.returncode != 0:
+            return False
+    except:
+        raise
+    finally:
+        try:
+            kill(proc2)
+        except UnboundLocalError:
+            pass
+
+def run_file(files, parameters, mode, handle_output):
+    """Compiles the given sequence of files, feeds them the given input in the given mode,
+       and handles their output."""
+    # Resolve file
+    import os.path
+
+    time.sleep(0.01)
+    port = get_free_port()
+    address = "http://127.0.0.1:%i" % port
+    try:
+        # Run Modelverse server
+        proc = execute("run_local_modelverse", [str(port)], wait=False)
+
+        threads = []
+        mod_files = []
+        for filename in files:
+            if os.path.isfile("%s/%s" % (get_code_folder_name(), filename)):
+                mod_filename = "%s/%s" % (get_code_folder_name(), filename)
+            elif os.path.isfile("%s/%s" % (BOOTSTRAP_FOLDER_NAME, filename)):
+                mod_filename = "%s/%s" % (BOOTSTRAP_FOLDER_NAME, filename)
+            else:
+                raise Exception("File not found: %s" % filename)
+            mod_files.append(mod_filename)
+
+        to_compile = to_recompile(address, mod_files)
+
+        for mod_filename in to_compile:
+            if PARALLEL_PUSH:
+                import threading
+                threads.append(
+                    threading.Thread(
+                        target=compile_file,
+                        args=[address, mod_filename, mod_filename, mode, proc]))
+                threads[-1].start()
+            else:
+                compile_file(address, mod_filename, mod_filename, mode, proc)
+
+        if PARALLEL_PUSH:
+            for t in threads:
+                t.join()
+
+        if mode[-1] == "O":
+            # Fire up the linker
+            val = execute("link_and_load", [address, USERNAME] + mod_files, wait=True)
+            if val != 0:
+                raise Exception("Linking error")
+
+        # Send the request ...
+        set_input_data(address, parameters)
+
+        # ... and wait for replies
+        while 1:
+            val = urllib2.urlopen(
+                urllib2.Request(
+                    address,
+                    urllib.urlencode({"op": "get_output", "username": USERNAME})),
+                timeout=240).read()
+            val = json.loads(val)
+
+            if proc.returncode is not None:
+                # Modelverse has terminated. This may or may not be what we want.
+                raise ModelverseTerminated()
+
+            if not handle_output(val):
+                return
+
+        # All passed!
+        return
+    except:
+        raise
+    finally:
+        try:
+            kill(proc)
+        except UnboundLocalError:
+            pass
+
+def run_file_to_completion(files, parameters, mode):
+    """Compiles the given sequence of files, feeds them the given input in the given mode,
+       then collects and returns their output."""
+    results = []
+    def handle_output(output):
+        """Appends the given output to the list of results."""
+        results.append(output)
+        return True
+
+    try:
+        run_file(files, parameters, mode, handle_output)
+    except ModelverseTerminated:
+        return results