ops-tune-workbench-plugin 0.0.0-stage → 0.0.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/NOTICE.md +14 -0
  2. package/README.md +39 -2
  3. package/cordis.patch.yml +20 -0
  4. package/lib/client.js +4253 -0
  5. package/lib/host.js +2518 -0
  6. package/package.json +53 -4
  7. package/skills/tool-ops-tune/INSTALL.md +52 -0
  8. package/skills/tool-ops-tune/README.md +167 -0
  9. package/skills/tool-ops-tune/SKILL.md +93 -0
  10. package/skills/tool-ops-tune/agent/AGENTS.md +195 -0
  11. package/skills/tool-ops-tune/agent/agents/perf-implementer.md +68 -0
  12. package/skills/tool-ops-tune/agent/agents/perf-reviewer.md +86 -0
  13. package/skills/tool-ops-tune/agent/workflows/task-prompts.md +362 -0
  14. package/skills/tool-ops-tune/agent/workflows/troubleshooting.md +43 -0
  15. package/skills/tool-ops-tune/docs/figures/opstune-architecture.png +0 -0
  16. package/skills/tool-ops-tune/docs/figures/opstune-architecture.svg +253 -0
  17. package/skills/tool-ops-tune/docs/ops-tune-design.md +404 -0
  18. package/skills/tool-ops-tune/docs//347/224/250/344/276/213/346/236/204/345/273/272.md +714 -0
  19. package/skills/tool-ops-tune/docs//347/237/245/350/257/206/345/272/223/350/247/204/350/214/203.md +103 -0
  20. package/skills/tool-ops-tune/evals/evals.json +242 -0
  21. package/skills/tool-ops-tune/ops-collect/SKILL.md +146 -0
  22. package/skills/tool-ops-tune/ops-collect/references/tool-routing.md +86 -0
  23. package/skills/tool-ops-tune/ops-collect/scripts/collect_board.sh +444 -0
  24. package/skills/tool-ops-tune/ops-collect/scripts/collect_cases.py +368 -0
  25. package/skills/tool-ops-tune/ops-collect/scripts/collect_sim.sh +134 -0
  26. package/skills/tool-ops-tune/ops-collect/scripts/csv_to_db.py +314 -0
  27. package/skills/tool-ops-tune/ops-collect/scripts/db_bench.py +545 -0
  28. package/skills/tool-ops-tune/ops-collect/scripts/facts_bridge.py +1063 -0
  29. package/skills/tool-ops-tune/ops-collect/scripts/isolation_test.py +454 -0
  30. package/skills/tool-ops-tune/ops-collect/scripts/jsonl_to_cases.py +163 -0
  31. package/skills/tool-ops-tune/ops-family/SKILL.md +76 -0
  32. package/skills/tool-ops-tune/ops-family/references/broadcast/advanced_tiling.md +92 -0
  33. package/skills/tool-ops-tune/ops-family/references/broadcast/broadcast_design.md +160 -0
  34. package/skills/tool-ops-tune/ops-family/references/broadcast/code/broadcast_add_kernel.cpp +126 -0
  35. package/skills/tool-ops-tune/ops-family/references/broadcast/code/broadcast_add_tiling.cpp +144 -0
  36. package/skills/tool-ops-tune/ops-family/references/broadcast/code/broadcast_tiling_common.h +401 -0
  37. package/skills/tool-ops-tune/ops-family/references/broadcast/code/onedim_add_kernel.cpp +107 -0
  38. package/skills/tool-ops-tune/ops-family/references/broadcast/code/onedim_add_tiling.cpp +64 -0
  39. package/skills/tool-ops-tune/ops-family/references/broadcast/datacopypad_design.md +46 -0
  40. package/skills/tool-ops-tune/ops-family/references/broadcast/guide.md +14 -0
  41. package/skills/tool-ops-tune/ops-family/references/broadcast/nddma_design.md +53 -0
  42. package/skills/tool-ops-tune/ops-family/references/broadcast/onedim_design.md +114 -0
  43. package/skills/tool-ops-tune/ops-family/references/broadcast/ub_broadcast_design.md +67 -0
  44. package/skills/tool-ops-tune/ops-family/references/common/datacopy_optimization_design.md +351 -0
  45. package/skills/tool-ops-tune/ops-family/references/common/index.md +9 -0
  46. package/skills/tool-ops-tune/ops-family/references/common/tail_block_design.md +268 -0
  47. package/skills/tool-ops-tune/ops-family/references/common/timing_harness/index.md +38 -0
  48. package/skills/tool-ops-tune/ops-family/references/common/timing_harness/timing_harness_aclrt_event.cpp +199 -0
  49. package/skills/tool-ops-tune/ops-family/references/common/timing_harness/timing_harness_torch_event.py +130 -0
  50. package/skills/tool-ops-tune/ops-family/references/common/ub_resident_design.md +342 -0
  51. package/skills/tool-ops-tune/ops-family/references/conversion/guide.md +69 -0
  52. package/skills/tool-ops-tune/ops-family/references/conversion/index.md +4 -0
  53. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_base.template +81 -0
  54. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_big_dim.template +217 -0
  55. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_cut_one_axis.template +336 -0
  56. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_cut_two_axis.template +781 -0
  57. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_n_last.template +340 -0
  58. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_small_shape.template +321 -0
  59. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_tensor_move.template +102 -0
  60. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_transdata_5hd.template +480 -0
  61. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_transdata_5hd_021axis.template +533 -0
  62. package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_with_gather.template +688 -0
  63. package/skills/tool-ops-tune/ops-family/references/conversion/templates/transpose_tiling_data.template +192 -0
  64. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_big_dim.md +220 -0
  65. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_cut_one_axis.md +175 -0
  66. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_cut_two_axis.md +177 -0
  67. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_fusion_design.md +398 -0
  68. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_gather.md +191 -0
  69. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_n_last.md +276 -0
  70. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_small_shape.md +315 -0
  71. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_tensor_move.md +203 -0
  72. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_tiling_data.md +176 -0
  73. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_vconv_021.md +206 -0
  74. package/skills/tool-ops-tune/ops-family/references/conversion/transpose_vconv_5hd.md +179 -0
  75. package/skills/tool-ops-tune/ops-family/references/elementwise/double_buffer_design.md +288 -0
  76. package/skills/tool-ops-tune/ops-family/references/elementwise/guide.md +46 -0
  77. package/skills/tool-ops-tune/ops-family/references/elementwise/index.md +10 -0
  78. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/CMakeLists.txt +131 -0
  79. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/README.md +55 -0
  80. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/add_custom_torch.cpp +80 -0
  81. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/ops.h +23 -0
  82. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/register.cpp +30 -0
  83. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_host/add_custom.asc +149 -0
  84. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_host/data_utils.h +97 -0
  85. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_kernel/add_custom_kernel.asc +136 -0
  86. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_kernel/add_custom_tiling.h +31 -0
  87. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/run.sh +86 -0
  88. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/gen_data.py +70 -0
  89. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/golden.py +34 -0
  90. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/test_torch.py +99 -0
  91. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/verify_result.py +56 -0
  92. package/skills/tool-ops-tune/ops-family/references/elementwise/templates/usage_guide.md +61 -0
  93. package/skills/tool-ops-tune/ops-family/references/elementwise/vector_efficiency_design.md +203 -0
  94. package/skills/tool-ops-tune/ops-family/references/fa/fa_mixed_kernel_design.md +174 -0
  95. package/skills/tool-ops-tune/ops-family/references/fa/fa_roofline_design.md +141 -0
  96. package/skills/tool-ops-tune/ops-family/references/fa/guide.md +87 -0
  97. package/skills/tool-ops-tune/ops-family/references/knowledge_gaps.json +56 -0
  98. package/skills/tool-ops-tune/ops-family/references/matmul/best-practices-guide.md +14 -0
  99. package/skills/tool-ops-tune/ops-family/references/matmul/fullload_design.md +344 -0
  100. package/skills/tool-ops-tune/ops-family/references/matmul/guide.md +52 -0
  101. package/skills/tool-ops-tune/ops-family/references/matmul/mte2_preload_design.md +320 -0
  102. package/skills/tool-ops-tune/ops-family/references/matmul/pingpong_design.md +254 -0
  103. package/skills/tool-ops-tune/ops-family/references/matmul/scale_coalescing_design.md +282 -0
  104. package/skills/tool-ops-tune/ops-family/references/matmul/streamk_design.md +374 -0
  105. package/skills/tool-ops-tune/ops-family/references/matmul/swat_design.md +423 -0
  106. package/skills/tool-ops-tune/ops-family/references/matmul/templates/matmul_basic_blaze.template +165 -0
  107. package/skills/tool-ops-tune/ops-family/references/matmul/templates/usage_guide.md +29 -0
  108. package/skills/tool-ops-tune/ops-family/references/mc2/best-practices-guide.md +43 -0
  109. package/skills/tool-ops-tune/ops-family/references/mc2/guide.md +42 -0
  110. package/skills/tool-ops-tune/ops-family/references/mc2/local_matmul_design.md +130 -0
  111. package/skills/tool-ops-tune/ops-family/references/mc2/pipeline_balancing_design.md +502 -0
  112. package/skills/tool-ops-tune/ops-family/references/reduce/guide.md +178 -0
  113. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/kernel_utils.template +75 -0
  114. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_full_load.template +429 -0
  115. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_recompute.template +485 -0
  116. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_small_r.template +348 -0
  117. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_full_load.template +574 -0
  118. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_online.template +324 -0
  119. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_recompute.template +436 -0
  120. package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_base.template +950 -0
  121. package/skills/tool-ops-tune/ops-family/references/reduce/templates/fused_attention_online_softmax_design.md +428 -0
  122. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_full_load.md +137 -0
  123. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_recompute.md +135 -0
  124. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_small_r.md +122 -0
  125. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_full_load.md +144 -0
  126. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_online.md +185 -0
  127. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_recompute.md +163 -0
  128. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_tiling.template +460 -0
  129. package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_tiling_data.template +278 -0
  130. package/skills/tool-ops-tune/ops-family/references/reduce/templates/state_resident_design.md +337 -0
  131. package/skills/tool-ops-tune/ops-family/references/reduce/templates/usage_guide.md +253 -0
  132. package/skills/tool-ops-tune/ops-family/references/scalar/coding_principles.md +476 -0
  133. package/skills/tool-ops-tune/ops-family/references/scalar/conv_scalar.md +163 -0
  134. package/skills/tool-ops-tune/ops-family/references/scalar/guide.md +30 -0
  135. package/skills/tool-ops-tune/ops-family/references/simt/guide.md +91 -0
  136. package/skills/tool-ops-tune/ops-family/references/simt/optimization-guide.md +110 -0
  137. package/skills/tool-ops-tune/ops-family/references/sort/guide.md +83 -0
  138. package/skills/tool-ops-tune/ops-family/references/sort/radix_sort.md +354 -0
  139. package/skills/tool-ops-tune/ops-family/scripts/family_asset_audit.py +68 -0
  140. package/skills/tool-ops-tune/ops-family/scripts/tiling_candidates.py +419 -0
  141. package/skills/tool-ops-tune/ops-mechanism/SKILL.md +23 -0
  142. package/skills/tool-ops-tune/ops-mechanism/cases/ascendc/case_groupedmatmul_pipeline.md +23 -0
  143. package/skills/tool-ops-tune/ops-mechanism/cases/ascendc/case_triton_atomic_revert.md +19 -0
  144. package/skills/tool-ops-tune/ops-mechanism/cases/mc2/case_mc2_fusion.md +19 -0
  145. package/skills/tool-ops-tune/ops-mechanism/references/optimize/api-usage.md +70 -0
  146. package/skills/tool-ops-tune/ops-mechanism/references/optimize/ascendc-regbase-vf.md +45 -0
  147. package/skills/tool-ops-tune/ops-mechanism/references/optimize/ascendc-tiling.md +51 -0
  148. package/skills/tool-ops-tune/ops-mechanism/references/optimize/data-copy.md +67 -0
  149. package/skills/tool-ops-tune/ops-mechanism/references/optimize/index.md +45 -0
  150. package/skills/tool-ops-tune/ops-mechanism/references/optimize/mc2-balancing.md +77 -0
  151. package/skills/tool-ops-tune/ops-mechanism/references/optimize/mc2.md +103 -0
  152. package/skills/tool-ops-tune/ops-mechanism/references/optimize/memory-hierarchy.md +40 -0
  153. package/skills/tool-ops-tune/ops-mechanism/references/optimize/pipeline.md +95 -0
  154. package/skills/tool-ops-tune/ops-mechanism/scripts/case_backfill.py +170 -0
  155. package/skills/tool-ops-tune/ops-mechanism/scripts/log_gap.py +145 -0
  156. package/skills/tool-ops-tune/ops-mechanism/scripts/mc2_search.py +367 -0
  157. package/skills/tool-ops-tune/ops-report/SKILL.md +77 -0
  158. package/skills/tool-ops-tune/ops-verdict/evals/run_evals.py +837 -0
  159. package/skills/tool-ops-tune/ops-verdict/evals/smoke/install-hooks.sh +65 -0
  160. package/skills/tool-ops-tune/ops-verdict/evals/smoke/run_smoke.sh +405 -0
  161. package/skills/tool-ops-tune/ops-verdict/fixtures/core_tail_a5.csv +25 -0
  162. package/skills/tool-ops-tune/ops-verdict/fixtures/few_cores_a5.csv +5 -0
  163. package/skills/tool-ops-tune/ops-verdict/fixtures/mte2_bound_a2.csv +17 -0
  164. package/skills/tool-ops-tune/ops-verdict/fixtures/multi_kernel_mix_a5.csv +7 -0
  165. package/skills/tool-ops-tune/ops-verdict/fixtures/no_bound_a5.csv +9 -0
  166. package/skills/tool-ops-tune/ops-verdict/fixtures/serial_no_overlap_a2.csv +9 -0
  167. package/skills/tool-ops-tune/ops-verdict/fixtures/vec_bound_a5.csv +9 -0
  168. package/skills/tool-ops-tune/ops-verdict/references/io-contracts.md +94 -0
  169. package/skills/tool-ops-tune/ops-verdict/references/rule-schema.md +130 -0
  170. package/skills/tool-ops-tune/ops-verdict/references/scope-schema.md +61 -0
  171. package/skills/tool-ops-tune/ops-verdict/references/soc-spec.yaml +140 -0
  172. package/skills/tool-ops-tune/ops-verdict/rules/L0-instruction.yaml +67 -0
  173. package/skills/tool-ops-tune/ops-verdict/rules/L1-single-core.yaml +316 -0
  174. package/skills/tool-ops-tune/ops-verdict/rules/L2-inter-core.yaml +173 -0
  175. package/skills/tool-ops-tune/ops-verdict/rules/L3-inter-card.yaml +156 -0
  176. package/skills/tool-ops-tune/ops-verdict/scripts/batch_pipeline.py +444 -0
  177. package/skills/tool-ops-tune/ops-verdict/scripts/calibrate.py +249 -0
  178. package/skills/tool-ops-tune/ops-verdict/scripts/delta_compare.py +244 -0
  179. package/skills/tool-ops-tune/ops-verdict/scripts/render_html.py +274 -0
  180. package/skills/tool-ops-tune/ops-verdict/scripts/snapshot.py +200 -0
  181. package/skills/tool-ops-tune/ops-verdict/scripts/trace_bubble.py +331 -0
  182. package/skills/tool-ops-tune/ops-verdict/scripts/verdict.py +1072 -0
  183. package/skills/tool-ops-tune/scripts/diff_audit.py +281 -0
