Transcription
以下是与 Chris Flattener 的对话。目前,他是 Google 的一名高级总监,负责多个项目,包括 TensorFlow 的 CPU、GPU、TPU 加速器,以及 TensorFlow 的 Swift,以及幕后进行的各种机器学习编译器魔法。他是全球编译器技术领域的顶尖专家之一,这意味着他深刻理解硬件和软件如何协同工作以创建高效代码的复杂性。他创建了 LLVM 编译器基础设施项目和 Clang 编译器。他在 Apple 领导了重要的工程项目,包括 Swift 编程语言的创建。他还曾在 Tesla 担任自动驾驶软件副总裁,负责从自动驾驶硬件 1 到硬件 2 的过渡时期,当时 Tesla essentially 从零开始构建了内部的自动驾驶软件基础设施。我可以轻松地与 Chris 再聊上几个小时。将代码编译到不同抽象级别是计算机最基本也是最迷人的方面之一,而他是这一过程的世界级专家之一。这是一门严谨的科学,也是一门混乱而美丽艺术。本次对话是人工智能播客的一部分。如果您喜欢,请在 YouTube、iTunes 上订阅,或在 Twitter 上与我联系,我的用户名是 Lex Friedman,拼写为 FRI D。现在,这是我和 Chris Ladner 的对话。
你写过的第一个程序是什么?
我记得我小时候,父母给我买了一本基础编程书。所以,我开始的时候是照着书上的程序打字,看看它们是怎么运行的,然后打错字,再试图找出为什么它们运行不正确。就是那种基础的东西。
你还记得自己爱上过的第一门语言吗?就是那种真正产生共鸣的?
我不知道。我觉得我一路学了很多东西,每一种语言都有它独特的地方。我从 BASIC 开始,然后是 GW-BASIC,在 DOS 时代很流行。然后升级到 QBASIC,最后是 QuickBASIC,这些都是微软 BASIC 的稍微高级一些的版本。我转向了 Pascal,并开始用 Pascal 进行机器语言编程和汇编,那真的很酷。Pascal 在当时很棒。最终转向了 C、C++,然后做了很多其他奇怪的事情。
我觉得你走了邪路。你可以走 Lisp 的路。你选择了更高级别的、有点哲学性的、嬉皮士式的函数式路线,而不是直接深入到机器的“黑暗艺术”中。
所以,我从 BASIC 开始,然后是 Pascal,汇编,然后写了很多汇编。最后我做了 Smalltalk 和其他类似的东西,但那不是起点。
那么,这条通往 C 的旅程,是在高中还是大学?
是在高中。是的。然后,当时主要是想做一些 Pascal 做不到的更强大的事情,同时也想了解一个不同的世界。它真的让我很困惑,关于指针和语法等等,花了一段时间。但 Pascal 在很多方面都更讲原则。C 呢,我意思是,它有它的历史根源,但它不像指针那么容易学习。有内存管理这个东西,你必须意识到。
那是你第一次开始理解有需要你管理的资源吗?
是的,在 Pascal 中也有,但在 Pascal 中,它们更像是“帽子”(caret),而不是“星号”(star),有一些这样的小区别。但它不是关于指针算术。而在 C 中,你最终会更多地考虑事情在内存中的布局方式。所以在 Pascal 中,你有分配和释放内存,拥有内存,但程序更简单,你不需要……嗯,例如,Pascal 有字符串类型,所以你可以把字符串看作是一个字符串,而不是一串连续存储在内存中的字符数组。所以它是一个稍微高级别的抽象。
那么,让我们深入探讨一下 LLVM、Clang 和编译器吧。
当然。首先,你能告诉我什么是 LLVM 和 Clang 吗?你是如何成为当今最强大的编译器优化系统之一的创建者和首席开发者的?
嗯,我觉得它们是不同的东西。所以,让我们从什么是编译器开始。这是一个好的起点吗?编译器的阶段有哪些?它的组成部分是什么?
它是什么?编译器是用来做什么的?
我这样看待这个问题:你有一个双向问题。一方面是人类需要编写代码,另一方面是机器需要运行人类编写的程序。出于很多原因,人类不想用二进制编写代码,也不想考虑每一块硬件。所以,同时,你有人类,也有很多种硬件。所以,编译器就是一种艺术,它允许人类以他们想要的抽象级别思考,然后让那个程序,让他们编写的东西,在特定的硬件上运行。所有这些有趣和令人兴奋的部分是,现在有很多不同种类的芯片,比如 x86、PowerPC、ARM 等等,还有用于机器学习和其他事物的 But also high-performance accelerators,还有不同种类的硬件,比如 GPU。这些都是新型硬件。同时,在编程方面,你有你的基础 C 语言,你有 JavaScript,你有 Python。所以,你有很多其他语言,它们都在试图以不同的方式与人类交流,使他们更具表现力、能力和强大。所以,编译器就是从一个到另一个的东西。
不,然后从一开始到结束。所以,你从人类编写的代码开始,编程语言最终是为了表达意图,不仅仅是为了编译器和硬件,编程语言的职责是捕获程序员想要的意图的表达,这样其他人类以及解释器和编译器都可以维护、适应和演进。
所以,当你审视这个问题时,一方面是复杂的人类,另一方面是复杂的硬件。所以,编译器通常分多个阶段工作。所以,你在这里面临的软件工程挑战是,试图最大化你编写的代码的复用性,因为这些编译器非常复杂。所以,通常的工作方式是,你有一个叫做“前端”或“解析器”的东西,它是语言特定的。所以,你会有 C 解析器,这就是 Clang,或者 C++,JavaScript,Python,或者任何东西。那就是前端。然后,你有一个中间部分,通常是优化器。然后,你有一个后期部分,它是硬件特定的。所以,编译器最终有很多不同的层,但这三个大组在编译器中非常常见。LLVM 试图做的是标准化中间部分和最后一部分。所以,LLVM 的一个很酷的地方是,有很多不同的语言可以编译到它。所以,像 Swift,还有 Julia、Rust、Clang(用于 C、C++、Objective-C),这些都是非常不同的语言,它们都可以使用相同的优化基础设施,从而获得更好的性能和相同的代码生成,用于硬件支持。所以,LLVM 确实是那个通用层,所有这些不同的特定编译器都可以使用。
它是一个标准,一个规范,还是一个实现?
它是一个实现。所以,我觉得有几种不同的看待方式,因为这取决于你从哪个角度来看。LLVM 最终是一堆代码。所以,它是一堆人们可以复用并用它来构建编译器的代码。我们称之为编译器基础设施,因为它有点像你可以构建具体编译器的底层平台。但它也是一个社区,LLVM 社区有数百人共同协作。LLVM 长期以来最迷人的事情之一是,我们设法成功地让商业领域的激烈竞争对手在共享基础设施上进行合作。所以,你有 Google、Apple,你有 AMD、Intel,你有 Nvidia 和戴尔(Dian)在图形方面,你有 Prey 和其他所有公司都在做这些事情。就像所有这些公司都在合作,让这个共享的基础设施变得非常非常棒。它们这样做不是因为商业原因,而是因为它们有非常棒的基础设施可以建立,并且面对现实,它太昂贵了,以至于没有一家公司,即使是大公司,也不想自己实现所有这些。
昂贵还是困难?
两者都有。这是一个很好的观点,因为这还涉及到技能。而这些技能非常难以找到。LLVM 有多大?
它总是看起来像开源项目,你知道 LLVM 是开源的吗?
是的,它是开源的。它已经有 19 年了,所以相当老了。
看起来魔法通常发生在很小的圈子里,是吗?早期诞生的时候?
是的。LLVM 起源于一个大学项目。我在伊利诺伊大学,那里有我和我的导师,然后是研究小组里的两三个研究生的团队。我们最初构建了许多核心部分。然后我毕业去了 Apple。Apple 首先在 OpenGL 图形堆栈中使用了它,但最终也用在了 C 编译器领域,并最终构建了 Clang,最终构建了 Swift 等。在此过程中,我们组建了一个由非常出色的编译器工程师组成的团队,他们帮助构建了其中很多。随着它的发展势头,以及 Apple 的使用,并且它是开源的、公开的,并鼓励贡献,许多其他人,例如 Google 的人,也开始贡献。在某些情况下,Google 实际上拥有 Clang,因为它非常关心 C++ 及其生态系统的演进。所以,它在 C++ 世界和工具等方面投入了很多。同样,Nvidia 非常关心 CUDA。所以,CUDA 使用 Clang 和 LLVM 进行图形和 GPGPU 计算。
所以,当你刚开始作为一个硕士项目时,你认为它会发展到如此程度吗?你是否雄心勃勃?
不,一点也不是。所以,我的目标是,我在伊利诺伊大学的目的是,一年内拿到非论文硕士学位,然后回去工作。所以,我并没有计划在那里待五年,然后构建这个庞大的基础设施。我被“书呆子狙击”留了下来,很大程度上是因为 LLVM 很有趣。我正在构建很酷的东西,学习非常有趣的东西,并面临软件工程的挑战,同时也学会了如何在团队中工作等等。在那之前,我在很多公司实习过,但有一个团队一起工作,尝试在版本控制中协作,这确实是不同的。就像我说的,我刚和 Don Knuth 谈过,他认为世界上 2% 的人大脑里有什么奇怪的东西,他们是书呆子,他们理解计算机。他把它精确地定义为 2%。
所以,这个特定的人非常具体。他说,我无法证明,但它是非常经验性的。有什么东西吸引你对优化代码的想法?这似乎是它最酷的事情之一。
哦,是的,这是主要的事情之一。我之所以涉足这个领域,是因为一个人。所以,在我本科期间,我有一位名叫 Steve Bechtel 的教授。我去了那所非常小的私立学校,我们计算机科学系只有七八个学生。那是一所非常非常小的学校,当时有点像数学系的附属机构。我想现在已经发展了很多。但 Steve Eggdal 是个编译器专家,他非常热情,他的热情感染了我。我喜欢编译器的一点是,它们是大型复杂的软件。所以,当时许多计算机科学系的毕业班课程是,你学习算法和数据结构以及所有核心课程,然后编译器课程是你最后上的课程之一,因为它将所有内容整合在一起。然后,你整个学期都在研究一个代码片段。你不断地在自己的工作基础上进行构建,这真的很有趣。它也很有挑战性,因为在许多课程中,如果你没有完成一个项目,你就会把它抛在脑后,继续下一个项目,拿到你的 B 或其他分数。但在这里,你必须接受你做出的决定,并继续投入。我真的很喜欢这一点。然后,我在接下来的学期做了一个额外的研究项目,他真的很棒,在很多方面也是一位很棒的导师。所以,从他那里,从他的建议,他鼓励我去读研究生。我并不特别想去读研究生,我想要硕士学位,但不想留在学术界。但就像我说的,我有点被“骗”留了下来,玩得很开心,我绝对不后悔。
编译器的哪些方面让你产生了共鸣?
LLVM 还有另一部分,这真的很有趣,如果你对语言感兴趣的话,那就是解析和分析语言,把它分解,解析。那对你来说有趣吗?你是更倾向于引擎优化吗?
对我来说,更多的是。我不是一个真正擅长数学的人。我可以做数学,我理解其中的一些部分,当我深入研究时。但数学从来不是吸引我的东西。所以,编译器解析部分有很多很好的形式理论,Don Knuth 就很了解。我还在等他的那本书。但……但我就是喜欢构建一个东西,看看它能做什么,探索它,让它做更多的事情,然后设定新的目标并努力实现它们。在编译器方面,在我开始研究 LLVM 时,我的研究导师是一位编译器专家。所以,我和他特意找到了彼此,因为我们都对编译器感兴趣。所以我开始和他一起工作,上他的课。LLVM 最初的很多工作都是实现所有标准的算法和所有那些大家都谈论过的、在高级编译器研究课程中众所周知的、并且在课程中都有的内容。所以,能够构建它真的很有趣,我通过构建而不是阅读学到了很多。所以我很享受。
所以,你说了编译器是复杂的系统。你能用语言描述一下,你如何将一个 C++ 程序变成代码吗?有哪些难点?为什么这很难?
我给你举一些难点的例子。C++ 是一种非常复杂的编程语言,它的规范有大约 1400 页。所以,人们觉得 C++ 疯狂地复杂。
是什么让一门语言在语法上如此复杂?就是字符的排列方式。
是的。还有语义,它的行为方式。在 C++ 的情况下,它有大量的历史。C 语言是建立在 C 语言之上的。你把它向前发展,然后做了一些在某些情况下不是最优的决定,它们会累积,然后越来越多的东西被添加到 C++ 中,而且它可能永远不会停止。所以,从这个角度来看,这门语言非常复杂。子系统之间的交互非常复杂。那里有很多东西。当你谈论前端时,一个主要的挑战,Clang 项目,也就是我(和许多人)构建的 C/C++ 编译器,我们承担的一个挑战是,我们看了看 GCC。当时 GCC 是一个非常好的行业标准编译器,它整合了世界上许多其他编译器,并且是一个标准。但它并不适合研究。它的设计非常难以处理,并且充满了全局变量和其他东西,这使得它很难以它最初设计的方式进行复用。所以,对于 Clang,我们想做的是推动更好的用户界面。所以,让错误消息比 GCC 的更好。这实际上很难,因为你必须以高效的方式进行大量的簿记。今天,我们这样做。我们想让编译时间更好。所以,编译时间就是让它高效,这也很难,当你需要跟踪额外信息时。我们想提供新的工具,比如重构工具和其他分析工具,GCC 从未支持过。还利用我们保留的额外信息,并启用这些新的工具,然后将它们构建到 IDE 中。所以,这是 Clang 真正推动 C 和 C++ 以及类似工具世界向前发展的一个领域。但 C++ 和前端部分很复杂,你必须构建语法树,你必须检查规范中的每一个规则,你必须把它转换成人类可以理解的错误消息,当他们做错了什么的时候。但然后你开始做所谓的“降低”(lowering),也就是从 C++ 代码表示方式到机器代码的转换。当你这样做时,你会经历很多阶段。LLVM 大约有 150 个所谓的“传递”(passes),代码会通过这些传递。这些传递以非常复杂的方式组织起来,影响生成的代码、性能、编译时间和许多其他事情。
它们通过什么传递?所以,在 Clang 解析之后,图是什么样的?数据结构是什么?
是的。在解析器中,通常是一个树,称为抽象语法树。所以,想法是,你有一个节点代表人类在代码中写的“加号”,或者函数调用。你有一个节点代表调用,带有他们调用的函数和他们传递的参数等等。然后,它会被“降低”到一个叫做中间表示(Intermediate Representation)的东西。中间表示就像 LLVM 有一个,它叫做控制流图。所以,你将程序中的每个操作表示为一个非常简单的……这将是两个数字相加,这将是两个数字相乘,也许我们会进行一个调用。但然后它们被放入所谓的“块”(blocks)中。所以,你得到了一系列直线操作的块。而不是像树那样嵌套,而是直线操作。所以,这些操作有一个序列和顺序。然后在块内,以及块外,都在块内。所以,这是块内的一系列直线操作。然后,你会有分支,比如块之间的条件分支。所以,当你写一个循环时,例如,在语法树中,你会有一个“for”节点,比如“for”语句。在 C 语言中,你会有一个“for”节点,并且有一个指向初始化器表达式的指针,指向增量表达式的指针,指向比较表达式的指针,指向循环体的指针。这些都嵌套在它下面。在控制流图中,你会有一个在循环之前运行的代码块,也就是初始化代码。然后,你有一个循环体代码块。所以,循环体代码放在那里,但也有增量和其他东西。然后,你有一个回到顶部的分支,以及一个出去的比较和分支。所以,它更像是一个汇编级别的表示。但这种表示的好处是,它更独立于语言。所以,有很多不同种类的语言,有不同种类的……例如,JavaScript 对“false”有很多不同的想法。所有这些都可以保留在前端,但然后中间部分可以跨所有这些语言共享。
那个中间表示离神经网络有多近?例如,它们是……因为一切都被描述为一种神经网络图,对吧?
是的。它们在细节上相当不同,但在想法上非常相似。神经网络做的一件事是,它们在不同抽象级别上学习数据的表示。然后,它们通过层来转换这些表示。编译器也做类似的事情。但编译器做的一件事是,它有相对较少的不同表示。而神经网络通常,当你深入时,你会得到许多不同的表示,每个层或一组操作都在这些不同的表示之间进行转换。而编译器通常只有一个表示,然后进行许多转换。这些转换通常是迭代应用的。对于程序员来说,有一些熟悉的类型的东西,例如,试图在循环中找到表达式并将它们拉出循环。所以,如果它们执行四次。或者找到冗余计算,或者找到常量折叠或其他简化。将“2 乘以 x”变成“x 左移一位”等等。这些都是发生的事情的例子。但编译器最终会得到大量的定理证明和其他算法,试图找到程序的更高级属性,然后优化器可以使用这些属性。
那么,优化最大的收益是什么?
嗯,在 80 年代,很多都是像寄存器分配这样的事情。所以,想法是,在现代的微处理器中,你会遇到内存,它相对较慢,然后是寄存器,它相对较快。但寄存器数量不多。所以,当你写一堆代码时,你只是说“计算这个,把它放在临时变量里,计算那个,计算这个,计算这个,放在临时变量里”。我有一个循环,我还有其他事情在进行。现在你在 x86 上运行,比如台式电脑。在某些情况下,它只有八个寄存器。所以,现在编译器必须选择在程序的哪个点将哪些值放入哪些寄存器。这确实是一件大事。所以,如果你有一个循环,然后一个内循环,执行数百万次。也许如果你在循环中进行加载和存储,那会非常慢。但如果你能设法将循环中的所有值放入寄存器,那么它就非常快了。所以,正确地做到这一点需要大量的工作,因为有很多方法可以做到这一点。通常,编译器最终会以一种与人类编写代码不同的表示方式来思考。你写了 `x = y + z`。编译器会把它看作是函数中具有不同生命周期的四个不同值,每个值都可以放入寄存器或内存,或者不同的内存,或者在代码的某些部分重新计算而不是存储和重新加载。有很多这样的技术可以使用。所以,它几乎是增加了时间维度。它试图跨时间进行优化。
考虑到……你在编程时,你并没有这样想。
是的,绝对。所以,RISC 时代让事情变得……所以,RISC 芯片,RISC 芯片与 CISC 芯片相反。RISC 芯片让编译器的事情变得更复杂,因为它们最终在处理器中增加了流水线,处理器可以同时做多件事情。但这意味着操作的顺序非常重要。所以,一个经典的编译器技术叫做调度。所以,移动指令,以便处理器可以保持其流水线满载,而不是停滞和阻塞。所以,有很多这样的事情,它们是编译器技术的“面包和黄油”,几十年来一直被研究。但让它们成为现实的工程方面仍然非常困难。
你谈到了机器学习。这是一个巨大的机会。因为许多这些算法充满了……这些是粗糙的手工实现的启发式方法,在特定的基准测试上效果很好,但不能泛化,充满了魔法数字。我听说有一些技术擅长处理这些。
所以,如果你将机器学习应用于这个领域,你会尝试优化什么?最终是运行时间吗?
你可以选择你的指标。有运行时间,有内存使用量,有很多不同的东西可以优化。代码大小也是一些人在嵌入式领域关心的一个问题。
这是在展望未来,还是有人真的疯狂到尝试让基于机器学习的参数调优来优化编译器?
这是目前的研究。有很多研究系统在各种论坛上应用搜索,并使用强化学习作为一种形式。但蛮力搜索也尝试了很长时间。通常,这些是在小问题空间中。所以,找到为 GPU 生成矩阵乘法的最佳方式。类似这样的东西,我们说有很多设计空间。你是否展开循环?你是否并行执行多项任务?这里有很多相互关联的因素,因为图形卡有不同数量的线程、寄存器、执行端口、内存带宽以及许多以非线性方式相互作用的不同约束。所以,搜索非常强大。它在某些方面被使用,但它不是很有条理。这是我们作为一个行业需要解决的问题。
所以,有没有过重大的改进和优化?
是的,是的。自那时以来,这在很大程度上是由硬件驱动的。硬件和软件。在 90 年代中期,Java 完全改变了世界。我仍然惊叹于它引入了多少变化。以好的方式。所以,回顾一下,Java 一次性引入了像 JIT 编译这样的东西。这些都不是新颖的,但它将它们整合在一起,并使其成为主流,并让人们投入其中。JIT 编译、垃圾回收、可移植代码、安全代码、内存安全代码。一个非常动态的调度执行模型。这些许多事情,在研究系统中已经完成,并且在各种地方以小规模完成,真正地走到了前沿,真正地改变了事物的工作方式,因此改变了人们对问题的思考方式。JavaScript 也是一个基于其工作方式的重大世界变化。但从硬件方面来说,多核和向量指令真的改变了问题空间。它们并没有消除编译器过去面临的任何问题,但它们增加了新的问题。你如何找到足够的工作来保持一个四路向量忙碌?或者,如果你正在进行矩阵乘法,你如何同时处理该矩阵的不同列?你如何最大限度地利用一个核心的算术计算能力?然后如何将其扩展到多个核心?
虚拟机是如何改变编译管道的?
所以,Java 虚拟机所做的是,它就像我之前谈到的那样进行分割,你有一个解析代码的前端,然后你有一个中间表示,它会被转换。Java 所做的是,他们说,我们将解析代码,然后编译成所谓的 Java 字节码。这个字节码现在是一个可移植的代码表示,它是行业标准,并且是固定的,不能改变。然后,编译器后端,负责优化和代码生成,现在可以由不同的供应商构建。Java 字节码可以跨网络传输,它是内存安全的,并且相对可信。因此,它可以运行在浏览器中。这就是它在浏览器中运行的原因。所以,这样你就可以……再次,回到过去,你会编写一个 Java Applet,作为 Web 开发人员,你会构建这个小程序,它运行在网页上。而用户运行的是他们计算机上的 Web 浏览器。你下载那个 Java 字节码,它是可信的,然后你所有的编译器工作都在你的机器上完成。所以,你知道你信任那个……
那是一个好主意,还是一个坏主意?
这是一个好主意。这是一个好主意,适用于某些问题。我非常相信技术本身既不是好也不是坏,而是如何应用它。对于软件堆栈的非常低的级别来说,这会是一个非常非常糟糕的事情。但在解决一些软件可移植性和透明性问题方面,我认为它一直很好。现在,Java 最终并没有在桌面上获胜,而且有很好的原因。但它在服务器上非常成功,并且在许多地方,它几十年来一直非常成功。
那么,LLVM 和 Clang 在其历史上的优化改进是什么?有哪些时刻我们遇到了挫折?
我为所取得的成就感到非常自豪。我认为 LLVM 有趣之处不在于编译器研究中的创新。它无疑拥有各种重要算法的优秀实现,而且有很多聪明人为此工作过。但我认为 LLVM 最深刻之处在于,通过标准化,它使得原本不可能发生的事情成为可能。所以,LLVM 发生的一些有趣的事情是,索尼采用了 LLVM,并用它来完成他们电影制作流程中的所有图形编译。所以,现在他们能够获得更好的特效,这很酷。这并不是它的设计初衷。但这就是良好基础设施的标志,当它可以被用于它从未被设计过的用途时,因为它有良好的分层和软件工程,并且是可组合的。
就像你说的,它与 GCC 不同。
是的。GCC 在各个方面也很棒,但它作为基础设施技术不如 LLVM。它是……它是一个 C 编译器,或者是一个 Fortran 编译器。它不是基础设施,不像 LLVM 那样。
现在,你可以看出我不知道我在说什么,因为我一直在说 Clang。你总是能看出一个人是否接近,因为他们发音的方式。我不知道我是否曾经完全使用过 Clang。
有可能。你用过它生成的代码吗?
Clang 是 LLVM 的一部分,它用于编译 iPhone 上的所有应用程序以及操作系统。它编译 Google 的生产服务器应用程序。我用它来构建我的 GameCube 游戏和 PlayStation 4 等等。
我是一个用户。但我经历过的所有 Linux 上的东西,我相信一直都是 GCC。
是的。Linux 仍然默认使用 GCC。
有原因吗?
这是一个技术和社会原因的结合。许多 GCC 的开发者……你确实在使用 Clang。但发行版出于各种原因,历史上一直使用 GCC,并且没有切换。
是的,而且在网上,人们似乎认为 LLVM 已经达到了 GCC 的水平,或者在某些功能上已经超越了它。
我会这样说:曾经有过……它们非常接近,以至于不重要了。是的,就是这样。在某些方面略好,在某些方面略差,但实际上已经不重要了。
所以,在优化突破方面,这只是扎实的渐进式工作。
是的。这描述了很多编译器。在我看来,编译器最难的是工程,软件工程。让数百人能够协作进行非常详细的底层工作,并进行扩展。这真的很难。我认为 LLVM 在这方面做得很好。这又回到了最初的设计目标,即模块化。顺便说一句,我不想把所有的功劳都归于我。LLVM 最好的部分之一是它的模块化设计。当我开始时,例如,我写了一个寄存器分配器,然后一个比我聪明得多的人会把它拿出来,替换成他们想出的东西。因为它模块化,他们能够做到这一点。这就是 GCC 的挑战之一,替换子系统非常困难。可以做到,但它不是为此设计的。这也是 LLVM 在研究领域非常成功的原因之一。
但在社区意义上,就像 Guido van Rossum(Python 的创始人)一样,他从“终身仁慈的独裁者”的位置上退休了。在管理这个由杰出的编译器专家组成的社区时,你是否也曾一度扮演这个角色,来批准事情?
哦,是的。所以我仍然在 LLVM 中拥有比其他人多一个数量级的补丁。其中很多是我自己写的。但他仍然……你仍然……我不知道这个表达是什么,贴近“金属”。你仍然写代码。
是的,很好。
不像我在研究生时那样多,但这是我身份的重要组成部分。但 LLVM 的工作方式是,当我还是个研究生时,我可以做所有工作,指导一切,审查每一个补丁,确保一切都按照我主观认为应该的方式进行。那很好。但我认为,规模上,你做不到。所以,发生的事情是,LLVM 有一个叫做“代码所有者”的层级系统。这些代码所有者被赋予责任,不是做所有工作,不一定审查所有补丁,而是确保补丁得到审查,并确保在他们的领域内发生正确的事情。所以,你会看到,例如,硬件制造商最终拥有他们硬件的特定部分。社区中的领导者,他们做了非常出色的工作,自然而然地成为了某个事物的实际所有者。然后通常会有人说,“我们为什么不让他们成为官方的代码所有者呢?”然后,我们会有人来确保整个补丁得到及时审查。然后大家都会说,“是的,这是显而易见的。”然后它就发生了。这通常是一个非常有机的事情,这很棒。所以我名义上仍然是这个体系的顶端,但我花在审查补丁上的时间不多。我所做的是,我帮助协商很多最终发生的技??术分歧,并确保整个社区取得进展,并朝着正确的方向前进。
所以,我们还启动了一个非营利组织。六年前,七年前。时间过得真快。非营利组织,LLVM 基金会,负责监督所有业务方面的事情,并确保 LLVM 社区的活动得到资助、组织和正确运行。但基金会非常超然于项目的技术方向。
听起来很多都是有机的。
是的。LLVM 已经快二十年了,这很难相信。最近有人指出,LLVM 现在比它开始时 GCC 的年龄还要大。时间过得真快。但好消息是,它拥有一个真正强大、真正令人惊叹的社区。人们分布在许多不同的公司,但在他们的职业生涯中。这是一个对类似问题感兴趣的人们组成的社区,并且多年来一直有效地合作,并且彼此之间有很多信任和尊重。即使他们不总是意见一致,我们也会找到前进的道路。
那么,在稍微不同的努力方向上,你于 2005 年加入 Apple,任务是让 LLVM 达到生产就绪状态。然后,最终在 2013 年至 2017 年期间,你领导了整个开发者工具部门。我们正在谈论 LLVM、Xcode、Objective-C 到 Swift。快速概述一下你在那里的时间。首先,领导如此庞大的开发者团队面临哪些挑战?创建 Swift 的背后有什么大的动力、梦想、使命?它的早期诞生,从 Objective-C 等等,以及 Xcode。
嗯,是的,这些是不同的问题。
我知道。但其他事情呢?我会坚持技术方面。我们可以谈谈大型团队方面的事情。
那好吧。当然。所以,为了极大地简化多年的辛勤工作,我们大多数人开始加入 Apple,它变得成功,并且得到了部署。但当时有一个问题,我们如何实际解析源代码。所以,LLVM 是后端,优化器和代码生成器。LLVM 对 Apple 来说非常有用,因为它经历了两次数百次的转变。我加入的时候正好是 Intel 过渡时期,以及 64 位过渡时期。然后是向 iPhone 的过渡。所以,LLVM 在这些类型的方面非常有用。但同时,关于开发者体验有很多问题。所以,如果你当时是一个程序员,敲打 Objective-C 代码,你得到的错误消息,编译时间,周转周期,工具和 IDE 都不是很好。不如它本可以好。所以,我偶尔会想,好吧,写一个 C 编译器有多难?所以我不会向任何人承诺,我不会告诉任何人,我只是在周末和晚上开始工作。然后,我构建了 C 语言中的预处理器,人们不喜欢它,但它实际上非常难,而且很复杂,包含了许多奇怪的东西,比如“try graphs”和其他一些非常棘手的东西。它是编译器性能问题的一个关键点。我开始研究解析器,然后我到了一个点,我心想,嗯,你知道吗,我们实际上可以做到这一点。每个人都说这不可能做到,但它实际上只是很难,而不是不可能。最终我告诉了我的经理,他说,“哦,哇,这太棒了。我们确实需要解决这个问题。哦,这太棒了,我们可以让你再找一个人和你一起做这个。”然后,慢慢地,一个团队形成了,它开始起飞。C++,例如,一门巨大而复杂的语言。人们总是认为它不可能实现,而且它几乎不可能,但它真的非常非常难。到达那里的方法是,一次构建一小块,逐步构建。而且,这之所以成为可能,是因为我们很幸运地聘请了一些非常出色的工程师,他们非常了解其中的各个部分,并且能够做得很棒。Swift 也是类似的事情。Swift 是在我们完成了 Clang 中的第一个版本的 C++ 支持后出现的。C++ 是一门非常强大且非常重要的语言,但它在很多方面也很丑陋。你不影响 C++ 而不认为必须有更好的东西。所以,我再次开始研究 Swift,没有任何希望或雄心壮志,它会走向任何地方。只是,“让我们看看能做什么。让我们玩玩这个东西。”那是我在业余时间做的事情,没有告诉任何人。它取得了一些不错的进展。我心想,“实际上,这样做是有意义的。”与此同时,我开始与当时的软件高级副总裁 Burt Ronstol 谈话。Burt 非常鼓励他。他说,“嗯,让我们玩得开心,让我们谈谈这个。”他有点像个语言专家。所以,他指导了一些早期工作,鼓励了我,并帮助启动了项目。最终,我告诉了其他人,比如我的经理,告诉了其他人,它开始取得进展。Swift 的复杂之处在于,创造一门新语言的想法对任何人来说都不是显而易见的,包括我自己。当时的主流观点是,iPhone 的成功是因为 Objective-C。
哦,真有趣。
是的。或者只是很棒,因为它……而且你必须明白,当时 Apple 雇佣的软件人员都热爱 Objective-C。
哦。
他们不是因为 Objective-C 的缺点而雇佣他们,他们热爱 Objective-C,这就是他们被雇佣的原因。所以,你有一个软件团队,他们的领导层,在许多情况下,可以追溯到 NeXT,Objective-C 真正实现的地方。所以,他们“成长”为编写 Objective-C。而且,许多工程师都是因为热爱 Objective-C 而被雇佣的。所以,这个“好吧,让我们做一门新语言”的想法在很多方面有点异端。与此同时,我的感觉是,外部社区并不真正喜欢 Objective-C。有些人喜欢,其中一些最直言不讳的人也是如此。但其他人遇到了挑战,因为它有很多尖锐的角落,而且很难学习。所以,让 Swift 成功的挑战之一是完全非技术性的。那就是“我们该怎么做?”的问题。在 Apple,很多事情都不会被发布。所以,如果我们发布它,成功的衡量标准是什么?我们为什么要这样做?我们为什么不让 Objective-C 变得更好?如果 Objective-C 有问题,让我们把那些粗糙的角落和边缘磨掉。而一个主要的原因是“安全”的概念,内存安全。Objective-C 的工作方式是,它的许多对象系统和其他东西都建立在指针之上。C++ 是 C 的扩展。所以,指针是不安全的。如果你摆脱了指针,它就不再是 Objective-C 了。所以,从根本上说,这是一个问题,你无法在不从根本上改变语言的情况下修复安全或内存安全。所以,一旦我们……
我们已经完成了那个心理过程和思维过程的部分,它变成了一个设计过程,就是说,好吧,如果我们要做一些新的事情,什么是什么好的,我们如何看待这个问题,我们喜欢什么,我们在寻找什么,而那是一个非常不同的阶段,所以,早期在 Swift 中,有哪些设计选择呢?我们谈论的是大括号,你是在做一个类型语言还是不是?所有这些类型的事情,是的,所以其中一些鉴于上下文是显而易见的,例如,类型语言 Objective-C 是一个类型语言,而选择一个非类型语言并没有被认真考虑,我们想要性能,我们想要重构工具和其他类似的东西来配合类型语言,一个快速的愚蠢问题,是的,这是显而易见的吗?我认为这是一个愚蠢的问题,但语言必须是编译型语言,而不是解释型语言,这是显而易见的吗?是的,这不是一个愚蠢的问题,早期,我认为在 90 年代末,苹果公司认真考虑过将它的开发体验转移到 Java,但这开始于 2010 年,那是 iPhone 问世几年之后,那是 iPhone 肯定处于上升轨迹的时候,而 iPhone 仍然非常,而且仍然有点内存受限,对吧?所以能够编译代码然后发布它,然后拥有不经过 JIT 编译的独立代码,这是一个非常大的问题,而且它非常符合苹果的价值体系,JavaScript 也是如此,对吧?我的意思是,这并不是说这是独一无二的,技术的好坏取决于它们如何应用,对吧?但在 Swift 的设计中,就像我们如何让 Objective-C 变得更好?Objective-C 是静态编译的,而这是连续的、自然的事情,只是跳过一点,现在回到原点,只是作为一个问题,当你想到今天,2019 年,是的,你在谷歌的工作,大量的手机,等等,编译,静态编译,是正确的,仍然是正确的事情,是的,所以有趣的事情是,在编译器工作了很长时间之后,LVM 帮助了其中一些事情,我并不认为编译是静态的、动态的或解释的,这是一个光谱,对吧?而 Swift 的一个很酷的事情是,Swift 不仅仅是静态编译的,它实际上也是动态编译的,它也可以被解释,但没有人真正这样做过,所以当你使用 Swift 在工作簿中,例如在 Colab 和 Jupiter 中时,实际上是动态地编译你执行的语句,所以这又回到了软件工程问题,对吧?如果你正确地分层堆栈,你实际上可以完全改变编译的方式和时间,因为你有正确的抽象,所以 Colab 工作簿与 Swift 的工作方式是,我们开始输入,它创建一个进程,一个 UNIX 进程,然后你输入的每一行代码,它都会通过 Swift 编译器进行编译,有前端部分,然后将其发送给优化器,JIT 编译机器码,然后将其注入到该进程中,所以当你输入新的东西时,它就像喷射新的代码,覆盖和替换,原地更新代码,而它能够做到这一点并非偶然,Swift 就是为此而设计的,但这是语言设置方式以及它如何分层的重要组成部分,这是一个不那么明显的部分,而 Swift 的一个对我来说非常强大的设计点是,让它能够让你非常快速地学会它,所以从语言设计的角度来看,我总是回到这个 UI 原则,即渐进式披露复杂性,所以在 Swift 中,你可以开始说打印“你好,世界”对吧?没有换行符,就像 Python 一样,一行代码,没有 main,没有头文件,没有头文件,没有 public static class void blah blah blah string,就像 Java 有的那样,对吧?所以一行代码,对吧?你可以教这个,而且效果很好,然后你可以说,让我们引入变量,所以你可以用 var 声明一个变量,所以 VAR x = 4,什么是变量?你可以使用 xx + 1,这就是它的意思,然后你可以说,好吧,有一个控制流,好吧,这就是 if 语句,这就是 for 语句,这就是 while 语句,然后你可以说,让我们引入函数,对吧?许多语言,比如 Python,都有这种“让我们引入小东西,它们可以变得复杂”的概念,然后你可以引入类,然后你可以添加泛型,我反对 Swift,然后你可以模块化,并根据你表达的东西构建,但这对于编译型语言来说并不常见,所以这是一个非常强大的设计点,也是 Swift 总体上设计时考虑复杂性分解的原因之一,这样语言就可以表达强大的东西,如果你愿意,你可以用 Swift 编写固件,但它有一种非常高级的感觉,这确实是完美的融合,因为通常有非常高级的库作者想要使用细节,而其他人只想使用库并在更高级的抽象级别上工作,我看到你可以直接输入一个概率,我不知道我是否足够发音那个词,但你可以直接拖入 Python,它只是一个字符串,你可以导入,就像我在演示中看到的那样,是的,我指出了,但你是如何实现的?是的,是什么,是什么,是的,看起来有那么容易吗?是的,那不是舞台魔术把戏之类的,我不是从用户的角度说的,我是从实现的角度说的,所以一旦所有部件都到位,它就很容易了,如果你想一想像 Python 这样的动态类型语言,你可以从两种不同的方式来思考它,你可以说它没有类型,这是大多数人会说的,或者你可以说它有一个类型,你可以说它有一个类型,它就像 Python 对象,对吧?而 Python 对象被传递,因为只有一种类型,它是隐式的,对吧?所以当 Swift 和 Python 相互交谈时会发生什么?Swift 有很多类型,对吧?有数组,有字符串,还有所有这些类,但它现在有一个 Python 对象类型,对吧?所以有一个 Python 对象类型,所以当你导入 numpy 时,你得到的是一个 Python 对象,也就是 numpy 模块,然后你说 NPRA,它说,好吧,嘿,嘿,Python 对象,我不知道你是什么,给我你的数组成员,对吧?好的,酷,它只是,它只是使用动态的东西与 Python 解释器交谈,然后说,嘿,Python,那个 Python 对象中的 daughter a 成员是什么?它又给你一个 Python 对象,现在你说括号进行调用,参数将被传递,然后它说,嘿,Python 对象,这是 NPR a 调用与这些参数的结果,对吧?再次调用 Python 解释器来完成这项工作,所以现在这一切都很简单,如果你深入代码,你会发现 Swift 中的 Python 模块大约是十二行代码,或者什么的,是用纯 Swift 编写的,非常简单,而且它是建立在 C 互操作性之上的,因为它只是与 Python 解释器交谈,但要实现这一点,我们需要为 Swift 添加两个主要的语言功能,以便能够表达这些动态调用和动态成员查找,所以我们在过去一年里所做的是,我们已经提议、实现、标准化并贡献了新的语言功能到 Swift 语言中,以便使其真正变得微不足道,而这正是 Swift 的一个关键之处,对于 TensorFlow 的工作来说,那就是我们可以添加新的语言功能,并且添加这些功能的门槛很高,但这就是它成为可能的原因,所以你知道谷歌在几件事情上做了令人难以置信的工作,包括 TensorFlow,TensorFlow 2.0 或任何导致 2.0 的东西,默认情况下在 2.0 中有急切执行,为了优化 GPU 或 TP 或这些系统的计算,需要将其转换为图,这个过程是怎样的?那里的挑战是什么?是的,我只是间接参与了这件事,但 autograph 的工作方式是,你用装饰器标记你的函数,当 Python 调用时,该装饰器被调用,然后它说,在我调用这个函数之前,你可以转换它,所以 autograph 的工作方式是,据我所知,它实际上使用 Python 解析器来解析它,将其转换为语法树,然后应用编译器技术,再次将其转换为张量图,所以你可以认为它是在说,嘿,我有一个 if 语句,我将创建一个图中的 if 节点,就像你说 TF conned,你有一个乘法,好吧,我将把它变成图中的乘法节点,这就变成了树的转换,那么 Swift for Tensor for come 在哪里呢?你知道,与 Python 类似,Swift 是一个接口,就像 Python 是 TensorFlow 的接口一样,但似乎还有更多的工作要做,而不仅仅是语言接口,还有优化方法论,是的,所以 TensorFlow 世界有几种不同的,我称之为前端技术,所以 Swift、Python、Go、Rust、Julia 以及所有这些东西都共享 TensorFlow 图以及所有运行时等等,所以 Vertex Flow 仅仅是 TensorFlow 的另一个前端,就像其他任何系统一样,这里有三种技术阵营,有 Python,这是一个特例,因为绝大多数社区的努力都集中在 Python 接口上,Python 有自己的自动微分方法,它有自己的 API,等等,有 Swift,我稍后会谈到,然后是“其他所有”,所以“其他所有”基本上是语言绑定,它们调用 TensorFlow 运行时,但它们通常没有自动微分,或者它们通常不提供除了调用 TensorFlow C API 的 API 之外的任何东西,所以它们基本上是包装器,Swift 确实很特别,而且方法非常不同,Swift 4/10 below 是一个非常不同的方法,因为在那里我们说,让我们看看在 TensorFlow 编译过程中需要解决的所有问题,如果你那样想的话,因为 TensorFlow 本质上是一个编译器,它接受模型,然后让它们在硬件上运行得更快,这就是编译器所做的,它有一个前端,一个优化器,以及许多后端,所以如果你以正确的方式思考,或者如果你以特定的方式看待它,比如它是一个编译器,对吧?而 Swift 仅仅是另一个前端,但它说,设计原则是,让我们看看我们作为机器学习从业者面临的所有问题,以及考虑到我们可以改变这个整个堆栈中的任何东西,最好的方法是什么?例如 Python,绝大多数工程和努力都投入其中,它受到成为 Python 库最好的事情的限制,我不知道有任何 Python 语言功能是由于机器学习而添加的,他们添加了一个矩阵乘法运算符,但这就是你所能得到的,而对于 Swift,你可以,这很难,但你可以为语言添加语言功能,并且有一个社区流程,所以我们看看这些事情,然后说,人类程序员和编译器之间的劳动分工是什么?Swift 有一些东西可以改变这种平衡,因为它有一个类型系统,例如,它使得代码分析成为可能,编译器可以自动为你构建图,而你不需要考虑它们,这对程序员来说是一件大事,你就能获得免费的性能,你就能获得融合和优化等等,而你作为程序员不必手动去做,因为编译器可以为你完成,自动微分是另一件大事,我认为这是 Swift for TensorFlow 项目的关键贡献之一,关于自动微分的整个工作可以追溯到 Fortran 时代,人们进行了大量的数值计算,Fortran 曾经编写了所谓的源到源翻译器,你将一堆代码放入一个小型编译器中,然后输出更多的 Fortran 代码,但它会为你生成函数的反向传播,你的导数,所以在 70 年代的这项工作中,一位真正的优化大师开发了大量的技术来解决数值不稳定性和其他问题,但将它们移植到急切执行的世界中非常困难,在那里你一次获得一个操作,你需要能够查看整个函数并能够推理正在发生的事情,所以当你拥有语言集成自动微分时,这是 Swift 项目正在关注的事情之一,你可以打开所有这些技术并以熟悉的方式重用它们,但语言集成部分有很多设计空间,而且也很复杂,这里另一块拼图很有趣,那就是谷歌的 TPUs,是的,所以你知道我们正处于深度学习的新世界,它在不断变化,我猜想,在不泄露任何信息的情况下,我猜想,你知道,你仍然在 TPU 前沿进行创新,是的,那么软件和硬件之间有多少相互作用,以试图找出如何朝着最佳解决方案发展?有惊人的数量,我们的第三代 TPU,现在在一个非常大的液冷箱中,在一个虚拟箱中,没有盖子,有 100 Petaflops,正如你可能想象的那样,我们还没有用完想法,TPU 的伟大之处在于它们是硬件/软件协同设计的完美典范,所以这是一个赌注,它是关于说我们构建什么硬件来解决某些类别的机器学习问题?算法正在改变,就像硬件一样,需要数年时间才能生产出来,所以你必须下注并决定会发生什么,以及如何最好地花费晶体管来获得最大的每瓦性能或每面积成本或每成本,或者无论你优化什么,所以 TPU 的惊人之处之一是这种称为 b-flat 16 的数值格式,bfloat16 是一种压缩的 16 位浮点格式,但它将位放在不同的位置,从数值上看,它有一个更小的尾数和一个更大的指数,这意味着它不够精确,但它可以表示更大的值范围,在机器学习的背景下,这非常重要和有用,因为有时你需要累积非常小的梯度,以及非常非常小的数字,这些数字对于在学习过程中推动事物很重要,但有时你也有非常大的数字,而 bfloat16 不够精确,尾数很小,但事实证明机器学习算法实际上想要泛化,所以有理论认为这实际上增加了网络在数据集之间泛化的能力,无论好坏,在硬件层面实现起来要便宜得多,因为乘法器的面积和时间是尾数位数 N 的平方,但它与指数的大小成线性关系,所以这是一个重要的努力,在硬件和软件方面,是的,所以这是一个来自研究方面的突破,人们一直在优化网络上权重的传输,最初试图找到压缩方法,然后它被烧进了硅片,它是 CPU 性能如此惊人的一部分,而伟大的 TPU 有许多不同的重要方面,但低级编译器位与软件位与算法之间的协同设计都非常重要,这是谷歌独有的一个惊人的三因素,这非常令人兴奋,所以你能告诉我关于 MLI 的项目吗?以前是秘密的那个,是的,所以 EMA lair 是我们在三个星期前或某个时候的一个编译器会议上宣布的一个项目,编译器用于机器学习会议,基本上,如果你将 TensorFlow 视为一个编译器堆栈,它包含许多编译器算法,它还包含许多嵌入其中的编译器,它们由不同的供应商制造,例如,Google 有 XLA,这是一个很棒的编译器系统,NVIDIA 有 TensorRT,Intel 有 nGraph,有许多不同的编译器系统,它们非常硬件特定,并且它们试图解决问题的不同部分,但它们在某种程度上是相似的,它们都想与 TensorFlow 集成,TensorFlow 有一个优化器,它内置了这些不同的代码生成技术,MLR 的想法是构建一个通用的基础设施来支持所有这些不同的子系统,最初是为了让它们都能协同工作,并共享更多的代码,并且可以重用,但随着时间的推移,我们希望行业能够开始合作和共享代码,而不是一遍又一遍地重新发明相同的东西,我们可以真正促进一些合作,你知道共同解决问题的能量,这在编译器领域之前很有用,除此之外,有些人开玩笑说它有点像 LLVM,它学到了很多关于 LLVM 的优点和缺点,这是一个纠正它的机会,而且 LLVM 生态系统也存在挑战,LLVM 非常擅长它被设计来做的事情,但你知道,20 年后,世界已经改变了,人们正在尝试解决更高层次的问题,我们需要一些新技术,在这个背景下,开源的未来是什么?很快,所以它还没有开源,但希望它会,你仍然相信开源的价值吗?哦,绝对,而且我认为整个 TensorFlow 社区都相信开源,所以我的意思是,苹果公司和你以前在谷歌现在在精神和文化上有所不同,我想说,TensorFlow 的开源是软件史上的一个重要时刻,因为这家大公司发布了一个非常大的代码库作为开源,你对此有什么看法?你乐意还是不乐意看到这种程度的开源?所以在这两者之间,我更喜欢谷歌的方法,如果你是这个意思,苹果的方法考虑到苹果的历史背景是有道理的,但那已经是 35 年前了,我认为苹果肯定在适应,我看到的是,这个领域有不同种类的关注点,一个企业关心赚钱是非常合理的,这基本上就是企业所做的,但我也认为说它不是你的字符串库,它将为你赚钱,而是你建立在你字符串库之上的惊人的 UI 产品差异化功能和其他东西,所以保守你的字符串库专有和秘密等等,可能不再是重要的事情了,或者以前的平台是不同的,即使是 15 年前,事情也有些不同,但世界在变化,所以谷歌取得了很好的平衡,我认为,而 TensorFlow 的开源确实改变了整个机器学习领域,它本身就引起了一场革命,所以我认为这非常棒,非常有远见,因为我可以想象,我在谷歌工作的时候,我可以想象不同的背景和不同的世界,一家公司说机器学习对我们正在做的事情至关重要,我们不会把它交给别人,所以这个决定是一个深刻的、深刻的、辉煌的见解,我认为它确实让世界变得更好,对谷歌来说也更好,而且它有各种各样的连锁反应,我认为它真的,我的意思是,你不能低估谷歌所做的,这对于软件来说是多么深刻,太棒了,而且它再次,我可以理解关于如果我们发布我们的机器学习软件,我们的竞争对手是否会更快地发展的担忧,另一方面,我认为 TensorFlow 的开源对谷歌来说非常棒,我相信那个决定当时非常不明显,但我认为它进展得非常好,所以我们快速尝试一下,是的,你在特斯拉工作了五个月,担任自动驾驶软件副总裁,你领导团队从硬件一号硬件过渡到,我有一些问题,所以首先,对我来说,这是汽车行业中最勇敢的工程决策之一,从软件角度来说,从零开始,这是一个非常勇敢的决定,所以我的一个问题是,挑战是什么?你的意思是职业生涯的决定,从一份舒适的好工作跳到未知,还是两者兼而有之?所以,在个人层面,你做出这个决定,然后你出现时,你知道这是一个非常困难的工程过程,你也可以选择留在硬件一号,或者那些决定,完全投入,让我们从头开始,那是什么样的?好吧,所以我的意思是,我认为特斯拉没有慢慢来的文化,它就是这样,吸引我的特斯拉的一件事是,它非常像一个“让我们改变世界,让我们弄清楚”的地方,所以我非常尊重这一点,特斯拉在硬件一号方面做了非常聪明的事情,硬件一号设计最初是为了汽车的非常简单的自动化功能,比如交通感知巡航控制之类的,而他们能够有效地通过功能蔓延将其变成车道保持和非常有用的驾驶员辅助功能,这相当令人惊讶,特别是考虑到硬件硬件二号的细节,它在很多方面都建立在这些基础上,而那里的挑战是,他们正在从第三方提供的视觉堆栈过渡到内部构建的视觉堆栈,所以对于我主要帮助的第一步,是迁移到这个新的视觉堆栈,这非常具有挑战性,而且由于各种原因,时间非常紧迫,这是一个巨大的飞跃,但幸运的是,它建立在构建硬件一号驾驶员辅助功能的团队的许多知识和专业知识之上,你以一种体贴的方式谈论你在特斯拉的时光,但最终并不适合,埃隆·马斯克,我们在他的播客上谈过几次,他几乎一直在做世界上一些最大胆、最具创新性的工程工作,有时是以牺牲特斯拉团队的一些成员为代价的,你从在埃隆混乱的世界中工作中学到了什么?是的,所以我想说,我在特斯拉的时候,我经历了并看到了我从未在一家公司见过的最高程度的离职率,这有点令人震惊,但我学到的一件事,我开始尊重的是,埃隆能够吸引优秀的人才,因为他对未来有非常清晰的愿景,他能够让人们接受它,因为他们想要那个未来发生,对吧?而愿景的力量是我非常尊重的东西,我认为埃隆在让他人们相信他能够做到的事情方面是独一无二的,而且,非常,有很多人站在街角说,啊,我们要去火星了,但是,但是,有几个人能够让其他人接受它,相信它,建立道路并使其发生,所以我尊重这一点,我不尊重他所有的做法,但是,但是,我非常尊重这一点,你在几个地方都提到过,包括在这个背景下,努力工作,努力工作意味着什么?当你回顾你的生活时,你不得不真正投入一切的那些最残酷的时期是什么?好问题,努力工作可以有很多不同的定义,所以工作时间很长,是的,这是真的,对我来说最难的是,既要短期专注于交付和执行,让事情发生,同时又要考虑长期并试图平衡,对吧?因为如果你只关注解决任务并完成它,只考虑下一步的增量步骤,你就会错过你应该跳过的下一个大山,对吧?所以我非常幸运,我能够在这两者之间来回切换,历史上,例如在苹果公司,这是可能的,因为我能够与一些非常了不起的人合作,建立团队和领导结构,并让他们在职业生涯中成长并承担责任,从而让我能够疯狂地思考下一件事,所以这很多都是,但它也关于,你知道,有了经验,你就能做出别人不一定能做出的联系,所以我认为这是很大一部分,但基础就是很多时间,你知道,这对我来说没问题,关于工作与生活的平衡有不同的理论,我为自己制定的理论,我不会强加给团队,但为我自己制定的理论是,你知道,我想要热爱我所做的事情,并努力工作,我的目标,我觉得,我的目标是改变世界,让它变得更好,这就是我真正想做的,最后一个问题,LLVM 的标志是一条龙,你知道,你解释说这是因为龙具有力量、速度、智慧的含义,它也可以是流畅、优雅和模块化的,直到你去掉模块化部分,你最喜欢的虚构、视频或电影中的龙相关角色是什么?所以这些都是非常友好的解释方式,你想知道真正的原因是龙吗?是的,所以有一本关于编译器设计的经典书籍叫做《龙书》,这是一本非常老的关于编译器的书,所以 LLVM 的龙标志的出现是因为在苹果公司,我们一直在谈论 LLVM 相关的技术,而幻灯片上没有标志,有点像我们该怎么办?有人说,好吧,编译器技术应该有什么样的标志?我不知道,我的意思是,龙是我们拥有的最好的东西,你知道,苹果公司以某种神奇的方式创造了这个标志,这是一个很棒的事情,整个社区都围绕着它,然后随着其他平面设计师的参与,它变得更好,但最初就是这样来的,故事是,虚构作品中有你喜欢的龙吗?《权力的游戏》、《指环王》之类的?《指环王》很棒,我也喜欢角色扮演游戏,比如电脑角色扮演游戏,所以龙经常出现在那里,但真的回到了书,哦不,我们需要,我们需要一个东西,而且可笑的是,LLVM 的一个有趣的事情是,我的妻子非常棒,她经营着 LVM 基金会,她去格蕾丝·霍珀会议,并试图让更多女性参与进来,她也是编译器工程师,所以她试图让其他女性对编译器等事物产生兴趣,所以她分发贴纸,人们喜欢 LVM 贴纸,因为《权力的游戏》,所以有时文化也会有这种效果,让下一代希拉里工程师参与到这个事业中来,好的,太棒了,克里斯,非常感谢你的时间,很高兴与你交谈,你。