Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/ut/src/asys/collect/ops/ops_collect.py: 93%

180 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-08-21 15:37 +0800

1#!/usr/bin/env python3 

2# -*- coding: utf-8 -*- 

3# ---------------------------------------------------------------------------- 

4# Copyright (c) 2025 Huawei Technologies Co., Ltd. 

5# 

6# Licensed under the Apache License, Version 2.0 (the "License"); 

7# you may not use this file except in compliance with the License. 

8# You may obtain a copy of the License at 

9# 

10# http://www.apache.org/licenses/LICENSE-2.0 

11# 

12# Unless required by applicable law or agreed to in writing, software 

13# distributed under the License is distributed on an "AS IS" BASIS, 

14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

15# See the License for the specific language governing permissions and 

16# limitations under the License. 

17# ---------------------------------------------------------------------------- 

18 

19import json 

20import os.path 

21import re 

22 

23from params import ParamDict 

24from common import consts 

25from common import log_debug, log_warning 

26from common import FileOperate as f 

27from common.file_operate import COPY_MODE, MOVE_MODE 

28from drv import EnvVarName 

29 

30__all__ = ["collect_ops"] 

31 

32 

33def get_fault_kernel_name(output_root_path): 

34 """ 

35 Obtains fault_kernel_name from plog. 

36 """ 

37 error_msg = ["Aicore kernel execute failed|AI Core kernel execution failed", "fftsplus task execute failed"] 

38 run_plog = os.path.join(output_root_path, "dfx", "log", "host", "cann", "run", "plog") 

39 debug_plog = os.path.join(output_root_path, "dfx", "log", "host", "cann", "debug", "plog") 

40 plog_files = [run_plog, debug_plog] 

41 for plog in plog_files: 

42 if not f.check_dir(plog): 

43 continue 

44 plog_lines = [] 

45 for msg in error_msg: 

46 cmd_ret = os.popen(f"grep '{msg}' -inrE {plog}") 

47 plog_lines += cmd_ret.readlines() 

48 cmd_ret.close() 

49 if len(plog_lines) == 0: 

50 continue 

51 

52 static_regexp = r" stream_id=\d+,.*?task_id=\d+,.*?fault kernel_name=.*?,.*?" \ 

53 r" fault kernel info ext=(.*?)," 

54 dynamic_regexp = r" stream_id=\d+,.*?task_id=\d+,.*?fault kernel_name=(.*?)," 

55 

56 for regexp in [static_regexp, dynamic_regexp]: 

57 kernel_name_ret = re.findall(regexp, plog_lines[0]) 

58 if not kernel_name_ret or kernel_name_ret[0] == 'none': 

59 continue 

60 kernel_name = kernel_name_ret[0] 

61 return kernel_name.replace("_mix_aic", "").replace("_mix_aiv", "") 

62 return None 

63 

64 

65def get_all_kernel_name_from_file(file_path): 

66 """ 

67 read JSON file and check whether they contain kernel_name. 

68 """ 

69 all_kernel_name = [] 

70 try: 

71 with open(file_path, 'r') as json_file: 

72 dict_obj = json.load(json_file) 

73 all_kernel_name.append(dict_obj.get("binFileName")) 

74 all_kernel_name.append(dict_obj.get("kernelName")) 

75 all_kernel_name += [kernel.get("kernelName") for kernel in dict_obj.get("kernelList", [])] 

76 except Exception as e: 

77 log_debug(f"Failed to load the '{file_path}', {e}") 

78 return all_kernel_name 

79 

80 # remove its 'None' elements 

81 return list(filter(None, all_kernel_name)) 

82 

83 

84def get_fault_kernel_name_files(collect_path, kernel_name): 

85 """ 

86 Obtain the .o.json file corresponding to fault_kernel_name. 

87 """ 

88 collect_files = [] 

89 if not kernel_name: 

90 return collect_files 

91 opp_path = EnvVarName().opp_path 

92 for path, _, files in os.walk(collect_path): 

