Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / functional / _triton / gated_delta_net / utils.py: 0%

201 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-10-25 05:45 +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# Copyright (c) 2023-2025, Songlin Yang, Yu Zhang 

16 

17# pylint: disable=no-name-in-module,consider-using-from-import,pointless-string-statement 

18# pylint: disable=redefined-outer-name,missing-public-type-hints,missing-public-docstring 

19# pylint: disable=unused-argument,no-member,import-outside-toplevel 

20# pylint: disable=invalid-name,missing-module-docstring,missing-function-docstring 

21# pylint: disable=missing-class-docstring,broad-exception-caught,protected-access 

22# pylint: disable=forbidden-backend-import 

23 

24import itertools 

25import contextlib 

26import os 

27import functools 

28import warnings 

29import logging 

30from enum import Enum 

31from functools import lru_cache 

32from typing import Any, Callable, Optional 

33from packaging import version 

34 

35import torch 

36import triton 

37import triton.language as tl 

38import triton.language.extra.libdevice as tldevice 

39import triton.runtime.driver as driver 

40 

41logger = logging.getLogger(__name__) 

42 

43FLA_CI_ENV = os.getenv("FLA_CI_ENV") == "1" 

44 

45 

46def tensor_cache(fn: Optional[Callable[..., torch.Tensor]] = None, *, maxsize: int = 1) -> Any: 

47 """ 

48 A decorator that caches the most recent results of a function with tensor inputs. 

49 

50 This decorator will store the outputs of the decorated function for the most recent 

51 set of input tensors, up to `maxsize` entries. If the function is called again with 

52 the same input tensors, it will return the cached result. 

53 

54 When maxsize=1 (default), the behavior is identical to caching only the most recent result. 

55 Can be used as @tensor_cache or @tensor_cache(maxsize=n). 

56 

57 Args: 

58 fn (Callable[..., torch.Tensor], optional): 

59 The function to be decorated when used without parentheses. 

60 maxsize (int): 

61 Maximum number of input combinations to cache. Default is 1. 

62 

63 Returns: 

64 Callable[..., torch.Tensor]: 

65 A wrapped version of the input function with caching. 

66 """ 

67 if maxsize < 1: 

68 raise ValueError("maxsize must be at least 1") 

69 

70 def _is_match(a: Any, b: Any) -> bool: 

71 if isinstance(a, torch.Tensor) and isinstance(b, torch.Tensor): 

72 return a is b 

73 try: 

74 return a == b 

75 except Exception: 

76 return a is b 

77 

78 def _make_wrapper(fn: Callable[..., torch.Tensor]) -> Callable[..., torch.Tensor]: 

79 cache: list = [] 

80 

81 @functools.wraps(fn) 

82 def wrapper(*args: Any, **kwargs: Any) -> Any: 

83 for i, (cached_args, cached_kwargs, cached_result) in enumerate(cache): 

84 if len(args) == len(cached_args) and len(kwargs) == len(cached_kwargs): 

85 if all(_is_match(a, b) for a, b in zip(args, cached_args)) and all( 

86 k in cached_kwargs and _is_match(v, cached_kwargs[k]) for k, v in kwargs.items() 

87 ): 

88 if i != 0: 

89 cache.insert(0, cache.pop(i)) 

90 return cached_result 

91 

92 result = fn(*args, **kwargs) 

93 cache.insert(0, (args, kwargs, result)) 

94 if len(cache) > maxsize: 

95 cache.pop() 

96 return result 

97 

98 return wrapper 

99 

100 if fn is not None: 

101 return _make_wrapper(fn) 

102 return _make_wrapper 

103 

104 

105@tensor_cache 

106def prepare_lens(cu_seqlens: torch.LongTensor) -> torch.LongTensor: 

107 return cu_seqlens[1:] - cu_seqlens[:-1] 

108 

109 

110@tensor_cache(maxsize=3) 

