Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/ut/src/asys/analyze/asys_analyze.py: 91%

361 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-19 17:46 +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 os 

20import shlex 

21import stat 

22import time 

23import sys 

24import struct 

25 

26from analyze.coredump_analyze import CoreDump 

27from common import log_error, log_warning, log_info, log_debug 

28from common import FileOperate as f 

29from common.cmd_run import check_command, real_time_output 

30from common.task_common import get_target_cnt 

31from common.const import DSMI_UB_PORT_NUM, DL_PORT_RX_VL_NUM, STATS_ITEM_NUM, UBQOS_MAX_SL_NUM 

32from common.const import UB_ENTIRE_STATUS_MAP, UB_PORT_STATUS_MAP, BALANCE_ALGORITHM_MAP 

33from collect.coretrace import ParseCoreTrace 

34from collect.trace import ParseTrace 

35from collect.stackcore import ParseStackCore 

36from collect import AsysCollect 

37from params import ParamDict 

38 

39ub_file_names = ["ubnl_dfx_statistic", "ubnl_dfx_ssu_schedule", "ubnl_dfx_config_item", 

40 "ubmem_daw", "ubtpl_acl_src", "sl_to_vl"] 

41 

42 

43class AsysAnalyze: 

44 def __init__(self): 

45 self.file = self.get_param_arg('file') 

46 self.path = self.get_param_arg('path') 

47 self.exe_file = self.get_param_arg("exe_file") 

48 self.core_file = self.get_param_arg("core_file") 

49 self.symbol = self.get_param_arg('symbol') 

50 self.symbol_path = self.get_param_arg('symbol_path') 

51 self.output = ParamDict().asys_output_timestamp_dir 

52 self.run_mode = self.get_param_arg('run_mode') 

53 self.device_id = ParamDict().get_arg('device_id', 0) 

54 

55 def clean_output(self): 

56 f.remove_dir(self.output) 

57 

58 @staticmethod 

59 def get_param_arg(mode): 

60 if mode == "symbol": 

61 return ParamDict().get_arg(mode) 

62 return ParamDict().get_arg(mode) if ParamDict().get_arg(mode) else None 

63 

64 @staticmethod 

65 def _convert_ub_port_status(bin_file_path, txt_file_path): 

66 fmt = f'I{DSMI_UB_PORT_NUM}I' 

67 try: 

68 with open(bin_file_path, 'rb') as bin_f: 

69 bin_data = bin_f.read() 

70 

71 expected_size = struct.calcsize(fmt) 

72 if len(bin_data) < expected_size: 

73 raise ValueError(f"Binary expected {expected_size} bytes, actual {len(bin_data)} bytes") 

74 

75 unpacked_data = struct.unpack(fmt, bin_data[:expected_size]) 

76 link_status = unpacked_data[0] 

77 port_status = unpacked_data[1: 1 + DSMI_UB_PORT_NUM] 

78 

79 with open(txt_file_path, 'w', encoding='utf-8') as txt_f: 

80 txt_f.write("=== DSMI UB Port Status Data ===\n\n") 

81 txt_f.write("1. Overall UB Link Status:\n") 

82 ub_link_desc = UB_ENTIRE_STATUS_MAP.get(link_status, f"Unknown status (Value: {link_status})") 

83 txt_f.write(f" Status Value: {link_status} -> {ub_link_desc}\n\n") 

84 txt_f.write("2. Status of Each UB Port (Total 36 ports):\n") 

85 txt_f.write(" Port No | Status Val | Status Description\n") 

86 txt_f.write(" --------|------------|-------------------\n") 

87 for port_idx in range(DSMI_UB_PORT_NUM): 

88 status_val = port_status[port_idx] 

89 status_desc = UB_PORT_STATUS_MAP.get(status_val, f"Unknown status (Value: {status_val})") 

90 txt_f.write(f" {port_idx:7d} | {status_val:10d} | {status_desc}\n") 

91 

92 log_info(f"Conversion successful! {bin_file_path} has been converted to text file {txt_file_path}") 

93 

94 except FileNotFoundError: 

95 log_warning(f"Error: {bin_file_path} not found") 