93 for file in files: 

94 file_path = os.path.join(path, file) 

95 # ASCEND_OPP_PATH only needs to read files in the '/kernel/'. 

96 if not file.endswith(".json") or (collect_path == opp_path and "kernel" not in path.split("/")): 

97 continue 

98 # read all JSON files and check whether they contain kernel_name. 

99 if kernel_name not in get_all_kernel_name_from_file(file_path): 

100 continue 

101 # collect the .json file and .o file that contain kernel_name. 

102 collect_files.append(file_path) 

103 o_file_path = os.path.join(path, file.replace(".json", ".o")) 

104 if os.path.isfile(o_file_path): 

105 collect_files.append(o_file_path) 

106 

107 return collect_files 

108 

109 

110def collect_op_files(ops_res, target_dir, mode=COPY_MODE): 

111 """ 

112 Collect the .o.json file corresponding to fault_kernel_name. 

113 """ 

114 ret = True 

115 for file_path in ops_res: 

116 op_file_ret = f.collect_file_to_dir(file_path, target_dir, mode) 

117 ret = ret and op_file_ret 

118 return ret 

119 

120 

121def collect_ops_from_dump(output_root_path): 

122 """ 

123 Collect ops files from the dump directory. 

124 """ 

125 target_dir = os.path.join(output_root_path, "dfx", "ops") 

126 dump_path = os.path.join(output_root_path, "dfx", "data-dump") 

127 if not f.check_dir(dump_path): 

128 return False 

129 ops_files = [] 

130 for path, _, files in os.walk(dump_path): 

131 for file in files: 

132 if file.endswith(".o") or file.endswith(".json"): 

133 ops_files.append(os.path.join(path, file)) 

134 if len(ops_files) >= 3: # two .o, one .json 

135 return collect_op_files(ops_files, target_dir, MOVE_MODE) 

136 

137 return False 

138 

139 

140def collect_ops_files_env_var(output_root_path, ops_target_dir): 

141 

142 collect_path_list = [] 

143 task_dir = ParamDict().get_arg("task_dir") 

144 # ops files priority: NPU_COLLECT_PATH > ASCEND_CACHE_PATH > ASCEND_WORK_PATH > $HOME/atc_data > 

145 # ASCEND_CUSTOM_OPP_PATH > ASCEND_OPP_PATH > ./ 

146 env_var = EnvVarName() 

147 for collect_path in [task_dir, env_var.npu_collect_path, env_var.cache_path, env_var.work_path, 

148 os.path.join(env_var.home_path, "atc_data"), env_var.custom_opp_path, env_var.opp_path, 

149 env_var.current_path]: 

150 if collect_path and f.check_dir(collect_path): 

151 collect_path_list.append(collect_path) 

152 

153 kernel_name = get_fault_kernel_name(output_root_path) 

154 for path in collect_path_list: 

155 collect_files = get_fault_kernel_name_files(path, kernel_name) 

156 if collect_files: 

157 return collect_op_files(collect_files, ops_target_dir, COPY_MODE) 

158 

159 log_warning("The JSON file of the fault kernel_name is not found.") 

160 return False 

161 

162 

163def check_launch_ops(): 

164 if (ParamDict().get_command() == consts.launch_cmd) and (not ParamDict().get_ini("ops") == "1"): 

165 log_debug("ops is not set on, not collect ops files") 

166 return False 

167 return True 

168 

169 

170def collect_debug_kernel(output_root_path): 

171 ops_target_dir = os.path.join(output_root_path, "dfx", "ops") 

172 opp_path = EnvVarName().opp_path 

173 if opp_path is None: 

174 log_debug("ASCEND_OPP_PATH not set") 

175 return 

176 debug_kernel_path = os.path.join(opp_path, "debug_kernel") 

177 if debug_kernel_path and f.check_access(debug_kernel_path) and f.check_dir(debug_kernel_path): 

178 if f.list_dir(debug_kernel_path): 

