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.
- package/NOTICE.md +14 -0
- package/README.md +39 -2
- package/cordis.patch.yml +20 -0
- package/lib/client.js +4253 -0
- package/lib/host.js +2518 -0
- package/package.json +53 -4
- package/skills/tool-ops-tune/INSTALL.md +52 -0
- package/skills/tool-ops-tune/README.md +167 -0
- package/skills/tool-ops-tune/SKILL.md +93 -0
- package/skills/tool-ops-tune/agent/AGENTS.md +195 -0
- package/skills/tool-ops-tune/agent/agents/perf-implementer.md +68 -0
- package/skills/tool-ops-tune/agent/agents/perf-reviewer.md +86 -0
- package/skills/tool-ops-tune/agent/workflows/task-prompts.md +362 -0
- package/skills/tool-ops-tune/agent/workflows/troubleshooting.md +43 -0
- package/skills/tool-ops-tune/docs/figures/opstune-architecture.png +0 -0
- package/skills/tool-ops-tune/docs/figures/opstune-architecture.svg +253 -0
- package/skills/tool-ops-tune/docs/ops-tune-design.md +404 -0
- package/skills/tool-ops-tune/docs//347/224/250/344/276/213/346/236/204/345/273/272.md +714 -0
- package/skills/tool-ops-tune/docs//347/237/245/350/257/206/345/272/223/350/247/204/350/214/203.md +103 -0
- package/skills/tool-ops-tune/evals/evals.json +242 -0
- package/skills/tool-ops-tune/ops-collect/SKILL.md +146 -0
- package/skills/tool-ops-tune/ops-collect/references/tool-routing.md +86 -0
- package/skills/tool-ops-tune/ops-collect/scripts/collect_board.sh +444 -0
- package/skills/tool-ops-tune/ops-collect/scripts/collect_cases.py +368 -0
- package/skills/tool-ops-tune/ops-collect/scripts/collect_sim.sh +134 -0
- package/skills/tool-ops-tune/ops-collect/scripts/csv_to_db.py +314 -0
- package/skills/tool-ops-tune/ops-collect/scripts/db_bench.py +545 -0
- package/skills/tool-ops-tune/ops-collect/scripts/facts_bridge.py +1063 -0
- package/skills/tool-ops-tune/ops-collect/scripts/isolation_test.py +454 -0
- package/skills/tool-ops-tune/ops-collect/scripts/jsonl_to_cases.py +163 -0
- package/skills/tool-ops-tune/ops-family/SKILL.md +76 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/advanced_tiling.md +92 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/broadcast_design.md +160 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/code/broadcast_add_kernel.cpp +126 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/code/broadcast_add_tiling.cpp +144 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/code/broadcast_tiling_common.h +401 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/code/onedim_add_kernel.cpp +107 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/code/onedim_add_tiling.cpp +64 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/datacopypad_design.md +46 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/guide.md +14 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/nddma_design.md +53 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/onedim_design.md +114 -0
- package/skills/tool-ops-tune/ops-family/references/broadcast/ub_broadcast_design.md +67 -0
- package/skills/tool-ops-tune/ops-family/references/common/datacopy_optimization_design.md +351 -0
- package/skills/tool-ops-tune/ops-family/references/common/index.md +9 -0
- package/skills/tool-ops-tune/ops-family/references/common/tail_block_design.md +268 -0
- package/skills/tool-ops-tune/ops-family/references/common/timing_harness/index.md +38 -0
- package/skills/tool-ops-tune/ops-family/references/common/timing_harness/timing_harness_aclrt_event.cpp +199 -0
- package/skills/tool-ops-tune/ops-family/references/common/timing_harness/timing_harness_torch_event.py +130 -0
- package/skills/tool-ops-tune/ops-family/references/common/ub_resident_design.md +342 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/guide.md +69 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/index.md +4 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_base.template +81 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_big_dim.template +217 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_cut_one_axis.template +336 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_cut_two_axis.template +781 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_n_last.template +340 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_small_shape.template +321 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_tensor_move.template +102 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_transdata_5hd.template +480 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_transdata_5hd_021axis.template +533 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_with_gather.template +688 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/templates/transpose_tiling_data.template +192 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_big_dim.md +220 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_cut_one_axis.md +175 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_cut_two_axis.md +177 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_fusion_design.md +398 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_gather.md +191 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_n_last.md +276 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_small_shape.md +315 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_tensor_move.md +203 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_tiling_data.md +176 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_vconv_021.md +206 -0
- package/skills/tool-ops-tune/ops-family/references/conversion/transpose_vconv_5hd.md +179 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/double_buffer_design.md +288 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/guide.md +46 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/index.md +10 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/CMakeLists.txt +131 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/README.md +55 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/add_custom_torch.cpp +80 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/ops.h +23 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/register.cpp +30 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_host/add_custom.asc +149 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_host/data_utils.h +97 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_kernel/add_custom_kernel.asc +136 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_kernel/add_custom_tiling.h +31 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/run.sh +86 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/gen_data.py +70 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/golden.py +34 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/test_torch.py +99 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/verify_result.py +56 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/templates/usage_guide.md +61 -0
- package/skills/tool-ops-tune/ops-family/references/elementwise/vector_efficiency_design.md +203 -0
- package/skills/tool-ops-tune/ops-family/references/fa/fa_mixed_kernel_design.md +174 -0
- package/skills/tool-ops-tune/ops-family/references/fa/fa_roofline_design.md +141 -0
- package/skills/tool-ops-tune/ops-family/references/fa/guide.md +87 -0
- package/skills/tool-ops-tune/ops-family/references/knowledge_gaps.json +56 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/best-practices-guide.md +14 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/fullload_design.md +344 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/guide.md +52 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/mte2_preload_design.md +320 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/pingpong_design.md +254 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/scale_coalescing_design.md +282 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/streamk_design.md +374 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/swat_design.md +423 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/templates/matmul_basic_blaze.template +165 -0
- package/skills/tool-ops-tune/ops-family/references/matmul/templates/usage_guide.md +29 -0
- package/skills/tool-ops-tune/ops-family/references/mc2/best-practices-guide.md +43 -0
- package/skills/tool-ops-tune/ops-family/references/mc2/guide.md +42 -0
- package/skills/tool-ops-tune/ops-family/references/mc2/local_matmul_design.md +130 -0
- package/skills/tool-ops-tune/ops-family/references/mc2/pipeline_balancing_design.md +502 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/guide.md +178 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/kernel_utils.template +75 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_full_load.template +429 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_recompute.template +485 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_small_r.template +348 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_full_load.template +574 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_online.template +324 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_recompute.template +436 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_base.template +950 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/fused_attention_online_softmax_design.md +428 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_full_load.md +137 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_recompute.md +135 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_small_r.md +122 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_full_load.md +144 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_online.md +185 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_recompute.md +163 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_tiling.template +460 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_tiling_data.template +278 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/state_resident_design.md +337 -0
- package/skills/tool-ops-tune/ops-family/references/reduce/templates/usage_guide.md +253 -0
- package/skills/tool-ops-tune/ops-family/references/scalar/coding_principles.md +476 -0
- package/skills/tool-ops-tune/ops-family/references/scalar/conv_scalar.md +163 -0
- package/skills/tool-ops-tune/ops-family/references/scalar/guide.md +30 -0
- package/skills/tool-ops-tune/ops-family/references/simt/guide.md +91 -0
- package/skills/tool-ops-tune/ops-family/references/simt/optimization-guide.md +110 -0
- package/skills/tool-ops-tune/ops-family/references/sort/guide.md +83 -0
- package/skills/tool-ops-tune/ops-family/references/sort/radix_sort.md +354 -0
- package/skills/tool-ops-tune/ops-family/scripts/family_asset_audit.py +68 -0
- package/skills/tool-ops-tune/ops-family/scripts/tiling_candidates.py +419 -0
- package/skills/tool-ops-tune/ops-mechanism/SKILL.md +23 -0
- package/skills/tool-ops-tune/ops-mechanism/cases/ascendc/case_groupedmatmul_pipeline.md +23 -0
- package/skills/tool-ops-tune/ops-mechanism/cases/ascendc/case_triton_atomic_revert.md +19 -0
- package/skills/tool-ops-tune/ops-mechanism/cases/mc2/case_mc2_fusion.md +19 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/api-usage.md +70 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/ascendc-regbase-vf.md +45 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/ascendc-tiling.md +51 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/data-copy.md +67 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/index.md +45 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/mc2-balancing.md +77 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/mc2.md +103 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/memory-hierarchy.md +40 -0
- package/skills/tool-ops-tune/ops-mechanism/references/optimize/pipeline.md +95 -0
- package/skills/tool-ops-tune/ops-mechanism/scripts/case_backfill.py +170 -0
- package/skills/tool-ops-tune/ops-mechanism/scripts/log_gap.py +145 -0
- package/skills/tool-ops-tune/ops-mechanism/scripts/mc2_search.py +367 -0
- package/skills/tool-ops-tune/ops-report/SKILL.md +77 -0
- package/skills/tool-ops-tune/ops-verdict/evals/run_evals.py +837 -0
- package/skills/tool-ops-tune/ops-verdict/evals/smoke/install-hooks.sh +65 -0
- package/skills/tool-ops-tune/ops-verdict/evals/smoke/run_smoke.sh +405 -0
- package/skills/tool-ops-tune/ops-verdict/fixtures/core_tail_a5.csv +25 -0
- package/skills/tool-ops-tune/ops-verdict/fixtures/few_cores_a5.csv +5 -0
- package/skills/tool-ops-tune/ops-verdict/fixtures/mte2_bound_a2.csv +17 -0
- package/skills/tool-ops-tune/ops-verdict/fixtures/multi_kernel_mix_a5.csv +7 -0
- package/skills/tool-ops-tune/ops-verdict/fixtures/no_bound_a5.csv +9 -0
- package/skills/tool-ops-tune/ops-verdict/fixtures/serial_no_overlap_a2.csv +9 -0
- package/skills/tool-ops-tune/ops-verdict/fixtures/vec_bound_a5.csv +9 -0
- package/skills/tool-ops-tune/ops-verdict/references/io-contracts.md +94 -0
- package/skills/tool-ops-tune/ops-verdict/references/rule-schema.md +130 -0
- package/skills/tool-ops-tune/ops-verdict/references/scope-schema.md +61 -0
- package/skills/tool-ops-tune/ops-verdict/references/soc-spec.yaml +140 -0
- package/skills/tool-ops-tune/ops-verdict/rules/L0-instruction.yaml +67 -0
- package/skills/tool-ops-tune/ops-verdict/rules/L1-single-core.yaml +316 -0
- package/skills/tool-ops-tune/ops-verdict/rules/L2-inter-core.yaml +173 -0
- package/skills/tool-ops-tune/ops-verdict/rules/L3-inter-card.yaml +156 -0
- package/skills/tool-ops-tune/ops-verdict/scripts/batch_pipeline.py +444 -0
- package/skills/tool-ops-tune/ops-verdict/scripts/calibrate.py +249 -0
- package/skills/tool-ops-tune/ops-verdict/scripts/delta_compare.py +244 -0
- package/skills/tool-ops-tune/ops-verdict/scripts/render_html.py +274 -0
- package/skills/tool-ops-tune/ops-verdict/scripts/snapshot.py +200 -0
- package/skills/tool-ops-tune/ops-verdict/scripts/trace_bubble.py +331 -0
- package/skills/tool-ops-tune/ops-verdict/scripts/verdict.py +1072 -0
- package/skills/tool-ops-tune/scripts/diff_audit.py +281 -0
|
@@ -0,0 +1,545 @@
|
|
|
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
|
+
"""db_bench.py — CSV vs summary.db 消费性能基准(Roadmap #4「查询更快」的验证载体)
|
|
13
|
+
|
|
14
|
+
目的:把「DB 格式比读 CSV 快」从口号变成**可复跑、带等价性门禁的实测数字**。
|
|
15
|
+
- 数字只在套件真实消费形态下测(不测与消费无关的极端形态):
|
|
16
|
+
W1 facts 标量提取 — facts_bridge 核心形态(逐 Section 目标列 mean,
|
|
17
|
+
NA 剔除在 CSV 侧由 Python 完成 / DB 侧由 WHERE IS NOT NULL 下推)
|
|
18
|
+
W2 verdict 全表加载 — verdict.py 形态(整表 dict 化喂规则引擎)
|
|
19
|
+
W3 分析查询批 — 报告/复盘形态(AVG/MAX/MIN/SUM/COUNT/过滤 6 条)
|
|
20
|
+
W4 PcSampling stall 分布 — L0 判定形态(DB 独有,CSV 通道标 N/A)
|
|
21
|
+
- **等价性断言是正确性门禁**:W1-W3 双通道数值必须相等(容差 1e-9),
|
|
22
|
+
不等 = 转换或查询 bug → exit 1(提速数字不作门禁——机器相关)。
|
|
23
|
+
- 提速比如实逐负载呈现:DB 并非处处更快(W2 全表 dict 化实测 DB 更慢,
|
|
24
|
+
SQLite 行对象化开销 > csv.DictReader)——报告如实写慢,不粉饰。
|
|
25
|
+
|
|
26
|
+
用法:
|
|
27
|
+
python3 db_bench.py --dir <npu-compute 解包目录> [-o report.json] [--repeat 30]
|
|
28
|
+
目录无 summary.db 时自动 csv_to_db.py 构造(等价性门禁即转换器校验)。
|
|
29
|
+
|
|
30
|
+
输出(opstune.db-bench/1.0):
|
|
31
|
+
{ "workloads": {W1..W4: {csv_ms, db_ms, speedup, csv_value, db_value, equivalent}},
|
|
32
|
+
"report": {...行数/列数/输入摘要...} }
|
|
33
|
+
退出码:0 全绿(等价全过)/ 1 等价性失败或输入错误。
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
import argparse
|
|
39
|
+
import csv
|
|
40
|
+
import json
|
|
41
|
+
import sqlite3
|
|
42
|
+
import statistics
|
|
43
|
+
import subprocess
|
|
44
|
+
import sys
|
|
45
|
+
import tempfile
|
|
46
|
+
import time
|
|
47
|
+
from pathlib import Path
|
|
48
|
+
|
|
49
|
+
SCHEMA = "opstune.db-bench/1.0"
|
|
50
|
+
HERE = Path(__file__).resolve().parent
|
|
51
|
+
CSV_TO_DB = HERE / "csv_to_db.py"
|
|
52
|
+
UNIT_TABLE = "FieldUnitMap"
|
|
53
|
+
SECTIONS = (
|
|
54
|
+
"PipeUtilization",
|
|
55
|
+
"L2Cache",
|
|
56
|
+
"ArithmeticUtilization",
|
|
57
|
+
"ResourceConflictRatio",
|
|
58
|
+
"Memory",
|
|
59
|
+
"MemoryL0",
|
|
60
|
+
"MemoryUB",
|
|
61
|
+
)
|
|
62
|
+
# W1 标量提取契约(每 Section 一个语义明确的标量;csv 侧带单位后缀 / db 侧为
|
|
63
|
+
# 规范化名,两通道候选序列必须同语义序——等价性门禁的比对基准)
|
|
64
|
+
W1_COLUMNS = {
|
|
65
|
+
"PipeUtilization": (
|
|
66
|
+
["aiv_vec_ratio", "aic_vec_ratio"],
|
|
67
|
+
["aiv_vec_ratio", "aic_vec_ratio"],
|
|
68
|
+
),
|
|
69
|
+
"L2Cache": (
|
|
70
|
+
["aiv_read_hit_rate", "aic_read_hit_rate"],
|
|
71
|
+
["aiv_read_hit_rate(%)", "aic_read_hit_rate(%)"],
|
|
72
|
+
),
|
|
73
|
+
}
|
|
74
|
+
# W3 查询批(全部落 PipeUtilization + L2Cache,与报告/复盘消费一致)。
|
|
75
|
+
# 契约元组:(标签, DB SQL, CSV 等价所需 Section, 规范化列, CSV 带单位后缀列)
|
|
76
|
+
W3_QUERIES = (
|
|
77
|
+
(
|
|
78
|
+
"AVG(aiv_vec_ratio) | PipeUtilization",
|
|
79
|
+
"SELECT AVG(aiv_vec_ratio) FROM PipeUtilization WHERE aiv_vec_ratio IS NOT NULL",
|
|
80
|
+
("PipeUtilization", "aiv_vec_ratio", "aiv_vec_ratio"),
|
|
81
|
+
),
|
|
82
|
+
(
|
|
83
|
+
"MAX/MIN(aiv_mte2_ratio) | PipeUtilization",
|
|
84
|
+
"SELECT MAX(aiv_mte2_ratio), MIN(aiv_mte2_ratio) FROM PipeUtilization",
|
|
85
|
+
("PipeUtilization", "aiv_mte2_ratio", "aiv_mte2_ratio"),
|
|
86
|
+
),
|
|
87
|
+
(
|
|
88
|
+
"SUM(aiv_read_close_miss) | L2Cache",
|
|
89
|
+
"SELECT SUM(aiv_read_close_miss) FROM L2Cache",
|
|
90
|
+
("L2Cache", "aiv_read_close_miss", "aiv_read_close_miss"),
|
|
91
|
+
),
|
|
92
|
+
(
|
|
93
|
+
"MAX(aiv_time)-MIN(aiv_time) | PipeUtilization",
|
|
94
|
+
"SELECT MAX(aiv_time) - MIN(aiv_time) FROM PipeUtilization",
|
|
95
|
+
("PipeUtilization", "aiv_time", "aiv_time(us)"),
|
|
96
|
+
),
|
|
97
|
+
(
|
|
98
|
+
"COUNT(aiv_vec_ratio>0.5) | PipeUtilization",
|
|
99
|
+
"SELECT COUNT(*) FROM PipeUtilization WHERE aiv_vec_ratio > 0.5",
|
|
100
|
+
("PipeUtilization", "aiv_vec_ratio", "aiv_vec_ratio"),
|
|
101
|
+
),
|
|
102
|
+
(
|
|
103
|
+
"AVG(aic_scalar_ratio) | PipeUtilization",
|
|
104
|
+
"SELECT AVG(aic_scalar_ratio) FROM PipeUtilization WHERE aic_scalar_ratio IS NOT NULL",
|
|
105
|
+
("PipeUtilization", "aic_scalar_ratio", "aic_scalar_ratio"),
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
STALL_COLUMNS = (
|
|
109
|
+
"ibuf_empty",
|
|
110
|
+
"nop_cycles",
|
|
111
|
+
"scoreboard_not_ready",
|
|
112
|
+
"register_bank_conflict",
|
|
113
|
+
"resource_conflict",
|
|
114
|
+
"warp_level_sync",
|
|
115
|
+
"divergence_stack_spill",
|
|
116
|
+
"others",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def open_ro(db_path: Path) -> sqlite3.Connection:
|
|
121
|
+
return sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def table_columns(db: sqlite3.Connection, table: str) -> set[str]:
|
|
125
|
+
"""实际列集合(PRAGMA 先验)——SQLite 对双引号未知标识符按字符串字面量
|
|
126
|
+
处理(AVG('不存在的列') 合法且返回 0.0,不报错!),「列不存在」不能交给
|
|
127
|
+
OperationalError 判定(检视 #4 修复,facts_bridge._table_columns 同款)。"""
|
|
128
|
+
return {d[1] for d in db.execute(f'PRAGMA table_info("{table}")')}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def median_ms(fn, repeat: int) -> float:
|
|
132
|
+
ts = []
|
|
133
|
+
for _ in range(repeat):
|
|
134
|
+
t0 = time.perf_counter()
|
|
135
|
+
fn()
|
|
136
|
+
ts.append((time.perf_counter() - t0) * 1000.0)
|
|
137
|
+
return round(statistics.median(ts), 3)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ---------------------------------------------------------------- W1: facts 标量提取
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def w1_csv(data_dir: Path) -> dict[str, float]:
|
|
144
|
+
"""逐 Section 目标列 mean(候选列首个可解析者),NA 剔除。"""
|
|
145
|
+
out = {}
|
|
146
|
+
for section, (db_cols, csv_cols) in W1_COLUMNS.items():
|
|
147
|
+
path = data_dir / f"{section}.csv"
|
|
148
|
+
if not path.exists():
|
|
149
|
+
continue
|
|
150
|
+
with open(path, encoding="utf-8-sig", errors="replace") as f:
|
|
151
|
+
rows = list(csv.DictReader(f))
|
|
152
|
+
vals = []
|
|
153
|
+
for r in rows:
|
|
154
|
+
for col in csv_cols:
|
|
155
|
+
v = str(r.get(col) or "").strip()
|
|
156
|
+
if v not in ("", "NA", "N/A", "-"):
|
|
157
|
+
try:
|
|
158
|
+
vals.append(float(v.replace("%", "")))
|
|
159
|
+
except ValueError:
|
|
160
|
+
continue
|
|
161
|
+
break
|
|
162
|
+
if vals:
|
|
163
|
+
out[section] = sum(vals) / len(vals)
|
|
164
|
+
return out
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def w1_db(db_path: Path) -> dict[str, float]:
|
|
168
|
+
"""同标量 DB 通道:COALESCE 逐行回退后 AVG——与 w1_csv 的逐行取首个
|
|
169
|
+
可解析候选列**同语义**(检视 #5 修复:此前按列取首个有值列整列求均值,
|
|
170
|
+
aiv_*/aic_* 部分行 NULL 的混排 Section 下两通道必然分叉,门禁误报)。
|
|
171
|
+
|
|
172
|
+
单列形态退化为该列 AVG(COALESCE 至少两参——列集过滤后只剩一列时
|
|
173
|
+
直接单列聚合,语义等价:逐行回退的候选序里只有一个可解析源)。"""
|
|
174
|
+
out = {}
|
|
175
|
+
db = open_ro(db_path)
|
|
176
|
+
try:
|
|
177
|
+
for section, (db_cols, _) in W1_COLUMNS.items():
|
|
178
|
+
# 列存在性 PRAGMA 先验(检视 #4):双引号未知列不报错而返回 0.0
|
|
179
|
+
actual = table_columns(db, section)
|
|
180
|
+
present = [c for c in db_cols if c in actual]
|
|
181
|
+
if not present:
|
|
182
|
+
continue
|
|
183
|
+
if len(present) == 1:
|
|
184
|
+
col = present[0]
|
|
185
|
+
v = db.execute(
|
|
186
|
+
f'SELECT AVG("{col}") FROM "{section}" WHERE "{col}" IS NOT NULL'
|
|
187
|
+
).fetchone()[0]
|
|
188
|
+
else:
|
|
189
|
+
coalesce = ", ".join(f'"{c}"' for c in present)
|
|
190
|
+
v = db.execute(
|
|
191
|
+
f"SELECT AVG(COALESCE({coalesce})) FROM"
|
|
192
|
+
f' "{section}" WHERE COALESCE({coalesce}) IS NOT NULL'
|
|
193
|
+
).fetchone()[0]
|
|
194
|
+
if v is not None:
|
|
195
|
+
out[section] = v
|
|
196
|
+
finally:
|
|
197
|
+
db.close()
|
|
198
|
+
return out
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# ---------------------------------------------------------------- W2: verdict 全表加载
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def w2_csv(data_dir: Path, table: str) -> list[dict]:
|
|
205
|
+
with open(data_dir / f"{table}.csv", encoding="utf-8-sig", errors="replace") as f:
|
|
206
|
+
return list(csv.DictReader(f))
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def w2_db(db_path: Path, table: str) -> list[dict]:
|
|
210
|
+
"""行 dict 化 + FieldUnitMap 还原单位后缀键名(verdict --db 同款加载器)。"""
|
|
211
|
+
db = open_ro(db_path)
|
|
212
|
+
try:
|
|
213
|
+
units = dict(db.execute(f"SELECT field_name, unit FROM {UNIT_TABLE}"))
|
|
214
|
+
cur = db.execute(f'SELECT * FROM "{table}" ORDER BY rowid')
|
|
215
|
+
names = [d[0] for d in cur.description]
|
|
216
|
+
keys = [f"{n}({units[n]})" if units.get(n) else n for n in names]
|
|
217
|
+
return [
|
|
218
|
+
{k: ("NA" if v is None else v) for k, v in zip(keys, row)}
|
|
219
|
+
for row in cur.fetchall()
|
|
220
|
+
]
|
|
221
|
+
finally:
|
|
222
|
+
db.close()
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# ---------------------------------------------------------------- W3: 分析查询批
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def w3_csv(data_dir: Path) -> dict[str, float]:
|
|
229
|
+
"""6 条查询的 CSV 等价实现(只解析所需 Section,与消费语义一致)。
|
|
230
|
+
|
|
231
|
+
缺 Section 文件按「无数据」跳过(检视 #2 修复:Section 子集目录——
|
|
232
|
+
npu-compute --sections 追加可能只采部分 Section——不再 FileNotFoundError
|
|
233
|
+
traceback,与 w1_csv 容错同款)。
|
|
234
|
+
"""
|
|
235
|
+
needed: dict[str, list[str]] = {}
|
|
236
|
+
for _, _, (section, _, csv_col) in W3_QUERIES:
|
|
237
|
+
needed.setdefault(section, []).append(csv_col)
|
|
238
|
+
loaded = {}
|
|
239
|
+
for section, _cols in needed.items():
|
|
240
|
+
section_csv = data_dir / f"{section}.csv"
|
|
241
|
+
if not section_csv.exists():
|
|
242
|
+
continue
|
|
243
|
+
with open(section_csv, encoding="utf-8-sig", errors="replace") as f:
|
|
244
|
+
loaded[section] = list(csv.DictReader(f))
|
|
245
|
+
out = {}
|
|
246
|
+
for label, _, (section, _db_col, csv_col) in W3_QUERIES:
|
|
247
|
+
if section not in loaded:
|
|
248
|
+
continue # Section 缺失:该查询双通道都按「无数据」处理(DB 侧同理跳过)
|
|
249
|
+
rows = loaded[section]
|
|
250
|
+
vals = []
|
|
251
|
+
for r in rows:
|
|
252
|
+
v = str(r.get(csv_col) or "").strip()
|
|
253
|
+
if v not in ("", "NA", "N/A", "-"):
|
|
254
|
+
try:
|
|
255
|
+
vals.append(float(v.replace("%", "")))
|
|
256
|
+
except ValueError:
|
|
257
|
+
continue
|
|
258
|
+
if "AVG" in label:
|
|
259
|
+
out[label] = sum(vals) / len(vals) if vals else None
|
|
260
|
+
elif "MAX/MIN" in label:
|
|
261
|
+
out[label] = (max(vals), min(vals)) if vals else None
|
|
262
|
+
elif "SUM" in label:
|
|
263
|
+
out[label] = sum(vals) if vals else None
|
|
264
|
+
elif "MAX(aiv_time)-MIN" in label:
|
|
265
|
+
out[label] = max(vals) - min(vals) if vals else None
|
|
266
|
+
elif "COUNT" in label:
|
|
267
|
+
out[label] = float(sum(1 for v in vals if v > 0.5))
|
|
268
|
+
return out
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def w3_db(db_path: Path) -> dict[str, float]:
|
|
272
|
+
"""DB 通道查询批:列存在性 PRAGMA 先验(检视 #4)+ Section 缺失同跳过。"""
|
|
273
|
+
db = open_ro(db_path)
|
|
274
|
+
try:
|
|
275
|
+
out = {}
|
|
276
|
+
for label, sql, (section, db_col, _) in W3_QUERIES:
|
|
277
|
+
# 缺 Section 表 / 缺列:按「无数据」跳过(与 w3_csv 的容错一致;
|
|
278
|
+
# 不交给 OperationalError——双引号未知列在启用 double-quoted-string
|
|
279
|
+
# misfeature 的构建上不报错而返回 0.0/列名字符串,门禁会被污染)
|
|
280
|
+
actual = table_columns(db, section)
|
|
281
|
+
if db_col not in actual:
|
|
282
|
+
continue
|
|
283
|
+
row = db.execute(sql).fetchone()
|
|
284
|
+
if "MAX/MIN" in label:
|
|
285
|
+
out[label] = tuple(row)
|
|
286
|
+
else:
|
|
287
|
+
out[label] = row[0]
|
|
288
|
+
return out
|
|
289
|
+
finally:
|
|
290
|
+
db.close()
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# ---------------------------------------------------------------- W4: PcSampling
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def w4_db(db_path: Path) -> dict | None:
|
|
297
|
+
"""stall 分布(DB 独有;白名单防表结构演进引入非 stall 列污染)。"""
|
|
298
|
+
db = open_ro(db_path)
|
|
299
|
+
try:
|
|
300
|
+
tables = {
|
|
301
|
+
r[0]
|
|
302
|
+
for r in db.execute("SELECT name FROM sqlite_master WHERE type='table'")
|
|
303
|
+
}
|
|
304
|
+
if "PcSampling" not in tables:
|
|
305
|
+
return None
|
|
306
|
+
cur = db.execute("SELECT * FROM PcSampling")
|
|
307
|
+
cols = [d[0] for d in cur.description]
|
|
308
|
+
rows = cur.fetchall()
|
|
309
|
+
finally:
|
|
310
|
+
db.close()
|
|
311
|
+
if not rows:
|
|
312
|
+
return None
|
|
313
|
+
agg = {c: 0.0 for c in STALL_COLUMNS if c in cols}
|
|
314
|
+
for row in rows:
|
|
315
|
+
for c, v in zip(cols, row):
|
|
316
|
+
if c in agg:
|
|
317
|
+
agg[c] += float(v or 0)
|
|
318
|
+
total = sum(agg.values())
|
|
319
|
+
if total <= 0:
|
|
320
|
+
return None
|
|
321
|
+
dist = {
|
|
322
|
+
c: round(v / total * 100, 2)
|
|
323
|
+
for c, v in sorted(agg.items(), key=lambda kv: -kv[1])
|
|
324
|
+
}
|
|
325
|
+
top = max(dist, key=dist.get)
|
|
326
|
+
return {
|
|
327
|
+
"samples_total": int(total),
|
|
328
|
+
"address_rows": len(rows),
|
|
329
|
+
"top_stall": top,
|
|
330
|
+
"top_stall_pct": dist[top],
|
|
331
|
+
"distribution_pct": dist,
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def close_enough(a, b, tol: float = 1e-9) -> bool:
|
|
336
|
+
if a is None and b is None:
|
|
337
|
+
return True
|
|
338
|
+
if isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)):
|
|
339
|
+
return len(a) == len(b) and all(close_enough(x, y, tol) for x, y in zip(a, b))
|
|
340
|
+
if isinstance(a, (int, float)) and isinstance(b, (int, float)):
|
|
341
|
+
return abs(float(a) - float(b)) <= tol
|
|
342
|
+
return a == b
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def main() -> int:
|
|
346
|
+
ap = argparse.ArgumentParser(
|
|
347
|
+
description="CSV vs summary.db 消费性能基准(等价性门禁 + 提速比实测)"
|
|
348
|
+
)
|
|
349
|
+
ap.add_argument(
|
|
350
|
+
"--dir",
|
|
351
|
+
required=True,
|
|
352
|
+
help="npu-compute 解包目录(含 Section CSV;无 summary.db 时自动转换构造)",
|
|
353
|
+
)
|
|
354
|
+
ap.add_argument(
|
|
355
|
+
"--db",
|
|
356
|
+
default=None,
|
|
357
|
+
help="对照 summary.db 路径(缺省 <dir>/summary.db;不存在则 csv_to_db 构造)",
|
|
358
|
+
)
|
|
359
|
+
ap.add_argument(
|
|
360
|
+
"--repeat",
|
|
361
|
+
type=int,
|
|
362
|
+
default=30,
|
|
363
|
+
help="每负载重复次数(取中位数;冒烟场景可 --repeat 3)",
|
|
364
|
+
)
|
|
365
|
+
ap.add_argument(
|
|
366
|
+
"--table", default="PipeUtilization", help="W2 全表加载的目标表(缺省主输入)"
|
|
367
|
+
)
|
|
368
|
+
ap.add_argument("-o", "--output", default=None, help="report JSON 输出路径")
|
|
369
|
+
args = ap.parse_args()
|
|
370
|
+
|
|
371
|
+
data_dir = Path(args.dir)
|
|
372
|
+
if not data_dir.is_dir():
|
|
373
|
+
print(f"ERROR: --dir 不是目录: {data_dir}", file=sys.stderr)
|
|
374
|
+
return 1
|
|
375
|
+
if not (data_dir / f"{args.table}.csv").exists():
|
|
376
|
+
print(
|
|
377
|
+
f"ERROR: 目录缺 {args.table}.csv(非 7 组 Section 解包形态——PmSampling 专项报告"
|
|
378
|
+
"(如 verify_pipeline_pm.npu-rep)只有 summary.db/objdump,无 Section CSV;"
|
|
379
|
+
"PcSampling 的消费链走 facts_bridge --db,不经本基准): {data_dir}",
|
|
380
|
+
file=sys.stderr,
|
|
381
|
+
)
|
|
382
|
+
return 1
|
|
383
|
+
repeat = max(1, args.repeat)
|
|
384
|
+
|
|
385
|
+
db_path = Path(args.db) if args.db else data_dir / "summary.db"
|
|
386
|
+
built = False
|
|
387
|
+
if not db_path.exists():
|
|
388
|
+
tmp = Path(tempfile.mkdtemp(prefix="db-bench-"))
|
|
389
|
+
db_path = tmp / "summary.db"
|
|
390
|
+
p = subprocess.run(
|
|
391
|
+
[
|
|
392
|
+
sys.executable,
|
|
393
|
+
str(CSV_TO_DB),
|
|
394
|
+
"--csv-dir",
|
|
395
|
+
str(data_dir),
|
|
396
|
+
"--db",
|
|
397
|
+
str(db_path),
|
|
398
|
+
"--quiet",
|
|
399
|
+
],
|
|
400
|
+
capture_output=True,
|
|
401
|
+
text=True,
|
|
402
|
+
)
|
|
403
|
+
if p.returncode != 0:
|
|
404
|
+
print(f"ERROR: csv_to_db 构造失败: {p.stderr.strip()}", file=sys.stderr)
|
|
405
|
+
return 1
|
|
406
|
+
built = True
|
|
407
|
+
|
|
408
|
+
# ---- W1:facts 标量提取 ----
|
|
409
|
+
w1_c = median_ms(lambda: w1_csv(data_dir), repeat)
|
|
410
|
+
w1_d = median_ms(lambda: w1_db(db_path), repeat)
|
|
411
|
+
w1_csv_v, w1_db_v = w1_csv(data_dir), w1_db(db_path)
|
|
412
|
+
w1_eq = all(
|
|
413
|
+
section in w1_db_v and close_enough(v, w1_db_v[section])
|
|
414
|
+
for section, v in w1_csv_v.items()
|
|
415
|
+
) and set(w1_csv_v) == set(w1_db_v)
|
|
416
|
+
|
|
417
|
+
# ---- W2:verdict 全表加载 ----
|
|
418
|
+
w2_c = median_ms(lambda: w2_csv(data_dir, args.table), repeat)
|
|
419
|
+
w2_d = median_ms(lambda: w2_db(db_path, args.table), repeat)
|
|
420
|
+
w2_rows_c, w2_rows_d = w2_csv(data_dir, args.table), w2_db(db_path, args.table)
|
|
421
|
+
|
|
422
|
+
# 数值经 DB REAL 化后失去字符串尾零('36.787880' vs 36.78788)——比对按
|
|
423
|
+
# 数值语义(parse_float 同款容差),非字符串字面
|
|
424
|
+
def _num_or_na(v):
|
|
425
|
+
s = str(v).strip()
|
|
426
|
+
if s in ("", "NA", "N/A", "-"):
|
|
427
|
+
return None
|
|
428
|
+
try:
|
|
429
|
+
return float(s.replace("%", ""))
|
|
430
|
+
except ValueError:
|
|
431
|
+
return s
|
|
432
|
+
|
|
433
|
+
w2_eq = len(w2_rows_c) == len(w2_rows_d) and all(
|
|
434
|
+
_num_or_na(csv_row.get("aiv_time(us)"))
|
|
435
|
+
== _num_or_na(db_row.get("aiv_time(us)"))
|
|
436
|
+
and _num_or_na(csv_row.get("aiv_vec_ratio"))
|
|
437
|
+
== _num_or_na(db_row.get("aiv_vec_ratio"))
|
|
438
|
+
for csv_row, db_row in zip(w2_rows_c, w2_rows_d)
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
# ---- W3:分析查询批 ----
|
|
442
|
+
w3_c = median_ms(lambda: w3_csv(data_dir), repeat)
|
|
443
|
+
w3_d = median_ms(lambda: w3_db(db_path), repeat)
|
|
444
|
+
w3_csv_v, w3_db_v = w3_csv(data_dir), w3_db(db_path)
|
|
445
|
+
# 等价比对按双通道共同命中集合(Section 子集目录各自缺列时按交集断言;
|
|
446
|
+
# 全 7 组目录下两集合应当一致)
|
|
447
|
+
common_w3 = set(w3_csv_v) & set(w3_db_v)
|
|
448
|
+
w3_eq = bool(common_w3) and all(
|
|
449
|
+
close_enough(w3_csv_v[k], w3_db_v[k]) for k in common_w3
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
# ---- W4:PcSampling(DB 独有)----
|
|
453
|
+
w4 = w4_db(db_path)
|
|
454
|
+
w4_d = median_ms(lambda: w4_db(db_path), repeat) if w4 else None
|
|
455
|
+
|
|
456
|
+
def ratio(c: float, d: float | None) -> float | None:
|
|
457
|
+
return round(c / d, 2) if d and d > 0 else None
|
|
458
|
+
|
|
459
|
+
workloads = {
|
|
460
|
+
"W1-facts-scalar-extract": {
|
|
461
|
+
"desc": "facts_bridge 核心形态:逐 Section 目标列 mean",
|
|
462
|
+
"csv_ms": w1_c,
|
|
463
|
+
"db_ms": w1_d,
|
|
464
|
+
"speedup_csv_over_db": ratio(w1_c, w1_d),
|
|
465
|
+
"csv_value": w1_csv_v,
|
|
466
|
+
"db_value": w1_db_v,
|
|
467
|
+
"equivalent": w1_eq,
|
|
468
|
+
},
|
|
469
|
+
"W2-verdict-full-load": {
|
|
470
|
+
"desc": f"verdict.py 形态:{args.table} 全表 dict 化(DB 行对象化有额外开销,如实呈现)",
|
|
471
|
+
"csv_ms": w2_c,
|
|
472
|
+
"db_ms": w2_d,
|
|
473
|
+
"speedup_csv_over_db": ratio(w2_c, w2_d),
|
|
474
|
+
"rows": len(w2_rows_c),
|
|
475
|
+
"equivalent": w2_eq,
|
|
476
|
+
},
|
|
477
|
+
"W3-analytical-batch": {
|
|
478
|
+
"desc": "报告/复盘形态:AVG/MAX/MIN/SUM/COUNT/过滤 6 条",
|
|
479
|
+
"csv_ms": w3_c,
|
|
480
|
+
"db_ms": w3_d,
|
|
481
|
+
"speedup_csv_over_db": ratio(w3_c, w3_d),
|
|
482
|
+
"csv_value": w3_csv_v,
|
|
483
|
+
"db_value": w3_db_v,
|
|
484
|
+
"equivalent": w3_eq,
|
|
485
|
+
},
|
|
486
|
+
"W4-pcsampling-dist": {
|
|
487
|
+
"desc": "L0 判定形态:PcSampling stall 分布(DB 独有,无 CSV 对应物)",
|
|
488
|
+
"csv_ms": None,
|
|
489
|
+
"db_ms": w4_d,
|
|
490
|
+
"speedup_csv_over_db": None,
|
|
491
|
+
"db_value": w4,
|
|
492
|
+
"equivalent": True,
|
|
493
|
+
},
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
row_counts = {}
|
|
497
|
+
for s in SECTIONS:
|
|
498
|
+
if (data_dir / f"{s}.csv").exists():
|
|
499
|
+
with open(data_dir / f"{s}.csv", encoding="utf-8-sig") as f:
|
|
500
|
+
row_counts[s] = max(0, sum(1 for _ in f) - 1)
|
|
501
|
+
report = {
|
|
502
|
+
"schema": SCHEMA,
|
|
503
|
+
"dir": str(data_dir),
|
|
504
|
+
"db_path": str(db_path),
|
|
505
|
+
"db_built_by_bench": built,
|
|
506
|
+
"repeat": repeat,
|
|
507
|
+
"row_counts": row_counts,
|
|
508
|
+
"workloads": workloads,
|
|
509
|
+
"all_equivalent": all(w["equivalent"] for w in workloads.values()),
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
print(
|
|
513
|
+
f"[db-bench] dir={data_dir} rows={row_counts} repeat={repeat} db_built={built}"
|
|
514
|
+
)
|
|
515
|
+
for name, w in workloads.items():
|
|
516
|
+
sp = w.get("speedup_csv_over_db")
|
|
517
|
+
sp_text = f"speedup={sp}x" if sp is not None else "—"
|
|
518
|
+
print(
|
|
519
|
+
f" {name}: csv={w['csv_ms']}ms db={w['db_ms']}ms {sp_text} equivalent={w['equivalent']}"
|
|
520
|
+
)
|
|
521
|
+
if w4:
|
|
522
|
+
print(
|
|
523
|
+
f" W4 top_stall: {w4['top_stall']}={w4['top_stall_pct']}% (samples={w4['samples_total']})"
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
if args.output:
|
|
527
|
+
out = Path(args.output)
|
|
528
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
529
|
+
out.write_text(
|
|
530
|
+
json.dumps(report, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
|
|
531
|
+
)
|
|
532
|
+
print(f"[done] {out}")
|
|
533
|
+
|
|
534
|
+
if not report["all_equivalent"]:
|
|
535
|
+
print(
|
|
536
|
+
"ERROR: 等价性断言失败——双通道数值不一致,转换器或查询实现有 bug,禁止引用本数字",
|
|
537
|
+
file=sys.stderr,
|
|
538
|
+
)
|
|
539
|
+
return 1
|
|
540
|
+
print("[gate] 等价性全过(W1-W3 双通道数值一致)")
|
|
541
|
+
return 0
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
if __name__ == "__main__":
|
|
545
|
+
sys.exit(main())
|