96 except (struct.error, ValueError) as e: 

97 log_error(f"Parse error: port_status {e}") 

98 except Exception as e: 

99 log_error(f"Unexpected error: port_status {e}") 

100 

101 @staticmethod 

102 def _convert_ub_port_perf_test(bin_file_path, txt_file_path): 

103 fmt = f"4I{DL_PORT_RX_VL_NUM}I{DL_PORT_RX_VL_NUM}I28I4I{DL_PORT_RX_VL_NUM}I{DL_PORT_RX_VL_NUM}I28I" 

104 expected_size = struct.calcsize(fmt) 

105 

106 try: 

107 with open(bin_file_path, 'rb') as bin_f: 

108 d = struct.unpack(fmt, bin_f.read()) 

109 if len(d) * 4 < expected_size: 

110 raise ValueError(f"Binary expected {expected_size} bytes, actual {len(d)*4} bytes") 

111 

112 p, s = 0, DL_PORT_RX_VL_NUM 

113 rx_cnt = (d[p + 1] << 32) | d[p] 

114 p += 2 

115 rx_max = (d[p + 1] << 32) | d[p] 

116 p += 2 

117 rx_vl_cnt, rx_vl_max = d[p: p + s], d[p + s: p + 2 * s] 

118 p += 2 * s 

119 p += 28 # skip rsv1 

120 tx_cnt = (d[p + 1] << 32) | d[p] 

121 p += 2 

122 tx_max = (d[p + 1] << 32) | d[p] 

123 p += 2 

124 tx_vl_cnt, tx_vl_max = d[p: p + s], d[p + s: p + 2 * s] 

125 

126 with open(txt_file_path, 'w', encoding='utf-8') as txt_f: 

127 txt_f.write("=== MAMI Port Performance Test Counter ===\n") 

128 txt_f.write(f"RX Total: 0x{rx_cnt:016X} ({rx_cnt}) | RX Max: 0x{rx_max:016X} ({rx_max})\n") 

129 txt_f.write(f"TX Total: 0x{tx_cnt:016X} ({tx_cnt}) | TX Max: 0x{tx_max:016X} ({tx_max})\n\n") 

130 txt_f.write(f"{'VL':<4}|{'RX Cnt':<20}|{'RX Max':<20}|{'TX Cnt':<20}|{'TX Max':<20}\n{'-'*90}\n") 

131 for i in range(s): 

132 txt_f.write(f"{i:<4}|{rx_vl_cnt[i]:<20}|{rx_vl_max[i]:<20}|" 

133 f"{tx_vl_cnt[i]:<20}|{tx_vl_max[i]:<20}\n") 

134 log_info(f"Conversion successful! {bin_file_path} has been converted to text file {txt_file_path}") 

135 

136 except FileNotFoundError: 

137 log_warning(f"Error: {bin_file_path} not found") 

138 except (struct.error, ValueError) as e: 

139 log_error(f"Parse error: port_perf_test {e}") 

140 except Exception as e: 

141 log_error(f"Unexpected error: port_perf_test {e}") 

142 

143 @staticmethod 

144 def _convert_ub_ubnl_dfx(bin_file_path, txt_file_path, dfx_type): 

145 item_fmt = "64BQ" 

146 struct_fmt = f"I{item_fmt * STATS_ITEM_NUM}" 

147 expected_size = struct.calcsize(struct_fmt) 

148 try: 

149 with open(bin_file_path, "rb") as bin_f: 

150 bin_data = bin_f.read() 

151 

152 if len(bin_data) < expected_size: 

153 raise ValueError(f"Binary expected {expected_size} bytes, actual {len(bin_data)} bytes") 

154 

155 unpacked = struct.unpack(struct_fmt, bin_data[:expected_size]) 

156 ptr = 0 

157 count = unpacked[ptr] 

158 ptr += 1 

159 

160 stats_items = [] 

161 for _ in range(count): 

162 # 提取64个char的原始字节 

163 name_raw = bytes(unpacked[ptr: ptr + 64]) 

164 ptr += 64 

165 value = unpacked[ptr] 

166 ptr += 1 

167 

168 name = name_raw.split(b'\x00')[0].decode("utf-8", errors="replace") 

