Browse Source

Create the adaptive-jit-favor-loops kernel, make it the default

jonathanvdc 8 years ago
parent
commit
24a9339ea6

+ 8 - 2
hybrid_server/classes/mvkcontroller.xml

@@ -40,12 +40,18 @@
                     self.mvk.jit.set_function_body_compiler(jit.compile_function_body_fast)
                     self.mvk.jit.set_function_body_compiler(jit.compile_function_body_fast)
                 elif opt == 'baseline-jit':
                 elif opt == 'baseline-jit':
                     self.mvk.jit.set_function_body_compiler(jit.compile_function_body_baseline)
                     self.mvk.jit.set_function_body_compiler(jit.compile_function_body_baseline)
-                elif opt == 'adaptive-jit' or opt == 'adaptive-jit-favor-large-functions':
-                    self.mvk.jit.set_function_body_compiler(jit.compile_function_body_adaptive)
+                elif opt == 'adaptive-jit-favor-large-functions':
+                    self.mvk.jit.set_function_body_compiler(
+                            lambda *args: jit.compile_function_body_adaptive(
+                                *args, temperature_heuristic=jit.favor_large_functions))
                 elif opt == 'adaptive-jit-favor-small-functions':
                 elif opt == 'adaptive-jit-favor-small-functions':
                     self.mvk.jit.set_function_body_compiler(
                     self.mvk.jit.set_function_body_compiler(
                         lambda *args: jit.compile_function_body_adaptive(
                         lambda *args: jit.compile_function_body_adaptive(
                             *args, temperature_heuristic=jit.favor_small_functions))
                             *args, temperature_heuristic=jit.favor_small_functions))
+                elif opt == 'adaptive-jit' or opt == 'adaptive-jit-favor-loops':
+                    self.mvk.jit.set_function_body_compiler(
+                        lambda *args: jit.compile_function_body_adaptive(
+                            *args, temperature_heuristic=jit.favor_loops))
                 else:
                 else:
                     print("warning: unknown kernel option '%s'." % opt)
                     print("warning: unknown kernel option '%s'." % opt)
 
 

+ 10 - 2
kernel/modelverse_jit/bytecode_ir.py

@@ -7,7 +7,8 @@ class Instruction(object):
         self.debug_information = None
         self.debug_information = None
 
 
     def get_directly_reachable(self):
     def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
+        """Gets all instructions that are directly reachable from this instruction, excluding the
+           next instruction."""
         raise NotImplementedError()
         raise NotImplementedError()
 
 
     def get_reachable(self):
     def get_reachable(self):
@@ -18,8 +19,12 @@ class Instruction(object):
         while len(stack) > 0:
         while len(stack) > 0:
             instr = stack.pop()
             instr = stack.pop()
             results.add(instr)
             results.add(instr)
+            next_instr = instr.next_instruction
+            if next_instr is not None and next_instr not in results:
+                stack.append(next_instr)
             for other in instr.get_directly_reachable():
             for other in instr.get_directly_reachable():
                 if other not in results:
                 if other not in results:
+                    assert other is not None
                     stack.append(other)
                     stack.append(other)
 
 
         return results
         return results
@@ -120,7 +125,10 @@ class ReturnInstruction(Instruction):
 
 
     def get_directly_reachable(self):
     def get_directly_reachable(self):
         """Gets all instructions that are directly reachable from this instruction."""
         """Gets all instructions that are directly reachable from this instruction."""
-        return (self.value,)
+        if self.value is None:
+            return ()
+        else:
+            return (self.value,)
 
 
     constructor_parameters = (('value', Instruction),)
     constructor_parameters = (('value', Instruction),)
 
 

+ 28 - 1
kernel/modelverse_jit/jit.py

@@ -4,6 +4,7 @@ import modelverse_kernel.primitives as primitive_functions
 import modelverse_jit.bytecode_parser as bytecode_parser
 import modelverse_jit.bytecode_parser as bytecode_parser
 import modelverse_jit.bytecode_to_tree as bytecode_to_tree
 import modelverse_jit.bytecode_to_tree as bytecode_to_tree
 import modelverse_jit.bytecode_to_cfg as bytecode_to_cfg
 import modelverse_jit.bytecode_to_cfg as bytecode_to_cfg
+import modelverse_jit.bytecode_ir as bytecode_ir
 import modelverse_jit.cfg_optimization as cfg_optimization
 import modelverse_jit.cfg_optimization as cfg_optimization
 import modelverse_jit.cfg_to_tree as cfg_to_tree
 import modelverse_jit.cfg_to_tree as cfg_to_tree
 import modelverse_jit.cfg_ir as cfg_ir
 import modelverse_jit.cfg_ir as cfg_ir
@@ -806,12 +807,37 @@ def favor_small_functions(body_bytecode):
             '+',
             '+',
             tree_ir.LiteralInstruction(1)))
             tree_ir.LiteralInstruction(1)))
 
 
+ADAPTIVE_JIT_LOOP_INSTRUCTION_MULTIPLIER = 4
+
 ADAPTIVE_FAST_JIT_TEMPERATURE_THRESHOLD = 200
 ADAPTIVE_FAST_JIT_TEMPERATURE_THRESHOLD = 200
 """The threshold temperature at which fast-jit will be used."""
 """The threshold temperature at which fast-jit will be used."""
 
 
