Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
448 changes: 448 additions & 0 deletions docs/diagnostics.md

Large diffs are not rendered by default.

165 changes: 165 additions & 0 deletions docs/t2_5_adapter_observability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# T2.5 Adapter 可观测性指标

## 使用方式

命令与 T2.1 诊断完全一致,无需额外参数,输出自动包含指标:

```bash
python -m triton_anchor.diagnose /path/to/input.mlir \
--pipeline triton-linalg \
--output-dir ./out
```

---

## 测试

以下命令在仓库根目录执行:

```bash
cd /your/path/triton-anchor
source .venv/bin/activate
RUN_ROOT="/tmp/anchor-diagnose/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$RUN_ROOT"
```

先验证正常 TTIR 诊断,预期退出码为 `0`:

```bash
PYTHONPATH=triton/python:python:. python -m triton_anchor.diagnose \
--python tests.test_smoke:_smoke_add_kernel \
--signature '*fp32,*fp32,*fp32,i32' \
--constant BLOCK=256 \
--pipeline ttir \
--output-dir "$RUN_ROOT/success-ttir"
echo "exit code: $?"
```

再运行预期失败的 Adapter 样例,预期退出码为 `1`,失败点为
`triton_linalg.triton_to_linalg`:

```bash
TRITON_ANCHOR_DIAGNOSE_ON_ERROR=1 \
TRITON_ANCHOR_DIAGNOSE_DIR="$RUN_ROOT/bad-inline" \
python ops-diagnose-cli/test/anchor_diag_bad_kernels.py
echo "exit code: $?"
```

检查失败诊断和可观测性指标:

```bash
python -m json.tool \
"$RUN_ROOT/bad-inline/triton-linalg/summary.json"
```

运行 diagnose 单元测试:

```bash
PYTHONPATH=triton/python:python:. python \
-m pytest python/triton_anchor/tests/test_diagnostics.py -q
```

---

## 提供的指标

指标的采集范围是 **Adapter 层**:从 TTIR 进入 Adapter 开始,到 Linalg IR 输出为止(即 `--pipeline triton-linalg` 的 15 个 pass)。不包含 TTIR 优化阶段、PPLIR 及后续编译阶段。

**逐 Pass 指标**(写入每条 `records[]`,反映 Adapter 内单个 pass 的行为):

| 字段 | 说明 |
|---|---|
| `duration_ms` | 该 pass 在 Adapter 内的墙钟耗时(毫秒) |
| `before_ir_bytes` | 该 pass 处理前的 IR 大小(字节) |
| `after_ir_bytes` | 该 pass 处理后的 IR 大小(字节,失败时为 0) |
| `ir_delta_bytes` | 该 pass 造成的 IR 大小变化(失败时为 0) |
| `peak_rss_bytes` | 该 pass 结束时采样的进程峰值 RSS(字节) |

**Adapter 层汇总指标**(写入 `summary.json` 顶层,反映整个 Adapter 转换的代价):

| 字段 | 说明 |
|---|---|
| `total_duration_ms` | Adapter 所有 pass 的总耗时(TTIR→Linalg 转换总时间) |
| `input_ir_bytes` | 进入 Adapter 的 TTIR 大小 |
| `output_ir_bytes` | Adapter 输出的 Linalg IR 大小(失败时为失败前最后已知值) |
| `peak_rss_bytes` | Adapter 执行过程中的进程峰值 RSS |
| `slowest_pass` | Adapter 中耗时最长的 pass(含 `name` 和 `duration_ms`) |

**CLI 输出示例(成功)**:
```
OK: pipeline triton-linalg completed, 9/9 passes executed.
total duration: 342.56 ms
input IR: 1523 bytes
output IR: 2847 bytes
peak RSS: 87.34 MB
slowest pass: #7 triton_to_linalg (189.23 ms)
summary: ./out/summary.json
Comment on lines +90 to +96
```