169 name = name.strip() or "Unnamed_Stat" 

170 stats_items.append((name, value)) 

171 

172 with open(txt_file_path, "w", encoding="utf-8") as txt_f: 

173 txt_f.write(f"=== MAMI {dfx_type} Data (UBNL DFX) ===\n") 

174 txt_f.write(f"Reported Count (from struct): {count}\n") 

175 txt_f.write("-" * 90 + "\n") 

176 txt_f.write(f"{'Index':<6} | {'Stats Name':<40} | {'64-bit Value':<20}\n") 

177 txt_f.write(f"{'------':<6} | {'----------------------------------------':<40} | " 

178 f"{'--------------------':<20}\n") 

179 

180 for idx, (name, value) in enumerate(stats_items, 1): 

181 txt_f.write(f"{idx:<6} | {name:<40} | {value:<20}\n") 

182 

183 log_info(f"Conversion successful! {bin_file_path} has been converted to text file {txt_file_path}") 

184 

185 except FileNotFoundError: 

186 log_warning(f"Error: {bin_file_path} not found") 

187 except (struct.error, ValueError) as e: 

188 log_error(f"Parse error: ubnl_dfx {dfx_type} {e}") 

189 except Exception as e: 

190 log_error(f"Unexpected error: ubnl_dfx {dfx_type} {e}") 

191 

192 @staticmethod 

193 def _convert_ub_ubmem_daw(bin_file_path, txt_file_path): 

194 fmt = '4B' 

195 try: 

196 with open(bin_file_path, 'rb') as bin_f: 

197 bin_data = bin_f.read() 

198 

199 expected_size = struct.calcsize(fmt) 

200 if len(bin_data) < expected_size: 

201 raise ValueError(f"Binary expected {expected_size} bytes, actual {len(bin_data)} bytes") 

202 

203 unpacked_data = struct.unpack(fmt, bin_data[:expected_size]) 

204 

205 template_id = unpacked_data[0] 

206 balance_algorithm = unpacked_data[1] 

207 balance_start_bit = unpacked_data[2] 

208 reserved = unpacked_data[3] 

209 

210 algorithm_desc = BALANCE_ALGORITHM_MAP.get(balance_algorithm, 

211 f"Unknown algorithm (value: {balance_algorithm})") 

212 

213 with open(txt_file_path, 'w', encoding='utf-8') as txt_f: 

214 txt_f.write("=== MAMI Dynamic Address Window (DAW) Table Properties ===\n\n") 

215 txt_f.write("DAW Table Configuration:\n") 

216 txt_f.write("--------------------------------------------------------\n") 

217 txt_f.write(f"Template ID: {template_id} (Defined by BIOS, used by control plane)\n") 

218 txt_f.write(f"Balance Algorithm: {balance_algorithm} -> {algorithm_desc}\n") 

219 txt_f.write(f"Balance Start Bit: {balance_start_bit} (Lowest address bit for hash)\n") 

220 txt_f.write(f"Reserved Field: {reserved} (For struct alignment)\n") 

221 

222 log_info(f"Conversion successful! {bin_file_path} has been converted to text file {txt_file_path}") 

223 

224 except FileNotFoundError: 

225 log_warning(f"Error: {bin_file_path} not found") 

226 except (struct.error, ValueError) as e: 

227 log_error(f"Parse error: ubmem_daw {e}") 

228 except Exception as e: 

229 log_error(f"Unexpected error: ubmem_daw {e}") 

230 

231 @staticmethod 

232 def _convert_ub_ubtpl_acl_src(bin_file_path, txt_file_path): 

233 head_fmt = "HHI8B" 

234 head_size = struct.calcsize(head_fmt) 

235 eid_fmt = "B3B4I" 

236 struct_fmt = f"IH2B{eid_fmt}IBI12B" 

237 struct_size = struct.calcsize(struct_fmt) 

238 try: 

239 with open(bin_file_path, 'rb') as bin_f: 

240 bin_data = bin_f.read() 

241 if len(bin_data) < head_size: 

242 raise ValueError(f"Binary too short! expected ≥{head_size}B, act {len(bin_data)}B") 