+def favor_loops(body_bytecode):
+    """Computes the initial temperature of a function. Code within a loop makes
+       the function hotter; code outside loops makes the function colder. The
+       temperature is incremented by one on every call."""
+    reachable_instructions = body_bytecode.get_reachable()
+    # First set the temperature to the negative number of instructions.
+    temperature = ADAPTIVE_FAST_JIT_TEMPERATURE_THRESHOLD - len(reachable_instructions)
+    for instruction in reachable_instructions:
+        if isinstance(instruction, bytecode_ir.WhileInstruction):
+            # Then increase the temperature by the number of instructions reachable
+            # from loop bodies. Note that the algorithm will count nested loops twice.
+            # This is actually by design.
+            loop_body_instructions = instruction.body.get_reachable()
+            temperature += ADAPTIVE_JIT_LOOP_INSTRUCTION_MULTIPLIER * len(loop_body_instructions)
+
+    return (
+        temperature,
+        lambda old_value:
+        tree_ir.BinaryInstruction(
+            old_value,
+            '+',
+            tree_ir.LiteralInstruction(1)))
+
 def compile_function_body_adaptive(
 def compile_function_body_adaptive(
         jit, function_name, body_id, task_root,
         jit, function_name, body_id, task_root,
-        temperature_heuristic=favor_large_functions):
+        temperature_heuristic=favor_loops):
     """Compile the function with the given name and body id. An execution engine is picked
     """Compile the function with the given name and body id. An execution engine is picked
        automatically, and the function may be compiled again at a later time."""
        automatically, and the function may be compiled again at a later time."""
     # The general idea behind this compilation technique is to first use the baseline JIT
     # The general idea behind this compilation technique is to first use the baseline JIT
@@ -821,6 +847,7 @@ def compile_function_body_adaptive(
 
 
     body_bytecode, = yield [("CALL_ARGS", [jit.jit_parse_bytecode, (body_id,)])]
     body_bytecode, = yield [("CALL_ARGS", [jit.jit_parse_bytecode, (body_id,)])]
     initial_temperature, increment_temperature = temperature_heuristic(body_bytecode)
     initial_temperature, increment_temperature = temperature_heuristic(body_bytecode)
+    print('Initial temperature for %s: %d' % (function_name, initial_temperature))
 
 
     if initial_temperature >= ADAPTIVE_FAST_JIT_TEMPERATURE_THRESHOLD:
     if initial_temperature >= ADAPTIVE_FAST_JIT_TEMPERATURE_THRESHOLD:
         # Initial temperature exceeds the fast-jit threshold.
         # Initial temperature exceeds the fast-jit threshold.

+ 7 - 1
performance/utils.py

@@ -30,12 +30,18 @@ OPTIMIZATION_LEVEL_INTERPRETER = "interpreter"
 OPTIMIZATION_LEVEL_BASELINE_JIT = "baseline-jit"
 OPTIMIZATION_LEVEL_BASELINE_JIT = "baseline-jit"
 OPTIMIZATION_LEVEL_BASELINE_JIT_NO_THUNKS = "baseline-jit,no-thunks"
 OPTIMIZATION_LEVEL_BASELINE_JIT_NO_THUNKS = "baseline-jit,no-thunks"
 OPTIMIZATION_LEVEL_FAST_JIT = "fast-jit"
 OPTIMIZATION_LEVEL_FAST_JIT = "fast-jit"
+OPTIMIZATION_LEVEL_ADAPTIVE_JIT_FAVOR_LARGE_FUNCTIONS = "adaptive-jit-favor-large-functions"
+OPTIMIZATION_LEVEL_ADAPTIVE_JIT_FAVOR_SMALL_FUNCTIONS = "adaptive-jit-favor-small-functions"
+OPTIMIZATION_LEVEL_ADAPTIVE_JIT_FAVOR_LOOPS = "adaptive-jit-favor-loops"
 ALL_OPTIMIZATION_LEVELS = [
 ALL_OPTIMIZATION_LEVELS = [
     OPTIMIZATION_LEVEL_LEGACY_INTERPRETER,
     OPTIMIZATION_LEVEL_LEGACY_INTERPRETER,
     OPTIMIZATION_LEVEL_INTERPRETER,
     OPTIMIZATION_LEVEL_INTERPRETER,
     OPTIMIZATION_LEVEL_BASELINE_JIT,
     OPTIMIZATION_LEVEL_BASELINE_JIT,
     OPTIMIZATION_LEVEL_BASELINE_JIT_NO_THUNKS,
     OPTIMIZATION_LEVEL_BASELINE_JIT_NO_THUNKS,
-    OPTIMIZATION_LEVEL_FAST_JIT
+    OPTIMIZATION_LEVEL_FAST_JIT,
+    OPTIMIZATION_LEVEL_ADAPTIVE_JIT_FAVOR_LARGE_FUNCTIONS,
+    OPTIMIZATION_LEVEL_ADAPTIVE_JIT_FAVOR_SMALL_FUNCTIONS,
+    OPTIMIZATION_LEVEL_ADAPTIVE_JIT_FAVOR_LOOPS
 ]
 ]
 
 
 class ModelverseTerminated(Exception):
 class ModelverseTerminated(Exception):