Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/ut/utils/show_kernel_debug_data/show_kernel_debug_data/dump_parser.py: 95%

916 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-07-27 14:38 +0800

1#!/usr/bin/python 

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

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

4# Copyright (c) 2025 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 

13import glob 

14import json 

15import os 

16import stat 

17import struct 

18import subprocess 

19from dataclasses import dataclass, field 

20from enum import Enum, auto 

21from typing import List, Dict, Any 

22from .data_converter import decode_bfloat16 

23from .dump_logger import DUMP_PARSER_LOG 

24 

25FILE_FLAG = os.O_WRONLY | os.O_CREAT 

26FILE_MODE_640 = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP 

27 

28ONE_MEGA_BYTE = 1024 * 1024 

29 

30 

31class TimeStampId(Enum): 

32 TIME_STAMP_WRAP_FIRST = 0x000 

33 TIME_STAMP_WRAP_MC2_CTX = auto() 

34 TIME_STAMP_WRAP_WK_SPACE = auto() 

35 TIME_STAMP_WRAP_INIT_DUMP = auto() 

36 TIME_STAMP_WRAP_FFTS_ADDR = auto() 

37 TIME_STAMP_WRAP_CLEAR_WK_SPAC = auto() 

38 

39 TIME_STAMP_TPIPE = 0x030 

40 TIME_STAMP_BUFFER = auto() 

41 

42 TIME_STAMP_MATMUL_SERVER = 0x060 

43 TIME_STAMP_MATMUL_SERVER_INIT = auto() 

44 TIME_STAMP_MATMUL_SERVER_OBJ = auto() 

45 TIME_STAMP_MATMUL_MATRIX_KFC = auto() 

46 TIME_STAMP_MATMUL_CLIENT_KFC = auto() 

47 TIME_STAMP_MATMUL_WAIT_EVE = auto() 

48 TIME_STAMP_MATMUL_OBJ = auto() 

49 

50 TIME_STAMP_TILING_DATA = 0x090 

51 TIME_STAMP_TILING_DATA_STRUCT = auto() 

52 TIME_STAMP_TILING_DATA_MEMBER = auto() 

53 

54 TIME_STAMP_MAX = 0xfff 

55 

56 

57def get_enum_member_name(enum_type, value): 

58 for member in enum_type: 

59 if member.value == value: 

60 return member.name 

61 return value 

62 

63 

64@dataclass(repr=False) 

65class TLV: 

66 tag: int = 0 

67 length: int = 0 

68 value: bytes = None 

69 

70 def read(self, f): 

71 tl_fmt = self.get_tl_format() 

72 tl_size = self.get_tl_size() 

73 self.tag, self.length = struct.unpack(tl_fmt, f.read(tl_size)) 

74 self.value = f.read(self.length) 

75 

76 def write_to(self, buffer, offset): 

77 tl_fmt = self.get_tl_format() 

78 struct.pack_into(tl_fmt, buffer, offset, self.tag, self.length) 

79 value_offset = offset + self.get_tl_size() 

80 val_fmt = f'{self.length}s' 

81 struct.pack_into(val_fmt, buffer, value_offset, self.value) 

82 return self.get_tl_size() + self.length 

83 

84 def __repr__(self): 

85 return f'TLV(tag={self.tag}, length={self.length})' 

86 

87 @classmethod 

88 def get_tl_format(cls): 

89 # TLV header uses uint32_t type/length. 

90 return 'II' 

91 

92 @classmethod 

93 def get_tl_size(cls): 

94 return struct.calcsize(cls.get_tl_format()) 

95 

96 def get_size(self): 

97 return self.get_tl_size() + self.length 

98 

99 

100@dataclass 

101class DumpMessageHeader: 

102 addr: int = 0 

103 data_type: int = 0 

104 desc: int = 0 

105 buffer_id: int = 0 

106 position: int = 0 

107 reserved: int = 0 

108 

109 @classmethod 

110 def get_format(cls): 

111 return 'iiiiii' 

112 

113 @classmethod 

114 def get_size(cls): 

115 fmt = cls.get_format() 

116 return struct.calcsize(fmt) 

117 

118 def unpack(self, buffer): 

119 fmt = self.get_format() 

120 self.addr, self.data_type, self.desc, self.buffer_id, self.position, self.reserved = struct.unpack( 

121 fmt, buffer) 

122 

123 def pack(self): 

124 fmt = self.get_format() 

125 return struct.pack(fmt, self.addr, self.data_type, self.desc, self.buffer_id, self.position, self.reserved) 

126 

127 

128@dataclass 

129class ShapeInfo: 

130 dim: int = 0 

131 shape: List[Any] = field(default_factory=list) 

132 rsv: int = 0 

133 total_ele_num = 0 

134 

135 @classmethod 

136 def get_format(cls): 

137 # value format of ShapeInfo bin: dim, shape0, ..., shape7, rsv 

138 return 'iiiiiiiiii' 

139 

140 @classmethod 

141 def get_size(cls): 

142 fmt = cls.get_format() 

143 return struct.calcsize(fmt) 

144 

145 def unpack(self, buffer): 

146 fmt = self.get_format() 

147 unpacked_data = struct.unpack(fmt, buffer) 

148 self.dim = unpacked_data[0] 

149 self.total_ele_num = 1 

150 for i in range(self.dim): 

151 self.shape.append(unpacked_data[i + 1]) 

152 self.total_ele_num *= self.shape[-1] 

153 

154 def parse_from(self, tlv: TLV): 

155 self.unpack(tlv.value) 

156 

157 

158@dataclass 

159class MetaInfo: 

160 blk_dim: int = 0 

161 core_type: int = 0 

162 task_ration: int = 0 

163 rsv: int = 0 

164 content: str = '' 

165 

166 

167 @classmethod 

168 def get_format(cls): 

169 return 'HbbI' 

170 

171 @classmethod 

172 def get_size(cls): 

173 fmt = cls.get_format() 

174 return struct.calcsize(fmt) 

175 

176 def unpack(self, buffer): 

177 core_type_convert = { 

178 0: "MIX", 

179 1: "AIC", 

180 2: "VEC" 

181 } 

182 fmt = self.get_format() 

183 self.blk_dim, self.core_type, self.task_ration, self.rsv = struct.unpack(fmt, buffer) 

184 self.content = "[Meta Info] block num: {}, core type: {}, isMix: {}\n".format(self.blk_dim, 

185 core_type_convert.get(self.core_type, "Unknown"), bool(self.task_ration)) 

186 

187 def parse_from(self, tlv: TLV): 

188 self.unpack(tlv.value) 

189 

190 

191@dataclass 

192class TimeStampInfo: 

193 desc_id: int = 0 

194 rsv: int = 0 

195 sys_cycle: int = 0 

196 pc_ptr: int = 0 

