From ed218be1f89d4d41fca16a6469c71f5ab7ba584b Mon Sep 17 00:00:00 2001 From: feifei-111 <2364819892@qq.com> Date: Mon, 9 Oct 2023 11:45:34 +0000 Subject: [PATCH 1/7] update --- sot/opcode_translator/executor/opcode_executor.py | 2 +- sot/opcode_translator/executor/opcode_inline_executor.py | 4 +++- sot/opcode_translator/transform.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sot/opcode_translator/executor/opcode_executor.py b/sot/opcode_translator/executor/opcode_executor.py index 1ab7d2df..36230f03 100644 --- a/sot/opcode_translator/executor/opcode_executor.py +++ b/sot/opcode_translator/executor/opcode_executor.py @@ -426,7 +426,7 @@ def inner(self: OpcodeExecutor, instr: Instruction): self.stack.pop() # fallback when in OpcodeExecutor # raise error in OpcodeInlineExecutor - log(3, "[BreakGraph] jump break graph, because if tensor") + log(3, "[BreakGraph] jump break graph, because if tensor\n") self._break_graph_in_jump(result, instr) return Stop(state="BreakGraph") else: diff --git a/sot/opcode_translator/executor/opcode_inline_executor.py b/sot/opcode_translator/executor/opcode_inline_executor.py index 9a0ba967..252e4aba 100644 --- a/sot/opcode_translator/executor/opcode_inline_executor.py +++ b/sot/opcode_translator/executor/opcode_inline_executor.py @@ -276,7 +276,9 @@ def _break_graph_in_jump(self, result, instr: Instruction): result: The result of the operation. instr (Instruction): The jump instruction. """ - raise BreakGraphError("_break_graph_in_jump.") + raise BreakGraphError( + "OpcodeInlineExecutor want call _break_graph_in_jump." + ) def _create_resume_fn(self, index: int, stack_size: int = 0): """ diff --git a/sot/opcode_translator/transform.py b/sot/opcode_translator/transform.py index 70b55f16..bb61c357 100644 --- a/sot/opcode_translator/transform.py +++ b/sot/opcode_translator/transform.py @@ -87,7 +87,7 @@ def eval_frame_callback(frame, **kwargs) -> CustomCode: ): log( 3, - "[eval_frame_callback] Code has no graph, block it.", + "[eval_frame_callback] Code has no graph, block it.\n", ) return CustomCode(None, True) From adc8813dd21dce298173973e3feedacd9f4e5fb7 Mon Sep 17 00:00:00 2001 From: feifei-111 <2364819892@qq.com> Date: Tue, 10 Oct 2023 06:43:01 +0000 Subject: [PATCH 2/7] update --- .../executor/opcode_executor.py | 215 +----------------- sot/opcode_translator/transform.py | 9 +- tests/test_12_for_loop.py | 6 +- tests/test_case_base.py | 6 +- tests/test_instruction_translator_cache.py | 18 +- tests/tests_legacy/test_optransform_cache.py | 8 +- 6 files changed, 21 insertions(+), 241 deletions(-) diff --git a/sot/opcode_translator/executor/opcode_executor.py b/sot/opcode_translator/executor/opcode_executor.py index 36230f03..a872a1fc 100644 --- a/sot/opcode_translator/executor/opcode_executor.py +++ b/sot/opcode_translator/executor/opcode_executor.py @@ -9,25 +9,24 @@ import types from dataclasses import dataclass from itertools import chain -from typing import Any, Callable, List, NamedTuple, Tuple +from typing import Any, Callable import opcode -from ...psdb import NO_BREAKGRAPH_CODES, NO_FALLBACK_CODES +from ...psdb import NO_BREAKGRAPH_CODES from ...utils import ( BreakGraphError, EventGuard, FallbackError, InnerError, OrderedSet, - Singleton, SotUndefinedVar, event_register, - is_strict_mode, log, log_do, min_graph_size, ) +from ..custom_code import CustomCode from ..instruction_utils import ( Instruction, Space, @@ -47,7 +46,6 @@ ) from .dispatcher import Dispatcher from .function_graph import FunctionGraph -from .guard import Guard from .instr_flag import CALL_FUNCTION_EX_FLAG as CFE from .instr_flag import FORMAT_VALUE_FLAG as FV from .instr_flag import MAKE_FUNCTION_FLAG as MF @@ -79,18 +77,6 @@ VariableFactory, ) - -class CustomCode(NamedTuple): - code: types.CodeType | None - disable_eval_frame: bool - - -GuardedFunction = Tuple[CustomCode, Guard] -GuardedFunctions = List[GuardedFunction] -dummy_guard: Guard = lambda frame: True -dummy_guard.expr = "lambda frame: True" -dummy_guard.lambda_expr = "lambda frame: True" - SUPPORT_COMPARE_OP = { ">": operator.gt, "<": operator.lt, @@ -112,201 +98,6 @@ class Stop: state: str -@Singleton -class InstructionTranslatorCache: - """ - A singleton class that implements a cache for translated instructions. - This cache is used to store previously translated instructions along with their corresponding guard functions. - - Attributes: - cache (dict): A dictionary that maps code objects to tuples of a cache getter function and a list of guarded functions. - translate_count (int): The count of how many instructions have been translated. It is used to test whether the cache hits. - """ - - MAX_CACHE_SIZE = 20 - cache: dict[types.CodeType, GuardedFunctions] - translate_count: int - - def __init__(self): - self.cache = {} - self.translate_count = 0 - - def clear(self): - """ - Clears the cache and resets the translate count. - """ - self.cache.clear() - self.translate_count = 0 - - def __call__(self, frame: types.FrameType, **kwargs) -> CustomCode: - code: types.CodeType = frame.f_code - if code not in self.cache: - log(2, f"[Cache]: Firstly call {code}\n") - new_custom_code, guard_fn = self.translate(frame, **kwargs) - self.cache[code] = [(new_custom_code, guard_fn)] - return new_custom_code - guarded_fns = self.cache[code] - return self.lookup(frame, guarded_fns, **kwargs) - - @event_register("lookup") - def lookup( - self, frame: types.FrameType, guarded_fns: GuardedFunctions, **kwargs - ) -> CustomCode: - """ - Looks up the cache for a matching code object and returns a custom code object if a matching guard function is found, otherwise None. - - Args: - frame (types.FrameType): The frame whose code object needs to be looked up in the cache. - guarded_fns (GuardedFunctions): The list of guarded functions associated with the code object. - - Returns: - CustomCode | None: The custom code object if a matching guard function is found, otherwise None. - """ - - if len(guarded_fns) >= self.MAX_CACHE_SIZE: - log(2, "[Cache]: Exceed max cache size, skip it\n") - return CustomCode(None, False) - - for custom_code, guard_fn in guarded_fns: - try: - with EventGuard("try guard"): - guard_result = guard_fn(frame) - if guard_result: - log( - 2, - f"[Cache]: Cache hit, Guard is \n{getattr(guard_fn, 'expr', 'None')}\n", - ) - return custom_code - else: - log_do( - 4, - self.analyse_guard_global_object(guard_fn), - ) - log( - 2, - f"[Cache]: Cache miss, Guard is \n{getattr(guard_fn, 'expr', 'None')}\n", - ) - log_do( - 2, - self.analyse_guard_error(guard_fn, frame), - ) - except Exception as e: - log(2, f"[Cache]: Guard function error: {e}\n") - continue - - log(2, "[Cache]: all guards missed\n") - new_custom_code, guard_fn = self.translate(frame, **kwargs) - guarded_fns.append((new_custom_code, guard_fn)) - return new_custom_code - - def translate( - self, frame: types.FrameType, **kwargs - ) -> tuple[CustomCode, Guard]: - """ - Translates the given frame's code object and returns the cache getter function and a guarded function for the translated code object. - - Args: - frame (types.FrameType): The frame whose code object needs to be translated. - - Returns: - tuple[CustomCode, Guard]: The cache getter function and a guarded function for the translated code object. - """ - code: types.CodeType = frame.f_code - self.translate_count += 1 - custom_new_code, guard_fn = start_translate(frame, **kwargs) - return custom_new_code, guard_fn - - def analyse_guard_global_object(self, guard_fn): - def inner(): - for key in guard_fn.__globals__.keys(): - if key.startswith("__object"): - print( - f"[Cache] meet global object: {key} : {guard_fn.__globals__[key]}", - ) - - return inner - - def analyse_guard_error(self, guard_fn, frame): - def inner(): - guard_expr = guard_fn.lambda_expr - lambda_head = "lambda frame: " - guard_expr = guard_expr.replace(lambda_head, "") - guards = guard_expr.split(" and ") - for guard_str in guards: - guard = eval(lambda_head + guard_str, guard_fn.__globals__) - result = False - try: - result = guard(frame) - except Exception as e: - print( - f"[Cache]: skip checking {guard_str}\n because error occured {e}" - ) - if result is False: - print(f"[Cache]: missed at {guard_str}") - return - print("[Cache]: missed guard not found.") - - return inner - - -def start_translate(frame: types.FrameType, **kwargs) -> GuardedFunction: - """ - Starts the translation process for the given frame and returns the translated code object and its guard function, or None if translation fails. - - Args: - frame: The frame to be translated. - - Returns: - GuardedFunction | None: The translated code object and its guard function, or None if translation fails. - """ - with EventGuard( - f"start_translate: {frame.f_code.co_name.replace('<', '(').replace('>', ')')}, file {frame.f_code.co_filename}, line {int(frame.f_code.co_firstlineno)}" - ): - simulator = OpcodeExecutor(frame, **kwargs) - try: - new_custom_code, guard_fn = simulator.transform() - return new_custom_code, guard_fn - # TODO(zrr1999): InnerError maybe place before (FallbackError, BreakGraphError) - # TODO(0x45f): handle BreakGraphError to trigger fallback - except BreakGraphError as e: - raise RuntimeError( - f"Found BreakGraphError raised, it should not be catch at start_translate!\n{e}" - ) - except FallbackError as e: - if simulator._code in NO_FALLBACK_CODES: - raise InnerError( - f"{simulator._code.co_name} should not fallback, but got '{e}'" - ) - # if disable_eval_frame is True, it means we want fallback to speedup rather than error occured - if is_strict_mode() and e.disable_eval_frame is False: - raise - log( - 2, - f"Unsupport Frame is {frame.f_code}, error message is: \n" - + "".join( - traceback.format_exception(type(e), e, e.__traceback__) - ), - ) - - # NOTE: If resume fn need fallback, we should replace NullVariable using NULL otherwise will fail to run - py_codegen = PyCodeGen(frame) - new_code = py_codegen.replace_null_variable() - # simulation not complete, not sure whether this code has sir, set disable_eval_frame = False - guard_fn = ( - dummy_guard - if e.disable_eval_frame is False - else simulator.guard_fn - ) - return ( - CustomCode(new_code, e.disable_eval_frame), - guard_fn, - ) - except Exception as e: - raise InnerError(OpcodeExecutorBase.error_message_summary(e)) from e - finally: - simulator.cleanup() - - def tos_op_wrapper(fn: Callable): """ A decorator function that wraps an opcode operation and applies certain functionality to it. diff --git a/sot/opcode_translator/transform.py b/sot/opcode_translator/transform.py index bb61c357..461b99f4 100644 --- a/sot/opcode_translator/transform.py +++ b/sot/opcode_translator/transform.py @@ -2,15 +2,12 @@ import dis from functools import partial -from typing import TYPE_CHECKING from ..utils import CodeStatus, EventGuard, log, log_do -from .executor.opcode_executor import CustomCode, InstructionTranslatorCache +from .custom_code import CustomCode +from .executor.executor_cache import OpcodeExecutorCache from .skip_files import need_skip -if TYPE_CHECKING: - pass - def print_locals(frame): local_key = [ @@ -62,7 +59,7 @@ def eval_frame_callback(frame, **kwargs) -> CustomCode: log(3, f"[transform] OriginCode: {frame.f_code.co_name}\n") log_do(3, lambda: dis.dis(frame.f_code)) - custom_code = InstructionTranslatorCache()(frame, **kwargs) + custom_code = OpcodeExecutorCache()(frame, **kwargs) if custom_code.code is None: log( diff --git a/tests/test_12_for_loop.py b/tests/test_12_for_loop.py index 710af847..f14f9eaa 100644 --- a/tests/test_12_for_loop.py +++ b/tests/test_12_for_loop.py @@ -10,9 +10,7 @@ import paddle import sot from sot import symbolic_translate -from sot.opcode_translator.executor.opcode_executor import ( - InstructionTranslatorCache, -) +from sot.opcode_translator.executor.opcode_executor import OpcodeExecutorCache def gener(): @@ -245,7 +243,7 @@ def test_run(self): out = symbolic_translate(for_enumerate_cache)(func_list, x) out = symbolic_translate(for_enumerate_cache)(func_list, x) - self.assert_nest_match(InstructionTranslatorCache().translate_count, 1) + self.assert_nest_match(OpcodeExecutorCache().translate_count, 1) # after_loop_fn need zzz, and zzz is created as UndefinedVar when generating loop body diff --git a/tests/test_case_base.py b/tests/test_case_base.py index dfa712cc..6277fc9e 100644 --- a/tests/test_case_base.py +++ b/tests/test_case_base.py @@ -11,14 +11,12 @@ import paddle from sot import symbolic_translate -from sot.opcode_translator.executor.opcode_executor import ( - InstructionTranslatorCache, -) +from sot.opcode_translator.executor.opcode_executor import OpcodeExecutorCache @contextlib.contextmanager def test_instruction_translator_cache_context(): - cache = InstructionTranslatorCache() + cache = OpcodeExecutorCache() cache.clear() yield cache cache.clear() diff --git a/tests/test_instruction_translator_cache.py b/tests/test_instruction_translator_cache.py index 1b3f8464..4a43d250 100644 --- a/tests/test_instruction_translator_cache.py +++ b/tests/test_instruction_translator_cache.py @@ -13,7 +13,7 @@ from sot.opcode_translator.executor.opcode_executor import ( CustomCode, - InstructionTranslatorCache, + OpcodeExecutorCache, ) @@ -81,11 +81,11 @@ def mock_start_translate(frame: types.FrameType, **kwargs): return translate_map[frame] -class TestInstructionTranslatorCache(unittest.TestCase): +class TestOpcodeExecutorCache(unittest.TestCase): def reset(self): global translate_count translate_count = 0 - InstructionTranslatorCache().clear() + OpcodeExecutorCache().clear() @patch( "sot.opcode_translator.executor.opcode_executor.start_translate", @@ -93,12 +93,12 @@ def reset(self): ) def test_cache_hit(self): with test_instruction_translator_cache_context() as ctx: - translated_code_1 = InstructionTranslatorCache()(FRAME_1) + translated_code_1 = OpcodeExecutorCache()(FRAME_1) assert translated_code_1 is not None self.assertEqual(translated_code_1.code, FRAME_2.f_code) self.assertEqual(ctx.translate_count, 1) # cache hit - translated_code_2 = InstructionTranslatorCache()(FRAME_1) + translated_code_2 = OpcodeExecutorCache()(FRAME_1) assert translated_code_2 is not None self.assertEqual(translated_code_2.code, FRAME_2.f_code) self.assertEqual(ctx.translate_count, 1) @@ -109,12 +109,12 @@ def test_cache_hit(self): ) def test_cache_miss_due_to_unknown_code(self): with test_instruction_translator_cache_context() as ctx: - translated_code_1 = InstructionTranslatorCache()(FRAME_1) + translated_code_1 = OpcodeExecutorCache()(FRAME_1) assert translated_code_1 is not None self.assertEqual(translated_code_1.code, FRAME_2.f_code) self.assertEqual(ctx.translate_count, 1) # cache miss - translated_code_2 = InstructionTranslatorCache()(FRAME_3) + translated_code_2 = OpcodeExecutorCache()(FRAME_3) assert translated_code_2 is not None self.assertEqual(translated_code_2.code, FRAME_4.f_code) self.assertEqual(ctx.translate_count, 2) @@ -125,12 +125,12 @@ def test_cache_miss_due_to_unknown_code(self): ) def test_cache_miss_due_to_check_failed(self): with test_instruction_translator_cache_context() as ctx: - translated_code_1 = InstructionTranslatorCache()(FRAME_3) + translated_code_1 = OpcodeExecutorCache()(FRAME_3) assert translated_code_1 is not None self.assertEqual(translated_code_1.code, FRAME_4.f_code) self.assertEqual(ctx.translate_count, 1) # cache miss - translated_code_2 = InstructionTranslatorCache()(FRAME_3) + translated_code_2 = OpcodeExecutorCache()(FRAME_3) assert translated_code_2 is not None self.assertEqual(translated_code_2.code, FRAME_4.f_code) self.assertEqual(ctx.translate_count, 2) diff --git a/tests/tests_legacy/test_optransform_cache.py b/tests/tests_legacy/test_optransform_cache.py index f876b73f..25d762e3 100644 --- a/tests/tests_legacy/test_optransform_cache.py +++ b/tests/tests_legacy/test_optransform_cache.py @@ -4,9 +4,7 @@ import paddle from sot import symbolic_translate -from sot.opcode_translator.instruction_translator import ( - InstructionTranslatorCache, -) +from sot.opcode_translator.instruction_translator import OpcodeExecutorCache def case1(x): @@ -20,9 +18,7 @@ def test(self): symbolic_translate(case1)(paddle.to_tensor([4])) symbolic_translate(case1)(paddle.to_tensor([4])) symbolic_translate(case1)(paddle.to_tensor([4])) - assert ( - InstructionTranslatorCache().hit_num == 2 - ), "cache hit num should be 2" + assert OpcodeExecutorCache().hit_num == 2, "cache hit num should be 2" if __name__ == "__main__": From 3c0d05d78141f5cb264b5f2be3ecf6eba59830ce Mon Sep 17 00:00:00 2001 From: feifei-111 <2364819892@qq.com> Date: Tue, 10 Oct 2023 06:43:49 +0000 Subject: [PATCH 3/7] update --- sot/opcode_translator/custom_code.py | 7 + .../executor/executor_cache.py | 222 ++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 sot/opcode_translator/custom_code.py create mode 100644 sot/opcode_translator/executor/executor_cache.py diff --git a/sot/opcode_translator/custom_code.py b/sot/opcode_translator/custom_code.py new file mode 100644 index 00000000..f44f260f --- /dev/null +++ b/sot/opcode_translator/custom_code.py @@ -0,0 +1,7 @@ +import types +from typing import NamedTuple + + +class CustomCode(NamedTuple): + code: types.CodeType | None + disable_eval_frame: bool diff --git a/sot/opcode_translator/executor/executor_cache.py b/sot/opcode_translator/executor/executor_cache.py new file mode 100644 index 00000000..9b0b37ef --- /dev/null +++ b/sot/opcode_translator/executor/executor_cache.py @@ -0,0 +1,222 @@ +import traceback +import types +from typing import List, Tuple + +from ...psdb import NO_FALLBACK_CODES +from ...utils import ( + BreakGraphError, + EventGuard, + FallbackError, + InnerError, + Singleton, + event_register, + is_strict_mode, + log, + log_do, +) +from ..custom_code import CustomCode +from .guard import Guard +from .opcode_executor import OpcodeExecutor, OpcodeExecutorBase +from .pycode_generator import PyCodeGen + +GuardedFunction = Tuple[CustomCode, Guard] +GuardedFunctions = List[GuardedFunction] + +dummy_guard: Guard = lambda frame: True +dummy_guard.expr = "lambda frame: True" +dummy_guard.lambda_expr = "lambda frame: True" + + +@Singleton +class OpcodeExecutorCache: + """ + A singleton class that implements a cache for translated instructions. + This cache is used to store previously translated instructions along with their corresponding guard functions. + + Attributes: + cache (dict): A dictionary that maps code objects to tuples of a cache getter function and a list of guarded functions. + translate_count (int): The count of how many instructions have been translated. It is used to test whether the cache hits. + """ + + MAX_CACHE_SIZE = 20 + cache: dict[types.CodeType, GuardedFunctions] + translate_count: int + + def __init__(self): + self.cache = {} + self.translate_count = 0 + + def clear(self): + """ + Clears the cache and resets the translate count. + """ + self.cache.clear() + self.translate_count = 0 + + def __call__(self, frame: types.FrameType, **kwargs) -> CustomCode: + code: types.CodeType = frame.f_code + if code not in self.cache: + log(2, f"[Cache]: Firstly call {code}\n") + new_custom_code, guard_fn = self.translate(frame, **kwargs) + self.cache[code] = [(new_custom_code, guard_fn)] + return new_custom_code + guarded_fns = self.cache[code] + return self.lookup(frame, guarded_fns, **kwargs) + + @event_register("lookup") + def lookup( + self, frame: types.FrameType, guarded_fns: GuardedFunctions, **kwargs + ) -> CustomCode: + """ + Looks up the cache for a matching code object and returns a custom code object if a matching guard function is found, otherwise None. + + Args: + frame (types.FrameType): The frame whose code object needs to be looked up in the cache. + guarded_fns (GuardedFunctions): The list of guarded functions associated with the code object. + + Returns: + CustomCode | None: The custom code object if a matching guard function is found, otherwise None. + """ + + if len(guarded_fns) >= self.MAX_CACHE_SIZE: + log(2, "[Cache]: Exceed max cache size, skip it\n") + return CustomCode(None, False) + + for custom_code, guard_fn in guarded_fns: + try: + with EventGuard("try guard"): + guard_result = guard_fn(frame) + if guard_result: + log( + 2, + f"[Cache]: Cache hit, Guard is \n{getattr(guard_fn, 'expr', 'None')}\n", + ) + return custom_code + else: + log_do( + 4, + self.analyse_guard_global_object(guard_fn), + ) + log( + 2, + f"[Cache]: Cache miss, Guard is \n{getattr(guard_fn, 'expr', 'None')}\n", + ) + log_do( + 2, + self.analyse_guard_error(guard_fn, frame), + ) + except Exception as e: + log(2, f"[Cache]: Guard function error: {e}\n") + continue + + log(2, "[Cache]: all guards missed\n") + new_custom_code, guard_fn = self.translate(frame, **kwargs) + guarded_fns.append((new_custom_code, guard_fn)) + return new_custom_code + + def translate( + self, frame: types.FrameType, **kwargs + ) -> tuple[CustomCode, Guard]: + """ + Translates the given frame's code object and returns the cache getter function and a guarded function for the translated code object. + + Args: + frame (types.FrameType): The frame whose code object needs to be translated. + + Returns: + tuple[CustomCode, Guard]: The cache getter function and a guarded function for the translated code object. + """ + code: types.CodeType = frame.f_code + self.translate_count += 1 + custom_new_code, guard_fn = start_translate(frame, **kwargs) + return custom_new_code, guard_fn + + def analyse_guard_global_object(self, guard_fn): + def inner(): + for key in guard_fn.__globals__.keys(): + if key.startswith("__object"): + print( + f"[Cache] meet global object: {key} : {guard_fn.__globals__[key]}", + ) + + return inner + + def analyse_guard_error(self, guard_fn, frame): + def inner(): + guard_expr = guard_fn.lambda_expr + lambda_head = "lambda frame: " + guard_expr = guard_expr.replace(lambda_head, "") + guards = guard_expr.split(" and ") + for guard_str in guards: + guard = eval(lambda_head + guard_str, guard_fn.__globals__) + result = False + try: + result = guard(frame) + except Exception as e: + print( + f"[Cache]: skip checking {guard_str}\n because error occured {e}" + ) + if result is False: + print(f"[Cache]: missed at {guard_str}") + return + print("[Cache]: missed guard not found.") + + return inner + + +def start_translate(frame: types.FrameType, **kwargs) -> GuardedFunction: + """ + Starts the translation process for the given frame and returns the translated code object and its guard function, or None if translation fails. + + Args: + frame: The frame to be translated. + + Returns: + GuardedFunction | None: The translated code object and its guard function, or None if translation fails. + """ + with EventGuard( + f"start_translate: {frame.f_code.co_name.replace('<', '(').replace('>', ')')}, file {frame.f_code.co_filename}, line {int(frame.f_code.co_firstlineno)}" + ): + simulator = OpcodeExecutor(frame, **kwargs) + try: + new_custom_code, guard_fn = simulator.transform() + return new_custom_code, guard_fn + # TODO(zrr1999): InnerError maybe place before (FallbackError, BreakGraphError) + # TODO(0x45f): handle BreakGraphError to trigger fallback + except BreakGraphError as e: + raise RuntimeError( + f"Found BreakGraphError raised, it should not be catch at start_translate!\n{e}" + ) + except FallbackError as e: + if simulator._code in NO_FALLBACK_CODES: + raise InnerError( + f"{simulator._code.co_name} should not fallback, but got '{e}'" + ) + # if disable_eval_frame is True, it means we want fallback to speedup rather than error occured + if is_strict_mode() and e.disable_eval_frame is False: + raise + log( + 2, + f"Unsupport Frame is {frame.f_code}, error message is: \n" + + "".join( + traceback.format_exception(type(e), e, e.__traceback__) + ), + ) + + # NOTE: If resume fn need fallback, we should replace NullVariable using NULL otherwise will fail to run + py_codegen = PyCodeGen(frame) + new_code = py_codegen.replace_null_variable() + # simulation not complete, not sure whether this code has sir, set disable_eval_frame = False + guard_fn = ( + dummy_guard + if e.disable_eval_frame is False + else simulator.guard_fn + ) + return ( + CustomCode(new_code, e.disable_eval_frame), + guard_fn, + ) + except Exception as e: + raise InnerError(OpcodeExecutorBase.error_message_summary(e)) from e + finally: + simulator.cleanup() From d33d3bc50938bf9f3c9318db1ed7e4c33c867e2c Mon Sep 17 00:00:00 2001 From: feifei-111 <2364819892@qq.com> Date: Tue, 10 Oct 2023 06:55:23 +0000 Subject: [PATCH 4/7] update --- sot/opcode_translator/custom_code.py | 2 + .../executor/executor_cache.py | 85 +++++++++---------- tests/test_12_for_loop.py | 2 +- tests/test_instruction_translator_cache.py | 12 ++- 4 files changed, 48 insertions(+), 53 deletions(-) diff --git a/sot/opcode_translator/custom_code.py b/sot/opcode_translator/custom_code.py index f44f260f..f55afb33 100644 --- a/sot/opcode_translator/custom_code.py +++ b/sot/opcode_translator/custom_code.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import types from typing import NamedTuple diff --git a/sot/opcode_translator/executor/executor_cache.py b/sot/opcode_translator/executor/executor_cache.py index 9b0b37ef..b0274055 100644 --- a/sot/opcode_translator/executor/executor_cache.py +++ b/sot/opcode_translator/executor/executor_cache.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import traceback import types from typing import List, Tuple @@ -174,49 +176,42 @@ def start_translate(frame: types.FrameType, **kwargs) -> GuardedFunction: Returns: GuardedFunction | None: The translated code object and its guard function, or None if translation fails. """ - with EventGuard( - f"start_translate: {frame.f_code.co_name.replace('<', '(').replace('>', ')')}, file {frame.f_code.co_filename}, line {int(frame.f_code.co_firstlineno)}" - ): - simulator = OpcodeExecutor(frame, **kwargs) - try: - new_custom_code, guard_fn = simulator.transform() - return new_custom_code, guard_fn - # TODO(zrr1999): InnerError maybe place before (FallbackError, BreakGraphError) - # TODO(0x45f): handle BreakGraphError to trigger fallback - except BreakGraphError as e: - raise RuntimeError( - f"Found BreakGraphError raised, it should not be catch at start_translate!\n{e}" - ) - except FallbackError as e: - if simulator._code in NO_FALLBACK_CODES: - raise InnerError( - f"{simulator._code.co_name} should not fallback, but got '{e}'" - ) - # if disable_eval_frame is True, it means we want fallback to speedup rather than error occured - if is_strict_mode() and e.disable_eval_frame is False: - raise - log( - 2, - f"Unsupport Frame is {frame.f_code}, error message is: \n" - + "".join( - traceback.format_exception(type(e), e, e.__traceback__) - ), - ) - - # NOTE: If resume fn need fallback, we should replace NullVariable using NULL otherwise will fail to run - py_codegen = PyCodeGen(frame) - new_code = py_codegen.replace_null_variable() - # simulation not complete, not sure whether this code has sir, set disable_eval_frame = False - guard_fn = ( - dummy_guard - if e.disable_eval_frame is False - else simulator.guard_fn - ) - return ( - CustomCode(new_code, e.disable_eval_frame), - guard_fn, + simulator = OpcodeExecutor(frame, **kwargs) + try: + new_custom_code, guard_fn = simulator.transform() + return new_custom_code, guard_fn + # TODO(zrr1999): InnerError maybe place before (FallbackError, BreakGraphError) + # TODO(0x45f): handle BreakGraphError to trigger fallback + except BreakGraphError as e: + raise RuntimeError( + f"Found BreakGraphError raised, it should not be catch at start_translate!\n{e}" + ) + except FallbackError as e: + if simulator._code in NO_FALLBACK_CODES: + raise InnerError( + f"{simulator._code.co_name} should not fallback, but got '{e}'" ) - except Exception as e: - raise InnerError(OpcodeExecutorBase.error_message_summary(e)) from e - finally: - simulator.cleanup() + # if disable_eval_frame is True, it means we want fallback to speedup rather than error occured + if is_strict_mode() and e.disable_eval_frame is False: + raise + log( + 2, + f"Unsupport Frame is {frame.f_code}, error message is: \n" + + "".join(traceback.format_exception(type(e), e, e.__traceback__)), + ) + + # NOTE: If resume fn need fallback, we should replace NullVariable using NULL otherwise will fail to run + py_codegen = PyCodeGen(frame) + new_code = py_codegen.replace_null_variable() + # simulation not complete, not sure whether this code has sir, set disable_eval_frame = False + guard_fn = ( + dummy_guard if e.disable_eval_frame is False else simulator.guard_fn + ) + return ( + CustomCode(new_code, e.disable_eval_frame), + guard_fn, + ) + except Exception as e: + raise InnerError(OpcodeExecutorBase.error_message_summary(e)) from e + finally: + simulator.cleanup() diff --git a/tests/test_12_for_loop.py b/tests/test_12_for_loop.py index f14f9eaa..83602319 100644 --- a/tests/test_12_for_loop.py +++ b/tests/test_12_for_loop.py @@ -10,7 +10,7 @@ import paddle import sot from sot import symbolic_translate -from sot.opcode_translator.executor.opcode_executor import OpcodeExecutorCache +from sot.opcode_translator.executor.executor_cache import OpcodeExecutorCache def gener(): diff --git a/tests/test_instruction_translator_cache.py b/tests/test_instruction_translator_cache.py index 4a43d250..530f2ef9 100644 --- a/tests/test_instruction_translator_cache.py +++ b/tests/test_instruction_translator_cache.py @@ -11,10 +11,8 @@ test_instruction_translator_cache_context, ) -from sot.opcode_translator.executor.opcode_executor import ( - CustomCode, - OpcodeExecutorCache, -) +from sot.opcode_translator.custom_code import CustomCode +from sot.opcode_translator.executor.executor_cache import OpcodeExecutorCache def fake_frames() -> ( @@ -88,7 +86,7 @@ def reset(self): OpcodeExecutorCache().clear() @patch( - "sot.opcode_translator.executor.opcode_executor.start_translate", + "sot.opcode_translator.executor.executor_cache.start_translate", mock_start_translate, ) def test_cache_hit(self): @@ -104,7 +102,7 @@ def test_cache_hit(self): self.assertEqual(ctx.translate_count, 1) @patch( - "sot.opcode_translator.executor.opcode_executor.start_translate", + "sot.opcode_translator.executor.executor_cache.start_translate", mock_start_translate, ) def test_cache_miss_due_to_unknown_code(self): @@ -120,7 +118,7 @@ def test_cache_miss_due_to_unknown_code(self): self.assertEqual(ctx.translate_count, 2) @patch( - "sot.opcode_translator.executor.opcode_executor.start_translate", + "sot.opcode_translator.executor.executor_cache.start_translate", mock_start_translate, ) def test_cache_miss_due_to_check_failed(self): From 719cbc660de172567a901d41f771bec90ec744fa Mon Sep 17 00:00:00 2001 From: feifei-111 <2364819892@qq.com> Date: Tue, 10 Oct 2023 06:59:13 +0000 Subject: [PATCH 5/7] update --- tests/test_case_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_case_base.py b/tests/test_case_base.py index 6277fc9e..1cf34409 100644 --- a/tests/test_case_base.py +++ b/tests/test_case_base.py @@ -11,7 +11,7 @@ import paddle from sot import symbolic_translate -from sot.opcode_translator.executor.opcode_executor import OpcodeExecutorCache +from sot.opcode_translator.executor.executor_cache import OpcodeExecutorCache @contextlib.contextmanager From b0a6b102bf9e802e67104536ff5c8750a1b2cb68 Mon Sep 17 00:00:00 2001 From: feifei-111 <2364819892@qq.com> Date: Tue, 10 Oct 2023 07:18:00 +0000 Subject: [PATCH 6/7] update --- .../executor/executor_cache.py | 3 +- .../executor/function_graph.py | 33 +++++++------------ sot/opcode_translator/executor/guard.py | 11 ++----- .../executor/opcode_executor.py | 7 +--- .../executor/opcode_inline_executor.py | 3 +- .../executor/variables/base.py | 3 +- .../executor/variables/callable.py | 2 +- sot/opcode_translator/transform.py | 3 +- sot/{utils/SotProfiler.py => profiler.py} | 0 sot/symbolic/compile_cache.py | 2 +- sot/symbolic/symbolic_context.py | 6 +--- sot/utils/__init__.py | 4 --- 12 files changed, 26 insertions(+), 51 deletions(-) rename sot/{utils/SotProfiler.py => profiler.py} (100%) diff --git a/sot/opcode_translator/executor/executor_cache.py b/sot/opcode_translator/executor/executor_cache.py index b0274055..79c66b78 100644 --- a/sot/opcode_translator/executor/executor_cache.py +++ b/sot/opcode_translator/executor/executor_cache.py @@ -4,14 +4,13 @@ import types from typing import List, Tuple +from ...profiler import EventGuard, event_register from ...psdb import NO_FALLBACK_CODES from ...utils import ( BreakGraphError, - EventGuard, FallbackError, InnerError, Singleton, - event_register, is_strict_mode, log, log_do, diff --git a/sot/opcode_translator/executor/function_graph.py b/sot/opcode_translator/executor/function_graph.py index 0ecc57c5..1bbfa969 100644 --- a/sot/opcode_translator/executor/function_graph.py +++ b/sot/opcode_translator/executor/function_graph.py @@ -11,13 +11,12 @@ from typing import Any, Callable from ...infer_meta import InferMetaCache, LayerInferMetaCache, MetaInfo +from ...profiler import EventGuard, event_register from ...symbolic.statement_ir import Symbol from ...symbolic.symbolic_context import SymbolicTraceContext from ...utils import ( - EventGuard, NameGenerator, OrderedSet, - event_register, inner_error_default_handler, is_inplace_api, is_paddle_api, @@ -162,19 +161,16 @@ def save_memo(self) -> FunctionGraph.Memo: NOTE: Why don't use __deepcopy__, because memo is not a deepcopy, i.e inner_out is only a shallow copy, SIR is a deepcopy. """ - with EventGuard( - f"Save SIR Checkpoint: len({len(self.sir_ctx.TOS)})", event_level=2 - ): - saved_stmt_ir = deepcopy(self.sir_ctx.TOS) - return FunctionGraph.Memo( - inner_out=set(self.inner_out), - input_variables=list(self.input_variables), - stmt_ir=saved_stmt_ir, - global_guards=OrderedSet(self._global_guarded_variables), - side_effects_state=self.side_effects.get_state(), - print_variables=list(self._print_variables), - inplace_tensors=OrderedSet(self._inplace_tensors), - ) + saved_stmt_ir = deepcopy(self.sir_ctx.TOS) + return FunctionGraph.Memo( + inner_out=set(self.inner_out), + input_variables=list(self.input_variables), + stmt_ir=saved_stmt_ir, + global_guards=OrderedSet(self._global_guarded_variables), + side_effects_state=self.side_effects.get_state(), + print_variables=list(self._print_variables), + inplace_tensors=OrderedSet(self._inplace_tensors), + ) def restore_memo(self, memo: FunctionGraph.Memo): """ @@ -333,7 +329,6 @@ def start_compile(self, *ret_vars: VariableBase): view_tracker(list(ret_vars), tracker_output_path, format="png") - @event_register("call_paddle_api", event_level=2) def call_paddle_api( self, func: Callable[..., Any], @@ -359,7 +354,6 @@ def message_handler(*args, **kwargs): InferMetaCache(), self.sir_ctx.call_API, func, *args, **kwargs ) - @event_register("call_tensor_method", event_level=2) def call_tensor_method( self, method_name: str, *args: VariableBase, **kwargs ): @@ -411,7 +405,6 @@ def get_opcode_executor_stack(): stack.append(f' {code_line}') return stack - @event_register("call_layer", event_level=2) def call_layer( self, layer: PaddleLayerVariable, @@ -444,7 +437,6 @@ def message_handler(*args, **kwargs): infer_meta_fn, compute_fn, layer, *args, **kwargs ) - @event_register("symbolic_call", event_level=2) def symbolic_call(self, infer_meta_fn, compute_fn, func, *args, **kwargs): """ Using infer_meta_fn and compute_fn convert func to symbolic function. @@ -459,8 +451,7 @@ def symbolic_call(self, infer_meta_fn, compute_fn, func, *args, **kwargs): metas = convert_to_meta(args) kwmetas = convert_to_meta(kwargs) - with EventGuard("infer_meta"): - out_metas = infer_meta_fn(func, *metas, **kwmetas) + out_metas = infer_meta_fn(func, *metas, **kwmetas) inputs_symbols = ( convert_to_symbol(args), convert_to_symbol(kwargs), diff --git a/sot/opcode_translator/executor/guard.py b/sot/opcode_translator/executor/guard.py index 1766dc17..5df45e0d 100644 --- a/sot/opcode_translator/executor/guard.py +++ b/sot/opcode_translator/executor/guard.py @@ -4,13 +4,8 @@ import weakref from typing import TYPE_CHECKING, Any, Callable, TypeVar -from ...utils import ( - EventGuard, - InnerError, - current_tmp_name_records, - log, - log_do, -) +from ...profiler import EventGuard +from ...utils import InnerError, current_tmp_name_records, log, log_do Guard = Callable[[types.FrameType], bool] @@ -71,7 +66,7 @@ def make_guard(stringify_guards: list[StringifyExpression]) -> Guard: Args: stringify_guards: a list of StringifyExpression. """ - with EventGuard(f"make_guard: ({len(stringify_guards)})"): + with EventGuard("make_guard"): num_guards = len(stringify_guards) if not num_guards: guard = lambda frame: True diff --git a/sot/opcode_translator/executor/opcode_executor.py b/sot/opcode_translator/executor/opcode_executor.py index a872a1fc..3956e609 100644 --- a/sot/opcode_translator/executor/opcode_executor.py +++ b/sot/opcode_translator/executor/opcode_executor.py @@ -13,15 +13,14 @@ import opcode +from ...profiler import EventGuard, event_register from ...psdb import NO_BREAKGRAPH_CODES from ...utils import ( BreakGraphError, - EventGuard, FallbackError, InnerError, OrderedSet, SotUndefinedVar, - event_register, log, log_do, min_graph_size, @@ -1509,7 +1508,6 @@ def _create_resume_fn(self, index, stack_size=0): fn, inputs = pycode_gen.gen_resume_fn_at(index, stack_size) return fn, inputs - @event_register("_break_graph_in_jump") @fallback_when_occur_error def _break_graph_in_jump(self, result: VariableBase, instr: Instruction): """ @@ -1596,7 +1594,6 @@ def _break_graph_in_jump(self, result: VariableBase, instr: Instruction): self.new_code = self._graph.pycode_gen.gen_pycode() self.guard_fn = self._graph.guard_fn - @event_register("_break_graph_in_call") @fallback_when_occur_error def _break_graph_in_call( self, @@ -1766,7 +1763,6 @@ def _gen_loop_body_between( pycode_gen.gen_outputs_and_return(inputs) return pycode_gen.create_fn_with_inputs(inputs) - @event_register("_break_graph_in_for_loop") @fallback_when_occur_error def _break_graph_in_for_loop( self, iterator: VariableBase, for_iter: Instruction @@ -1942,7 +1938,6 @@ def _break_graph_in_for_loop( self.new_code = self._graph.pycode_gen.gen_pycode() self.guard_fn = self._graph.guard_fn - @event_register("_inline_call_for_loop") def _inline_call_for_loop( self, iterator: VariableBase, for_iter: Instruction ): diff --git a/sot/opcode_translator/executor/opcode_inline_executor.py b/sot/opcode_translator/executor/opcode_inline_executor.py index 252e4aba..97d011d5 100644 --- a/sot/opcode_translator/executor/opcode_inline_executor.py +++ b/sot/opcode_translator/executor/opcode_inline_executor.py @@ -5,7 +5,8 @@ import re from typing import TYPE_CHECKING -from ...utils import BreakGraphError, event_register, log +from ...profiler import event_register +from ...utils import BreakGraphError, log from ..instruction_utils import Instruction from .guard import StringifyExpression, union_free_vars from .opcode_executor import OpcodeExecutorBase, Stop diff --git a/sot/opcode_translator/executor/variables/base.py b/sot/opcode_translator/executor/variables/base.py index 534642f5..526f8899 100644 --- a/sot/opcode_translator/executor/variables/base.py +++ b/sot/opcode_translator/executor/variables/base.py @@ -8,7 +8,8 @@ import paddle -from ....utils import NameGenerator, event_register, get_unbound_method, log +from ....profiler import event_register +from ....utils import NameGenerator, get_unbound_method, log from ....utils.exceptions import FallbackError, HasNoAttributeError from ..dispatcher import Dispatcher from ..guard import StringifyExpression, check_guard, union_free_vars diff --git a/sot/opcode_translator/executor/variables/callable.py b/sot/opcode_translator/executor/variables/callable.py index e5731da9..b9913c6e 100644 --- a/sot/opcode_translator/executor/variables/callable.py +++ b/sot/opcode_translator/executor/variables/callable.py @@ -9,8 +9,8 @@ import paddle from .... import psdb +from ....profiler import EventGuard from ....utils import ( - EventGuard, is_break_graph_api, is_break_graph_tensor_methods, is_builtin_fn, diff --git a/sot/opcode_translator/transform.py b/sot/opcode_translator/transform.py index 461b99f4..053aa726 100644 --- a/sot/opcode_translator/transform.py +++ b/sot/opcode_translator/transform.py @@ -3,7 +3,8 @@ import dis from functools import partial -from ..utils import CodeStatus, EventGuard, log, log_do +from ..profiler import EventGuard +from ..utils import CodeStatus, log, log_do from .custom_code import CustomCode from .executor.executor_cache import OpcodeExecutorCache from .skip_files import need_skip diff --git a/sot/utils/SotProfiler.py b/sot/profiler.py similarity index 100% rename from sot/utils/SotProfiler.py rename to sot/profiler.py diff --git a/sot/symbolic/compile_cache.py b/sot/symbolic/compile_cache.py index 1c9c8524..3f7233df 100644 --- a/sot/symbolic/compile_cache.py +++ b/sot/symbolic/compile_cache.py @@ -4,10 +4,10 @@ import paddle +from ..profiler import EventGuard from ..utils import ( Cache, CodeStatus, - EventGuard, GraphLogger, Singleton, StepInfoManager, diff --git a/sot/symbolic/symbolic_context.py b/sot/symbolic/symbolic_context.py index 9b8509d9..a6de3c05 100644 --- a/sot/symbolic/symbolic_context.py +++ b/sot/symbolic/symbolic_context.py @@ -1,6 +1,6 @@ from __future__ import annotations -from ..utils import event_register, log +from ..utils import log from .compile_cache import CompileSIRCache from .statement_ir import ( ApiStatement, @@ -43,7 +43,6 @@ def TOS(self): return self.sir_stack[-1] - @event_register("call_SIR", event_level=2) def call_SIR(self, sirname, inputs, outputs, stacks): """ Call a SIR, which is a subgraph. @@ -52,7 +51,6 @@ def call_SIR(self, sirname, inputs, outputs, stacks): stmt = CallStatement(sirname, inputs, outputs, stacks) self.TOS.add_statement(stmt) - @event_register("call_API", event_level=2) def call_API(self, api, inputs, outputs, stacks): """ Call a paddle api. @@ -62,7 +60,6 @@ def call_API(self, api, inputs, outputs, stacks): stmt = ApiStatement(api, inputs, outputs, stacks) self.TOS.add_statement(stmt) - @event_register("call_METHOD", event_level=2) def call_METHOD(self, method_name, inputs, outputs, stacks): """ Call a method of a api. The API here can be python or Paddle @@ -76,7 +73,6 @@ def call_METHOD(self, method_name, inputs, outputs, stacks): stmt = MethodStatement(method_name, inputs, outputs, stacks) self.TOS.add_statement(stmt) - @event_register("call_LAYER", event_level=2) def call_LAYER(self, layer, inputs, outputs, stacks): """ Call a layer of a api. diff --git a/sot/utils/__init__.py b/sot/utils/__init__.py index 1ed75f2c..4cbe91fd 100644 --- a/sot/utils/__init__.py +++ b/sot/utils/__init__.py @@ -11,7 +11,6 @@ is_inplace_api, paddle_tensor_methods, ) -from .SotProfiler import EventGuard, SotProfiler, event_register from .utils import ( Cache, GraphLogger, @@ -82,9 +81,6 @@ "get_unbound_method", "GraphLogger", "SotUndefinedVar", - "event_register", - "EventGuard", - "SotProfiler", "hashable", "is_inplace_api", "sotprof_range", From 41ba386eaedfa167cb82f7acbffd5364839631c8 Mon Sep 17 00:00:00 2001 From: feifei-111 <2364819892@qq.com> Date: Tue, 10 Oct 2023 07:53:32 +0000 Subject: [PATCH 7/7] update --- sot/opcode_translator/transform.py | 5 +---- sot/utils/__init__.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/sot/opcode_translator/transform.py b/sot/opcode_translator/transform.py index 053aa726..629727c3 100644 --- a/sot/opcode_translator/transform.py +++ b/sot/opcode_translator/transform.py @@ -50,10 +50,7 @@ def eval_frame_callback(frame, **kwargs) -> CustomCode: new_code = frame.f_code else: log( - 2, - "[eval_frame_callback] start to translate: " - + str(frame.f_code) - + "\n", + 2, f"[eval_frame_callback] start to translate: {frame.f_code}\n" ) log_do(4, partial(print_locals, frame)) diff --git a/sot/utils/__init__.py b/sot/utils/__init__.py index 4cbe91fd..c4e1e944 100644 --- a/sot/utils/__init__.py +++ b/sot/utils/__init__.py @@ -11,7 +11,7 @@ is_inplace_api, paddle_tensor_methods, ) -from .utils import ( +from .utils import ( # noqa: F401 Cache, GraphLogger, NameGenerator,