Skip to content
Merged
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
146 changes: 130 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@ on:
pull_request:

jobs:
# wt 2026-10-07-fix 新增 packaging 门: 算子包化回归(CPU 可跑部分)
# ——全算子 __init__.py 导入扫描; NPU 消费段在本机跑, CI 里跳过。
# # wt <wangt635@ustc.edu.cn>
ops-catalog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: 安装 CPU 依赖
run: pip install pyyaml -q
- name: 算子目录一致性检查
run: python3 scripts/build_ops_index.py --check

ops-packaging:
runs-on: ubuntu-latest
steps:
Expand All @@ -20,7 +29,7 @@ jobs:
run: |
pip install pyyaml -q
pip install torch --index-url https://download.pytorch.org/whl/cpu -q
- name: 算子包化导入扫描(16 目录)
- name: 算子包化导入扫描
run: |
python3 - <<'EOF'
import importlib, pathlib, sys
Expand All @@ -36,7 +45,8 @@ jobs:
except Exception as e:
bad.append(f'{d.name}: {type(e).__name__}: {e}')
if bad:
print('\n'.join(bad)); sys.exit(1)
print('\n'.join(bad))
sys.exit(1)
print(f'ops-packaging: {len(dirs)}/{len(dirs)} 目录导入+导出 OK')
EOF

Expand All @@ -51,8 +61,8 @@ jobs:
run: |
pip install pytest pyyaml -q
pip install torch --index-url https://download.pytorch.org/whl/cpu -q
- name: 单元测试(无 GPU)
run: python -m pytest tests/unit -q
- name: 单元测试
run: python3 -m pytest tests/unit -q

docs-and-syntax:
runs-on: ubuntu-latest
Expand All @@ -67,12 +77,116 @@ jobs:
errs = []
anchor_cache = {}

def anchors_of(p):
k = str(p)
if k not in anchor_cache:
text = p.read_text(encoding='utf-8', errors='replace')
hs = re.findall(r'^#{1,6}\s+(.*)$', text, re.M)
anchor_cache[k] = {
re.sub(r'[^\w\u4e00-\u9fff-]', '', h.strip().lower().replace(' ', '-'))
for h in hs}
return anchor_cache[k]
def anchors_of(path):
key = str(path)
if key not in anchor_cache:
try:
text = path.read_text(encoding='utf-8', errors='replace')
anchor_cache[key] = set(re.findall(
r'<a id="([^"]+)"', text
))
except Exception:
anchor_cache[key] = set()
return anchor_cache[key]

for md in root.rglob('*.md'):
if '.git' in str(md):
continue
raw = md.read_text(encoding='utf-8', errors='replace')
text = re.sub(r'```.*?```', '', raw, flags=re.S)
for match in re.finditer(
r'\[([^\]]*)\]\(([^)#\s]+)(?:#([^)\s]+))?\)', text
):
target, anchor = match.group(2), match.group(3)
if target.startswith(('http', 'mailto')):
continue
target_path = (md.parent / target).resolve()
if not target_path.exists():
errs.append(f'{md}: -> {target}')
elif anchor and anchor not in anchors_of(target_path):
errs.append(f'{md}: #{anchor} in {target}')

print(f'检查完成: {len(errs)} 个错误')
for error in errs:
print(f' - {error}')
sys.exit(1 if errs else 0)
EOF

- name: Python 语法检查
run: |
python3 - <<'EOF'
import ast, pathlib, sys
fails = []
for path in pathlib.Path('.').rglob('*.py'):
if '.git' in str(path):
continue
try:
ast.parse(path.read_text(), filename=str(path))
except SyntaxError as exc:
fails.append(f'{path}: {exc}')
if fails:
for failure in fails:
print(f' - {failure}')
sys.exit(1)
print('Python 语法检查通过')
EOF

- name: YAML 配置检查
run: |
pip install pyyaml -q
python3 - <<'EOF'
import glob, sys, yaml
fails = []
files = (
glob.glob('configs/devices/*.yaml')
+ glob.glob('inputs/*.yaml')
+ ['.github/workflows/ci.yml', 'ops/catalog.yaml']
)
for name in files:
try:
with open(name, encoding='utf-8') as handle:
yaml.safe_load(handle)
except Exception as exc:
fails.append(f'{name}: {exc}')
if fails:
for failure in fails:
print(f' - {failure}')
sys.exit(1)
print('YAML 检查通过')
EOF