197 

198 @classmethod 

199 def get_format(cls): 

200 # value format of TimeStampInfo bin:desc_id(u32), rsv(u32), sys_cycle(u64) 

201 return 'IIQQ' 

202 

203 @classmethod 

204 def get_size(cls): 

205 fmt = cls.get_format() 

206 return struct.calcsize(fmt) 

207 

208 def unpack(self, buffer): 

209 fmt = self.get_format() 

210 unpacked_data = struct.unpack(fmt, buffer) 

211 self.desc_id = unpacked_data[0] 

212 self.rsv = unpacked_data[1] 

213 self.sys_cycle = unpacked_data[2] 

214 self.pc_ptr = unpacked_data[3] 

215 

216 def parse_from(self, tlv: TLV): 

217 self.unpack(tlv.value) 

218 

219 

220@dataclass 

221class FifoTimeStampInfo: 

222 desc_id: int = 0 

223 block_idx: int = 0 

224 rsv: int = 0 

225 sys_cycle: int = 0 

226 pc_ptr: int = 0 

227 entry: int = 0 

228 resv_mem0: int = 0 

229 resv_mem1: int = 0 

230 

231 @classmethod 

232 def get_format(cls): 

233 # value format of ringbuf TimeStampTlvInfo: 

234 return 'IHHQQQII' 

235 

236 @classmethod 

237 def get_size(cls): 

238 fmt = cls.get_format() 

239 return struct.calcsize(fmt) 

240 

241 def unpack(self, buffer): 

242 fmt = self.get_format() 

243 unpacked_data = struct.unpack(fmt, buffer) 

244 self.desc_id = unpacked_data[0] 

245 self.block_idx = unpacked_data[1] 

246 self.rsv = unpacked_data[2] 

247 self.sys_cycle = unpacked_data[3] 

248 self.pc_ptr = unpacked_data[4] 

249 self.entry = unpacked_data[5] 

250 self.resv_mem0 = unpacked_data[6] 

251 self.resv_mem1 = unpacked_data[7] 

252 

253 def parse_from(self, tlv: TLV): 

254 self.unpack(tlv.value) 

255 

256 

257dtype_to_fmt = { 

258 0: 'f', # DT_FLOAT 

259 1: 'e', # DT_FLOAT16 

260 2: 'b', # DT_INT8 

261 3: 'i', # DT_INT32 

262 4: 'B', # DT_UINT8 

263 6: 'h', # DT_INT16 

264 7: 'H', # DT_UINT16 

265 8: 'I', # DT_UINT32 

266 9: 'q', # DT_UINT64 

267 10: 'Q', # DT_UINT64 

268 27: "H", # DT_BF16 

269 33: '' # DT_MAX 

270} 

271 

272dtype_to_data_type = { 

273 0: 'float32', # DT_FLOAT 

274 1: 'float16', # DT_FLOAT16 

275 2: 'int8', # DT_INT8 

276 3: 'int32', # DT_INT32 

277 4: 'uint8', # DT_UINT8 

278 6: 'int16', # DT_INT16 

279 7: 'uint16', # DT_UINT16 

280 8: 'uint32', # DT_UINT32 

281 9: 'int64', # DT_INT64 

282 10: 'uint64', # DT_UINT64 

283 27: 'bfloat16', # DT_BF16 

284 33: '' # DT_MAX 

285} 

286 

287special_data_type = { 

288 27: decode_bfloat16, # 'bfloat16' 

289} 

290 

291@dataclass(repr=False) 

292class DumpTensor: 

293 tag: int = 0 

294 length: int = 0 

295 dump_header: DumpMessageHeader = None 

296 dump_data: bytes = b'' 

297 dump_value: List[Any] = field(default_factory=list) 

298 dump_shape: List[int] = field(default_factory=list) 

299 

300 def parse_from(self, tlv): 

301 self.tag = tlv.tag 

302 self.length = tlv.length 

303 

304 head_size = DumpMessageHeader.get_size() 

305 head_buffer = tlv.value[0: head_size] 

306 self.dump_header = DumpMessageHeader() 

307 self.dump_header.unpack(head_buffer) 

308 self.dump_data = tlv.value[head_size:] 

309 self._parse_dump_data() 

310 

311 def parse_to(self): 

312 tlv = TLV() 

313 tlv.tag = self.tag 

314 tlv.length = self.length 

315 head_buffer = self.dump_header.pack() 

316 

317 tlv.value = head_buffer 

318 tlv.value += self.dump_data 

319 return tlv 

320 

321 def __repr__(self): 

322 return f'DumpTensor(tag={self.tag}, length={self.length}, dump_header={self.dump_header},\ 

323 tensor_shape={self.dump_shape}, dump_data_size={len(self.dump_data)})' 

324 

325 def _parse_dump_data(self): 

326 fmt = dtype_to_fmt.get(self.dump_header.data_type, '') 

327 if not fmt: 

328 DUMP_PARSER_LOG.debug(f'data type {self.dump_header.data_type} is not supported') 

329 return 

330 if self.dump_header.data_type in special_data_type.keys(): 

331 converter = special_data_type[self.dump_header.data_type] 

332 special_data = [converter(value[0]) for value in struct.iter_unpack(fmt, self.dump_data)] 

333 self.dump_value.extend(special_data) 

334 else: 

335 self.dump_value.extend( 

336 value[0] for value in struct.iter_unpack(fmt, self.dump_data)) 

337 

338 

339@dataclass(repr=False) 

340class FifoDumpTensor(DumpTensor): 

341 def parse_from(self, tlv): 

342 self.tag = tlv.tag 

343 self.length = tlv.length 

344 

345 head_size = struct.calcsize('IIIIHHI8III') 

346 if len(tlv.value) < head_size: 

347 raise RuntimeError('FifoDumpTensor: invalid TLV value length') 

348 

349 unpacked = struct.unpack('IIIIHHI8III', tlv.value[:head_size]) 

350 tensor_addr = unpacked[0] 

351 data_type = unpacked[1] 

352 desc = unpacked[2] 

353 buffer_id = unpacked[3] 

354 position = unpacked[4] 

355 # unpacked[5] is blockIdx, [6] is dim, [7:15] shape, [15] resv1 

356 dump_size = unpacked[16] 

357 

358 self.dump_header = DumpMessageHeader( 

359 addr=tensor_addr, 

360 data_type=data_type, 

361 desc=desc, 

362 buffer_id=buffer_id, 

363 position=position, 

364 reserved=0 

365 ) 

366 

367 data_start = head_size 

368 data_end = data_start + dump_size 

369 if data_end > len(tlv.value): 

370 raise RuntimeError('FifoDumpTensor: dump_size out of range') 

371 self.dump_data = tlv.value[data_start:data_end] 

372 self._parse_dump_data() 

373 

