专栏名称: 自动驾驶之心
自动驾驶开发者社区,关注计算机视觉、多维感知融合、部署落地、定位规控、领域方案等,坚持为领域输出最前沿的技术方向!
目录
相关文章推荐
爱否科技  ·  联发科天玑开发者大会 2025 官宣 4 ... ·  2 天前  
CINNO  ·  诺视科技完成A轮融资!Micro ... ·  2 天前  
环球物理  ·  【物理动图】超炫酷的机械动图 ·  2 天前  
51好读  ›  专栏  ›  自动驾驶之心

如何优雅地测量GPU CUDA Kernel耗时?

自动驾驶之心  · 公众号  ·  · 2024-10-30 07:30

正文

作者 | Rainlin  编辑 | 自动驾驶之心

原文链接:https://zhuanlan.zhihu.com/p/3278397099

点击下方 卡片 ,关注“ 自动驾驶之心 ”公众号

戳我-> 领取 自动驾驶近15个 方向 学习 路线

>> 点击进入→ 自动驾驶之心 CUDA 技术交流群

本文只做学术分享,如有侵权,联系删文

背景

Rainlin:如何优雅地测量GPU CUDA Kernel耗时?(一)中介绍了常用的测量gpu耗时方法,而实际应用中,还会遇到其他的问题,比如:

  1. 为什么同样的输入,测量的耗时存在较大差距?
  2. 怎样才能精确的测量kernel耗时?

问题

我们看以下常见代码,仅仅做了linear操作:

def test():
    a_size = (20, 8192)
    b_size = (5120, 8192)
    events = [
        [torch.cuda.Event(enable_timing=True) for _ in range(6)] for _ in range(50)
    ]

    # warm up
    for _ in range(10):
        a = torch.rand(a_size, dtype=torch.float16).cuda()
        b = torch.rand(
            b_size,
            dtype=torch.float16,
        ).cuda()
        c = F.linear(a, b)

    # 测量
    for i in range(10):
        a = torch.rand(a_size, dtype=torch.float16).cuda()
        b = torch.rand(b_size, dtype=torch.float16).cuda()

        events[i][0].record()
        c = F.linear(a, b)
        events[i][1].record()

        events[i][2].record()
        c = F.linear(a, b)
        events[i][3].record()

        events[i][4].record()
        c = F.linear(a, b)
        events[i][5].record()
    torch.cuda.synchronize()

    # 输出时间
    for i in range(5):
        print(
            f"{i}: t1:{events[i][0].elapsed_time(events[i][1])},t2:{events[i][2].elapsed_time(events[i][3])},t3:{events[i][4].elapsed_time(events[i][5])}"
        )
    torch.cuda.synchronize()


if __name__ == "__main__":
    test()

以上代码在A100上输出为:

可以看到,t1耗时远大于t2与t3,显然这不合理,同样的输入,计算时间不可能相差这么多,接下来我们逐步分析。

为什么同样的输入,kernel的耗时相差巨大?

我们先对以上代码进行nsys分析:

观察到:三次linear在kernel层面只有60us+,但torch.cuda.event测量与nsys没对齐,第一次远大于kernel运行的时间。 推测第一次torch.cuda.event测量的耗时并非kernel的耗时,应该包含了其他部分的耗时。

观察到代码:

 a = torch.rand(a_size, dtype=torch.float16).cuda()
        b = torch.rand(b_size, dtype=torch.float16).cuda()

这里存在cpu数据拷贝到gpu,猜测torch.cuda.event把拷贝的时间也算进去了,那我们去掉拷贝试试:

.....
 
for i in range(10):
        # 改成直接从GPU生成rand数据,而不是拷贝
        a = torch.rand(a_size, dtype=torch.float16, device="cuda")
        b = torch.rand(b_size, dtype=torch.float16, device="cuda"






请到「今天看啥」查看全文