**CLI 输出示例(失败)**:
```
FAILED: pipeline triton-linalg failed at pass 4/9: pointer_strength_reduction
pass duration: 23.45 ms
before IR: 1523 bytes
total duration (up to failure): 98.76 ms
peak RSS: 65.21 MB
location: kernel.py:12:8
operation: tt.load
summary: ./out/summary.json
```
Comment on lines +101 to +109

---

## ⚠️ 准确性前提:descriptor 必须与 adapter 保持同步

**这是使用这些指标时最需要注意的一点。**

指标采集**不调用** adapter 的 `convert()`(它内部把 15 个 pass 塞进一个 `pass_manager` 一次 `pm.run()` 跑完,是黑盒,中间插不进埋点)。诊断路径走的是 `build_triton_linalg_pass_descriptors()`——它把 adapter 那条流水线**逐 pass 手抄成了一份独立的 descriptor 列表**,诊断时按这份列表逐个 pass 单独跑并埋点。

因此存在两处 pass 列表:

| 位置 | 作用 |
|---|---|
| `triton_linalg_adapter.py` 的 `_add_passes()` | adapter 真实运行的 pass 序列 |
| `diagnostics.py` 的 `build_triton_linalg_pass_descriptors()` | 指标采集实际测量的 pass 序列 |

**两份列表是各写一份、手动对齐的,没有任何自动校验机制。**

**风险**:如果有人改了 adapter 的 pass 顺序、增删了 pass,却忘了同步 `build_triton_linalg_pass_descriptors()`,那么诊断器测的就不再是 adapter 真实跑的东西——耗时、IR 大小、`slowest_pass` 全都会失真,而且**不会报错**,指标看起来照常正常,审查人无法从输出中察觉偏差。

**改动 adapter pass 序列时的纪律**:任何对 `_add_passes()` 的修改(增删 pass、调顺序、换 pass 名),都必须同步修改 `build_triton_linalg_pass_descriptors()`,否则本文档所有指标失去意义。

---

## 改动文件

**零新文件**,全部改动在 T2.1 已有文件里:

| 文件 | 改动内容 |
|---|---|
| `python/triton_anchor/diagnostics.py` | `PassRunRecord` 新增 5 个指标字段;`PassDiagnosticResult` 新增 4 个汇总字段和 `slowest_pass` 属性;`_diagnose_pipeline` 里对每个 pass 计时、计算 IR 大小、采样 RSS |
| `python/triton_anchor/diagnose.py` | `_print_result` 增加总耗时、peak RSS、输入/输出 IR 大小、最慢 pass 的展示 |
| `python/triton_anchor/tests/test_diagnostics.py` | 新增 2 个测试,覆盖成功路径和失败路径的指标采集 |

---

## 测试结果

新增 2 个测试,与 T2.1 原有 6 个合并后共 **8 项全部通过**:

| 测试项 | 覆盖点 |
|---|---|
| `test_pass_diagnostic_records_timing_and_ir_sizes` | 逐 pass 计时、IR 大小、汇总指标、`slowest_pass` |
| `test_pass_diagnostic_metrics_on_failure` | 失败时指标仍被采集、`output_ir_bytes` 为最后已知正确值 |
| T2.1 原有 6 项 | 失败定位、MLIR location 提取、summary.json、CLI |

---

## 构建细节

- **计时**:每个 pass 用 `time.monotonic()` 包裹,精度为毫秒。
- **IR 大小**:对 `str(module)` 做 UTF-8 编码后计字节数,pass 前后各采样一次。
- **RSS 采样**:调用 `resource.getrusage(RUSAGE_SELF).ru_maxrss`,采样整个 Python 进程峰值 RSS。对 pybind adapter 是进程级粗粒度监控,不能精确归因到单个 pass;macOS 单位为字节,Linux 为 KB(已做换算)。
- **失败时**:失败 pass 的 `duration_ms` 和 `before_ir_bytes` 仍会记录;`after_ir_bytes` 和 `ir_delta_bytes` 置 0;`output_ir_bytes` 保留失败前最后一个成功 pass 的 IR 大小。


Loading
Loading