374 

375@dataclass(repr=False) 

376class PrintStruct: 

377 tag: int = 0 

378 length: int = 0 

379 fmt: str = '' 

380 args: List[Any] = field(default_factory=list) 

381 content: str = None 

382 

383 def parse_from(self, tlv): 

384 self.tag = tlv.tag 

385 self.length = tlv.length 

386 

387 args_start, args_end = self._read_fmt(tlv.value) # fmt 

388 self._read_args(tlv.value, args_start, args_end) # args 

389 

390 self.fmt = self.fmt.replace('%p', '0x%x') # python not support %p 

391 self.content = self.fmt % tuple(self.args) 

392 

393 def _read_fmt(self, buffer): 

394 self.fmt, fmt_offset = self._read_arg_str(buffer, 0) 

395 return (8, fmt_offset) 

396 

397 def _all_fmt_placehold(self): 

398 import re 

399 pattern = r"%[a-zA-Z]{1,2}" 

400 matches = re.findall(pattern, self.fmt) 

401 fmt_placehold_list = [] 

402 for x in matches: 

403 if not (len(x) == 3 and '%l' not in x.lower()): 

404 fmt_placehold_list.append(x) 

405 return fmt_placehold_list 

406 

407 def _read_args(self, buffer, args_start, args_end): 

408 args_plds = self._all_fmt_placehold() 

409 args_num = len(args_plds) 

410 

411 for i in range(0, args_num): 

412 offset = args_start + i * 8 

413 if offset + 8 > args_end: 

414 raise RuntimeError( 

415 f'arg {i} at [{offset}:{offset + 8}] over arg end({args_end}): \"{self.fmt}\"') 

416 pld = args_plds[i] 

417 self._read_arg(buffer, offset, pld) 

418 

419 def _read_arg(self, buffer, offset, pld): 

420 if pld == '%d' or pld == '%i': 

421 arg = self._read_arg_long(buffer, offset) 

422 elif pld == '%ld': 

423 arg = self._read_arg_long(buffer, offset) 

424 elif pld == '%f' or pld == '%F': 

425 arg = self._read_arg_float(buffer, offset) 

426 elif pld == '%lf' or pld == '%LF': 

427 arg = self._read_arg_double(buffer, offset) 

428 elif pld == '%x' or pld == '%X': 

429 arg = self._read_arg_hex(buffer, offset) 

430 elif pld == '%s': 

431 arg, _ = self._read_arg_str(buffer, offset) 

432 elif pld == '%p': 

433 arg = self._read_arg_point(buffer, offset) 

434 elif pld == '%u': 

435 arg = self._read_arg_unsigned_long(buffer, offset) 

436 else: 

437 raise RuntimeError(f'not support pld({pld}), fmt: {self.fmt}') 

438 self.args.append(arg) 

439 

440 @staticmethod 

441 def _read_arg_unsigned_long(buffer, offset): 

442 return struct.unpack('Q', buffer[offset: offset + 8])[0] 

443 

444 @staticmethod 

445 def _read_arg_long(buffer, offset): 

446 return struct.unpack('q', buffer[offset: offset + 8])[0] 

447 

448 @staticmethod 

449 def _read_arg_float(buffer, offset): 

450 is_double = False 

451 for buf_val in buffer[offset + 4: offset + 8]: 

452 if int(buf_val) != 0: 

453 is_double = True 

454 break 

455 if is_double: 

456 return struct.unpack('d', buffer[offset: offset + 8])[0] 

457 return struct.unpack('f', buffer[offset: offset + 4])[0] 

458 

459 @staticmethod 

460 def _read_arg_double(buffer, offset): 

461 return struct.unpack('d', buffer[offset: offset + 8])[0] 

462 

463 @staticmethod 

464 def _read_arg_hex(buffer, offset): 

465 return struct.unpack('Q', buffer[offset: offset + 8])[0] 

466 

467 @staticmethod 

468 def _read_arg_str(buffer, offset): 

469 relv_offset = struct.unpack('Q', buffer[offset: offset + 8])[0] 

470 abs_offset = offset + relv_offset 

471 return (PrintStruct._read_string(buffer, abs_offset), relv_offset) 

472 

473 @staticmethod 

474 def _read_arg_point(buffer, offset): 

475 return struct.unpack('P', buffer[offset: offset + 8])[0] 

476 

477 @staticmethod 

478 def _read_string(buffer: bytes, offset: int): 

479 max_length = len(buffer) 

480 if offset > max_length: 

481 raise RuntimeError( 

482 f'read str offset {offset} over max buffer length {max_length}') 

483 s: str = '' 

484 for i in range(offset, max_length): 

485 b = struct.unpack('1s', buffer[i: i + 1])[0] 

486 if b == b'\x00': 

487 return s 

488 s = s + b.decode('utf-8') 

489 return s 

490 

491 

492@dataclass(repr=False) 

493class FifoPrintStruct(PrintStruct): 

494 block_idx: int = 0 

495 resv: int = 0 

496 

497 def parse_from(self, tlv): 

498 self.tag = tlv.tag 

499 self.length = tlv.length 

500 

501 if len(tlv.value) < 16: 

502 raise RuntimeError('FifoPrintStruct: invalid TLV value length') 

503 self.block_idx, self.resv, _fmt_offset = struct.unpack('IIQ', tlv.value[:16]) 

504 

505 # Skip blockIdx/resv (8 bytes) so buffer starts at fmtOffset field. 

506 fifo_buffer = tlv.value[8:] 

507 args_start, args_end = self._read_fmt(fifo_buffer) # fmt 

508 self._read_args(fifo_buffer, args_start, args_end) # args 

509 

510 self.fmt = self.fmt.replace('%p', '0x%x') # python not support %p 

511 self.content = self.fmt % tuple(self.args) 

512 

513 

514@dataclass(repr=False) 

515class FifoSimtPrintStruct(PrintStruct): 

516 block_idx: List[int] = field(default_factory=lambda: [0, 0, 0]) 

517 thread_idx: List[int] = field(default_factory=lambda: [0, 0, 0]) 

518 resv: List[int] = field(default_factory=lambda: [0, 0, 0, 0]) 

519 

520 def parse_from(self, tlv): 

521 self.tag = tlv.tag 

522 self.length = tlv.length 

523 

524 header_size = struct.calcsize('3I3I4IQ') 

525 if len(tlv.value) < header_size: 

526 raise RuntimeError('FifoSimtPrintStruct: invalid TLV value length') 

527 

528 unpacked = struct.unpack('3I3I4IQ', tlv.value[:header_size]) 

529 self.block_idx = list(unpacked[0:3]) 

530 self.thread_idx = list(unpacked[3:6]) 

531 self.resv = list(unpacked[6:10]) 

532 

533 # Buffer starts from fmtOffset field. 

