Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/dttest/api/python/ge/ge/custom_op/_bridge.py: 96%

154 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-18 20:50 +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# ----------------------------------------------------------------------------------------------------------- 

12 

13"""Bridge-facing Python runtime helpers for GE custom op implementations.""" 

14 

15import inspect 

16import sys 

17import threading 

18from dataclasses import dataclass 

19from typing import Dict, Optional 

20 

21from ._ir_types import InputType, OutputType 

22from ._signature import _get_runtime_attr_spec, _validate_args_signature 

23from .base import EagerOpExecutionContext 

24from .bootstrap import get_registered_op_impls, load_custom_op_plugins 

25from .context import _declare_launch_args_ctx_scope, _execute_ctx_scope 

26from .registry import ( 

27 INTERFACE_ANNOTATED_ARGS, 

28 INTERFACE_EAGER_EXECUTE, 

29 get_registered_op_impl_by_descriptor_key, 

30) 

31 

32 

33@dataclass 

34class _OpImplHolder: 

35 descriptor_key: str 

36 instance_id: str 

37 instance: object 

38 

39 

40_HOLDER_LOCK = threading.RLock() 

41_OP_IMPL_HOLDERS: Dict[str, _OpImplHolder] = {} 

42 

43 

44def load_and_get_op_impl_descriptors() -> list: 

45 load_custom_op_plugins() 

46 return get_registered_op_impls() 

47 

48 

49def _get_holder(instance_id: str) -> _OpImplHolder: 

50 with _HOLDER_LOCK: 

51 holder = _OP_IMPL_HOLDERS.get(instance_id) 

52 if holder is None: 

53 raise KeyError(f"python op impl holder is not created: {instance_id}") 

54 return holder 

55 

56 

57def _get_eager_execute_holder(instance_id: str) -> _OpImplHolder: 

58 holder = _get_holder(instance_id) 

59 if not callable(getattr(holder.instance, "execute", None)): 

60 raise TypeError( 

61 f"python op impl does not implement callable execute: {instance_id}" 

62 ) 

63 return holder 

64 

65 

66def _get_eager_execute_op(instance_id: str) -> object: 

67 return _get_eager_execute_holder(instance_id).instance 

68 

69 

70def create_op_impl_holder(instance_id: str, descriptor_key: str) -> bool: 

71 descriptor = get_registered_op_impl_by_descriptor_key(descriptor_key) 

72 if descriptor is None: 

73 raise KeyError(f"python op impl descriptor_key not found: {descriptor_key}") 

74 with _HOLDER_LOCK: 

75 if instance_id in _OP_IMPL_HOLDERS: 

76 return True 

77 _OP_IMPL_HOLDERS[instance_id] = _OpImplHolder( 

78 descriptor_key=descriptor_key, 

79 instance_id=instance_id, 

80 instance=descriptor.cls(), 

81 ) 

82 return True 

83 

84 

85def destroy_op_impl_holder(instance_id: str) -> bool: 

86 with _HOLDER_LOCK: 

87 return _OP_IMPL_HOLDERS.pop(instance_id, None) is not None 

88 

89 

90def _is_legacy_execute(method) -> bool: 

91 params = list(inspect.signature(method).parameters.values()) 

92 return ( 

93 len(params) == 1 

94 and params[0].name == "ctx" 

95 and params[0].kind 

96 in ( 

97 inspect.Parameter.POSITIONAL_ONLY, 

98 inspect.Parameter.POSITIONAL_OR_KEYWORD, 

99 ) 

100 ) 

101 

102 

103def _get_callback_for_signature(cls, method_name: str): 

104 method = inspect.getattr_static(cls, method_name) 

105 if isinstance(method, staticmethod): 

106 return method.__func__ 

107 if isinstance(method, classmethod): 

108 return method.__get__(None, cls) 

109 if inspect.isfunction(method): 

110 return method.__get__(object(), cls) 

111 return getattr(cls, method_name) 

112 

113 

114def validate_op_impl_descriptor(descriptor_key: str, ir_meta: Optional[dict]) -> bool: 

115 descriptor = get_registered_op_impl_by_descriptor_key(descriptor_key) 

116 if descriptor is None: 

117 raise KeyError(f"python op impl descriptor_key not found: {descriptor_key}") 

118 

119 if INTERFACE_EAGER_EXECUTE in descriptor.interfaces: 

120 method = _get_callback_for_signature(descriptor.cls, "execute") 

121 if not _is_legacy_execute(method): 

122 if ir_meta is None: 

123 raise RuntimeError( 

124 "canonical IR not found for schema-bound execute: " 

125 f"{descriptor.op_type}" 

126 ) 

127 _validate_args_signature(method, ir_meta, descriptor, method_name="execute") 

128 

129 if INTERFACE_ANNOTATED_ARGS in descriptor.interfaces: 

130 if ir_meta is None: 

131 raise RuntimeError( 

132 "canonical IR not found for schema-bound declare_launch_args" 

133 ) 

134 method = _get_callback_for_signature(descriptor.cls, "declare_launch_args") 

135 _validate_args_signature( 

136 method, ir_meta, descriptor, method_name="declare_launch_args" 

137 ) 

138 return True 

139 

140 

141def _build_inputs( 

142 ir_inputs: list, 

143 get_required_input, 

144 get_optional_input, 

145 get_dynamic_input_num, 

146 get_dynamic_input, 

147) -> list: 

148 args = [] 

149 for ir_index, item in enumerate(ir_inputs): 

150 kind = item["kind"] 

151 if kind == InputType.REQUIRED: 

