软硬件协同迷思
软硬件的技术隔阂
最初的出发点是用自动调优在软件性能优化和硬件设计间建立直接联系,与传统自动调优不同的是,这要基于一些硬件设计参数去建模,并计算程序性能,而不是用真机或机器学习的黑盒模型,因为这样才能获得硬件设计参数的直接反馈,例如哪些参数组合是均衡的,哪些存在瓶颈且瓶颈在哪。
由此得出以下几个判断:
- 从改硬件设计、kernel优化、瓶颈分析再回到硬件设计,这个反馈链太长,互动效率往往不高;
- 手动优化汇编是落后的生产力,工作量大扩展性差;
- 算力比人力更有竞争力,机器自动搜索比人力搜索适用性更强;
- 问题复杂度增加时,算力比人力更容易扩展;
根据上述判断,结合目前可行的技术分析,可以在现有编译器的基础上,只加入新功能的简单支持,然后用上层语言最多是IR实现自动调优。
遇到的问题:
- 硬件功能在设计时就没仔细考虑软件的用法和使用场景。同时具备“硬件工程师+了解具体使用场景和流程”的人很少,这是架构师的能力范围。每个功能的软硬件对接都需要慢慢调试,没有几代产品的相互磨合,是很难做好的。需要有人能够既懂软件应用,懂一点编译器,也懂一点硬件架构,承担技术串联的角色,才能打破技术壁垒,更流畅地实现从底层硬件到上层软件的功能输送。
- 编译器的后端优化自动化程度远远不够,依然费时费力。如果只是使用x86和CUDA的编译器,因为这两家的编译器比较成熟,所以优化效果比较好,但是如果要支持新的ISA或者硬件架构,就需要自己去重新实现优化。LLVM中仅有tablegen+支持后端自动化优化,很多部分都要重新磨合;MLIR中有Table Driven Declarative Rewrite Rule,但自动化程度也有限;TVM中自动调优多数在LLVM以上,硬件后端优化不是重点。所以后端优化问题也需要解决。
- 硬件建模还是有很多看不清的工作量。对于一些简单的算子和算法,其运算过程哪些硬件参数有影响,能够大致有谱,但像Cache Hit Rate的估计,就有些玄妙。大部分时候有统计规律可循,但也有严重偏离规律的情况发生。这时候,软硬协同的价值也体现出来了,提前对接有助于暴露问题。对于硬件设计的规律,多数情况是软件迁就硬件,软件一要补硬件的坑,二要发挥硬件的能力。并且软件更新迭代成本更小,所以要用软件去补足硬件短板。
软硬件的分工和协作是难点
软硬件设计不是竞技,但有时候能做的事情选择不做,也是有一定考量的。在软件实现中,CUDA一些函数的corner case中会用到local memory,即使GPR充裕也不转存GPR,因为用local memory,只要不进入到这个corner 分支,那就几乎没有开销,最多费一点指令cache。而如果用GPR,那即使不进入这个分支,也会影响总GPR数,从而影响Occupancy。也就是说只要使用了额外的GPR,不管这部分代码有没有运行,它都有开销,即使有时候是无害的。
NV的硬件运行逻辑上也有很多限制,比如64bit或128bit访存指令的地址必须对齐,操作64bit和128bit的GPR也必须对齐。NV也有一些常见的指令不支持,也有些指令会重复。所以,很多功能的做或不做,还是有诸多考虑的。
NV的一些调度逻辑,例如control codes,也从硬件转移到了软件,这应该是因为编译器具有更全局的视野,可以更好地做依赖分析和指令调度,同时也简化硬件设计,节省面积。
还有一些功能被直接舍弃了,例如NV中没有算数异常处理的功能,比如除0,移除之类的,L1 Cache之间也没有Coherence。这很难用软件弥补,所以干脆软件和硬件都不支持了。
软硬件的信息传递和协同优化密切相关
一个应用,从算法开始,到软件实现,再到编译的中间表示,再到机器指令,都是信息一级一级传递的过程。协同优化也是信息交互的过程,例如最常见的矩阵乘法,在算子曾可以用标准实现,也可以用快速矩阵乘法实现,如果知道是卷积或者其他特殊矩阵,就可以有特定的加速算法。普通的矩阵乘算法,有相应的矩阵乘加速器或是tensorcore,也可以做相应的加速。如果是矩阵连乘或可融合的操作,在上层也容易实现相应的优化。
但是信息传递也存在很多困难,不管是C还是LLVM的IR,都有一些硬件操作难以表述,最终变成内置函数。内置函数多了,上层表示就难以理解和优化,最后会堆积到硬件后端,这其中会损失一些可能的优化。
最后到指令集的问题,什么样的指令集方便优化呢?显然,每个指令都一样慢的最好优化,只要没有冗余就算是优化好了,但这显然与设计追求不相符。我认为好的指令集应该具有表述能力强(一个功能有多种独立实现),独立性好(类似函数式逻辑,相互干扰少),资源瓶颈少(例如各种barrier,carr flag都有多个选择,不会导致相关操作序列化)等特点。从上层看,就是指令调度和算数优化的可能性比较多,自由度大。另外一点是对信息的具体化能力较强,比如不同的依赖关系可以用不同的scoreboard保证次序,减少干扰。