534 simt_buffer = tlv.value[40:] 

535 args_start, args_end = self._read_fmt(simt_buffer) # fmt 

536 self._read_args(simt_buffer, args_start, args_end) # args 

537 

538 self.fmt = self.fmt.replace('%p', '0x%x') # python not support %p 

539 self.content = self.fmt % tuple(self.args) 

540 

541 

542@dataclass 

543class BlockInfo: 

544 total_size: int = 0 

545 block_id: int = 0 

546 block_num: int = 0 

547 remain_size: int = 0 

548 magic_num: int = 0 

549 reserved: int = 0 

550 dump_addr: int = 0 # 8 Byte 

551 

552 @classmethod 

553 def get_format(cls): 

554 return 'iiiiiiQ' 

555 

556 @classmethod 

557 def get_size(cls): 

558 fmt = cls.get_format() 

559 return struct.calcsize(fmt) 

560 

561 def unpack(self, buffer): 

562 fmt = self.get_format() 

563 self.total_size, self.block_id, self.block_num, self.remain_size, \ 

564 self.magic_num, self.reserved, self.dump_addr = struct.unpack( 

565 fmt, buffer) 

566 

567 def pack_into(self, buffer, offset): 

568 fmt = self.get_format() 

569 struct.pack_into(fmt, buffer, offset, self.total_size, self.block_id, self.block_num, 

570 self.remain_size, self.magic_num, self.reserved, self.dump_addr) 

571 return self.get_size() 

572 

573 def is_valid(self): 

574 block_info_magic = 0x5aa5bccd 

575 return block_info_magic == self.magic_num 

576 

577 

578@dataclass 

579class FifoBlockInfo: 

580 length: int = 0 

581 core_id: int = 0 

582 block_num: int = 0 

583 remain_len: int = 0 

584 magic: int = 0 

585 flag: int = 0 

586 rsv: int = 0 

587 dump_addr: int = 0 

588 resv: List[int] = field(default_factory=list) 

589 

590 def __repr__(self): 

591 return ( 

592 f'FifoBlockInfo(length={self.length}, core_id={self.core_id}, block_num={self.block_num}, ' 

593 f'remain_len={self.remain_len}, magic=0x{self.magic:04X}, flag={self.flag}, rsv={self.rsv}, ' 

594 f'dump_addr=0x{self.dump_addr:X}, resv={self.resv})' 

595 ) 

596 

597 @classmethod 

598 def get_format(cls): 

599 return 'IIIIHHIQ6I' 

600 

601 @classmethod 

602 def get_size(cls): 

603 fmt = cls.get_format() 

604 return struct.calcsize(fmt) 

605 

606 def unpack(self, buffer): 

607 fmt = self.get_format() 

608 unpacked = struct.unpack(fmt, buffer) 

609 self.length = unpacked[0] 

610 self.core_id = unpacked[1] 

611 self.block_num = unpacked[2] 

612 self.remain_len = unpacked[3] 

613 self.magic = unpacked[4] 

614 self.flag = unpacked[5] 

615 self.rsv = unpacked[6] 

616 self.dump_addr = unpacked[7] 

617 self.resv = list(unpacked[8:14]) 

618 

619 def is_valid(self): 

620 return self.magic == 0xAE86 

621 

622 

623@dataclass 

624class DumpCoreContent: 

625 block_info: BlockInfo = None 

626 dump_tensor_map: Dict[int, List[DumpTensor]] = field(default_factory=dict) 

627 print_list: List[str] = field(default_factory=list) 

628 simt_print_map: Dict[str, List[str]] = field(default_factory=dict) 

629 time_stamp_list: List[TimeStampInfo] = field(default_factory=list) 

630 index_dtype_dt = {} 

631 shape: List[int] = field(default_factory=list) 

632 

633 @staticmethod 

634 def _write_dump_tensor_data(dump_tensor, dump_data_path): 

635 with open(dump_data_path, 'wb+') as f: 

636 f.write(dump_tensor.dump_data) 

637 

638 @staticmethod 

639 def _write_dump_tensor_value(dump_tensor, dump_value_path): 

640 write_content = "" 

641 total_ele_num = 0 

642 if dump_tensor.dump_shape: 

643 total_ele_num = 1 

644 for ele in dump_tensor.dump_shape: 

645 total_ele_num = total_ele_num * ele 

646 if total_ele_num != 0: 

647 value_len = len(dump_tensor.dump_value) 

648 if total_ele_num > value_len: 

649 DUMP_PARSER_LOG.warning( 

650 f'tensor shape {dump_tensor.dump_shape} needs {total_ele_num} elements but only ' 

651 f'{value_len} dumped, missing values will be shown as "-"') 

652 elif total_ele_num < value_len: 

653 DUMP_PARSER_LOG.warning( 

654 f'tensor shape {dump_tensor.dump_shape} needs {total_ele_num} elements but ' 

655 f'{value_len} dumped, extra dumped values will be ignored') 

656 

657 shape = dump_tensor.dump_shape.copy() 

658 write_content = "[" * len(shape) 

659 for i in range(len(shape) - 2, -1, -1): 

660 shape[i] *= shape[i + 1] 

661 for i in range(total_ele_num): 

662 cnt = 0 

663 for s in shape: 

664 if (i + 1) % s == 0: 

665 cnt += 1 

666 if i < value_len: 

667 write_content += str(dump_tensor.dump_value[i]) 

668 else: 

669 write_content += "-" 

670 if cnt: 

671 write_content += "]" * cnt 

672 if i != total_ele_num - 1: 

673 write_content += ",\n" 

674 write_content += "[" * cnt 

675 elif i != total_ele_num - 1: 

676 write_content += "," 

677 if not write_content: 

678 line_count = 0 

679 for value in dump_tensor.dump_value: 

680 write_content += str(value) + "," 

681 line_count += 1 

682 if line_count == 8: 

683 write_content += "\n" 

684 line_count = 0 

685 with open(dump_value_path, 'w+') as f: 

686 f.write(write_content) 

687 

688 @classmethod 

689 def _flow_name(self): 

690 return 'legacy' 

691 

692 @classmethod 

693 def _create_dump_tensor(self): 

694 return DumpTensor() 

695 

696 @classmethod 

697 def _create_print_struct(self, _tlv_tag=None): 

698 return PrintStruct() 

699 

700 @classmethod 

701 def _create_time_stamp_info(self): 

702 return TimeStampInfo() 

703 

704 def add_tlv_data(self, tlv): 

705 if tlv.tag == DumpType.TENSOR_TYPE.value: 

706 dump_tensor = self._create_dump_tensor() 

707 dump_tensor.parse_from(tlv) 

708 index = dump_tensor.dump_header.desc 

709 data_type = dump_tensor.dump_header.data_type 

710 if self.shape: 