- name: Intake manifest 契约校验
run: python3 scripts/intake_validate.py --validate-only

- name: 性能基线结构检查
run: |
python3 - <<'EOF'
import glob, json, sys
fails = []
files = glob.glob('perf/baselines/*.json') + [
'intake/manifest.schema.json'
]
for name in files:
try:
with open(name, encoding='utf-8') as handle:
data = json.load(handle)
except Exception as exc:
fails.append(f'{name}: {exc}')
continue
if name.startswith('perf/'):
required = (
'schema', 'device', 'created_at', 'updated_at',
'git_commit', 'env_fingerprint', 'cases'
)
for key in required:
if key not in data:
fails.append(f'{name}: 缺字段 {key}')
for case_id, case in data.get('cases', {}).items():
if 'latency_ms' not in case.get('metrics', {}):
fails.append(f'{name}: {case_id} 缺 metrics.latency_ms')
if fails:
for failure in fails:
print(f' - {failure}')
sys.exit(1)
print('性能基线结构检查通过')
EOF
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@
## [Unreleased]

### Changed
- **ops/ 文档契约同步(2026-10-13)**: 13 个 MLU 算子的
README / REPORT / development / test-report 补记 PR #25 后的
`counter + platform` 注册契约、canonical `AutogradPrivateUse1` /
兼容 `PrivateUse1`、包态优先导入与 clone 包态执行用例;修正
`empty` 的自用/实验路线与 sdpa_math 黄金口径描述;`ops/README`
重组为核心多平台算子与 MLU 基础 ATen 算子两组,基础算子再按
布局/随机/分配/标量用途分组
- **可扩放算子目录(2026-10-14)**: 新增 `ops/catalog.yaml` 作为
算子 / 平台矩阵唯一事实来源,登记六个目标厂商平台家族与当前增量
交付状态;`scripts/build_ops_index.py` 生成 `ops/README.md` 并校验
profile、目录、平台声明和多平台文档,配套
`docs/operator-catalog.md` 与单元测试;新增 `ops-catalog` CI 门,
并恢复完整的 docs-and-syntax 链接 / 语法 / YAML / 基线检查
- sdpa `PLATFORM.md` 补记多算子 perf registry 顺序加载时的顶层
`reference` 遮蔽约束;backend 导入回归测试同步覆盖 P800 与 MLU

Expand Down
3 changes: 2 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ flowchart TB
| 完整走一遍开发 | [全链路指南](fullstack-guide.md)(七步流水线 + 覆盖矩阵) |
| 开发完成后交付/集成 | [集成指南](integration.md)(路径选择 + 分发开销实测) |
| 确认"精度/性能够不够" | [验收标准](acceptance.md)(口径 + Must/Should 分级 + 重验 runbook) |
| 存放/查找已开发算子 | [ops/](../ops/README.md)(样板同构 + 索引表) |
| 存放/查找已开发算子 | [ops/](../ops/README.md)(catalog 生成的增量矩阵) |
| 维护算子 / 平台矩阵 | [算子目录维护指南](operator-catalog.md)(六平台增量口径) |
| 理解每层验证 | [测试体系](testing.md) |
| 追踪性能回归 | [性能回归追踪](performance-regression.md) |
| 接入 AI 生成的算子 | [AI 生成算子接入](ai-intake.md) |
Expand Down
151 changes: 151 additions & 0 deletions docs/operator-catalog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# 算子目录维护指南

这份指南说明 FlagOS-OP 如何维护持续增长的算子 / 平台矩阵,并避免把
`ops/README.md` 变成难以维护的手工宽表。

## 事实来源

事实来源:

```text
ops/catalog.yaml
```

生成文件:

```text
ops/README.md
```

修改 catalog 后重新生成:

```bash
python3 scripts/build_ops_index.py
```

检查生成文件是否最新:

```bash
python3 scripts/build_ops_index.py --check
```