152 args.append(get_required_input(ir_index)) 

153 elif kind == InputType.OPTIONAL: 

154 args.append(get_optional_input(ir_index)) 

155 elif kind == InputType.DYNAMIC: 

156 instance_num = get_dynamic_input_num(ir_index) 

157 args.append( 

158 [ 

159 get_dynamic_input(ir_index, relative_index) 

160 for relative_index in range(instance_num) 

161 ] 

162 ) 

163 else: 

164 raise ValueError( 

165 f"unsupported custom op IR input kind: {kind}, ir index: {ir_index}" 

166 ) 

167 return args 

168 

169 

170def _build_execute_inputs(ctx: EagerOpExecutionContext, ir_inputs: list) -> list: 

171 return _build_inputs( 

172 ir_inputs, 

173 ctx.get_required_input_tensor, 

174 ctx.get_optional_input_tensor, 

175 ctx.get_dynamic_input_num, 

176 ctx.get_dynamic_input_tensor, 

177 ) 

178 

179 

180def _read_runtime_attr(attrs, index: int, ir_type: str): 

181 getter_name, _ = _get_runtime_attr_spec(ir_type, index) 

182 return getattr(attrs, getter_name)(index) 

183 

184 

185def _build_execute_attrs(ctx: EagerOpExecutionContext, ir_attrs: list) -> dict: 

186 if not ir_attrs: 

187 return {} 

188 attrs = ctx.get_attrs() 

189 return { 

190 item["name"]: _read_runtime_attr(attrs, index, item["type"]) 

191 for index, item in enumerate(ir_attrs) 

192 } 

193 

194 

195def _build_declare_inputs(ctx, ir_inputs: list) -> list: 

196 return _build_inputs( 

197 ir_inputs, 

198 ctx._get_required_input_tensor, 

199 ctx._get_optional_input_tensor, 

200 ctx._get_dynamic_input_num, 

201 ctx._get_dynamic_input_tensor, 

202 ) 

203 

204 

205def _build_declare_outputs(ctx, ir_outputs: list) -> list: 

206 args = [] 

207 for ir_index, item in enumerate(ir_outputs): 

208 kind = item["kind"] 

209 if kind == OutputType.REQUIRED: 

210 args.append(ctx._get_required_output_tensor(ir_index)) 

211 elif kind == OutputType.DYNAMIC: 

212 instance_num = ctx._get_dynamic_output_num(ir_index) 

213 args.append( 

214 [ 

215 ctx._get_dynamic_output_tensor(ir_index, relative_index) 

216 for relative_index in range(instance_num) 

217 ] 

218 ) 

219 else: 

220 raise ValueError(f"unsupported custom op IR output kind: {kind}") 

221 return args 

222 

223 

224def _build_declare_attrs(ctx, ir_attrs: list) -> dict: 

225 if not ir_attrs: 

226 return {} 

227 attrs = ctx._get_attrs() 

228 return { 

229 item["name"]: _read_runtime_attr(attrs, index, item["type"]) 

230 for index, item in enumerate(ir_attrs) 

231 } 

232 

233 

234def call_execute( 

235 instance_id: str, 

236 ir_meta: Optional[dict], 

237 ctx: EagerOpExecutionContext, 

238) -> None: 

239 try: 

240 holder = _get_eager_execute_holder(instance_id) 

241 custom_op = holder.instance 

242 method = custom_op.execute 

243 if _is_legacy_execute(method): 

244 method(ctx) 

245 return 

246 if ir_meta is None: 

247 descriptor = custom_op.__ge_op_impl_descriptor__ 

248 raise RuntimeError( 

249 f"canonical IR not found for schema-bound execute: {descriptor.op_type}" 

250 ) 

251 args = _build_execute_inputs(ctx, ir_meta["inputs"]) 

252 kwargs = _build_execute_attrs(ctx, ir_meta["attrs"]) 

253 with _execute_ctx_scope(ctx): 

254 method(*args, **kwargs) 

255 finally: 

256 ctx._invalidate() 

257 

258 

259def call_declare_launch_args(instance_id: str, ir_meta: Optional[dict], ctx) -> None: 

260 try: 

261 holder = _get_holder(instance_id) 

262 method = getattr(holder.instance, "declare_launch_args", None) 

263 if not callable(method): 

264 raise TypeError( 

265 f"python op impl does not implement declare_launch_args: {instance_id}" 

266 ) 

267 if ir_meta is None: 

268 raise RuntimeError( 

269 "canonical IR not found for schema-bound declare_launch_args" 

270 ) 

271 args = _build_declare_inputs(ctx, ir_meta["inputs"]) 

272 args.extend(_build_declare_outputs(ctx, ir_meta["outputs"])) 

273 kwargs = _build_declare_attrs(ctx, ir_meta["attrs"]) 

274 with _declare_launch_args_ctx_scope(ctx): 

275 result = method(*args, **kwargs) 

276 if result is not None: 

277 raise TypeError("declare_launch_args must return None") 

278 finally: 

279 ctx._invalidate() 

280 

281 

282def clear_op_impl_holders() -> None: 

283 with _HOLDER_LOCK: 

284 _OP_IMPL_HOLDERS.clear() 

285 

286 

287def clear_loaded_op_impl_modules() -> None: 

288 """Clear all dynamically loaded op implementation modules from sys.modules to avoid test pollution.""" 

289 keys_to_remove = [key for key in sys.modules if key.startswith("_ge_py_custom_op_")] 

290 for key in keys_to_remove: 

291 del sys.modules[key]