711 dump_tensor.dump_shape = self.shape.copy() 

712 self.shape.clear() 

713 self.index_dtype_dt[index] = dtype_to_data_type.get(data_type, '') 

714 self._add_dump_tensor(dump_tensor) 

715 elif tlv.tag in ( 

716 DumpType.SCALAR_TYPE.value, 

717 DumpType.ASSERT_TYPE.value, 

718 DumpType.SIMT_PRINTF_TYPE.value, 

719 DumpType.SIMT_ASSERT_TYPE.value 

720 ): 

721 print_struct = self._create_print_struct(tlv.tag) 

722 print_struct.parse_from(tlv) 

723 self.print_list.append(print_struct.content) 

724 if isinstance(print_struct, FifoSimtPrintStruct): 

725 thread_id = '_'.join([str(x) for x in print_struct.thread_idx]) 

726 if thread_id not in self.simt_print_map: 

727 self.simt_print_map[thread_id] = [] 

728 self.simt_print_map[thread_id].append(print_struct.content) 

729 elif tlv.tag == DumpType.SHAPE_TYPE.value: 

730 shape_info = ShapeInfo() 

731 shape_info.parse_from(tlv) 

732 self.shape = shape_info.shape 

733 elif tlv.tag == DumpType.TIME_STAMP.value: 

734 time_stamp_info = self._create_time_stamp_info() 

735 time_stamp_info.parse_from(tlv) 

736 self.time_stamp_list.append(time_stamp_info) 

737 elif tlv.tag == DumpType.META_TYPE.value: 

738 meta_info = MetaInfo() 

739 meta_info.parse_from(tlv) 

740 self.print_list.append(meta_info.content) 

741 else: 

742 DUMP_PARSER_LOG.error(f'Invalid dump Type: {tlv.tag}') 

743 

744 def get_core_id(self): 

745 if self.block_info is None: 

746 return 'unknown' 

747 if hasattr(self.block_info, 'core_id'): 

748 return str(self.block_info.core_id) 

749 return str(self.block_info.block_id) 

750 

751 def write_dump_tensor_data(self, dump_tensor, dump_data_path): 

752 self._write_dump_tensor_data(dump_tensor, dump_data_path) 

753 

754 def write_dump_tensor_value(self, dump_tensor, dump_value_path): 

755 self._write_dump_tensor_value(dump_tensor, dump_value_path) 

756 

757 def write_time_stamp(self, core_output_dir): 

758 self._write_time_stamp(core_output_dir) 

759 

760 def write_to_dir(self, output_dir): 

761 core_id = self.get_core_id() 

762 core_output_dir = os.path.join(output_dir, str(core_id)) 

763 os.makedirs(core_output_dir, exist_ok=True) 

764 DUMP_PARSER_LOG.info(f'write core {core_id} dump data to dir: {core_output_dir}') 

765 if self.dump_tensor_map: 

766 self._write_dump_tensor_by_index(core_output_dir) 

767 if self.time_stamp_list: 

768 self._write_time_stamp(core_output_dir) 

769 

770 def show_print(self): 

771 if len(self.print_list) > 0: 

772 core_id = self.get_core_id() 

773 print(f"================ block.{core_id} begin ==============") 

774 print(''.join(self.print_list), end='', flush=True) 

775 print(f"================ block.{core_id} end ================") 

776 DUMP_PARSER_LOG.info(f"================ block.{core_id} begin ==============") 

777 DUMP_PARSER_LOG.info(''.join(self.print_list)) 

778 DUMP_PARSER_LOG.info(f"================ block.{core_id} end ================") 

779 

780 def _add_dump_tensor(self, dump_tensor): 

781 index = dump_tensor.dump_header.desc 

782 if index not in self.dump_tensor_map: 

783 self.dump_tensor_map[index] = [] 

784 DUMP_PARSER_LOG.debug(f'Tensor[{index}][{len(self.dump_tensor_map[index])}] = {dump_tensor}') 

785 self.dump_tensor_map[index].append(dump_tensor) 

786 

787 def _write_dump_tensor_by_loop(self, index, index_output_dir): 

788 loop_cnt = len(self.dump_tensor_map[index]) 

789 core_id = self.get_core_id() 

790 for loop in range(0, loop_cnt): 

791 dump_tensor = self.dump_tensor_map[index][loop] 

792 dump_file_name = f'core_{core_id}_index_{index}_loop_{loop}.bin' 

793 dump_file_path = os.path.join(index_output_dir, dump_file_name) 

794 self._write_dump_tensor_data(dump_tensor, dump_file_path) 

795 

796 parsed_dump_file_name = f'core_{core_id}_index_{index}_loop_{loop}.txt' 

797 parsed_dump_file_path = os.path.join(index_output_dir, parsed_dump_file_name) 

798 self._write_dump_tensor_value(dump_tensor, parsed_dump_file_path) 

799 

800 def _write_dump_tensor_by_index(self, core_output_dir): 

801 for index in self.dump_tensor_map.keys(): 

802 index_output_dir = os.path.join(core_output_dir, f'index_{index}') 

803 os.makedirs(index_output_dir, exist_ok=True) 

804 DUMP_PARSER_LOG.info(f'write index {index} tensor to dir: {index_output_dir}') 

805 self._write_dump_tensor_by_loop(index, index_output_dir) 

806 

807 def _write_time_stamp(self, core_output_dir): 

808 import csv 

809 os.makedirs(core_output_dir, exist_ok=True) 

810 DUMP_PARSER_LOG.info(f'write time_stamp data to dir: {core_output_dir}') 

811 core_id = self.get_core_id() 

812 dump_file_name = f'time_stamp_core_{core_id}.csv' 

813 parsed_dump_file_path = os.path.join(core_output_dir, dump_file_name) 

814 with open(parsed_dump_file_path, 'w', encoding='utf-8-sig', newline="") as f: 

815 csv_write = csv.writer(f) 

816 csv_write.writerow(['打点标识', 'Cycle', 'Cycle间隔', 'PC指针']) 

817 last_cycle = 0 

818 for time_stamp in self.time_stamp_list: 

819 csv_write.writerow([str(get_enum_member_name(TimeStampId, int(time_stamp.desc_id))), 

820 str(time_stamp.sys_cycle), 

821 int(time_stamp.sys_cycle) - last_cycle, int(time_stamp.pc_ptr)] 

822 ) 

823 last_cycle = int(time_stamp.sys_cycle) 

824 

825 

826@dataclass 

827class FifoDumpCoreContent(DumpCoreContent): 

828 def _flow_name(self): 

829 return 'fifo' 

830 

831 def _create_dump_tensor(self): 

832 return FifoDumpTensor() 

833 

834 def _create_print_struct(self, tlv_tag=None): 