179 debug_kernel_target_path = os.path.join(ops_target_dir, os.path.basename(debug_kernel_path)) 

180 if debug_kernel_target_path.startswith(debug_kernel_path): 

181 log_debug("Cannot copy debug_kernel to %s" % debug_kernel_target_path) 

182 else: 

183 f.copy_dir(debug_kernel_path, debug_kernel_target_path) 

184 

185 

186def collect_file(output_root_path): 

187 

188 ops_target_dir = os.path.join(output_root_path, "dfx", "ops") 

189 ret = False 

190 if ParamDict().get_command() == consts.launch_cmd: 

191 ops_source_dir = os.path.join( 

192 ParamDict().asys_output_timestamp_dir, "npu_collect_intermediates", "extra-info", "ops") 

193 if f.check_dir(ops_source_dir): 

194 ret = f.collect_dir(ops_source_dir, ops_target_dir, MOVE_MODE) 

195 else: 

196 ret = collect_ops_files_env_var(output_root_path, ops_target_dir) 

197 if not ret: 

198 log_warning("Ops collect failed.") 

199 

200 

201def collect_cfg_json(output_root_path, cfg_dir, json_dir, config): 

202 if not os.path.exists(json_dir): 

203 return False 

204 

205 ret = True 

206 for path, _, files in os.walk(json_dir): 

207 if "/config/" not in path: 

208 continue 

209 for file in files: 

210 if not file.endswith(".json"): 

211 continue 

212 dst_dir = os.path.join(output_root_path, "dfx", "ops", config, cfg_dir, os.path.relpath(path, json_dir)) 

213 if not os.path.exists(dst_dir): 

214 os.makedirs(dst_dir) 

215 ret = ret and f.copy_file_to_dir(os.path.join(path, file), dst_dir) 

216 return ret 

217 

218 

219def collect_opp_config(output_root_path): 

220 opp_path = EnvVarName().opp_path 

221 if opp_path is None: 

222 log_debug("ASCEND_OPP_PATH is not set.") 

223 return False 

224 

225 config_path = os.path.join(opp_path, "vendors", "config.ini") 

226 if not os.path.isfile(config_path): 

227 log_debug(f"The {config_path} is not a file.") 

228 return False 

229 try: 

230 with open(config_path, 'r') as cfg: 

231 cfg_content = cfg.read() 

232 except PermissionError: 

233 log_warning(f"The {config_path} file does not have the read permission.") 

234 return False 

235 

236 load_priority = re.search("load_priority=(.+?)\n", cfg_content) 

237 if not load_priority: 

238 log_warning(f"The {config_path} file does not contain the load_priority field.") 

239 return False 

240 load_priority = load_priority.group(1).split(",") 

241 ret = True 

242 for cfg_dir in load_priority: 

243 # remove front and back spaces 

244 _cfg_dir = cfg_dir.strip() 

245 json_dir = os.path.join(opp_path, "vendors", _cfg_dir) 

246 ret = ret and collect_cfg_json(output_root_path, _cfg_dir, json_dir, "vendor_config") 

247 

248 ret = ret and f.copy_file_to_dir(config_path, os.path.join(output_root_path, "dfx", "ops", "vendor_config")) 

249 return ret 

250 

251 

252def collect_custom_opp_config(output_root_path): 

253 custom_opp_path = EnvVarName().custom_opp_path 

254 if custom_opp_path is None: 

255 log_debug("ASCEND_CUSTOM_OPP_PATH is not set.") 

256 return False 

257 return collect_cfg_json(output_root_path, "", custom_opp_path, "custom_config") 

258 

259 

260def collect_ops(output_root_path): 

261 if not check_launch_ops(): 

262 return 

263 

264 if not collect_ops_from_dump(output_root_path): 

265 collect_file(output_root_path) 

266 collect_debug_kernel(output_root_path) 

267 collect_opp_config(output_root_path) 

268 collect_custom_opp_config(output_root_path)