243 

244 # 解析固定头部+位段 

245 hdr = struct.unpack(head_fmt, bin_data[:head_size]) 

246 num, flag_rsv, end_idx = hdr[0], hdr[1], hdr[2] 

247 more_flag, rsv = flag_rsv & 0x01, (flag_rsv >> 1) & 0x7FFF 

248 body = bin_data[head_size:] 

249 

250 expected_size = num * struct_size + head_size 

251 if len(bin_data) < expected_size: 

252 raise ValueError(f"Binary expected {expected_size} bytes, actual {len(bin_data)} bytes") 

253 

254 acl_list = [] 

255 for i in range(num): 

256 acl = struct.unpack(struct_fmt, body[i * struct_size: (i + 1) * struct_size]) 

257 # 解析mamiEid:compressedFlag(acl[4]) + union(acl[8:12]) 

258 eid_flag = acl[4] 

259 if eid_flag == 0: # 128位非压缩EID,4个uint32_t拼接 

260 eid_hex = ''.join([f"{x:08X}" for x in acl[8:12]]).upper() 

261 else: # 20位压缩EID,提取低20位 

262 eid_20bit = acl[8] & 0x000FFFFF 

263 eid_hex = f"{eid_20bit:05X}".upper() 

264 # 提取aclGrpId低24位,整理核心字段 

265 acl_grp_id = acl[14] & 0x00FFFFFF 

266 acl_list.append((acl[0], acl[1], eid_flag, eid_hex, acl[12], acl[13], acl_grp_id)) 

267 

268 with open(txt_file_path, 'w', encoding='utf-8') as txt_f: 

269 txt_f.write("=== UBTPL Source ACL Config (Support 128/20bit EID) ===\n") 

270 txt_f.write(f"Return Count: {num} | More Flag: {more_flag} (0=No/1=Yes)\n") 

271 txt_f.write(f"End Index: 0x{end_idx:08X} ({end_idx})\n") 

272 txt_f.write(f"{'-'*130}\n") 

273 txt_f.write(f"{'Idx':<4}|{'PlaneId':<10}|{'UEIdx':<8}|{'EidFlag':<8}|{'EID':<32}|" 

274 f"{'TransType':<10}|{'AclType':<8}|{'AclGrpId':<10}\n") 

275 txt_f.write(f"{'-'*4}|{'-'*10}|{'-'*8}|{'-'*8}|{'-'*32}|{'-'*10}|{'-'*8}|{'-'*10}\n") 

276 for idx, (p, u, c, e, t, a, g) in enumerate(acl_list): 

277 txt_f.write(f"{idx:<4}|{p:<10}|{u:<8}|{c:<8}|{e:<32}|{t:<10}|{a:<8}|{g:<10}\n") 

278 

279 log_info(f"Conversion successful! {bin_file_path} has been converted to text file {txt_file_path}") 

280 

281 except FileNotFoundError: 

282 log_warning(f"Error: {bin_file_path} not found") 

283 except (struct.error, ValueError) as e: 

284 log_error(f"Parse error: ubtpl_acl_src {e}") 

285 except Exception as e: 

286 log_error(f"Unexpected error: ubtpl_acl_src {e}") 

287 

288 @staticmethod 

289 def _convert_ub_sl_to_vl(bin_file_path, txt_file_path): 

290 item_fmt = "2H" 

291 struct_fmt = f"2I{UBQOS_MAX_SL_NUM * 2}H" 

292 expected_size = struct.calcsize(struct_fmt) 

293 

294 try: 

295 with open(bin_file_path, 'rb') as bin_f: 

296 bin_data = bin_f.read() 

297 if len(bin_data) < expected_size: 

298 raise ValueError(f"Binary expected {expected_size} bytes, actual {len(bin_data)} bytes") 

299 

300 # 解包数据并提取核心字段 

301 d = struct.unpack(struct_fmt, bin_data[:expected_size]) 

302 plane_id, num = d[0], d[1] 

303 # 校验有效配置数范围,非法值自动修正 

304 num = max(0, min(num, UBQOS_MAX_SL_NUM)) 

305 # 提取SL-VL配置,按索引分组 

