Skip to content

Commit 397a0a3

Browse files
committed
update
1 parent c25932f commit 397a0a3

File tree

8 files changed

+83
-215
lines changed

8 files changed

+83
-215
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@
3131
*.out
3232
*.app
3333
.DS_Store
34+
.vscode

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
+ 使用多个 GPU 计算
5555
+ ...(补充中)
5656

57-
### 大师系列 💡
57+
### Triton 系列 💡
5858

59-
我现在还不知道写啥,毕竟我现在还是菜鸡~~
59+
+ [Triton 编程范式入门](./docs/18_triton/01_triton_programming_paradigms/README.md)
6060

6161
### LLM 推理技术 🤖
6262

docs/18_triton/01_triton_programming_paradigms/README.md

Lines changed: 11 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -198,38 +198,11 @@ Triton 的 `mask` 机制则完全不同。`mask = offsets < n_elements` 是一
198198

199199
#### CUDA 的执行方式
200200

201-
```
202-
配置:blockSize = 256, numBlocks = 40
203-
204-
Grid
205-
├── Block[0] Block[1] ... Block[39]
206-
│ ├── Thread[0] ├── Thread[0] ├── Thread[0]
207-
│ │ 处理 idx=0 │ 处理 idx=256 │ 处理 idx=9984
208-
│ ├── Thread[1] ├── Thread[1] ├── Thread[1]
209-
│ │ 处理 idx=1 │ 处理 idx=257 │ 处理 idx=9985
210-
│ ├── ... ├── ... ├── ...
211-
│ └── Thread[255] └── Thread[255] └── Thread[255]
212-
│ 处理 idx=255 处理 idx=511 处理 idx=10239 (越界!)
213-
214-
总共启动: 40 × 256 = 10240 个线程
215-
其中 240 个线程因为 if (idx < 10000) 被过滤掉
216-
```
201+
![图 0](images/a476e6f0adb4c9de8c67f9451247ff520d044a1cdc65708a2760b94fa4e803f3.png)
217202

218203
#### Triton 的执行方式
219204

220-
```
221-
配置:BLOCK_SIZE = 1024, numPrograms = 10
222-
223-
Grid
224-
├── Program[0] Program[1] ... Program[9]
225-
│ 处理元素 处理元素 处理元素
226-
│ [0~1023] [1024~2047] [9216~10239]
227-
│ (其中 10000~10239 被 mask 过滤)
228-
229-
总共启动: 10 个 Program Instance
230-
每个 Program 处理 1024 个元素(向量化)
231-
Triton 内部会自动映射到合适的线程配置
232-
```
205+
![图 1](images/0d3e9e7c3877312abfbde75dea15acc1e2b671548a26a4e86a114ce6a59a22cd.png)
233206

234207
从这个例子可以看出,CUDA 启动了 10240 个线程,你需要思考"我是第几号线程"。而 Triton 只启动了 10 个 Program Instance,你要思考的是"我处理哪批数据"。这种抽象层次的提升,让代码更简洁,也更容易理解。
235208