不要手工编辑 `ops/README.md`。文件内包含 AUTO-GENERATED 标记;生成结果
直接入库,是为了让 GitHub 页面保持可读。

## 目标范围

catalog 当前建模六个厂商平台家族:

| Family key | 显示名 | 当前状态 |
|---|---|---|
| `ascend` | 华为昇腾 | partial |
| `cambricon` | 寒武纪 | partial |
| `kunlunxin` | 昆仑芯 | partial |
| `thead` | 平头哥 | planned |
| `enflame` | 燧原 GCU | planned;已知型号 GCU300 / GCU400 / GCU410 |
| `biren` | 壁仞 | planned |

状态语义:

- **partial**:至少一个算子在该平台家族上有已合并证据;不表示所有算子都支持该平台。
- **planned**:只表示目标范围;没有算子条目、profile、dispatch key 或支持承诺。

平台矩阵会增量补齐。不要为了表格看起来完整而预填空平台单元格。

## 数据结构

### `platform_families`

每个平台家族记录:

```yaml
<family-key>:
display_name: <厂商显示名>
status: partial | planned
current_profiles: [<已有 configs/devices profile>]
known_variants: [<可选硬件型号>]
roadmap_note: <简短非承诺说明>
```

校验规则:

- 每个 `current_profiles` 项必须存在 `configs/devices/<name>.yaml`。
- `planned` 家族不能声明 current profile。
- 家族只有在至少一个算子登记后才可变为 `partial`。

### `operator_groups`

分组描述算子存在的读者原因,而不是提交历史。当前有两类:

- **core**:多平台计算算子,例如 attention、embedding。
- **foundation**:用于验证执行链路和集成链路的基础 ATen 语义。

生成页按 `rank` 输出分组。现有分类不能准确描述新算子时,应新增分组,
不要把未来算子硬塞进语义不清的组。

### `operators`

每个算子记录:

```yaml
name: <算子名>
directory: <ops 子目录>
group: <分组 key>
purpose: <面向读者的一句话作用>
key_result: <有证据支撑的简短结果>
platforms:
<family-key>:
profiles: [<已交付 profile>]
implementation: <实现摘要>
```

foundation 算子还需要顶层 `route`,除非每个平台条目单独声明 `route`。
算子里的 platform 条目表示已交付声明,必须由该算子的测试和报告支撑。

跨多个平台家族的算子必须维护:

```text
ops/<operator>/PLATFORM.md
ops/<operator>/MERGE.md
```

### `registration_contracts`

注册契约按平台族记录,避免把一个厂商或一个算子族的 dispatch key 复制到
无关代码。未来新增契约时应记录 canonical key、兼容 key、可注册算子数、
不可注册算子和实现约束。

## 新增算子

1. 从 `templates/operator/` 复制并完成算子目录。
2. 通过 kernel、op、framework/application 三层测试。
3. 补齐 golden 与性能证据。
4. 在 `ops/catalog.yaml` 的 `operators` 中登记。
5. 运行 `python3 scripts/build_ops_index.py`。
6. 确认 `python3 scripts/build_ops_index.py --check` 通过。

校验器要求 `ops/` 下每个目录都出现在 catalog 中,防止新算子合入后没有
库存索引记录。

## 新增平台实现

1. 新增 `configs/devices/<profile>.yaml`。
2. 把 profile 加入厂商家族的 `current_profiles`。
3. 只有当首个算子的实现和验证合入后,才把家族从 `planned` 改为 `partial`。
4. 在对应算子的 `platforms` 中登记该家族。
5. 更新算子的 `PLATFORM.md`;第二个及后续平台还需维护 `MERGE.md`。
6. 重新生成 `ops/README.md`。

新增厂商家族时,先登记 `planned` 家族和不承诺支持的 roadmap 说明;算子
条目等到实现和验证落地后再添加。

## 文档边界

生成页只回答:

- 当前有哪些算子;
- 哪些平台家族已有交付证据;
- 详细信息在哪里。

它不替代算子内文档。详细契约、fallback 边界、数值容差、性能协议和已知
限制仍维护在各算子的 README、REPORT、PLATFORM 和报告分册中。
Loading
Loading