306 sl2vl = [(d[2 + 2 * i], d[3 + 2 * i]) for i in range(UBQOS_MAX_SL_NUM)] 

307 

308 with open(txt_file_path, 'w', encoding='utf-8') as txt_f: 

309 txt_f.write("=== UBQOS SL to VL Mapping Configuration ===\n") 

310 txt_f.write(f"Plane ID: {plane_id} | Valid Config Num: {num} (Max: {UBQOS_MAX_SL_NUM})\n") 

311 txt_f.write(f"Struct Total Size: {expected_size} bytes\n{'-'*60}\n") 

312 txt_f.write(f"{'Idx':<6}|{'SL(0-15)':<10}|{'VL(0-15)':<10}|{'Status':<10}\n") 

313 txt_f.write(f"{'-'*6}|{'-'*10}|{'-'*10}|{'-'*10}\n") 

314 for i, (sl, vl) in enumerate(sl2vl): 

315 status = "Valid" if i < num else "Reserved" 

316 txt_f.write(f"{i:<6}|{sl:<10}|{vl:<10}|{status:<10}\n") 

317 log_info(f"Conversion successful! {bin_file_path} has been converted to text file {txt_file_path}") 

318 

319 except FileNotFoundError: 

320 log_warning(f"Error: {bin_file_path} not found") 

321 except (struct.error, ValueError) as e: 

322 log_error(f"Parse error: sl_to_vl {e}") 

323 except Exception as e: 

324 log_error(f"Unexpected error: sl_to_vl {e}") 

325 

326 def write_res_file(self, file_name, file_content): 

327 try: 

328 flags = os.O_WRONLY | os.O_CREAT 

329 modes = stat.S_IWUSR | stat.S_IRUSR 

330 with os.fdopen(os.open(f"{self.output}/{file_name}", flags, modes), 'w') as fw: 

331 fw.write(file_content) 

332 except Exception as e: 

333 log_error(e) 

334 

335 def run(self): 

336 if f.check_exists(self.path) and f.check_exists(self.output): 

337 if os.path.relpath(self.path, self.output).endswith(".."): 

338 self.clean_output() 

339 log_error('The output directory cannot be the same as the "path" directory or its subdirectories.') 

340 return False 

341 mode_function = { 

342 "trace": self.__atrace_analyze, 

343 "stackcore": self.__atrace_analyze, 

344 "coretrace": self.__atrace_analyze, 

345 "coredump": self.__core_dump_analyze, 

346 "aicore_error": self.__aicore_error_analyze, 

347 "ub": self.__ub_analyze 

348 } 

349 func = mode_function.get(self.run_mode) 

350 return func() 

351 

352 def __copy_dir(self): 

353 if self.run_mode == "trace": 

354 return f.copy_dir(self.path, self.output) 

355 # stackcore, coretrace 

356 for root, _, files in os.walk(self.path): 

357 for file in files: 

358 if self.run_mode in {"stackcore", "coretrace"} and not file.startswith(self.run_mode): 

359 continue 

360 root_path = os.path.relpath(root, self.path) 

361 if not f.copy_file_to_dir(os.path.join(root, file), os.path.join(self.output, root_path)): 

362 return False 

363 return True 

364 

365 def __atrace_analyze(self): 

366 """ 

367 parse the trace file. If the file exists, parse the file. If the directory exists, parse the directory. 

368 """ 

369 if self.run_mode == "trace": 

370 parse_struct = ParseTrace(True) 

371 elif self.run_mode == "stackcore": 

372 parse_struct = ParseStackCore(self.symbol_path, self.file) 

373 if not self.symbol_path: 

374 log_warning("'--symbol_path' is not set, the default path will be used to analyze.") 

375 elif self.run_mode == "coretrace": 

376 parse_struct = ParseCoreTrace(self.symbol_path, self.file) 

377 if not self.symbol_path: 

378 log_warning("'--symbol_path' is not set, the default path will be used to analyze.") 

379 else: 

380 return False 

381 

382 if self.file: 

383 f.copy_file_to_dir(self.file, self.output) 

384 log_info(f"Copy source file {self.file} into {self.output}") 