@@ -263,26 +236,21 @@ Triton 的 Grid 配置则简单得多,你只需要指定 `BLOCK_SIZE`(每个
263236

264237
## 四、课后练习
265238

266-
请打开 `01_exercises.py` 完成以下三个练习:练习 1 实现 AXPY 操作($Z = \alpha \cdot X + Y$),巩固基本的向量化加载和存储;练习 2 测试不同 `BLOCK_SIZE` 的性能影响,理解为什么 Triton 的最优 `BLOCK_SIZE` 比 CUDA 的 `blockDim` 要大;练习 3 实现 1D 卷积,体会如何用向量化方式处理滑动窗口操作。每个练习都包含了测试函数和思考题。
239+
请打开 [homework.ipynb](https://github.com/PaddleJitLab/CUDATutorial/tree/develop/docs/18_triton/01_triton_programming_paradigms/homework.ipynb) 完成以下练习:练习 1 实现 AXPY 操作($Z = \alpha \cdot X + Y$),巩固基本的向量化加载和存储;练习 2 实现 1D 卷积,体会如何用向量化方式处理滑动窗口操作。每个练习都包含了测试函数和思考题。
267240

268241
## 五、常见问题 FAQ
269242

270-
### Q1: Triton 的 BLOCK_SIZE 应该设置多大?
271-
272-
**A**: 如果你有 CUDA 经验,需要注意 CUDA 的经验值在这里不适用。CUDA 的 `blockDim.x` 通常设置为 128/256/512,而 Triton 的 `BLOCK_SIZE` 通常要大得多,一般是 1024/2048/4096。这是因为 Triton 的 `BLOCK_SIZE` 表示的是元素数,而不是线程数。建议从 1024 开始尝试,然后根据性能 profiling 的结果进行调整。影响最优 `BLOCK_SIZE` 的因素包括:寄存器使用量、Shared Memory 大小、以及数据复用程度。
273-
274-
275-
### Q2: Triton 内部到底有没有线程?性能会比 CUDA 差吗?
276-
277-
**A**: Triton 内部是有线程的,只是抽象层次更高,不暴露给程序员。Triton 编译器会将你写的向量化代码编译成高效的 PTX(GPU 汇编),最终还是在 GPU 的线程上执行。在性能方面,对于简单算子(如 element-wise 操作),Triton 的性能可以接近手写的优化 CUDA 代码;对于复杂算子(如 Flash Attention),Triton 可以达到优化后 CUDA 的 95% 以上的性能。但在开发效率方面,Triton 远远领先于 CUDA。
243+
### Q1: Triton 内部到底有没有线程?性能会比 CUDA 差吗?
278244

245+
**A**: 从硬件执行层面看,Triton 代码最终仍然运行在 GPU 的线程和 warp 上,只是 Triton 提供了更高层次的编程抽象,不直接暴露线程和 block 的概念。Triton 编译器会将向量化的程序描述转换为高效的 PTX / SASS,并映射到底层 GPU 执行模型。在性能方面,对于简单算子(如 element-wise 或带宽受限算子),Triton 通常可以达到接近手写 CUDA 的性能;对于高度优化的复杂算子(如 Flash Attention),Triton 在实践中也能达到与优化 CUDA 实现相当、或略低的性能水平。相比之下,Triton 在开发效率和可维护性方面通常具有明显优势。
279246

280-
### Q3: mask 操作会导致性能下降吗?(类似 Warp Divergence)
281247

282-
**A**: Triton 的 `mask` 是向量化的,编译器会生成 predicated instructions(带谓词的指令),不会像 CUDA 的标量 `if` 那样导致严重的 Warp Divergence。性能损失通常可以忽略。从技术细节来看,现代 GPU 支持 predicated execution,每个线程都有独立的 predicate 寄存器。Triton 编译器会自动将 `mask` 映射到这些硬件特性,因此可以在不引入分支的情况下实现条件执行。
248+
### Q2: mask 操作会导致性能下降吗?(类似 Warp Divergence
283249

250+
**A**: Triton 的 mask 是向量化语义,编译器通常会将其生成 predicated instructions(带谓词的指令),而不是显式的分支跳转,因此不会像 CUDA 中不当使用 if 那样引入严重的 warp divergence。
251+
在大多数连续访问、边界检查类场景中,mask 带来的性能开销较小;但如果 mask 覆盖比例很大或访问模式高度稀疏,仍然可能造成一定的算力浪费。总体而言,mask 是 Triton 中推荐且高效的边界处理方式。
284252

285-
### Q4: 什么时候不能用 Triton?
253+
### Q3: 什么时候不能用 Triton?
286254

287255
**A**: 以下场景建议使用 CUDA:
288256
1. 需要显式管理 Shared Memory 布局(如手动消除 Bank Conflicts)
@@ -291,7 +259,7 @@ Triton 的 Grid 配置则简单得多,你只需要指定 `BLOCK_SIZE`(每个
291259
4. 算法严重依赖线程间细粒度通信
292260
5. 需要与现有 CUDA 代码库深度集成
293261

294-
### Q5: 如何从 CUDA 代码迁移到 Triton?
262+
### Q4: 如何从 CUDA 代码迁移到 Triton?
295263

296264
**A**: 五步迁移法:
297265

@@ -355,4 +323,4 @@ Triton 的 Grid 配置则简单得多,你只需要指定 `BLOCK_SIZE`(每个
355323
- [OpenAI Triton GitHub](https://github.com/openai/triton)
356324
- [CUDA Programming Guide](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html)
357325

358-
**下一步**:完成所有练习后,进入 **Module 02: 内存与数据搬运**,学习更复杂的内存访问模式!
326+
**下一步**:完成所有练习后,进入 **02: 内存与数据搬运**,学习更复杂的内存访问模式!

docs/18_triton/01_triton_programming_paradigms/homework.ipynb

Lines changed: 56 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -132,145 +132,7 @@
132132
"source": [
133133
"---\n",
134134
"\n",
135-
"## 练习 2: 性能测试 - BLOCK_SIZE 的影响\n",
136-
"\n",
137-
"**目标**:探索不同 `BLOCK_SIZE` 对性能的影响,找出最优配置\n",
138-
"\n",
139-
"这个练习帮助你理解为什么 Triton 的 `BLOCK_SIZE` 通常比 CUDA 的 `blockDim` 大得多。\n",
140-
"\n",
141-
"**测试方案**:\n",
142-
"- 使用向量加法作为基准测试\n",
143-
"- 测试不同的 `BLOCK_SIZE`: [128, 256, 512, 1024, 2048, 4096]\n",
144-
"- 测量执行时间和内存带宽"
145-
]
146-
},
147-
{
148-
"cell_type": "code",
149-
"execution_count": null,
150-
"metadata": {},
151-
"outputs": [],
152-
"source": [
153-
"# 向量加法 Kernel(用于性能测试)\n",
154-
"@triton.jit\n",
155-
"def add_kernel(x_ptr, y_ptr, output_ptr, n_elements, BLOCK_SIZE: tl.constexpr):\n",
156-
" pid = tl.program_id(axis=0)\n",
157-
" block_start = pid * BLOCK_SIZE\n",
158-
" offsets = block_start + tl.arange(0, BLOCK_SIZE)\n",
159-
" mask = offsets < n_elements\n",
160-
" x = tl.load(x_ptr + offsets, mask=mask)\n",
161-
" y = tl.load(y_ptr + offsets, mask=mask)\n",
162-
" output = x + y\n",
163-
" tl.store(output_ptr + offsets, output, mask=mask)"
164-
]
165-
},
166-
{
167-
"cell_type": "code",
168-
"execution_count": null,
169-
"metadata": {},
170-
"outputs": [],
171-
"source": [
172-
"def benchmark_block_size(block_size, x, y, output, warmup=10, repeat=100):\n",
173-
" \"\"\"基准测试单个 BLOCK_SIZE\"\"\"\n",
174-
" n_elements = x.numel()\n",
175-
" grid = lambda meta: (triton.cdiv(n_elements, meta['BLOCK_SIZE']),)\n",
176-
" \n",
177-
" # Warmup\n",
178-
" for _ in range(warmup):\n",
179-
" add_kernel[grid](x, y, output, n_elements, BLOCK_SIZE=block_size)\n",
180-
" \n",
181-
" # Timing\n",
182-
" torch.cuda.synchronize()\n",
183-
" start_event = torch.cuda.Event(enable_timing=True)\n",
184-
" end_event = torch.cuda.Event(enable_timing=True)\n",
185-
" \n",
186-
" start_event.record()\n",
187-
" for _ in range(repeat):\n",
188-
" add_kernel[grid](x, y, output, n_elements, BLOCK_SIZE=block_size)\n",
189-
" end_event.record()\n",
190-
" \n",
191-
" torch.cuda.synchronize()\n",
192-
" time_ms = start_event.elapsed_time(end_event) / repeat\n",
193-
" \n",
194-
" # 计算带宽 (读 x, 读 y, 写 output)\n",
195-
" total_bytes = 3 * n_elements * 4 # float32 = 4 bytes\n",
196-
" bandwidth_gb_s = total_bytes / (time_ms * 1e-3) / 1e9\n",
197-
" \n",
198-
" return time_ms, bandwidth_gb_s"
199-
]
200-
},
201-
{
202-
"cell_type": "code",
203-
"execution_count": null,
204-
"metadata": {},
205-
"outputs": [],
206-
"source": [
207-
"# 运行基准测试\n",
208-
"size = 1024 * 1024 * 10 # 10M elements\n",
209-
"x = torch.randn(size, device='cuda', dtype=torch.float32)\n",
210-
"y = torch.randn(size, device='cuda', dtype=torch.float32)\n",
211-
"output = torch.empty_like(x)\n",
212-
"\n",
213-
"block_sizes = [128, 256, 512, 1024, 2048, 4096]\n",
214-
"results = []\n",
215-
"\n",
216-
"print(f\"{'BLOCK_SIZE':<15} {'Time (ms)':<15} {'Bandwidth (GB/s)':<20}\")\n",
217-
"print(\"-\" * 50)\n",
218-
"\n",
219-
"for bs in block_sizes:\n",
220-
" time_ms, bandwidth = benchmark_block_size(bs, x, y, output)\n",
221-
" results.append((bs, time_ms, bandwidth))\n",
222-
" print(f\"{bs:<15} {time_ms:<15.3f} {bandwidth:<20.2f}\")"
223-
]
224-
},
225-
{
226-
"cell_type": "code",
227-
"execution_count": null,
228-
"metadata": {},
229-
"outputs": [],
230-
"source": [
231-
"# 可视化结果\n",
232-
"block_sizes_list = [r[0] for r in results]\n",
233-
"bandwidths = [r[2] for r in results]\n",
234-
"\n",
235-
"plt.figure(figsize=(10, 5))\n",
236-
"plt.plot(block_sizes_list, bandwidths, marker='o', linewidth=2, markersize=8)\n",
237-
"plt.xlabel('BLOCK_SIZE', fontsize=12)\n",
238-
"plt.ylabel('Bandwidth (GB/s)', fontsize=12)\n",
239-
"plt.title('Triton BLOCK_SIZE vs Memory Bandwidth', fontsize=14)\n",
240-
"plt.grid(True, alpha=0.3)\n",
241-
"plt.xscale('log', base=2)\n",
242-
"plt.xticks(block_sizes_list, block_sizes_list)\n",
243-
"\n",
244-
"# 标注最佳 BLOCK_SIZE\n",
245-
"best_idx = bandwidths.index(max(bandwidths))\n",
246-
"plt.axvline(x=block_sizes_list[best_idx], color='r', linestyle='--', alpha=0.5)\n",
247-
"plt.text(block_sizes_list[best_idx], max(bandwidths) * 0.95, \n",
248-
" f'Best: {block_sizes_list[best_idx]}', ha='center', fontsize=10, color='r')\n",
249-
"\n",
250-
"plt.tight_layout()\n",
251-
"plt.show()\n",
252-
"\n",
253-
"print(f\"\\n🏆 最优 BLOCK_SIZE: {block_sizes_list[best_idx]}\")\n",
254-
"print(f\"🏆 最高带宽: {max(bandwidths):.2f} GB/s\")"
255-
]
256-
},
257-
{
258-
"cell_type": "markdown",
259-
"metadata": {},
260-
"source": [
261-
"**思考题**:\n",
262-
"1. 为什么 `BLOCK_SIZE=128` 性能较差?(提示:GPU 利用率)\n",
263-
"2. 为什么 `BLOCK_SIZE=4096` 可能也不理想?(提示:寄存器压力)\n",
264-
"3. 对比 CUDA 的 `blockDim.x` 常用值(256),Triton 的最优 `BLOCK_SIZE` 为什么更大?"
265-
]
266-
},
267-
{
268-
"cell_type": "markdown",
269-
"metadata": {},
270-
"source": [
271-
"---\n",
272-
"\n",
273-
"## 练习 3: 1D 卷积(挑战)\n",
135+
"## 练习 2: 1D 卷积(挑战)\n",
274136
"\n",
275137
"**目标**:实现简单的 1D 卷积(3-tap box filter):$Y[i] = X[i-1] + X[i] + X[i+1]$\n",
276138
"\n",
@@ -304,7 +166,6 @@
304166
" # ==================== 在下方编写代码 ====================\n",
305167
" \n",
306168
" \n",
307-
" \n",
308169
" # ========================================================\n",
309170
" pass\n",
310171
"\n",
@@ -351,36 +212,13 @@
351212
" print(f\"Torch: {y_torch[:5].cpu().numpy()}\")"
352213
]
353214
},
354-
{
355-
"cell_type": "code",
356-
"execution_count": null,
357-
"metadata": {},
358-
"outputs": [],
359-
"source": [
360-
"# 可视化卷积效果(可选)\n",
361-
"size = 100\n",
362-
"x = torch.randn(size, device='cuda', dtype=torch.float32)\n",
363-
"y = run_conv1d(x)\n",
364-
"\n",
365-
"plt.figure(figsize=(12, 5))\n",
366-
"plt.plot(x.cpu().numpy(), label='Input', alpha=0.7)\n",
367-
"plt.plot(y.cpu().numpy(), label='Output (Smoothed)', alpha=0.7, linewidth=2)\n",
368-
"plt.xlabel('Index')\n",
369-
"plt.ylabel('Value')\n",
370-
"plt.title('1D Convolution: Box Filter (3-tap)')\n",
371-
"plt.legend()\n",
372-
"plt.grid(True, alpha=0.3)\n",
373-
"plt.tight_layout()\n",
374-
"plt.show()"
375-
]
376-
},
377215
{
378216
"cell_type": "markdown",
379217
"metadata": {},
380218
"source": [
381219
"**思考题**(高级):\n",
382220
"1. 为什么这种方法效率不高?(提示:重复加载)\n",
383-
"2. 如何优化?(提示:Shared Memory 或加载更大的块然后切片"
221+
"2. 如何优化?(提示:加载更大的块然后切片"
384222
]
385223
},
386224
{
@@ -391,12 +229,61 @@
391229
"\n",
392230
"## 总结\n",
393231
"\n",
394-
"完成这三个练习后,你应该:\n",
395-
"- 掌握了 Triton kernel 的基本写法\n",
396-
"- 理解了 `BLOCK_SIZE` 对性能的重要影响\n",
397-
"- 学会了如何处理复杂的内存访问模式\n",
232+
"完成这三个练习后,你应该掌握了 Triton kernel 的基本写法\n",
233+
"\n",
234+
"**下一步**:学习 Triton 的 Shared Memory 和 Block Reduction 操作!\n",
235+
"\n",
236+
"## 课后答案\n",
237+
"\n",
238+
"```python\n",
239+
"@triton.jit\n",
240+
"def axpy_kernel(\n",
241+
" x_ptr, y_ptr, z_ptr,\n",
242+
" n_elements,\n",
243+
" alpha, # 标量参数\n",
244+
" BLOCK_SIZE: tl.constexpr\n",
245+
"):\n",
246+
" \"\"\"\n",
247+
" TODO: 实现 AXPY 操作\n",
248+
" 1. 计算 pid 和 offsets\n",
249+
" 2. 创建 mask\n",
250+
" 3. 加载 x 和 y\n",
251+
" 4. 计算 z = alpha * x + y\n",
252+
" 5. 存储 z\n",
253+
" \"\"\"\n",
254+
" # ==================== 在下方编写代码 ====================\n",
255+
" pid = tl.program_id(0)\n",
256+
" offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)\n",
257+
" mask = offsets < n_elements\n",
258+
" x = tl.load(x_ptr + offsets, mask=mask, other=0.0)\n",
259+
" y = tl.load(y_ptr + offsets, mask=mask, other=0.0)\n",
260+
" z = alpha * x + y\n",
261+
" tl.store(z_ptr + offsets, z, mask=mask)\n",
262+
" # ========================================================\n",
398263
"\n",
399-
"**下一步**:学习 Triton 的 Shared Memory 和 Block Reduction 操作!"
264+
"@triton.jit\n",
265+
"def conv1d_kernel(\n",
266+
" x_ptr, y_ptr,\n",
267+
" n_elements,\n",
268+
" BLOCK_SIZE: tl.constexpr\n",
269+
"):\n",
270+
" \"\"\"\n",
271+
" TODO: 实现 3-tap 1D 卷积\n",
272+
" Y[i] = X[i-1] + X[i] + X[i+1]\n",
273+
" \"\"\"\n",
274+
" # ==================== 在下方编写代码 ====================\n",
275+
" pid = tl.program_id(0)\n",
276+
" offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)\n",
277+
" mask = offsets < n_elements\n",
278+
" \n",
279+
" x_center = tl.load(x_ptr + offsets, mask=mask, other=0.0)\n",
280+
" x_left = tl.load(x_ptr + offsets - 1, mask=offsets > 0, other=0.0)\n",
281+
" x_right = tl.load(x_ptr + offsets + 1, mask=offsets < n_elements - 1, other=0.0)\n",
282+
" \n",
283+
" y = x_left + x_center + x_right\n",
284+
" tl.store(y_ptr + offsets, y, mask=mask)\n",
285+
" # =========================================================\n",
286+
"```"
400287
]
401288
}
402289
],
449 KB
Loading
473 KB
Loading

docs/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
+ 使用多个 GPU 计算
5050
+ ...(补充中)
5151

52-
### 大师系列 💡
52+
### Triton 系列 💡
53+
54+
+ [Triton 编程范式入门](/triton/triton_programming_paradigms)
5355

5456
我现在还不知道写啥,毕竟我现在还是菜鸡~~
5557

sidebars.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,16 @@ const sidebars = {
168168
}
169169
],
170170
},
171+
{
172+
type: 'category',
173+
label: 'Triton 系列',
174+
items: [
175+
{
176+
type: 'autogenerated',
177+
dirName: '18_triton/01_triton_programming_paradigms'
178+
},
179+
]
180+
},
171181
{
172182
type: 'category',
173183
label: 'LLM 推理技术',

0 commit comments

Comments
 (0)