英伟达Compiler岗二面

上次面完不久hr就发消息来约二面。 中间隔着感恩节就一直约到感恩节之后。 这次的老哥虽然工作年限比上次的少, 但是也是个Ph.D., 所以公开资料比较好找。 看样子后者的contribution更多, 所以很难说这俩职级谁高谁低好吧, 也问了以前做过HR的朋友, 说面试官level越来越高的case也不是没有。

搜索这个面试官发现还挺大佬的, 整个LLVM的NVPTX后端都是他12年写的。 顶会也发了几篇, 进了英伟达以后应该就脱离科研了, 也有可能科研结果在公司内部封存了也不是不可能。 看LLVM的commit log老哥维护NVPTX一直维护到15年。 (我都说的这么细了业内的应该都认识了, 要不我真的报身份证号算了)

来说面试体验把。 这老哥明显要求高一些, 问的东西也都深一点, 有点被难住的意思;有的问题甚至让我怀疑你是不是把我当三年工作经验的社招在问(知道了,就是我菜) 估计是看我主业软工/安全, 反而对术语之类的东西都有些解释,然后被我抢答出来反而很意外

开局先问我有没有什么问题。 这个给我说傻了。 因为我问题真蛮多的(毕竟不是每天都能抓到NVPTX的作者)。 从他十年前的paper到career advise到英伟达内部的工作都想问。 真让我自由问下去就变成我面试他了(反客为主?)

我就说我看了你之前的paper有些学术问题不如先面试看回头剩多少时间再讨论把(?)

起步还是简介之前的项目。 这次比上次提升的一点是学会了强调项目里的难点,然后忘了说自己的结果(?)

问这两个项目是不是就算我的ms thesis了。然后我就解释了一下的其实还在念Ph.D.这件事。 至于我为啥突然开始找工作了暂且不表。

他的兴趣就上来了问我下面如果继续读Ph.D.准备做什么方向。 我跟他说了一下我现在的项目和大致的进度。 我说我准备做Fuzzing下的个小领域。 因为我们实验发现这个taint analysis runtime overhead是瓶颈, 我们看了很多论文claim他们发明了新的方法work, 其实不行。 “You have a Ph.D. degree, you know what it is”, 说到这个他直接笑了,搞科研的哎懂得都懂。 后来他打圆场说科研确实很多时候只present最好的结果, 然后搞出一些不太能用的东西(比如菜鸡我)。 然后说我们的做法和你十年前的论文有点相似, 都是取data dependency graph, 只不过你想着哪些data无关可以做并行, 我们想着哪些data 有关可以去track。 (到这里, 我读过他的论文这个小细节已经悉数暴露了)

到这个时候估计扯得有点远搞得面试官有点尬, 因为说了半天主要的东西都是软工/安全, 和他们做编译器优化有点不搭。 牵强一点说是用一个工具做不同的事情。 所以就问我喜欢做什么, 他解释说只是像看下我是不是match, 意思是我们也不搞软工那一套的。 我说我知道, 虽然没做过优化但是其实我更喜欢写LLVM Pass (喜欢个锤子, LLVM你别再改API大小写半年一个大版本啊啊啊woc)

然后就问我除了写着的项目做过什么编译器相关的东西。 我感觉这个面试官属实有点尬聊了。 我心想你看我简历上三个经历还有一个是机器人项目硬凑的,有东西我不早就写了吗。

然后就知道说我把斯坦福的COOL compiler end to end实现了一遍(吹了上次没吹的逼)

还看了IR(Intermediate Representation) standard, 后端codegen的代码。 被尬聊的已经有点脑抽了这个时候忘了什么是language reference说了句IR standard出来, 面试官问我你说的是IR language reference吧我说啊是, 还有对应的ducumentation, 在LLVM里的实现都读过。