111def prepare_chunk_indices(cu_seqlens: torch.LongTensor, chunk_size: int) -> torch.LongTensor: 

112 indices = torch.cat([torch.arange(n) for n in triton.cdiv(prepare_lens(cu_seqlens), chunk_size).tolist()]) 

113 return torch.stack([indices.eq(0).cumsum(0) - 1, indices], 1).to(cu_seqlens) 

114 

115 

116def get_abs_err(x, y): 

117 return (x.detach() - y.detach()).flatten().abs().max().item() 

118 

119 

120def get_err_ratio(x, y): 

121 err = (x.detach() - y.detach()).flatten().square().mean().sqrt().item() 

122 base = (x.detach()).flatten().square().mean().sqrt().item() 

123 return err / (base + 1e-8) 

124 

125 

126def assert_close(prefix, ref, tri, ratio, warning=False, err_atol=1e-6): 

127 abs_atol = get_abs_err(ref, tri) 

128 msg = f"{prefix:>16} diff: {abs_atol:.6f} ratio: {get_err_ratio(ref, tri):.6f}" 

129 logger.info(msg) 

130 error_rate = get_err_ratio(ref, tri) 

131 if abs_atol <= err_atol: 

132 return 

133 allow_warning = warning or (FLA_CI_ENV and (error_rate < 0.01 or abs_atol <= 0.3)) 

134 if allow_warning: 

135 if error_rate > ratio: 

136 warnings.warn(msg) 

137 else: 

138 if not error_rate < ratio: 

139 raise AssertionError(msg) 

140 

141 

142if hasattr(triton.language, '_experimental_make_tensor_descriptor'): 

143 # For Triton 3.3.x 

144 make_tensor_descriptor = triton.language._experimental_make_tensor_descriptor 

145elif hasattr(triton.language, 'make_tensor_descriptor'): 

146 # For Triton 3.4.x and later 

147 make_tensor_descriptor = triton.language.make_tensor_descriptor 

148else: 

149 """ 

150 Fallback implementation when TMA is not supported. 

151 Returns None to indicate TMA descriptors are unavailable. 

152 Just make triton compiler happy. 

153 """ 

154 

155 @triton.jit 

156 def make_tensor_descriptor( 

157 base, 

158 shape, 

159 strides, 

160 block_shape, 

161 _builder=None, 

162 ): 

163 return None 

164 

165 

166@lru_cache(maxsize=None) 

167def get_available_device() -> str: 

168 try: 

169 return triton.runtime.driver.active.get_current_target().backend 

170 except Exception: 

171 _cpu_device_warning() 

172 return 'cpu' 

173 

174 

175def map_triton_backend_to_torch_device() -> str: 

176 backend = get_available_device() # 'cuda' | 'hip' | 'xpu' | 'cpu' | ... 

177 return {'cuda': 'cuda', 'hip': 'cuda', 'xpu': 'xpu'}.get(backend, backend) 

178 

179 

180device = get_available_device() if get_available_device() != 'hip' else 'cuda' 

181device_torch_lib = getattr(torch, device) 

182device_platform = get_available_device() 

183is_amd = device_platform == 'hip' 

184is_nvidia = device_platform == 'cuda' 

185is_nvidia_hopper = is_nvidia and ( 

186 'NVIDIA H' in torch.cuda.get_device_name(0) or torch.cuda.get_device_capability()[0] >= 9 

187) 

188 

189is_tf32_supported = is_nvidia and torch.cuda.get_device_capability(0)[0] >= 8 

190is_tma_supported = ( 

191 (is_nvidia and torch.cuda.get_device_capability(0)[0] >= 9) 

192 and os.environ.get('FLA_NO_USE_TMA', '0') != '1' 

193 and ( 

194 hasattr(triton.language, '_experimental_make_tensor_descriptor') 

195 or hasattr(triton.language, 'make_tensor_descriptor') 

196 ) 

197) 

198 

199if is_nvidia and not is_tf32_supported: 

