Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/dttest/api/python/ge/ge/passes/_bridge.py: 91%
109 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-27 10:03 +0800
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-27 10:03 +0800
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# -----------------------------------------------------------------------------------------------------------
4# Copyright (c) 2026 Huawei Technologies Co., Ltd.
5# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6# CANN Open Software License Agreement Version 2.0 (the "License").
7# Please refer to the License for details. You may not use this file except in compliance with the License.
8# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10# See LICENSE in the root of the software repository for the full text of the License.
11# -----------------------------------------------------------------------------------------------------------
13"""Bridge-facing Python runtime helpers for GE passes."""
15import sys
16import threading
17from collections.abc import Iterable
18from dataclasses import dataclass
19from typing import Dict, List, Optional, cast
21from ge.graph import Graph, Node
23from ._native import borrow_match_result, borrow_node, clone_pattern_matcher_config, release_graph
24from .base import (
25 DecomposePass,
26 FusionBasePass,
27 PassContext,
28 PatternFusionPass,
29 PatternMatcherConfig,
30 StatusLike,
31)
32from .bootstrap import get_registered_passes, load_pass_plugins
33from .pattern import ensure_pattern
34from .registry import get_registered_pass_by_descriptor_key
37@dataclass
38class _PassHolder:
39 descriptor_key: str
40 instance_id: str
41 instance: FusionBasePass
44_HOLDER_LOCK = threading.RLock()
45_PASS_HOLDERS: Dict[str, _PassHolder] = {}
48def load_and_get_pass_descriptors() -> list:
49 load_pass_plugins()
50 return get_registered_passes()
53def _get_holder(instance_id: str) -> _PassHolder:
54 with _HOLDER_LOCK:
55 holder = _PASS_HOLDERS.get(instance_id)
56 if holder is None:
57 raise KeyError(f"python pass holder is not created: {instance_id}")
58 return holder
61def _get_fusion_base_pass(instance_id: str) -> FusionBasePass:
62 return _get_holder(instance_id).instance
65def _get_pattern_fusion_pass(instance_id: str) -> PatternFusionPass:
66 instance = _get_holder(instance_id).instance
67 if not isinstance(instance, PatternFusionPass):
68 raise TypeError(f"python pass holder is not PatternFusionPass: {instance_id}")
69 return instance
72def _get_decompose_pass(instance_id: str) -> DecomposePass:
73 instance = _get_holder(instance_id).instance
74 if not isinstance(instance, DecomposePass):
75 raise TypeError(f"python pass holder is not DecomposePass: {instance_id}")
76 return instance
79def create_pass_holder(instance_id: str, descriptor_key: str) -> bool:
80 descriptor = get_registered_pass_by_descriptor_key(descriptor_key)
81 if descriptor is None:
82 raise KeyError(f"python pass descriptor_key not found: {descriptor_key}")
83 with _HOLDER_LOCK:
84 if instance_id in _PASS_HOLDERS:
85 return True
86 _PASS_HOLDERS[instance_id] = _PassHolder(
87 descriptor_key=descriptor_key,
88 instance_id=instance_id,
89 instance=descriptor.cls(),
90 )
91 return True
94def destroy_pass_holder(instance_id: str) -> bool:
95 with _HOLDER_LOCK:
96 return _PASS_HOLDERS.pop(instance_id, None) is not None
99def run_fusion_base_pass(instance_id: str, graph: Graph, context: Optional[PassContext] = None) -> StatusLike:
100 pass_instance = _get_fusion_base_pass(instance_id)
101 if context is not None and not isinstance(context, PassContext):
102 raise TypeError("context type error")
103 return pass_instance.run(graph, cast(PassContext, context))
106def _release_replacement_graph(replacement: Graph, pass_name: str) -> int:
107 if not isinstance(replacement, Graph):
108 raise TypeError(f"{pass_name}.replacement must return ge.graph.Graph")
109 return release_graph(replacement)
112def get_pass_patterns(instance_id: str) -> List[int]:
113 pass_instance = _get_pattern_fusion_pass(instance_id)
114 patterns = pass_instance.patterns()
115 if patterns is None:
116 return []
117 if not isinstance(patterns, Iterable) or isinstance(patterns, (str, bytes)):
118 raise TypeError("PatternFusionPass.patterns must return an iterable of Pattern or Graph")
120 released_patterns = []
121 for item in patterns:
122 pattern = ensure_pattern(item)
123 released_patterns.append(pattern.release())
124 return released_patterns
127def get_pattern_matcher_config(instance_id: str) -> Optional[int]:
128 pass_instance = _get_pattern_fusion_pass(instance_id)
129 matcher_config = pass_instance.matcher_config
130 if matcher_config is None:
131 return None
132 if not isinstance(matcher_config, PatternMatcherConfig):
133 raise TypeError("PatternFusionPass.matcher_config must be PatternMatcherConfig or None")
134 return clone_pattern_matcher_config(matcher_config)
137def call_meet_requirements(instance_id: str, match_result_handle: int) -> bool:
138 pass_instance = _get_pattern_fusion_pass(instance_id)
139 match_result = borrow_match_result(match_result_handle)
140 try:
141 return bool(pass_instance.meet_requirements(match_result))
142 finally:
143 match_result._invalidate()
146def call_replacement(instance_id: str, match_result_handle: int) -> int:
147 pass_instance = _get_pattern_fusion_pass(instance_id)
148 match_result = borrow_match_result(match_result_handle)
149 try:
150 replacement = pass_instance.replacement(match_result)
151 finally:
152 match_result._invalidate()
154 return _release_replacement_graph(replacement, "PatternFusionPass")
157def call_decompose_meet_requirements(instance_id: str, node_handle: int) -> bool:
158 pass_instance = _get_decompose_pass(instance_id)
159 node = cast(Node, borrow_node(node_handle))
160 return bool(pass_instance.meet_requirements(node))
163def call_decompose_replacement(instance_id: str, node_handle: int) -> int:
164 pass_instance = _get_decompose_pass(instance_id)
165 node = cast(Node, borrow_node(node_handle))
166 replacement = pass_instance.replacement(node)
167 return _release_replacement_graph(replacement, "DecomposePass")
170def clear_pass_holders() -> None:
171 with _HOLDER_LOCK:
172 _PASS_HOLDERS.clear()
175def clear_loaded_pass_modules() -> None:
176 """Clear all dynamically loaded pass modules from sys.modules to avoid test pollution."""
177 keys_to_remove = [key for key in sys.modules if key.startswith("_ge_py_pass_")]
178 for key in keys_to_remove:
179 del sys.modules[key]