835 if tlv_tag in (DumpType.SIMT_PRINTF_TYPE.value, DumpType.SIMT_ASSERT_TYPE.value): 

836 return FifoSimtPrintStruct() 

837 return FifoPrintStruct() 

838 

839 def _create_time_stamp_info(self): 

840 return FifoTimeStampInfo() 

841 

842 

843class DumpType(Enum): 

844 DEFAULT_TYPE = 0 

845 SCALAR_TYPE = 1 

846 TENSOR_TYPE = 2 

847 SHAPE_TYPE = 3 

848 ASSERT_TYPE = 4 

849 META_TYPE = 5 

850 TIME_STAMP = 6 

851 SIMT_PRINTF_TYPE = 0xF0E00F0E 

852 SIMT_ASSERT_TYPE = 0xF0F00F0F 

853 

854 

855class DumpBinFile: 

856 def __init__(self, dump_bin): 

857 self.dump_bin = self._pre_process(dump_bin) 

858 self.dump_core_contents = [] # 每个core dump 内容 

859 self.index_dtype_dt = {} 

860 

861 def _pre_process(self, dump_bin: str): 

862 dump_dir = os.path.dirname(dump_bin) 

863 temp_dir = os.path.join(dump_dir, "predump") 

864 dump_file_name = os.path.basename(dump_bin) 

865 install_path = get_install_path() 

866 search_re = f"{install_path}/**/operator_cmp/compare/msaccucmp.py" 

867 search_result = glob.glob(search_re, recursive=True) 

868 if not search_result or not os.path.exists(search_result[0]): 

869 return dump_bin 

870 msaccucmp_file = os.path.realpath(search_result[0]) 

871 cmd = f'python3 "{msaccucmp_file}" convert -d "{dump_bin}" -t bin -out "{temp_dir}"' 

872 log_file_tmp = DUMP_PARSER_LOG.get_log_file() 

873 with open(log_file_tmp, "a+") as f: 

874 try: 

875 process = subprocess.run(cmd, stdout=f, stderr=subprocess.STDOUT, shell=True, encoding='utf-8', 

876 timeout=120) 

877 except subprocess.TimeoutExpired as e: 

878 DUMP_PARSER_LOG.error(f'Command {cmd} TIME OUT.') 

879 dump_result_re = os.path.join(temp_dir, f"{dump_file_name}.space.*.bin") 

880 dump_result = glob.glob(dump_result_re, recursive=True) 

881 if dump_result and os.path.exists(dump_result[0]): 

882 DUMP_PARSER_LOG.info(f'Find new dump_bin use {dump_result[0]}') 

883 return dump_result[0] 

884 return dump_bin 

885 

886 def parse(self): 

887 file_size = os.path.getsize(self.dump_bin) 

888 with open(self.dump_bin, 'rb') as bin_file: 

889 self.get_dump_core_contents(bin_file, file_size) 

890 

891 def get_dump_core_contents(self, bin_file, file_size): 

892 block_id = 0 

893 read_pos = 0 

894 total_block_size = ONE_MEGA_BYTE 

895 block_info_size = BlockInfo.get_size() 

896 

897 while read_pos + block_info_size < file_size: 

898 DUMP_PARSER_LOG.debug(f'block.{block_id} read from: {read_pos}') 

899 core_content = DumpCoreContent() 

900 

901 # read block info 

902 block_info_buffer = bin_file.read(block_info_size) 

903 block_info = BlockInfo() 

904 block_info.unpack(block_info_buffer) 

905 

906 if block_info.reserved == 7: 

907 DUMP_PARSER_LOG.warning( 

908 f"block.{block_id} remain space is NOT enough for last dump !!!") 

909 

910 if not block_info.is_valid(): 

911 DUMP_PARSER_LOG.debug( 

912 f'block.{block_id} block info is not valid, skip this block...') 

913 read_pos += total_block_size 

914 bin_file.seek(read_pos) 

915 block_id += 1 

916 continue 

917 

918 DUMP_PARSER_LOG.debug(block_info) 

919 core_content.block_info = block_info 

920 total_block_size = block_info.total_size 

921 

922 # read tlv data 

923 tlv_offset = 0 

924 core_dump_size = block_info.total_size - \ 

925 block_info_size - block_info.remain_size 

926 while tlv_offset < core_dump_size: 

927 tlv = TLV() 

928 tlv.read(bin_file) 

929 core_content.add_tlv_data(tlv) 

930 tlv_offset += tlv.get_size() 

931 self.index_dtype_dt.update(core_content.index_dtype_dt) 

932 self.dump_core_contents.append(core_content) 

933 

934 # read remain data 

935 read_pos += block_info.total_size 

936 bin_file.seek(read_pos) 

937 block_id += 1 

938 

939 def write_result(self, output_dir): 

940 if len(self.dump_core_contents) == 0: 

941 DUMP_PARSER_LOG.debug('no dump data, exit...') 

942 return '' 

943 

944 parse_output_dir = os.path.join(output_dir, 'dump_data') 

945 DUMP_PARSER_LOG.info(f'write dump workspace result: {parse_output_dir}') 

946 os.makedirs(parse_output_dir, exist_ok=True) 

947 for core_content in self.dump_core_contents: 

948 core_content.write_to_dir(parse_output_dir) 

949 return parse_output_dir 

950 

951 def write_index_dtype(self, output_dir): 

952 if len(self.index_dtype_dt) == 0: 

953 DUMP_PARSER_LOG.debug('no dump index, exit...') 

954 # remove index_dtype.json 

955 return 

956 json_path = os.path.join(output_dir, 'dump_data', 'index_dtype.json') 

957 with os.fdopen(os.open(json_path, FILE_FLAG, FILE_MODE_640), 'w') as f: 

958 json.dump(self.index_dtype_dt, f, indent=4) 

959 

960 def show_print(self): 

961 for core_content in self.dump_core_contents: 

962 core_content.show_print() 

963 

964 

965def get_install_path() -> str: 

966 ascend_home = os.environ.get('ASCEND_HOME_PATH') 

967 if not ascend_home: 

968 raise RuntimeError(f'get install path env failed, Please set environment variables') 

969 return ascend_home 

970 

971 

972class FifoDumpBinFile: 

973 def __init__(self, dump_bin, core_type, core_id): 

974 self.dump_bin = dump_bin 

975 self.core_type = core_type 

976 self.core_id = core_id 

977 self.dump_core_contents = [] 

978 self.index_dtype_dt = {} 

979 

980 @staticmethod 

981 def _iter_core_tensors(core_content): 

982 for index, tensors in core_content.dump_tensor_map.items(): 

983 for loop, dump_tensor in enumerate(tensors): 

984 yield index, loop, dump_tensor 

985 

986 def parse(self): 

987 file_size = os.path.getsize(self.dump_bin) 

988 core_content = FifoDumpCoreContent() 