@@ -0,0 +1,314 @@
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
+ """csv_to_db.py — 采集 CSV 目录 → npu-compute 兼容 summary.db(Roadmap #4 转换器)
13
+
14
+ 设计对齐:
15
+ - npu-compute(950/A5 采集器)自 8b13bca 起原生产出 summary.db(SQLite):
16
+ 7 个 Section 表 + PcSampling(DB 独有)+ FieldUnitMap(字段→单位映射)。
17
+ 旧版 .npu-rep 无 DB,判定链只能逐 CSV 全量解析——本脚本把既有 CSV 产物
18
+ 升级为 DB 格式,供 facts_bridge DB 通道 / verdict.py --db / db_bench 消费。
19
+ - 规范化规则移植自 npu_tools/npu_compute/src/cli/report/csv_reader.cpp 的
20
+ ColumnWords / ParseColumn(同仓源码真源,逐条核验):
21
+ ① 单位后缀分离:`aic_time(us)` → 列名 `aic_time` + 单位 `us` 入 FieldUnitMap;
22
+ ② 词法规范化:转小写;含 `_` 保持既有词边界;不含 `_` 按驼峰切词;
23
+ 非字母数字字符作词边界(`(%)/(GB/s)` 等);
24
+ ③ `NA` / 空值 → SQL NULL(不是 0——NA 语义为不适用/未采集);
25
+ ④ 类型推断:整列合法整数 → INTEGER,含小数 → REAL,其余 → TEXT;
26
+ ⑤ 表名 = CSV 文件名去 .csv 后缀(Section 名保持不变)。
27
+ - 真实 .npu-rep 解包产物存在行尾拖尾逗号(表头/数据行末尾空字段,
28
+ vector_muladd_plain.npu-rep 实测)——先剥除再入库,防列数错位。
29
+
30
+ 用法:
31
+ python3 csv_to_db.py --csv-dir <解包目录> --db <out.db> [--drop-existing]
32
+ python3 csv_to_db.py --csv-dir <dir> --db <out.db> --tables PipeUtilization,L2Cache
33
+
34
+ 输出保护(检视 #1 修复):
35
+ --db 已存在时默认拒覆盖(exit 1)——现代 .npu-rep 解包目录的原生 summary.db
36
+ 携带 PcSampling 表(无 CSV 对应物,删后不可从 CSV 重建);确认覆盖须显式
37
+ --drop-existing,或另指定输出路径。
38
+
39
+ 产物校验(写入后回读):
40
+ - 表数 = 输入 CSV 数(含 FieldUnitMap +1);
41
+ - 每表行数 = CSV 数据行数(全 NA 行视为空行跳过,与 npu-compute
42
+ 「header-only CSVs are skipped」语义一致)。
43
+
44
+ 退出码:0 成功 / 1 输入或校验错误(fail loud,不产出半成品 db)。
45
+ """
46
+
47
+ from __future__ import annotations
48
+
49
+ import argparse
50
+ import csv
51
+ import sqlite3
52
+ import sys
53
+ from pathlib import Path
54
+
55
+ SCHEMA = "opstune.csv-to-db/1.0"
56
+ UNIT_TABLE = "FieldUnitMap"
57
+ # npu-compute 保留表名(csv_reader.cpp ValidateName):CSV 与之同名时拒建防冲突
58
+ RESERVED_TABLES = {"pcsampling", "fieldunitmap"}
59
+
60
+
61
+ def column_words(value: str) -> str:
62
+ """列名词法规范化(npu-compute ColumnWords 同规则)。
63
+
64
+ 含 `_` 保持既有词边界(硬件名 L0C 不被拆);不含 `_` 时按驼峰切词
65
+ (GMtoL1 → gm_to_l1);非字母数字字符一律作词边界。
66
+ """
67
+ result: list[str] = []
68
+ start_word = True
69
+ explicit = "_" in value
70
+ for i, ch in enumerate(value):
71
+ if not ch.isalnum():
72
+ start_word = True
73
+ continue
74
+ camel = (
75
+ not explicit
76
+ and i > 0
77
+ and ch.isupper()
78
+ and (
79
+ value[i - 1].islower()
80
+ or value[i - 1].isdigit()
81
+ or (
82
+ value[i - 1].isupper()
83
+ and i + 1 < len(value)
84
+ and value[i + 1].islower()
85
+ )
86
+ )
87
+ )
88
+ if result and (start_word or camel):
89
+ result.append("_")
90
+ result.append(ch.lower())
91
+ start_word = False
92
+ return "".join(result)
93
+
94
+
95
+ def parse_column(field: str) -> tuple[str, str | None]:
96
+ """表头 → (规范化列名, 单位或 None)。单位须为单一括号后缀。"""
97
+ body = field.strip()
98
+ unit = None
99
+ if "(" in body and body.endswith(")"):
100
+ start = body.find("(")
101
+ if body.find("(", start + 1) != -1 or not body[start + 1 : -1].strip():
102
+ raise ValueError(f"表头单位后缀非法(须单一括号后缀): {field!r}")
103
+ unit = body[start + 1 : -1].strip()
104
+ body = body[:start]
105
+ name = column_words(body)
106
+ if not name:
107
+ raise ValueError(f"表头规范化后为空: {field!r}")
108
+ if name[0].isdigit() or name.lower().startswith("sqlite_"):
109
+ raise ValueError(f"表头规范化后为保留名: {field!r} → {name!r}")
110
+ return name, unit
111
+
112
+
113
+ def sql_type(values: list[str]) -> str:
114
+ """整列扫描类型推断(npu-compute ColumnInference 同规则:NA/空不参与)。"""
115
+ integer = real = text = False
116
+ exact_integers = True
117
+ for v in values:
118
+ if v in ("", "NA"):
119
+ continue
120
+ try:
121
+ integer = True
122
+ parsed = int(v)
123
+ # 前导零的数字串("007")按 TEXT 处理,与 ParseCsvInteger 一致
124
+ if v.lstrip("-").startswith("0") and len(v.lstrip("-")) > 1:
125
+ integer = False
126
+ real = True
127
+ exact_integers = False
128
+ break
129
+ exact_integers = exact_integers and abs(parsed) <= 2**53
130
+ except ValueError:
131
+ integer = False
132
+ try:
133
+ float(v)
134
+ real = True
135
+ except ValueError:
136
+ text = True
137
+ break
138
+ if text or (not integer and not real) or (real and not exact_integers):
139
+ return "TEXT"
140
+ return "REAL" if real else "INTEGER"
141
+
142
+
143
+ def bind_value(v: str, col_type: str):
144
+ """数据值 → SQL 值。NA/空 → None;数值列按类型绑定,失配按 TEXT 兜底。"""
145
+ if v in ("", "NA"):
146
+ return None
147
+ if col_type == "INTEGER":
148
+ try:
149
+ return int(v)
150
+ except ValueError:
151
+ return v
152
+ if col_type == "REAL":
153
+ try:
154
+ return float(v)
155
+ except ValueError:
156
+ return v
157
+ return v
158
+
159
+
160
+ def read_csv_rows(path: Path) -> tuple[list[str], list[list[str]]]:
161
+ """读单份 CSV → (规范化列名列表, 数据行列表)。剥行尾拖尾空字段。"""
162
+ with open(path, encoding="utf-8-sig", errors="replace", newline="") as f:
163
+ reader = csv.reader(f)
164
+ try:
165
+ header = next(reader)
166
+ except StopIteration:
167
+ raise ValueError(f"CSV 无表头行: {path}")
168
+ if header and header[-1].strip() == "":
169
+ header = header[:-1] # 行尾拖尾逗号产物(真实 .npu-rep 实测形态)
170
+ names, units = [], []
171
+ for h in header:
172
+ name, unit = parse_column(h)
173
+ names.append(name)
174
+ units.append(unit)
175
+ rows = []
176
+ for r in reader:
177
+ if not any(c.strip() for c in r):
178
+ continue # 空行
179
+ if r and r[-1].strip() == "" and len(r) == len(names) + 1:
180
+ r = r[:-1] # 数据行同款拖尾逗号
181
+ if len(r) > len(names):
182
+ raise ValueError(
183
+ f"{path.name} 数据行字段数 {len(r)} > 表头 {len(names)}(非拖尾形态)"
184
+ )
185
+ r += [""] * (len(names) - len(r)) # 短行右补空 → NULL
186
+ rows.append(r)
187
+ return names, units, rows
188
+
189
+
190
+ def convert(
191
+ csv_dir: Path, db_path: Path, tables: list[str] | None, drop_existing: bool = False
192
+ ) -> dict:
193
+ """CSV 目录 → summary.db。返回逐表统计(供 stdout 摘要与调用方校验)。
194
+
195
+ 输出保护(检视 #1 修复):db_path 已存在时默认拒覆盖——现代 .npu-rep 解包
196
+ 目录的原生 summary.db 是 PcSampling(无 CSV 对应物,不可从 CSV 重建)的
197
+ 唯一载体,静默重建会打断 top_stall_pct → L0_STALL_DOMINANT 链路且无法
198
+ 恢复;确认覆盖须显式 --drop-existing。
199
+ """
200
+ csv_files = sorted(csv_dir.glob("*.csv"))
201
+ if tables:
202
+ wanted = {t.strip().lower() for t in tables if t.strip()}
203
+ csv_files = [p for p in csv_files if p.stem.lower() in wanted]
204
+ if not csv_files:
205
+ raise ValueError(f"目录无匹配 CSV: {csv_dir}(过滤 {tables})")
206
+
207
+ if db_path.exists():
208
+ if not drop_existing:
209
+ raise ValueError(
210
+ f"输出 DB 已存在: {db_path}(拒覆盖——若为 npu-compute 原生"
211
+ " summary.db,其 PcSampling 表不可从 CSV 重建;确认覆盖请加"
212
+ " --drop-existing,或另指定 --db 输出路径)"
213
+ )
214
+ db_path.unlink()
215
+ db_path.parent.mkdir(parents=True, exist_ok=True)
216
+ # DELETE journal:自包含单文件,无 -wal/-shm 伴随文件(npu-compute 同款)
217
+ db = sqlite3.connect(str(db_path))
218
+ try:
219
+ db.execute("PRAGMA journal_mode=DELETE")
220
+ db.execute(f"CREATE TABLE {UNIT_TABLE}(field_name TEXT PRIMARY KEY, unit TEXT)")
221
+ stats = {}
222
+ for csvf in csv_files:
223
+ table = csvf.stem
224
+ if table.lower() in RESERVED_TABLES:
225
+ raise ValueError(f"表名 {table} 为 npu-compute 保留名,拒建防冲突")
226
+ names, units, rows = read_csv_rows(csvf)
227
+ for name, unit in zip(names, units):
228
+ db.execute(
229
+ f"INSERT OR REPLACE INTO {UNIT_TABLE}(field_name, unit)"
230
+ " VALUES(?,?)",
231
+ (name, unit),
232
+ )
233
+ col_defs = []
234
+ for i, (name, _) in enumerate(zip(names, units)):
235
+ col_defs.append(f'"{name}" {sql_type([r[i] for r in rows])}')
236
+ db.execute(f'CREATE TABLE "{table}"(' + ", ".join(col_defs) + ")")
237
+ placeholders = ",".join("?" * len(names))
238
+ for r in rows:
239
+ vals = [
240
+ bind_value(r[i], col.split()[-1]) for i, col in enumerate(col_defs)
241
+ ]
242
+ db.execute(f'INSERT INTO "{table}" VALUES({placeholders})', vals)
243
+ stats[table] = {
244
+ "rows": len(rows),
245
+ "columns": len(names),
246
+ "csv": str(csvf),
247
+ }
248
+ db.commit()
249
+
250
+ # ---- 写入后回读校验(fail loud:行数漂移 = 转换 bug,不留半成品)----
251
+ for table, s in stats.items():
252
+ n = db.execute(f'SELECT COUNT(*) FROM "{table}"').fetchone()[0]
253
+ if n != s["rows"]:
254
+ raise ValueError(
255
+ f"表 {table} 回读行数 {n} ≠ 写入 {s['rows']}(转换错位)"
256
+ )
257
+ n_units = db.execute(f"SELECT COUNT(*) FROM {UNIT_TABLE}").fetchone()[0]
258
+ if n_units < len({u for s in stats.values() for u in [s["columns"]]}):
259
+ pass # FieldUnitMap 按列名去重(同名列共享一条),>= 表列数不成立为常态
260
+ finally:
261
+ db.close()
262
+ return stats
263
+
264
+
265
+ def main() -> int:
266
+ ap = argparse.ArgumentParser(
267
+ description="采集 CSV 目录 → npu-compute 兼容 summary.db(Roadmap #4 转换器)"
268
+ )
269
+ ap.add_argument(
270
+ "--csv-dir", required=True, help="CSV 产物目录(如 .npu-rep 解包目录)"
271
+ )
272
+ ap.add_argument(
273
+ "--db", required=True, help="输出 summary.db 路径(已存在时默认拒覆盖)"
274
+ )
275
+ ap.add_argument(
276
+ "--tables",
277
+ default=None,
278
+ help="逗号分隔 Section 表名过滤(缺省全部 CSV;PcSampling/FieldUnitMap 保留名拒建)",
279
+ )
280
+ ap.add_argument(
281
+ "--drop-existing",
282
+ action="store_true",
283
+ help="确认覆盖已存在的输出 DB(默认拒覆盖——原生 summary.db 的 PcSampling"
284
+ " 表不可从 CSV 重建,勿对现代 .npu-rep 解包目录原地覆盖)",
285
+ )
286
+ ap.add_argument("--quiet", action="store_true", help="只输出错误,不打印摘要")
287
+ args = ap.parse_args()
288
+
289
+ csv_dir = Path(args.csv_dir)
290
+ if not csv_dir.is_dir():
291
+ print(f"ERROR: --csv-dir 不是目录: {csv_dir}", file=sys.stderr)
292
+ return 1
293
+ try:
294
+ stats = convert(
295
+ csv_dir,
296
+ Path(args.db),
297
+ args.tables.split(",") if args.tables else None,
298
+ drop_existing=args.drop_existing,
299
+ )
300
+ except (ValueError, sqlite3.Error, OSError) as e:
301
+ print(f"ERROR: 转换失败: {e}", file=sys.stderr)
302
+ return 1
303
+
304
+ if not args.quiet:
305
+ print(f"[csv-to-db] {len(stats)} 表 ← {csv_dir}")
306
+ for table, s in stats.items():
307
+ print(f" {table}: {s['rows']} 行 × {s['columns']} 列")
308
+ print(f" {UNIT_TABLE}: 单位映射已写入")
309
+ print(f"[done] {args.db}")
310
+ return 0
311
+
312
+
313
+ if __name__ == "__main__":
314
+ sys.exit(main())