问我读过或者改过什么LLVM的Pass 只好说些现在项目上的工作。 我说DFSan代码我review过,魔改过, 换了后端的数据结构。 (有点夸张了,其实是师兄换的,我只是revieww了代码知道原理, 但是他能尬聊我为什么不能尬聊

然后不知道谁给他的自信,是不是我吹的太过了什么的, 突然难度暴涨。 来说说代码优化, Loop unrolling(卧槽又来?) 我说这个代码我没读过但是大致原理知道。

行, 那有什么heuristic要做unrolling。 我说一个是static能确定循环数量的可以直接展开。 另一个是可以做成 4-aligned循环体减少jump。

有的时候即使静态确定循环次数也没有unrolling,你有没有注意过? 为什么? 我脑子:啊啊啊啊啊啊??!?!

(以下开始断智乱讲,在此不表

额, 那你考虑一下如果一个loop循环了十万次, 要unroll吗。 我说哦那不要的, 不然binary太大了。

好, 从一个x86 CPU的视角, 那还有什么理由不unroll一个body很大的loop? (我求你放过我吧我散装的优化知识经不起这么吊打) 我就想了想, 我说你太大loop的话cache遭不住, hit rate极低大部分CPU时间都在等相同的instruction从内存搬过来。 其实就是和上一个理由差不多, 没想到我散装的体系结构也能用上一点。 他说是(那就是吧), 其实我心里是一点B Tree都没有的, 这个答案也是临场想的。

来说LLVM IR, SSA,是什么为什么。 SSA就是static single assignment, (省略解释若干, 面试类似岗位的自行维基百科), 有SSA保证的话编译器好做优化(我不知道我瞎讲的)

好, 那我们回到刚刚的loop案例,怎么用SSA实现。 这个我说了个PHI node基本上就可以了其实。 但是估计是我解释的不行,我说loop end 有self increment, 他详细的问如果是一个for loop, self increment在IR层面是怎么实现的。 这个幸好我第一个项目有一点读loop代码的经验, 最后干脆手写了个IR 分享屏幕给他看了眼。 这个语法也不精确, 但是差不多是这个意思。

%loop_head:
i_head = 0
br loop_body

%loop_body:
i_body = PHI[%loop_head: i_head, % loop_body: i_new]
// Body
i_new = i_body + 1
br (condition) %loop_body, %loop_end

%loop_end:
// End

虽然犯了点小错误, 我说这个好像有问题, 不能定义i_new之前用i_new。 但是他解释了这个不是问题, SSA的保证就好在可以保证i_new用的时候已经被定义了。 估计是看我能把IR(近似的)手撸出来面试官大喜。

转而问一些理论知识。 说CFG里有俩点 A和B, A dominate B是啥意思。 那把边都反过来… 我说你想说postdominate, 他说啊对, A postdominate B啥意思。 这个我熟, 过的很快。

CFG(Control Flow Graph)和CG(Call Graph)有什么区别。 这里我只解释了定义上的区别, 用法上其实没说, 因为我也没太用过CG。

所以就深入问下去了, 假想一个C程序, 如果函数A调用B, 再CG里一定有一条边吗? 我说不一定, 可能是函数指针调用, static time不可能推断出调用谁。

问我也没有graphic card编程经验或者了解programming model。 这个地方本来是想小小的吹一下他, 没想到有点用力过猛。 我说不幸没有。 不过我在读NVPTX和一些文档。 我本来想去看下你做了哪些NVPTX的贡献结果发现整个NVPTX都是你写的(然后胡乱吹了一通) 面试官表示很好。不知道说的具体是哪个部分。 是我主动去看了英伟达文档很好, 还是主动看LLVM NVPTX后端很好, 还是牛皮吹得很好(?)

到这里就时间到了, 问我有什么问题。 我就问了下他们组“到底”是做什么的。 因为上个面试官是做中间段IR的, 这个面试官开发的NVPTX, 明显是偏中后段, MIR(Machine Intermediate Representation)那边的。 他说我们这边是拿着IR做输入, 所以上层应用不太管; 然后输出到MIR, 再下面就给做硬件的了。我们在中间做优化。 说到这里就结束了, 中间有点困难, 多少在知识的盲区里狗刨的感觉, 但是整体感觉还行。