已合并
update DSL README #1132
init__zhb__创建于 23 天前
update DSL README #1132
已合并
init__zhb__创建于 23 天前
20 个文件变更+143-115
@@ -70,8 +70,8 @@ basic_mixed.py [-h] [--device DEVICE] [--m M] [--n N] [--k K]
70| `--device` | `0` | 上板执行使用的 NPU 设备号。 |70| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
71| `--m` / `--n` / `--k` | `32`, `32`, `32` | 矩阵乘加的问题大小 |71| `--m` / `--n` / `--k` | `32`, `32`, `32` | 矩阵乘加的问题大小 |
72| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |72| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |
73-| `--block-num` | `-1`(依据所使用的 NPU 设备采集其满核值) | 启用的 AI Core 核数 |73+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
74-| `--sentinel` | `-9.0` | Kernel 启动前入结果 C 哨兵值。 |74+| `--sentinel` | `-9.0` | Kernel 启动前预先填入结果矩阵的值。 |
75 75 
76### 执行示例76### 执行示例
77 77 
@@ -74,7 +74,7 @@ basic_matmul.py [-h] [--device DEVICE] [--m M] [--n N] [--k K]
74| `--k` | `1024` | 矩阵乘累加轴的大小 |74| `--k` | `1024` | 矩阵乘累加轴的大小 |
75| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |75| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"``"col"`,表示行优先或列优先布局。 |
76| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围包括`"f16"`, `"bf16"``"f32"` 。 |76| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围包括`"f16"`, `"bf16"``"f32"` 。 |
77-| `--block-num` | `-1`(依据所使用的 NPU 设备采集其满核值) | 启用的 AI Core 核数 |77+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
78 78 
79### 执行示例79### 执行示例
80 80 
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/README.mdpython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/README.md+30-17
@@ -1,24 +1,24 @@
1-# Matmul EVG 端到端示例1+# CV (Cube + Vector) 融合后处理类 端到端示例
2 2 
3-本目录下提供的系列样例演示 **CATLASS DSL** 下 基于 Ascend950 的 GEMM + EVG(Epilogue Visitor Graph)尾处理,对齐 C++ 参考实现 `examples/64_ascend950_matmul_evg_*`3+本目录下提供的系列样例演示 **CATLASS DSL** 下系列后处理类CV(Cube + Vector)融合算子的计算过程
4 4 
5## 功能说明5## 功能说明
6 6 
7-基础矩阵乘算子实现形如 `(m, k)` 和 `(k, n)` 两矩阵法,输出形如 `(m, n)`:7+后处理类算子实现基础矩阵乘并复合后续计算步骤。
8 8 
9$$9$$
10\begin{aligned}10\begin{aligned}
11-D &= A \times B \oplus \text{Epilogue}11+D &= f(A \times B)
12\end{aligned}12\end{aligned}
13$$13$$
14 14 
15-各变体在 GEMM 之后接入不同 EVG 尾处理算子(Add、Bias、LeakyRelu、Sigmoid、Silu、Tanh 等),由 AIV 融合完成15+本目录下样例包含处理操作见后续介绍
16 16 
17 17 
18## 代码组织18## 代码组织
19 19 
20```plain20```plain
21-./basic_mmad_evg21+./basic_mmad_epilogue
22├── matmul_add.py22├── matmul_add.py
23├── matmul_add_ub.py23├── matmul_add_ub.py
24├── matmul_bias.py24├── matmul_bias.py
@@ -31,16 +31,18 @@ $$
31 31 
32| 文件 | 概述 |32| 文件 | 概述 |
33|------|------|33|------|------|
34-| [**`matmul_add.py`**](matmul_add.py) | D = A×B + X;L0C→GM + AIV。 |34+| [**`matmul_add.py`**](matmul_add.py) | 实现 `D = A@B + X` 计算功能。 |
35-| [**`matmul_add_ub.py`**](matmul_add_ub.py) | D = A×B + XL0C→UB + AIV。 |35+| [**`matmul_add_ub.py`**](matmul_add_ub.py) | 实现 `D = A@B + X` 计算功能,启用L0C -> UB通路将矩阵乘结果搬出到 UB。 |
36-| [**`matmul_bias.py`**](matmul_bias.py) | D = A×B + bias(1×N);L0C→GM + RowBroadcast。 |36+| [**`matmul_bias.py`**](matmul_bias.py) | 实现 `D = A@B + bias` 计算功能,其中 `bias` 为一维 `(n,)` 的广播向量。 |
37-| [**`matmul_leaky_relu.py`**](matmul_leaky_relu.py) | D = LeakyRelu(A×B),α=0.1;L0C→GM + AIV。 |37+| [**`matmul_leaky_relu.py`**](matmul_leaky_relu.py) | 实现 `D = LeakyRelu(A@B)` 计算功能其中`α` 默认为 `0.1`。 |
38-| [**`matmul_sigmoid.py`**](matmul_sigmoid.py) | D = Sigmoid(A×B);L0C→GM + AIV。 |38+| [**`matmul_sigmoid.py`**](matmul_sigmoid.py) | 实现 `D = Sigmoid(A@B)` 计算功能。 |
39-| [**`matmul_silu.py`**](matmul_silu.py) | D = Silu(A×B);L0C→GM + AIV。 |39+| [**`matmul_silu.py`**](matmul_silu.py) | 实现 `D = Silu(A@B)` 计算功能。 |
40-| [**`matmul_tanh.py`**](matmul_tanh.py) | D = Tanh(A×B);L0C→GM + AIV。 |40+| [**`matmul_tanh.py`**](matmul_tanh.py) | 实现 `D = Tanh(A@B)` 计算功能。 |
41 41 
42## 约束说明42## 约束说明
43 43 
44+ - 左、右矩阵及结果矩阵所支持的数据组合类型如下。
45+ 
44| 算子 | `DTYPE_A` / `DTYPE_B` | `DTYPE_C` |46| 算子 | `DTYPE_A` / `DTYPE_B` | `DTYPE_C` |
45|------|-------------------|---------|47|------|-------------------|---------|
46| add, bias, leaky_relu, sigmoid, silu | f16 / bf16 / f32 | f16 或 f32 |48| add, bias, leaky_relu, sigmoid, silu | f16 / bf16 / f32 | f16 或 f32 |
@@ -61,8 +63,10 @@ $$
61| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |63| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
62| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |64| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |
63| `--k` | `256` | 矩阵乘累加轴的大小 |65| `--k` | `256` | 矩阵乘累加轴的大小 |
64-| `--layout-a` / `--layout-b` | `row` / `row` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |66+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |
65-| `--dtype-a` / `--dtype-b` / `--dtype-c` | `f32` / `f32` / `f32` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |67+| `--dtype-a` / `--dtype-b` | `"f32"` / `"f32"` | 左、右矩阵 A、B 的数据类型,可选范围参考约束说明。 |
68+| `--dtype-c` | `"f32"` | 结果矩阵 C 的数据类型,可选范围参考约束说明(`add_ub` / `tanh` 仅支持 f32)。 |
69+| `--block-num` | `-1` | 启用的 AIC 核数,`-1` 表示自动探测可用核数(满核)。 |
66 70 
67 71 
68### 执行示例72### 执行示例
@@ -73,9 +77,18 @@ $$
73cd python/tla_dsl77cd python/tla_dsl
74 78 
75# 其余变体替换文件名即可79# 其余变体替换文件名即可
76-python examples/end_to_end/basic_mmad_evg/matmul_add.py --device 0 \80+python examples/end_to_end/basic_mmad_epilogue/matmul_add.py --device 0 \
77 --m 256 --n 256 --k 256 \81 --m 256 --n 256 --k 256 \
78 --layout-a row --layout-b row \82 --layout-a row --layout-b row \
79 --dtype-a f16 --dtype-b f16 --dtype-c f3283 --dtype-a f16 --dtype-b f16 --dtype-c f32
80- 
81```84```
85+ 
86+默认测试条件下,预期输出:
87+ 
88+```text
89+--- mnk=(256,256,256) layout=row/row dtype=f16/f16/f32 ---
90+passed=True cache_key=<cache_key>
91+kernel.o=<cache_dir>/<cache_key>/kernel.o
92+```
93+ 
94+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_add.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_add.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_add_ub.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_add_ub.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_bias.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_bias.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_leaky_relu.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_leaky_relu.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_sigmoid.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_sigmoid.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_silu.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_silu.py+0-0
文件重命名但无更改。
Rpython/tla_dsl/examples/end_to_end/basic_mmad_evg/matmul_tanh.pypython/tla_dsl/examples/end_to_end/basic_mmad_epilogue/matmul_tanh.py+0-0
文件重命名但无更改。
@@ -1,6 +1,6 @@
1# StreamK MMAD 端到端示例1# StreamK MMAD 端到端示例
2 2 
3-本目录下的样例演示 **CATLASS DSL** 下 StreamK MatMul 的实现,对齐 C++ 参考实现`examples/66_ascend950_streamk_matmul`3+本目录下的样例演示 **CATLASS DSL** 下 StreamK MatMul 的实现。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -53,15 +53,13 @@ StreamK 通过将 K 维度的计算分摊到多个核上以均衡负载:normal
53| 参数 | 默认值 | 说明 |53| 参数 | 默认值 | 说明 |
54|------|--------|------|54|------|--------|------|
55| `--device` | `0` | 上板执行使用的 NPU 设备号。 |55| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
56-| `--run` | 默认开启 | 上板并校验精度。 |
57| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |56| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
58| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |57| `--n` | `256` | 矩阵乘右矩阵 B 的列数 |
59| `--k` | `512` | 矩阵乘累加轴的大小 |58| `--k` | `512` | 矩阵乘累加轴的大小 |
60| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"``"col"`,表示行优先或列优先布局。 |59| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"``"col"`,表示行优先或列优先布局。 |
61| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |60| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
62-| `--block` | `None` | 启用的 AIC 核数。 |61+| `--block-num` | `-1` | 启用的 AIC 核数,`-1` 表示自动探测可用核数(满核)。 |
63- 62+| `--atol` | `1e-3` | 精度比对时的绝对容差。 |
64-其余参数(`--sentinel``--atol``--cache-dir``--force-recompile``--no-cache` 等)详见 `--help`
65 63 
66### 执行示例64### 执行示例
67 65 
@@ -70,18 +68,18 @@ StreamK 通过将 K 维度的计算分摊到多个核上以均衡负载:normal
70```bash68```bash
71cd python/tla_dsl69cd python/tla_dsl
72 70 
73-# 上板并校验(默认即 --run,精度校验默认开启)71+# 上板并校验精度
74-python examples/end_to_end/basic_mmad_streamk/basic_mmad_streamk.py --run --device 0 \72+python examples/end_to_end/basic_mmad_streamk/basic_mmad_streamk.py --device 0 \
75 --layout-a row --layout-b col \73 --layout-a row --layout-b col \
76 --dtype-a f16 --dtype-b f16 --dtype-c f3274 --dtype-a f16 --dtype-b f16 --dtype-c f32
77```75```
78 76 
77+默认测试条件下,预期输出:
79 78 
80- 79+```text
81-```bash80+--- mnk=(256,256,512) layout=row/col dtype=f16/f16/f32 ---
82-python examples/end_to_end/basic_mmad_streamk/basic_mmad_streamk.py --help81+passed=True cache_key=<cache_key>
82+kernel.o=<cache_dir>/<cache_key>/kernel.o
83```83```
84 84 
85-执行测试后预期输出:85+其中 `passed`结果为`True`或`False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录 `cache_key` 是编译缓存的哈希值。
86- 
87-默认运行会打印 `compile_ok=True``host=torch_npu``launch_ok=True``kernel.o` 路径,以及 `C unchanged?` / `C equals expected matmul?` / `first mismatch=...` 等(与 `m×n×k`、block、`--sentinel`、dtype 有关;golden 为 **Torch** 在 NPU 上的 matmul)。
@@ -60,7 +60,7 @@ basic_vadd.py [-h] [--device DEVICE] [--n N]
60|------|--------|------|60|------|--------|------|
61| `--device` | `0` | 上板执行使用的 NPU 设备号。 |61| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
62| `--n` | `400` | 向量长度。 |62| `--n` | `400` | 向量长度。 |
63-| `--block-num` | `-1`(依据所使用的 NPU 设备采集其满核值) | 启用的 AI Vector 核数 |63+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
64| `--dtype` | `"f32"` | 数据类型,可选 `"f32"``"f16"``"i8"``"i16"``"i32"`。 |64| `--dtype` | `"f32"` | 数据类型,可选 `"f32"``"f16"``"i8"``"i16"``"i32"`。 |
65| `--use-mutex` | `False` | 切换到显式 Mutex `lock` / `unlock` 同步(执行 `basic_vadd_mutex`)。 |65| `--use-mutex` | `False` | 切换到显式 Mutex `lock` / `unlock` 同步(执行 `basic_vadd_mutex`)。 |
66| `--use-mutex-with` | `False` | 切换到 `with tla.mutex_guard(...)` 同步(执行 `basic_vadd_mutex_with`)。 |66| `--use-mutex-with` | `False` | 切换到 `with tla.mutex_guard(...)` 同步(执行 `basic_vadd_mutex_with`)。 |
@@ -125,7 +125,7 @@ tla.copy(ub_a, gm_a)
125mutex_ub_a.unlock(pipe=tla.arch.MTE2)125mutex_ub_a.unlock(pipe=tla.arch.MTE2)
126```126```
127 127 
128-## basic_vadd_mutex_with128+### basic_vadd_mutex_with
129 129 
130**文件**:[`basic_vadd.py`](basic_vadd.py#L127)130**文件**:[`basic_vadd.py`](basic_vadd.py#L127)
131 131 
@@ -139,7 +139,7 @@ with tla.mutex_guard(mutex_ub_a):
139 tla.copy(ub_a, gm_a)139 tla.copy(ub_a, gm_a)
140```140```
141 141 
142-## basic_vadd_atomic_add142+### basic_vadd_atomic_add
143 143 
144**文件**:[`basic_vadd.py`](basic_vadd.py#L175)144**文件**:[`basic_vadd.py`](basic_vadd.py#L175)
145 145 
@@ -1,6 +1,6 @@
1# Batched Matmul 端到端示例1# Batched Matmul 端到端示例
2 2 
3-本目录下的样例演示 **CATLASS DSL** 下的批量矩阵乘,对齐 C++ 参考实现 `examples/67_ascend950_batched_matmul*`3+本目录下的样例演示 **CATLASS DSL** 下的批量矩阵乘。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -12,8 +12,6 @@ $$
12 12 
13各 batch 的 `(M, N, K)` 相同。13各 batch 的 `(M, N, K)` 相同。
14 14 
15- 
16- 
17## 代码组织15## 代码组织
18 16 
19```plain17```plain
@@ -22,21 +20,21 @@ $$
22└── README.md20└── README.md
23```21```
24 22 
25-| 文件 | 概述 |23+| 文件 | 概述 |
26-|------|------|24+| --------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
27-| [**`batched_matmul.py`**](batched_matmul.py) | 设备侧 `@tla.kernel` 与 host 侧运行/校验逻辑同文件。执行数据生成、compile/launch、以及golden比对。 |25+| [**`batched_matmul.py`**](batched_matmul.py) | 设备侧`@tla.kernel` 与 host 侧运行/校验逻辑同文件。执行数据生成、compile/launch、以及golden比对。 |
28 26 
29## 约束说明27## 约束说明
30 28 
31- - 左、右矩阵及结果矩阵所支持的数据组合类型如下。29+- 左、右矩阵及结果矩阵所支持的数据组合类型如下。
32 30 
33| `DTYPE_A` | `DTYPE_B` | `DTYPE_C` |31| `DTYPE_A` | `DTYPE_B` | `DTYPE_C` |
34-|---------|---------|------------------|32+| ----------- | ----------- | ----------- |
35-| f16 | f16 | f32 |33+| f16 | f16 | f32 |
36-| f16 | f16 | f16 |34+| f16 | f16 | f16 |
37-| bf16 | bf16 | f32 |35+| bf16 | bf16 | f32 |
38-| bf16 | bf16 | bf16 |36+| bf16 | bf16 | bf16 |
39-| f32 | f32 | f32 |37+| f32 | f32 | f32 |
40 38 
41## 使用示例39## 使用示例
42 40 
@@ -44,33 +42,34 @@ $$
44 42 
45### 命令行参数43### 命令行参数
46 44 
47-| 参数 | 默认值 | 说明 |45+| 参数 | 默认值 | 说明 |
48-|------|--------|------|46+| --------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------ |
49-| `--device` | `0` | 上板执行使用的 NPU 设备号。 |47+| `--device` | `0` | 上板执行使用的 NPU 设备号。 |
50-| `--batch` | `5` | batch 数 B。 |48+| `--batch` | `5` | batch 数 B。 |
51-| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |49+| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
52-| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |50+| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |
53-| `--k` | `1024` | 矩阵乘累加轴的大小 |51+| `--k` | `1024` | 矩阵乘累加轴的大小 |
54-| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |52+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选`"row"` 或 `"col"`,表示行优先或列优先布局。 |
55-| `--dtype-a` / `--dtype-b` / `--dtype-c` | `f16` / `f16` / `f16` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |53+| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f32"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
56-| `--block` | `8` | 启用的核数 |54+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
57 55 
58### 执行示例56### 执行示例
59 57 
60`python/tla_dsl` 目录下执行:58`python/tla_dsl` 目录下执行:
61 59 
62```bash60```bash
63-cd "${CATLASS_ROOT}/python/tla_dsl/examples/end_to_end/batched_matmul"61+cd python/tla_dsl
64- 
65-python batched_matmul.py --run --device 0 --batch 4 --m 256 --n 256 --k 256 --block 8
66 62 
63+python examples/end_to_end/batched_matmul/batched_matmul.py --device 0 \
64+ --batch 4 --m 256 --n 256 --k 256
67```65```
68 66 
69-执行测试,预期输出:67+默认测试条件下,预期输出:
70 68 
71```text69```text
72-compile_ok=True ...70+--- batch=(4) mnk=(256,256,256) layout=row/row dtype=f16/f16/f32 ---
73-launch_ok=True71+passed=True cache_key=<cache_key>
74-C equals batched golden? True72+kernel.o=<cache_dir>/<cache_key>/kernel.o
75-first mismatch=None
76```73```
74+ 
75+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
@@ -78,7 +78,7 @@ block_sparse_attention.py [-h] [--device DEVICE] [--qseqlen QSEQLEN] [--kvseqlen
78| `--dtype` | `"fp16"` | 输入数据类型,可选 `"fp16"``"bf16"`。 |78| `--dtype` | `"fp16"` | 输入数据类型,可选 `"fp16"``"bf16"`。 |
79| `--pattern` | `"causal"` | mask 模式,可选 `"causal"` / `"doc_prefix"` / `"sliding_window"` / `"four_stage_forward"`。 |79| `--pattern` | `"causal"` | mask 模式,可选 `"causal"` / `"doc_prefix"` / `"sliding_window"` / `"four_stage_forward"`。 |
80| `--format` | `"BSND"` | Tensor 格式,可选 `"BSND"`(定长)或 `"TND"`(变长)。 |80| `--format` | `"BSND"` | Tensor 格式,可选 `"BSND"`(定长)或 `"TND"`(变长)。 |
81-| `--block-num` | `-1`(依据所使用的 NPU 设备采集其满核值) | 启用的 AI Core 核数。 |81+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
82| `--cache-dir` | `./artifacts/runtime-cache` | 编译缓存目录。 |82| `--cache-dir` | `./artifacts/runtime-cache` | 编译缓存目录。 |
83| `--force-recompile` | `False` | 强制重新编译。 |83| `--force-recompile` | `False` | 强制重新编译。 |
84| `--no-cache` | `False` | 禁用编译缓存。 |84| `--no-cache` | `False` | 禁用编译缓存。 |
@@ -95,7 +95,7 @@ flash_attention_infer.py [-h] [--device DEVICE] [--dtype {f16,bf16}]
95| `--kvheadnum` | `1` | KV 头数,覆盖 `KV_HEAD_NUM`。 |95| `--kvheadnum` | `1` | KV 头数,覆盖 `KV_HEAD_NUM`。 |
96| `--qseqlen` | `117` | Q 序列长度,覆盖 `Q_SEQ`。 |96| `--qseqlen` | `117` | Q 序列长度,覆盖 `Q_SEQ`。 |
97| `--kvseqlen` | `512` | KV 序列长度,覆盖 `KV_SEQ`。 |97| `--kvseqlen` | `512` | KV 序列长度,覆盖 `KV_SEQ`。 |
98-| `--block-num` | `-1` | 启用的 AI Core 核数`-1` 表示满 AIC`cube_core_num`)。 |98+| `--block-num` | `-1` | 启用的核数`-1` 表示自动探测可用核数满核)。 |
99| `--sentinel` | `-7.0` | O 的初始值,用于对比检测 kernel 是否真正写入。 |99| `--sentinel` | `-7.0` | O 的初始值,用于对比检测 kernel 是否真正写入。 |
100 100 
101### 执行示例101### 执行示例
@@ -1,6 +1,6 @@
1# Grouped Matmul Slice-M 端到端示例1# Grouped Matmul Slice-M 端到端示例
2 2 
3-本目录下的样例演示 **CATLASS DSL** 下按 M 切分的分组矩阵乘,对齐 C++ 参考实现`examples/60_ascend950_grouped_matmul_slice_m`3+本目录下的样例演示 **CATLASS DSL** 下按 M 切分的分组矩阵乘。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -49,22 +49,29 @@ $$
49| `--k` | `256` | 矩阵乘累加轴的大小 |49| `--k` | `256` | 矩阵乘累加轴的大小 |
50| `--groups` | `4` | 分组数 G。 |50| `--groups` | `4` | 分组数 G。 |
51| `--group-mode` | `random` | 组切分模式,可选 `average``random`。 |51| `--group-mode` | `random` | 组切分模式,可选 `average``random`。 |
52-| `--layout-a` / `--layout-b` | `row` / `row` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |52+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |
53-| `--dtype-a` / `--dtype-b` / `--dtype-c` | `f16` / `f16` / `f16` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |53+| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f16"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
54-| `--block` | `8` | 启用的核数。 |54+| `--block-num` | `-1` | 启用的核数,`-1` 表示自动探测可用核数(满核)。 |
55 55 
56### 执行示例56### 执行示例
57 57 
58`python/tla_dsl` 目录下执行:58`python/tla_dsl` 目录下执行:
59 59 
60```bash60```bash
61-cd "${CATLASS_ROOT}/python/tla_dsl"61+cd python/tla_dsl
62- 
63-python examples/end_to_end/grouped_matmul_slice_m/grouped_matmul_slice_m.py \
64- --run --device 4 --m 1024 --n 256 --k 256 --groups 4 --group-mode average --block 8
65 62 
63+python examples/end_to_end/grouped_matmul_slice_m/grouped_matmul_slice_m.py --device 0 \
64+ --m 1024 --n 256 --k 256 --groups 4 --group-mode average
66```65```
67 66 
68-执行测试,预期输出:67+默认测试条件下,预期输出:
69 68 
70-成功时可见 `compile_ok` / `launch_ok` 与 golden 比对结果。69+```text
70+--- groups=(4) mnk=(1024,256,256) layout=row/row dtype=f16/f16/f16 group_mode=average ---
71+GROUP_CURRENT_M=(256, 256, 256, 256)
72+GROUP_LIST_PREFIX=(0, 256, 512, 768, 1024)
73+passed=True cache_key=<cache_key>
74+kernel.o=<cache_dir>/<cache_key>/kernel.o
75+```
76+ 
77+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
@@ -1,6 +1,6 @@
1# 多核切 K Matmul 端到端示例1# 多核切 K Matmul 端到端示例
2 2 
3-本目录下提供的样例演示 **CATLASS DSL** 下多核切 K 矩阵乘的两种实现,对齐 C++ 参考实现 `examples/68_ascend950_multi_core_splitk_matmul` 和 `examples/69_ascend950_tail_multi_core_splitk_matmul` 3+本目录下提供的样例演示 **CATLASS DSL** 下多核切 K 矩阵乘的两种实现。
4 4 
5## 功能说明5## 功能说明
6 6 
@@ -12,7 +12,7 @@ C_{i,j} &= \Sigma_{k} A_{i,k}B_{k,j}
12\end{aligned}12\end{aligned}
13$$13$$
14 14 
15-Split-K 将 K 维度的计算切分到多个核上并行执行,各核的部分积累入 workspace,再由 AIV 做 ReduceAdd 归约得到最终结果 C15+Split-K 将 K 维度的计算切分到多个核上并行执行,各核的计算结果写回 GM,再由 AIV 做 ReduceAdd 归约计算
16 16 
17## 代码组织17## 代码组织
18 18 
@@ -25,8 +25,8 @@ Split-K 将 K 维度的计算切分到多个核上并行执行,各核的部分
25 25 
26| 文件 | 概述 |26| 文件 | 概述 |
27|------|------|27|------|------|
28-| [**`multi_core_splitk_matmul.py`**](multi_core_splitk_matmul.py) | 设备侧 `@tla.kernel` 与 host 侧运行/校验逻辑同文件。全部 M×N tile K 维 split-K 写入 workspace,AIV ReduceAdd 写回 GM C。 |28+| [**`multi_core_splitk_matmul.py`**](multi_core_splitk_matmul.py) | 全部 Tile 块在累加轴 K方向上做切分并在 AIV 核进行规约(ReduceAdd写回 GM。 |
29-| [**`tail_multi_core_splitk_matmul.py`**](tail_multi_core_splitk_matmul.py) | 设备侧 `@tla.kernel` 与 host 侧运行/校验逻辑同文件。normal tile full-K 直接写回 gmC;tail tile 再做 split-K + ReduceAdd。 |29+| [**`tail_multi_core_splitk_matmul.py`**](tail_multi_core_splitk_matmul.py) | 针对尾轮采取上述多核切K优化,以达成负载均衡。 |
30 30 
31## 约束说明31## 约束说明
32 32 
@@ -45,7 +45,7 @@ Split-K 将 K 维度的计算切分到多个核上并行执行,各核的部分
45 45 
46### 命令行参数46### 命令行参数
47 47 
48-CLI 与 basic 同形,主要参数如下:48+接收命令行参数如下:
49 49 
50| 参数 | 默认值 | 说明 |50| 参数 | 默认值 | 说明 |
51|------|--------|------|51|------|--------|------|
@@ -53,21 +53,32 @@ CLI 与 basic 同形,主要参数如下:
53| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |53| `--m` | `256` | 矩阵乘左矩阵 A 的行数 |
54| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |54| `--n` | `512` | 矩阵乘右矩阵 B 的列数 |
55| `--k` | `1024` | 矩阵乘累加轴的大小 |55| `--k` | `1024` | 矩阵乘累加轴的大小 |
56-| `--layout-a` / `--layout-b` | `row` / `row` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |56+| `--layout-a` / `--layout-b` | `"row"` / `"row"` | 左、右矩阵 A、B 的数据排布格式,可选 `"row"` 或 `"col"`,表示行优先或列优先布局。 |
57| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f16"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |57| `--dtype-a` / `--dtype-b` / `--dtype-c` | `"f16"` / `"f16"` / `"f16"` | 左、右矩阵 A、B 和结果矩阵 C 的数据类型,可选范围参考约束说明。 |
58+| `--block-num` | `-1` | 启用的 AIC 核数,`-1` 表示自动探测可用核数(满核)。 |
58 59 
59### 执行示例60### 执行示例
60 61 
61`python/tla_dsl` 目录下执行:62`python/tla_dsl` 目录下执行:
62 63 
63```bash64```bash
64-export PYTHONPATH="$(pwd):${PYTHONPATH:-}"65+cd python/tla_dsl
65 66 
66-# multi_core_splitk67+# multi_core_splitk (指定 NPU 设备ID, m/n/k 的值)
67python examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py \68python examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py \
68 --device 0 --m 256 --n 512 --k 102469 --device 0 --m 256 --n 512 --k 1024
69 70 
70-# tail_multi_core_splitk71+# tail_multi_core_splitk (指定 NPU 设备ID, m/n/k 的值)
71python examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py \72python examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py \
72 --device 0 --m 2048 --n 1024 --k 204873 --device 0 --m 2048 --n 1024 --k 2048
73```74```
75+ 
76+默认测试条件下,预期输出:
77+ 
78+```text
79+--- mnk=(256,512,1024) layout=row/row dtype=f16/f16/f16 ---
80+passed=True mismatch=0.0000% (budget=0.1000%) cache_key=<cache_key>
81+kernel.o=<cache_dir>/<cache_key>/kernel.o
82+```
83+ 
84+其中 `passed`结果为`True``False` 表明 NPU 计算结果与golden参考值精度校验是否通过;`mismatch`为超容差元素占比,不高于 `budget` 即判定通过;`cache_dir` 是指定的缓存目录, `cache_key` 是编译缓存的哈希值。
@@ -8,7 +8,7 @@
8向量运算是 NPU 上基础的计算原语,在 AIV 物理核上执行,整体执行流程包括:8向量运算是 NPU 上基础的计算原语,在 AIV 物理核上执行,整体执行流程包括:
91. 构造 GM (Global memory)上的输入/输出 `tla.Tensor`91. 构造 GM (Global memory)上的输入/输出 `tla.Tensor`
102. 启动MTE2,将数据搬运至 UB (Unified Buffer);102. 启动MTE2,将数据搬运至 UB (Unified Buffer);
11-3. 加载至寄存器上,以 `VL`(向量寄存器位宽)为粒度分块执行各类向量指令;11+3. 加载至寄存器上,以 `VL`(向量寄存器位宽, 256 字节)为粒度分块执行各类向量指令;
124. 输出回 UB,然后启动 MTE3,将数据搬运回 GM。124. 输出回 UB,然后启动 MTE3,将数据搬运回 GM。
13 13 
14 14 
@@ -219,7 +219,7 @@ def _cases(device: int) -> Iterator[tuple[str, list[list[str]]]]:
219 "--groups", "3", "--m", "768", "--n", "333", "--k", "333", *dev]]219 "--groups", "3", "--m", "768", "--n", "333", "--k", "333", *dev]]
220 ) 220 )
221 221 
222- # --- basic_mmad_evg: multiple epilogue examples ---222+ # --- basic_mmad_epilogue: multiple epilogue examples ---
223 for op in EVG_OPS:223 for op in EVG_OPS:
224 if op in ("add_ub", "tanh"):224 if op in ("add_ub", "tanh"):
225 # f32 (dtype-c) only examples225 # f32 (dtype-c) only examples
@@ -237,9 +237,9 @@ def _cases(device: int) -> Iterator[tuple[str, list[list[str]]]]:
237 for m, n, k in MMAD_SHAPES:237 for m, n, k in MMAD_SHAPES:
238 for dab, dc in triples:238 for dab, dc in triples:
239 yield (239 yield (
240- f"mmad-evg-{op.replace('_', '-')}-{m}x{n}x{k}-{dab}-{dc}",240+ f"mmad-epilogue-{op.replace('_', '-')}-{m}x{n}x{k}-{dab}-{dc}",
241 [[241 [[
242- f"basic_mmad_evg/matmul_{op}.py",242+ f"basic_mmad_epilogue/matmul_{op}.py",
243 "--m", m, "--n", n, "--k", k,243 "--m", m, "--n", n, "--k", k,
244 "--dtype-a", dab, "--dtype-b", dab, "--dtype-c", dc,244 "--dtype-a", dab, "--dtype-b", dab, "--dtype-c", dc,
245 *dev245 *dev
@@ -29,7 +29,7 @@
29# @dataclass instance unpacked into scalar kernel args).29# @dataclass instance unpacked into scalar kernel args).
30# python/tla_dsl/examples/end_to_end/print_tensor (print_tensor.py: all eight30# python/tla_dsl/examples/end_to_end/print_tensor (print_tensor.py: all eight
31# supported GM/UB dtypes plus multi-block and multi-call cases).31# supported GM/UB dtypes plus multi-block and multi-call cases).
32-# python/tla_dsl/examples/end_to_end/basic_mmad_evg (matmul_add.py, matmul_add_ub.py,32+# python/tla_dsl/examples/end_to_end/basic_mmad_epilogue (matmul_add.py, matmul_add_ub.py,
33# matmul_bias.py, matmul_leaky_relu.py, matmul_sigmoid.py, matmul_silu.py, matmul_tanh.py).33# matmul_bias.py, matmul_leaky_relu.py, matmul_sigmoid.py, matmul_silu.py, matmul_tanh.py).
34# python/tla_dsl/examples/end_to_end/flash_attention_infer (flash_attention_infer.py).34# python/tla_dsl/examples/end_to_end/flash_attention_infer (flash_attention_infer.py).
35# python/tla_dsl/examples/end_to_end/lazy_conditions (lazy_conditions.py).35# python/tla_dsl/examples/end_to_end/lazy_conditions (lazy_conditions.py).
@@ -140,13 +140,13 @@ LAZY_CONDITIONS_REL="examples/end_to_end/lazy_conditions/lazy_conditions.py"
140SIMT_VADD_REL="examples/end_to_end/simt/basic_vadd_simt.py"140SIMT_VADD_REL="examples/end_to_end/simt/basic_vadd_simt.py"
141MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py"141MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/multi_core_splitk_matmul.py"
142TAIL_MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py"142TAIL_MULTI_CORE_SPLITK_REL="examples/end_to_end/multi_core_splitk_matmul/tail_multi_core_splitk_matmul.py"
143-BASIC_MMAD_EVG_ADD_REL="examples/end_to_end/basic_mmad_evg/matmul_add.py"143+BASIC_MMAD_EPILOGUE_ADD_REL="examples/end_to_end/basic_mmad_epilogue/matmul_add.py"
144-BASIC_MMAD_EVG_ADD_UB_REL="examples/end_to_end/basic_mmad_evg/matmul_add_ub.py"144+BASIC_MMAD_EPILOGUE_ADD_UB_REL="examples/end_to_end/basic_mmad_epilogue/matmul_add_ub.py"
145-BASIC_MMAD_EVG_BIAS_REL="examples/end_to_end/basic_mmad_evg/matmul_bias.py"145+BASIC_MMAD_EPILOGUE_BIAS_REL="examples/end_to_end/basic_mmad_epilogue/matmul_bias.py"
146-BASIC_MMAD_EVG_LEAKY_RELU_REL="examples/end_to_end/basic_mmad_evg/matmul_leaky_relu.py"146+BASIC_MMAD_EPILOGUE_LEAKY_RELU_REL="examples/end_to_end/basic_mmad_epilogue/matmul_leaky_relu.py"
147-BASIC_MMAD_EVG_SIGMOID_REL="examples/end_to_end/basic_mmad_evg/matmul_sigmoid.py"147+BASIC_MMAD_EPILOGUE_SIGMOID_REL="examples/end_to_end/basic_mmad_epilogue/matmul_sigmoid.py"
148-BASIC_MMAD_EVG_SILU_REL="examples/end_to_end/basic_mmad_evg/matmul_silu.py"148+BASIC_MMAD_EPILOGUE_SILU_REL="examples/end_to_end/basic_mmad_epilogue/matmul_silu.py"
149-BASIC_MMAD_EVG_TANH_REL="examples/end_to_end/basic_mmad_evg/matmul_tanh.py"149+BASIC_MMAD_EPILOGUE_TANH_REL="examples/end_to_end/basic_mmad_epilogue/matmul_tanh.py"
150CAST_MULTI_REL="examples/end_to_end/vector_ops/cast_multi.py"150CAST_MULTI_REL="examples/end_to_end/vector_ops/cast_multi.py"
151GATHER_OP_REL="examples/end_to_end/vector_ops/gather_op.py"151GATHER_OP_REL="examples/end_to_end/vector_ops/gather_op.py"
152 152 
@@ -201,7 +201,7 @@ Run end-to-end validation for:
201 per-field scalar kernel args; constexpr + tensor + scalar fields)201 per-field scalar kernel args; constexpr + tensor + scalar fields)
202 - print_tensor (print_tensor.py: all supported GM/UB dtypes with AIV/AIC202 - print_tensor (print_tensor.py: all supported GM/UB dtypes with AIV/AIC
203 multi-block and multi-call coverage)203 multi-block and multi-call coverage)
204- - basic_mmad_evg (matmul_add.py, ...: CV fused examples)204+ - basic_mmad_epilogue (matmul_add.py, ...: CV fused examples)
205 - flash_attention_infer (flash_attention_infer.py)205 - flash_attention_infer (flash_attention_infer.py)
206 - lazy_conditions (lazy_conditions.py)206 - lazy_conditions (lazy_conditions.py)
207 - simt (basic_vadd_simt.py: SIMT thread-block add)207 - simt (basic_vadd_simt.py: SIMT thread-block add)
@@ -532,32 +532,32 @@ if [[ ! -f "${CATLASS_DSL_DIR}/${GROUPED_MATMUL_SLICEM_REL}" ]]; then
532 echo "error: missing ${GROUPED_MATMUL_SLICEM_REL} under ${CATLASS_DSL_DIR}" >&2532 echo "error: missing ${GROUPED_MATMUL_SLICEM_REL} under ${CATLASS_DSL_DIR}" >&2
533 exit 1533 exit 1
534fi534fi
535-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_ADD_REL}" ]]; then535+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_ADD_REL}" ]]; then
536- echo "error: missing ${BASIC_MMAD_EVG_ADD_REL} under ${CATLASS_DSL_DIR}" >&2536+ echo "error: missing ${BASIC_MMAD_EPILOGUE_ADD_REL} under ${CATLASS_DSL_DIR}" >&2
537 exit 1537 exit 1
538fi538fi
539-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_ADD_UB_REL}" ]]; then539+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_ADD_UB_REL}" ]]; then
540- echo "error: missing ${BASIC_MMAD_EVG_ADD_UB_REL} under ${CATLASS_DSL_DIR}" >&2540+ echo "error: missing ${BASIC_MMAD_EPILOGUE_ADD_UB_REL} under ${CATLASS_DSL_DIR}" >&2
541 exit 1541 exit 1
542fi542fi
543-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_BIAS_REL}" ]]; then543+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_BIAS_REL}" ]]; then
544- echo "error: missing ${BASIC_MMAD_EVG_BIAS_REL} under ${CATLASS_DSL_DIR}" >&2544+ echo "error: missing ${BASIC_MMAD_EPILOGUE_BIAS_REL} under ${CATLASS_DSL_DIR}" >&2
545 exit 1545 exit 1
546fi546fi
547-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_LEAKY_RELU_REL}" ]]; then547+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_LEAKY_RELU_REL}" ]]; then
548- echo "error: missing ${BASIC_MMAD_EVG_LEAKY_RELU_REL} under ${CATLASS_DSL_DIR}" >&2548+ echo "error: missing ${BASIC_MMAD_EPILOGUE_LEAKY_RELU_REL} under ${CATLASS_DSL_DIR}" >&2
549 exit 1549 exit 1
550fi550fi
551-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_SIGMOID_REL}" ]]; then551+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_SIGMOID_REL}" ]]; then
552- echo "error: missing ${BASIC_MMAD_EVG_SIGMOID_REL} under ${CATLASS_DSL_DIR}" >&2552+ echo "error: missing ${BASIC_MMAD_EPILOGUE_SIGMOID_REL} under ${CATLASS_DSL_DIR}" >&2
553 exit 1553 exit 1
554fi554fi
555-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_SILU_REL}" ]]; then555+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_SILU_REL}" ]]; then
556- echo "error: missing ${BASIC_MMAD_EVG_SILU_REL} under ${CATLASS_DSL_DIR}" >&2556+ echo "error: missing ${BASIC_MMAD_EPILOGUE_SILU_REL} under ${CATLASS_DSL_DIR}" >&2
557 exit 1557 exit 1
558fi558fi
559-if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EVG_TANH_REL}" ]]; then559+if [[ ! -f "${CATLASS_DSL_DIR}/${BASIC_MMAD_EPILOGUE_TANH_REL}" ]]; then
560- echo "error: missing ${BASIC_MMAD_EVG_TANH_REL} under ${CATLASS_DSL_DIR}" >&2560+ echo "error: missing ${BASIC_MMAD_EPILOGUE_TANH_REL} under ${CATLASS_DSL_DIR}" >&2
561 exit 1561 exit 1
562fi562fi
563if [[ ! -f "${CATLASS_DSL_DIR}/${CAST_MULTI_REL}" ]]; then563if [[ ! -f "${CATLASS_DSL_DIR}/${CAST_MULTI_REL}" ]]; then