989 

990 with open(self.dump_bin, 'rb') as bin_file: 

991 block_info_size = FifoBlockInfo.get_size() 

992 block_info_buffer = bin_file.read(block_info_size) 

993 if len(block_info_buffer) < block_info_size: 

994 raise RuntimeError('FifoDumpBinFile: incomplete BlockInfo header') 

995 block_info = FifoBlockInfo() 

996 block_info.unpack(block_info_buffer) 

997 if not block_info.is_valid(): 

998 raise RuntimeError('FifoDumpBinFile: invalid BlockInfo magic') 

999 core_content.block_info = block_info 

1000 while True: 

1001 tl_head = bin_file.read(TLV.get_tl_size()) 

1002 if not tl_head: 

1003 break 

1004 if len(tl_head) < TLV.get_tl_size(): 

1005 raise RuntimeError('FifoDumpBinFile: incomplete TLV header') 

1006 tlv = TLV() 

1007 tlv.tag, tlv.length = struct.unpack(tlv.get_tl_format(), tl_head) 

1008 if tlv.length > file_size: 

1009 raise RuntimeError(f'FifoDumpBinFile: TLV length overflow, length={tlv.length}') 

1010 remain_size = file_size - bin_file.tell() 

1011 if tlv.length > remain_size: 

1012 raise RuntimeError( 

1013 f'FifoDumpBinFile: TLV length overflow, length={tlv.length}, remain={remain_size}' 

1014 ) 

1015 tlv.value = bin_file.read(tlv.length) 

1016 if len(tlv.value) < tlv.length: 

1017 raise RuntimeError('FifoDumpBinFile: incomplete TLV value') 

1018 

1019 if tlv.tag in ( 

1020 DumpType.TENSOR_TYPE.value, 

1021 DumpType.SCALAR_TYPE.value, 

1022 DumpType.ASSERT_TYPE.value, 

1023 DumpType.SIMT_PRINTF_TYPE.value, 

1024 DumpType.SIMT_ASSERT_TYPE.value, 

1025 DumpType.TIME_STAMP.value, 

1026 DumpType.SHAPE_TYPE.value 

1027 ): 

1028 core_content.add_tlv_data(tlv) 

1029 self.index_dtype_dt.update(core_content.index_dtype_dt) 

1030 self.dump_core_contents.append(core_content) 

1031 

1032 def write_result(self, output_dir): 

1033 if len(self.dump_core_contents) == 0: 

1034 DUMP_PARSER_LOG.debug('no dump data, exit...') 

1035 return '' 

1036 

1037 parse_output_dir = os.path.join(output_dir, 'dump_data') 

1038 DUMP_PARSER_LOG.info(f'write dump workspace result: {parse_output_dir}') 

1039 os.makedirs(parse_output_dir, exist_ok=True) 

1040 for core_content in self.dump_core_contents: 

1041 core_output_dir = os.path.join(parse_output_dir, str(core_content.get_core_id())) 

1042 os.makedirs(core_output_dir, exist_ok=True) 

1043 for index, loop, dump_tensor in self._iter_core_tensors(core_content): 

1044 name_prefix = f'asc_kernel_data_{self.core_type}_{self.core_id}_index_{index}_loop_{loop}' 

1045 dump_file_path = os.path.join(core_output_dir, f'{name_prefix}.bin') 

1046 core_content.write_dump_tensor_data(dump_tensor, dump_file_path) 

1047 

1048 parsed_dump_file_path = os.path.join(core_output_dir, f'{name_prefix}.txt') 

1049 core_content.write_dump_tensor_value(dump_tensor, parsed_dump_file_path) 

1050 if self.core_type == 'simt' and core_content.simt_print_map: 

1051 self._write_simt_print_by_thread(core_content, core_output_dir) 

1052 if core_content.time_stamp_list: 

1053 core_content.write_time_stamp(core_output_dir) 

1054 return parse_output_dir 

1055 

1056 def write_index_dtype(self, output_dir): 

1057 if len(self.index_dtype_dt) == 0: 

1058 DUMP_PARSER_LOG.debug('no dump index, exit...') 

1059 return 

1060 json_path = os.path.join(output_dir, 'dump_data', 'index_dtype.json') 

1061 with os.fdopen(os.open(json_path, FILE_FLAG, FILE_MODE_640), 'w') as f: 

1062 json.dump(self.index_dtype_dt, f, indent=4) 

1063 

1064 def show_print(self): 

1065 for core_content in self.dump_core_contents: 

1066 core_content.show_print() 

1067 

1068 def _write_simt_print_by_thread(self, core_content, parse_output_dir): 

1069 for thread_id, print_list in core_content.simt_print_map.items(): 

1070 name_prefix = f'asc_kernel_data_{self.core_type}_{self.core_id}_thread_{thread_id}' 

1071 parsed_dump_file_path = os.path.join(parse_output_dir, f'{name_prefix}.txt') 

1072 with open(parsed_dump_file_path, 'w+') as f: 

1073 f.write(''.join(print_list)) 

1074 

1075 

1076def _make_parser_output_dir(output_path): 

1077 from datetime import datetime, timezone 

1078 output_dir = os.path.abspath(output_path) 

1079 cur_time_str = datetime.now(tz=timezone.utc).strftime('%Y%m%d%H%M%S%f') 

1080 output_dir = os.path.join(output_dir, f"PARSER_{cur_time_str}") 

1081 os.makedirs(output_dir, exist_ok=True) 

1082 return output_dir 

1083 

1084 

1085def _core_type_from_fifo_flag(flag): 

1086 flag_to_core_type = { 

1087 0: 'aic', 

1088 1: 'aiv', 

1089 2: 'simt' 

1090 } 

1091 return flag_to_core_type.get(flag, 'fifo') 

1092 

1093 

1094def _read_block_magic_core_id_and_flag(dump_bin): 

1095 raw_magic = None 

1096 fifo_core_id = None 

1097 fifo_flag = None 

1098 with open(dump_bin, 'rb') as bin_file: 

1099 header = bin_file.read(FifoBlockInfo.get_size()) 

1100 if len(header) >= 20: 

1101 raw_magic = struct.unpack('I', header[16:20])[0] 

1102 unpacked = struct.unpack(FifoBlockInfo.get_format(), header) 

1103 fifo_core_id = unpacked[1] 

1104 fifo_flag = unpacked[5] 

1105 return raw_magic, fifo_core_id, fifo_flag 

1106 

1107 

1108def _collect_bin_files(input_path): 

1109 input_path = os.path.abspath(input_path) 

1110 if os.path.isfile(input_path): 

1111 return [input_path] 

1112 if os.path.isdir(input_path): 

1113 search_re = os.path.join(input_path, '**', '*.bin') 

