Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / core / activation_checkpoint / recompute_state.py: 100%
49 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-08-04 05:18 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-08-04 05:18 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Dynamic execution state shared by activation recomputation features."""
16import contextvars
17from typing import Any, Callable, Dict, Optional, Tuple
20class _RecomputeInvocation:
21 """Own resources whose lifetime is one checkpoint invocation."""
23 def __init__(self) -> None:
24 """Initialize an empty invocation resource registry."""
25 self.identity = object()
26 self.resources: Dict[object, Any] = {}
28 def get_resource(self, key: object, factory: Callable[[], Any]) -> Any:
29 """Get or create one invocation-local resource."""
30 if key not in self.resources:
31 self.resources[key] = factory()
32 return self.resources[key]
34 def clear(self) -> None:
35 """Release invocation resources, including partially consumed caches."""
36 for resource in self.resources.values():
37 clear = getattr(resource, "clear", None)
38 if clear is not None:
39 clear()
40 self.resources.clear()
43class RecomputeState:
44 """Describe the current checkpoint invocation and execution phase."""
46 def __init__(self, invocation: _RecomputeInvocation, recomputing: bool) -> None:
47 """Initialize state for one phase of a checkpoint invocation."""
48 self._invocation = invocation
49 self.is_recomputing = recomputing
51 @property
52 def invocation_id(self) -> object:
53 """Return an identity that is stable across forward and recomputation."""
54 return self._invocation.identity
56 def get_resource(self, key: object, factory: Callable[[], Any]) -> Any:
57 """Get an invocation-local resource shared by both execution phases."""
58 return self._invocation.get_resource(key, factory)
60 def _clear_resources(self) -> None:
61 """Release all resources owned by this checkpoint invocation."""
62 self._invocation.clear()
65_CURRENT_RECOMPUTE_STATE: contextvars.ContextVar[Optional[RecomputeState]] = contextvars.ContextVar(
66 "hyper_parallel_recompute_state",
67 default=None,
68)
71class _RecomputeContext:
72 """Install one checkpoint execution phase in the current dynamic scope."""
74 def __init__(self, state: RecomputeState) -> None:
75 """Initialize a context for the supplied execution state."""
76 self._state = state
77 self._token = None
79 def __enter__(self) -> "_RecomputeContext":
80 """Expose this phase as the current recompute state."""
81 self._token = _CURRENT_RECOMPUTE_STATE.set(self._state)
82 return self
84 def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> bool:
85 """Restore the outer state and clear resources after recomputation."""
86 if self._token is not None:
87 _CURRENT_RECOMPUTE_STATE.reset(self._token)
88 if self._state.is_recomputing or exc_type is not None:
89 self._state._clear_resources() # pylint: disable=protected-access
90 return False
93def get_recompute_state() -> Optional[RecomputeState]:
94 """Return the current checkpoint execution state, if one is active."""
95 return _CURRENT_RECOMPUTE_STATE.get()
98def is_recomputing() -> bool:
99 """Return whether the current dynamic scope is replaying a checkpoint."""
100 state = get_recompute_state()
101 return state is not None and state.is_recomputing
104def create_recompute_contexts() -> Tuple[_RecomputeContext, _RecomputeContext]:
105 """Create forward and recompute contexts for one checkpoint invocation."""
106 invocation = _RecomputeInvocation()
107 return (
108 _RecomputeContext(RecomputeState(invocation, recomputing=False)),
109 _RecomputeContext(RecomputeState(invocation, recomputing=True)),
110 )