200 # Make old card happy, since triton will use tf32 by default. 

201 # This is a workaround for old nvidia card. 

202 os.environ['TRITON_F32_DEFAULT'] = 'ieee' 

203 

204 

205@lru_cache(maxsize=None) 

206def check_pytorch_version(version_s: str = '2.4') -> bool: 

207 return version.parse(torch.__version__) >= version.parse(version_s) 

208 

209 

210if check_pytorch_version('2.4'): 

211 device = 'cuda' if device == 'cpu' else device 

212 autocast_custom_fwd = functools.partial(torch.amp.custom_fwd, device_type=device) 

213 autocast_custom_bwd = functools.partial(torch.amp.custom_bwd, device_type=device) 

214 

215 def custom_device_ctx(index: int): 

216 return device_torch_lib.device(index) 

217else: 

218 if device != 'cuda': 

219 raise AssertionError('Only cuda device is supported for PyTorch version < 2.4.0.') 

220 autocast_custom_fwd = device_torch_lib.amp.custom_fwd 

221 autocast_custom_bwd = device_torch_lib.amp.custom_bwd 

222 

223 def custom_device_ctx(index: int): 

224 return torch.cuda.device(index) 

225 

226 

227def input_guard(fn: Callable[..., torch.Tensor]) -> Callable[..., torch.Tensor]: 

228 """ 

229 A decorator to make sure all input tensors are contiguous and set the device based on input tensors. 

230 """ 

231 

232 @functools.wraps(fn) 

233 def wrapper(*args, **kwargs): 

234 contiguous_args = (i if not isinstance(i, torch.Tensor) else i.contiguous() for i in args) 

235 contiguous_kwargs = {k: (v if not isinstance(v, torch.Tensor) else v.contiguous()) for k, v in kwargs.items()} 

236 

237 tensor = None 

238 for arg in args: 

239 if isinstance(arg, torch.Tensor): 

240 tensor = arg 

241 break 

242 if tensor is None: 

243 for value in kwargs.values(): 

244 if isinstance(value, torch.Tensor): 

245 tensor = value 

246 break 

247 

248 if tensor is not None: 

249 ctx = custom_device_ctx(tensor.device.index) 

250 else: 

251 ctx = contextlib.nullcontext() 

252 

253 with ctx: 

254 return fn(*contiguous_args, **contiguous_kwargs) 

255 

256 return wrapper 

257 

258 

259def _cpu_device_warning(): 

260 warnings.warn(('Triton is not supported on current platform, roll back to CPU.'), stacklevel=1) 

261 

262 

263@tensor_cache 

264def prepare_chunk_offsets(cu_seqlens: torch.LongTensor, chunk_size: int) -> torch.LongTensor: 

265 return torch.cat([cu_seqlens.new_tensor([0]), triton.cdiv(prepare_lens(cu_seqlens), chunk_size)]).cumsum(-1) 

266 

267 

268if os.environ.get('FLA_USE_FAST_OPS', '0') == '1': 

269 exp = tldevice.fast_expf 

270 exp2 = tldevice.exp2 

271 log = tldevice.fast_logf 

272 log2 = tldevice.fast_log2f 

273else: 

274 exp = tl.exp 

275 exp2 = tl.math.exp2 

276 log = tl.log 

277 log2 = tl.log2 

278 

279 

280def get_all_max_shared_mem(): 

281 try: 

282 return [ 

283 triton.runtime.driver.active.utils.get_device_properties(i)['max_shared_mem'] 

284 for i in range(device_torch_lib.device_count()) 

285 ] 

286 except Exception: 

287 _cpu_device_warning() 

288 return [-1] 

289 

290 

291class Backend(Enum): 

292 ADA = 101376 # RTX 4090 

293 AMPERE = 166912 # A100 

294 HOPPER = 232448 # H100 

295 DEFAULT = 102400 # Default 

296 

297 @classmethod 