1114 return sorted([bin_file for bin_file in glob.glob(search_re, recursive=True) if os.path.isfile(bin_file)]) 

1115 return [] 

1116 

1117 

1118def parse_dump_bin(bin_file_path, output_path, parse_output_dir=None, init_logger=True): 

1119 dump_bin = os.path.abspath(bin_file_path) 

1120 output_dir = parse_output_dir if parse_output_dir else _make_parser_output_dir(output_path) 

1121 output_dir = os.path.abspath(output_dir) 

1122 os.makedirs(output_dir, exist_ok=True) 

1123 if init_logger: 

1124 DUMP_PARSER_LOG.set_log_file(os.path.join(output_dir, "parser.log")) 

1125 DUMP_PARSER_LOG.set_log_level(os.environ.get('ASCEND_GLOBAL_LOG_LEVEL', '3')) 

1126 try: 

1127 name_no_ext, ext = os.path.splitext(os.path.basename(dump_bin)) 

1128 parts = name_no_ext.split('_') 

1129 is_asc_kernel_data = ( 

1130 ext == '.bin' 

1131 and len(parts) == 5 

1132 and parts[0] == 'asc' 

1133 and parts[1] == 'kernel' 

1134 and parts[2] == 'data' 

1135 ) 

1136 raw_magic, fifo_core_id, fifo_flag = _read_block_magic_core_id_and_flag(dump_bin) 

1137 

1138 if raw_magic is not None and (raw_magic & 0xFFFF) == 0xAE86: 

1139 if is_asc_kernel_data: 

1140 core_type = parts[3] 

1141 core_id = parts[4] 

1142 else: 

1143 core_type = _core_type_from_fifo_flag(fifo_flag) 

1144 core_id = str(fifo_core_id) if fifo_core_id is not None else 'unknown' 

1145 dump_file = FifoDumpBinFile(dump_bin, core_type, core_id) 

1146 elif raw_magic is None or raw_magic == 0x5aa5bccd: 

1147 if os.path.getsize(dump_bin) < BlockInfo.get_size(): 

1148 raise RuntimeError( 

1149 f'file too small ({os.path.getsize(dump_bin)} bytes), ' 

1150 f'at least {BlockInfo.get_size()} bytes required for a valid workspace dump') 

1151 dump_file = DumpBinFile(dump_bin) 

1152 else: 

1153 raise RuntimeError(f'unknown block magic: 0x{raw_magic:08X}') 

1154 

1155 dump_file.parse() 

1156 dump_file.write_result(output_dir) 

1157 dump_file.write_index_dtype(output_dir) 

1158 dump_file.show_print() 

1159 return 0 

1160 except Exception as e: 

1161 print(f"parse dump workspace bin occur exception, bin_file: {dump_bin}") 

1162 import traceback 

1163 traceback.print_exc() 

1164 return 255 

1165 

1166 

1167def _validate_and_prepare(bin_file_path, output_path): 

1168 """Validate input/output paths and collect bin files. 

1169 Returns (dump_bins, output_path, parser_output_dir) on success. 

1170 parser_output_dir is None when bin_file_path points to a single file. 

1171 """ 

1172 if not bin_file_path or not os.path.exists(bin_file_path): 

1173 if bin_file_path and not all(ord(c) < 128 for c in bin_file_path): 

1174 raise RuntimeError( 

1175 f'({bin_file_path}) path contains non-ASCII characters (e.g. Chinese), ' 

1176 f'which may cause encoding issues. Please use an ASCII-only path.') 

1177 raise RuntimeError(f'({bin_file_path}) file does not exist or permission denied!!!') 

1178 

1179 if not output_path: 

1180 raise RuntimeError(f'({output_path}) directory does not exist or permission denied!!!') 

1181 if not all(ord(c) < 128 for c in output_path): 

1182 raise RuntimeError( 

1183 f'({output_path}) output path contains non-ASCII characters (e.g. Chinese), ' 

1184 f'which may cause encoding issues. Please use an ASCII-only path.') 

1185 if os.path.exists(output_path): 

1186 if not os.path.isdir(output_path): 

1187 raise RuntimeError(f'({output_path}) is not a directory!!!') 

1188 else: 

1189 try: 

1190 os.makedirs(output_path, exist_ok=True) 

1191 except OSError as err: 

1192 raise RuntimeError( 

1193 f'({output_path}) failed to create directory: {err}') from err 

1194 

1195 if not os.path.isfile(bin_file_path) and not os.path.isdir(bin_file_path): 

1196 raise RuntimeError(f'({bin_file_path}) is neither a file nor a directory!!!') 

1197 

1198 dump_bins = _collect_bin_files(bin_file_path) 

1199 if not dump_bins: 

1200 raise RuntimeError(f'({bin_file_path}) does not contain any .bin file!!!') 

1201 

1202 parser_output_dir = None 

1203 if os.path.isdir(bin_file_path): 

1204 parser_output_dir = _make_parser_output_dir(output_path) 

1205 DUMP_PARSER_LOG.set_log_file(os.path.join(parser_output_dir, "parser.log")) 

1206 DUMP_PARSER_LOG.set_log_level(os.environ.get('ASCEND_GLOBAL_LOG_LEVEL', '3')) 

1207 

1208 return dump_bins, output_path, parser_output_dir 

1209 

1210 

1211def execute_parse(): 

1212 import sys 

1213 param_len = len(sys.argv[1:]) 

1214 bin_file_path = '' 

1215 output_path = os.getcwd() 

1216 help_info = "show_kernel_debug_data is a tool that parses dump binary data from AscendC debug API.\n"\ 

1217 "It takes two inputs:\n First mandatory param is binary file or directory\n"\ 

1218 " Second optional param is output path that stores result file," \ 

1219 " by default saving path is current directory.\n"\ 

1220 " ex: show_kernel_debug_data ./dump.bin ./output_dir" 

1221 if param_len == 2: 

1222 bin_file_path, output_path = sys.argv[1:] 

1223 elif param_len == 1 and sys.argv[1] in ['-h', '--help']: 

1224 print(help_info) 

1225 return 0 

1226 elif param_len == 1: 

1227 bin_file_path = sys.argv[1] 

1228 else: 

1229 print(help_info) 

1230 raise RuntimeError("parameters invalid, please check tool introduction.") 

1231 

1232 dump_bins, output_path, parser_output_dir = _validate_and_prepare(bin_file_path, output_path) 

1233 

1234 if parser_output_dir is not None: 

1235 for dump_bin in dump_bins: 

1236 ret = parse_dump_bin(dump_bin, output_path, parse_output_dir=parser_output_dir, init_logger=False) 

1237 if ret != 0: 

1238 return ret 

1239 else: 

1240 ret = parse_dump_bin(dump_bins[0], output_path) 

1241 if ret != 0: 

1242 return ret 

1243 return 0