|
@@ -4,6 +4,7 @@ import modelverse_kernel.primitives as primitive_functions
|
|
|
import modelverse_jit.bytecode_parser as bytecode_parser
|
|
|
import modelverse_jit.bytecode_to_tree as bytecode_to_tree
|
|
|
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_to_tree as cfg_to_tree
|
|
|
import modelverse_jit.cfg_ir as cfg_ir
|
|
@@ -806,12 +807,37 @@ def favor_small_functions(body_bytecode):
|
|
|
'+',
|
|
|
tree_ir.LiteralInstruction(1)))
|
|
|
|
|
|
+ADAPTIVE_JIT_LOOP_INSTRUCTION_MULTIPLIER = 4
|
|
|
+
|
|
|
ADAPTIVE_FAST_JIT_TEMPERATURE_THRESHOLD = 200
|
|
|
"""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(
|
|
|
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
|
|
|
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
|
|
@@ -821,6 +847,7 @@ def compile_function_body_adaptive(
|
|
|
|
|
|
body_bytecode, = yield [("CALL_ARGS", [jit.jit_parse_bytecode, (body_id,)])]
|
|
|
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:
|
|
|
# Initial temperature exceeds the fast-jit threshold.
|