298 def get_shared_memory(cls, arch: str) -> int: 

299 try: 

300 return cls[arch.upper()].value 

301 except KeyError: 

302 return cls.DEFAULT.value 

303 

304 

305@lru_cache(maxsize=None) 

306def check_shared_mem(arch: str = "none", tensor_idx: int = 0) -> bool: 

307 try: 

308 device_shared_mem_list = get_all_max_shared_mem() 

309 max_shared_memory = device_shared_mem_list[tensor_idx] 

310 return max_shared_memory >= Backend.get_shared_memory(arch) 

311 except Exception: 

312 return False 

313 

314 

315def get_autotune_config( 

316 multibuffer_list: tuple = (False,), 

317 unit_flag_list: tuple = (False,), 

318 limit_auto_multi_buffer_only_for_local_buffer_list: tuple = (False,), 

319 limit_auto_multi_buffer_of_local_buffer_list: tuple = ("no-l0c",), 

320 set_workspace_multibuffer_list: tuple = (2, 4), 

321 enable_hivm_auto_cv_balance_list: tuple = (True,), 

322 tile_mix_vector_loop_num_list: tuple = (2, 4), 

323 tile_mix_cube_loop_num_list: tuple = (2, 4), 

324): 

325 configs = [] 

326 for ( 

327 multibuffer, 

328 unit_flag, 

329 limit_auto_multi_buffer_only_for_local_buffer, 

330 limit_auto_multi_buffer_of_local_buffer, 

331 ) in itertools.product( 

332 list(multibuffer_list), 

333 list(unit_flag_list), 

334 list(limit_auto_multi_buffer_only_for_local_buffer_list), 

335 list(limit_auto_multi_buffer_of_local_buffer_list), 

336 ): 

337 base_config_dict = { 

338 'multibuffer': multibuffer, 

339 'unit_flag': unit_flag, 

340 'limit_auto_multi_buffer_only_for_local_buffer': limit_auto_multi_buffer_only_for_local_buffer, 

341 'limit_auto_multi_buffer_of_local_buffer': limit_auto_multi_buffer_of_local_buffer, 

342 } 

343 

344 if limit_auto_multi_buffer_only_for_local_buffer: 

345 configs.append(triton.Config(base_config_dict)) 

346 else: 

347 for ( 

348 set_workspace_multibuffer, 

349 enable_hivm_auto_cv_balance, 

350 tile_mix_vector_loop, 

351 tile_mix_cube_loop, 

352 ) in itertools.product( 

353 list(set_workspace_multibuffer_list), 

354 list(enable_hivm_auto_cv_balance_list), 

355 list(tile_mix_vector_loop_num_list), 

356 list(tile_mix_cube_loop_num_list), 

357 ): 

358 full_config_dict = base_config_dict.copy() 

359 full_config_dict.update( 

360 { 

361 'set_workspace_multibuffer': set_workspace_multibuffer, 

362 'enable_hivm_auto_cv_balance': enable_hivm_auto_cv_balance, 

363 'tile_mix_vector_loop': tile_mix_vector_loop, 

364 'tile_mix_cube_loop': tile_mix_cube_loop, 

365 } 

366 ) 

367 configs.append(triton.Config(full_config_dict)) 

368 return configs 

369 

370 

371def get_npu_properties(): 

372 return driver.active.utils.get_device_properties(torch.npu.current_device()) 

373 

374 

375@functools.cache 

376def get_vector_num() -> int: 

377 import torch_npu 

378 

379 current_device = torch_npu.npu.current_device() 

380 properties = driver.active.utils.get_device_properties(current_device) 

381 return properties["num_vectorcore"] 

382 

383 

384@lru_cache 

385def is_arch35(): 

386 try: 

387 import torch_npu 

388 

389 return "Ascend910_95" in torch_npu.npu.get_device_name() or "Ascend950" in torch_npu.npu.get_device_name() 

390 except Exception: 

391 return False