Skip to content

Commit 0a0697d

Browse files
committed
2 parents bc0de51 + 3ebfc1f commit 0a0697d

File tree

36 files changed

+13749
-0
lines changed

36 files changed

+13749
-0
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# CUPTI 活动跟踪教程
2+
3+
> GitHub 仓库和完整教程可在 <https://github.com/eunomia-bpf/cupti-tutorial> 获取。
4+
5+
## 简介
6+
7+
对CUDA应用程序进行性能分析对于理解其性能特征至关重要。CUPTI Activity API 提供了一种强大的方法来收集CUDA API调用和GPU活动的详细跟踪信息。本教程解释如何使用CUPTI收集和分析这些数据。
8+
9+
## 您将学到什么
10+
11+
- 如何初始化CUPTI Activity API
12+
- 设置和管理活动记录缓冲区
13+
- 处理来自多个源的活动记录
14+
- 解释活动数据以进行优化
15+
16+
## 代码演练
17+
18+
### 1. 设置活动跟踪
19+
20+
活动跟踪系统的核心围绕缓冲区管理展开。CUPTI请求缓冲区来存储活动记录,并在这些缓冲区被填满时通知。
21+
22+
```cpp
23+
// 缓冲区请求回调 - 当CUPTI需要新缓冲区时调用
24+
static void CUPTIAPI bufferRequested(uint8_t **buffer, size_t *size, size_t *maxNumRecords)
25+
{
26+
// 为CUPTI记录分配缓冲区
27+
*size = BUF_SIZE;
28+
*buffer = (uint8_t *)malloc(*size + ALIGN_SIZE);
29+
30+
// 确保缓冲区正确对齐
31+
*buffer = ALIGN_BUFFER(*buffer, ALIGN_SIZE);
32+
*maxNumRecords = 0;
33+
}
34+
```
35+
36+
当CUPTI请求缓冲区来存储活动记录时,此函数分配内存。对齐对性能很重要。
37+
38+
### 2. 处理已完成的缓冲区
39+
40+
```cpp
41+
// 缓冲区完成回调 - 当CUPTI填满缓冲区时调用
42+
static void CUPTIAPI bufferCompleted(CUcontext ctx, uint32_t streamId, uint8_t *buffer, size_t size, size_t validSize)
43+
{
44+
CUpti_Activity *record = NULL;
45+
46+
// 处理缓冲区中的所有记录
47+
CUptiResult status = CUPTI_SUCCESS;
48+
while (validSize > 0) {
49+
status = cuptiActivityGetNextRecord(buffer, validSize, &record);
50+
if (status == CUPTI_SUCCESS) {
51+
printActivity(record);
52+
validSize -= record->common.size;
53+
buffer += record->common.size;
54+
}
55+
else
56+
break;
57+
}
58+
59+
free(buffer);
60+
}
61+
```
62+
63+
当CUPTI用活动数据填满缓冲区时,此回调处理每个记录,然后释放缓冲区。
64+
65+
### 3. 活动记录处理
66+
67+
`printActivity` 函数是分析的核心,解释不同类型的活动:
68+
69+
```cpp
70+
static void printActivity(CUpti_Activity *record)
71+
{
72+
switch (record->kind) {
73+
case CUPTI_ACTIVITY_KIND_DEVICE:
74+
// 打印设备信息
75+
...
76+
case CUPTI_ACTIVITY_KIND_MEMCPY:
77+
// 打印内存复制详细信息
78+
...
79+
case CUPTI_ACTIVITY_KIND_KERNEL:
80+
// 打印内核执行详细信息
81+
...
82+
83+
// 更多活动类型...
84+
}
85+
}
86+
```
87+
88+
每种活动类型提供不同的见解:
89+
- 设备活动显示硬件能力
90+
- 内存复制活动显示数据传输模式和时间
91+
- 内核活动显示执行时间和参数
92+
93+
### 4. 初始化和清理
94+
95+
```cpp
96+
void initTrace()
97+
{
98+
// 为缓冲区管理注册回调
99+
CUPTI_CALL(cuptiActivityRegisterCallbacks(bufferRequested, bufferCompleted));
100+
101+
// 启用各种活动类型
102+
CUPTI_CALL(cuptiActivityEnable(CUPTI_ACTIVITY_KIND_DEVICE));
103+
CUPTI_CALL(cuptiActivityEnable(CUPTI_ACTIVITY_KIND_CONTEXT));
104+
CUPTI_CALL(cuptiActivityEnable(CUPTI_ACTIVITY_KIND_KERNEL));
105+
// ... 更多活动类型 ...
106+
107+
// 捕获时间戳以标准化时间
108+
CUPTI_CALL(cuptiGetTimestamp(&startTimestamp));
109+
}
110+
111+
void finiTrace()
112+
{
113+
// 刷新任何剩余数据
114+
CUPTI_CALL(cuptiActivityFlushAll(0));
115+
}
116+
```
117+
118+
初始化函数启用您想要监控的特定活动类型并注册回调。清理函数确保处理所有数据。
119+
120+
### 5. 测试内核
121+
122+
示例使用简单的向量加法内核(在 `vec.cu` 中)来生成要跟踪的活动:
123+
124+
```cpp
125+
__global__ void vecAdd(const float *A, const float *B, float *C, int numElements)
126+
{
127+
int i = blockDim.x * blockIdx.x + threadIdx.x;
128+
if (i < numElements)
129+
C[i] = A[i] + B[i];
130+
}
131+
```
132+
133+
## 运行示例
134+
135+
1. 构建示例:
136+
```bash
137+
make
138+
```
139+
140+
2. 运行活动跟踪:
141+
```bash
142+
./activity_trace
143+
```
144+
145+
## 理解输出
146+
147+
输出显示活动的时间顺序跟踪:
148+
149+
```
150+
设备 Device Name (0),计算能力 7.0,全局内存(带宽 900 GB/s,大小 16000 MB),多处理器 80,时钟 1530 MHz
151+
上下文 1,设备 0,计算 API CUDA,NULL 流 1
152+
驱动器_API cuCtxCreate [ 10223 - 15637 ]
153+
内存复制 HtoD [ 22500 - 23012 ] 设备 0,上下文 1,流 7,相关性 1/1
154+
内核 "vecAdd" [ 32058 - 35224 ] 设备 0,上下文 1,流 7,相关性 2
155+
内存复制 DtoH [ 40388 - 41002 ] 设备 0,上下文 1,流 7,相关性 3/3
156+
```
157+
158+
让我们解码这些信息:
159+
1. **设备信息**:显示GPU能力
160+
2. **上下文创建**:CUDA上下文初始化
161+
3. **内存复制**
162+
- `HtoD`(主机到设备)显示数据正在上传到GPU
163+
- `DtoH`(设备到主机)显示结果正在下载
164+
4. **内核执行**:显示我们向量加法的执行时间
165+
166+
时间戳(方括号中)标准化为跟踪开始时的时间,使得容易看到操作的相对时序。
167+
168+
## 性能见解
169+
170+
使用这些跟踪数据,您可以:
171+
- 识别内存传输中的瓶颈
172+
- 确定内核执行效率
173+
- 找到同步点及其影响
174+
- 测量CUDA API调用的开销
175+
176+
## 下一步
177+
178+
- 尝试修改向量大小以查看它如何影响性能
179+
- 启用其他活动类型以收集更详细的信息
180+
- 比较您自己应用程序中不同GPU操作的时序
181+
- 探索CUPTI的其他基于活动的示例以获得更高级的跟踪功能

0 commit comments

Comments
 (0)