385 return parse_struct.start_parse_file(os.path.join(self.output, os.path.basename(self.file))) 

386 elif self.path: 

387 self.path = os.path.abspath(self.path) 

388 self.output = os.path.join(self.output, self.path.split(os.sep)[-1]) 

389 copy_res = self.__copy_dir() 

390 if not copy_res: 

391 return False 

392 count = get_target_cnt(self.output) 

393 return parse_struct.run(self.output, count=count) 

394 else: 

395 log_error("Analyze requires either the --file or --path argument") 

396 return False 

397 

398 def __core_dump_analyze(self): 

399 stack_txt = "[process]\n" 

400 if not check_command("gdb"): 

401 log_error('Gdb does not exist, install gdb before using it.') 

402 return False 

403 if not self.exe_file: 

404 log_error("The --exe_file parameter must exist for analyze coredump.") 

405 return False 

406 if not self.core_file: 

407 log_error("The --core_file parameter must exist for analyze coredump.") 

408 return False 

409 core_dump = CoreDump(self.exe_file, self.core_file, self.symbol, self.output) 

410 stack_txt, pid = core_dump.start_gdb(stack_txt) 

411 if pid == 0: 

412 return False 

413 file_name = f"stackcore_{os.path.basename(self.exe_file)}_{pid}_{int(round(time.time() * 1000))}.txt" 

414 self.write_res_file(file_name, stack_txt) 

415 return True 

416 

417 def __aicore_error_analyze(self): 

418 output_path = os.path.dirname(self.output) 

419 msaicerr_path = ParamDict().tools_path.parents[1].joinpath("msaicerr", "msaicerr.py") 

420 log_debug(f"Start load msaicerr tools path: {msaicerr_path}") 

421 if not os.path.exists(msaicerr_path): 

422 log_error('The path of the msaicerr tool cannot be found, please install the whole package.') 

423 return False 

424 if self.path: 

425 log_debug(f"msaicerr analyze path {self.path}") 

426 cmd = (f"{sys.executable} {msaicerr_path} -p {shlex.quote(self.path)} " 

427 f"-dev {self.device_id} -out {shlex.quote(output_path)}") 

428 else: 

429 asys_collector = AsysCollect() 

430 task_res = AsysCollect().run() 

431 log_debug(f"Asys collect path {asys_collector.output_root_path} res {task_res}") 

432 if not task_res: 

433 log_error(f"Asys collect log failed") 

434 return False 

435 cmd = (f"{sys.executable} {msaicerr_path} -p {shlex.quote(str(asys_collector.output_root_path))} " 

436 f"-dev {self.device_id} -out {shlex.quote(output_path)}") 

437 log_debug(f"Start run: {cmd}") 

438 res = real_time_output(cmd) 

439 self.clean_output() 

440 return res 

441 

442 def __ub_analyze(self): 

443 if self.path: 

444 self.path = os.path.abspath(self.path) 

445 else: 

446 log_error("Please enter the path to the UB data collection file.") 

447 return True 

448 for ub_file_name in ub_file_names: 

449 func_name = "_convert_ub_" + ub_file_name 

450 bin_file_name = ub_file_name + ".bin" 

451 txt_file_name = ub_file_name + ".txt" 

452 bin_file_path = os.path.join(self.path, bin_file_name) 

453 txt_file_path = os.path.join(self.output, txt_file_name) 

454 func = getattr(self, func_name, None) 

455 if func: 

456 func(bin_file_path, txt_file_path) 

457 return True 

458 

459 def _convert_ub_ubnl_dfx_statistic(self, bin_file_path, txt_file_path): 

460 self._convert_ub_ubnl_dfx(bin_file_path, txt_file_path, "Statistic") 

461 

462 def _convert_ub_ubnl_dfx_ssu_schedule(self, bin_file_path, txt_file_path): 

463 self._convert_ub_ubnl_dfx(bin_file_path, txt_file_path, "Ssu Schedule") 

464 

465 def _convert_ub_ubnl_dfx_config_item(self, bin_file_path, txt_file_path): 

466 self._convert_ub_ubnl_dfx(bin_file_path, txt_file_path, "Config Item")