从版本1开始,用Java修复了成千上万的东西:甲骨文的谢尔盖·库克森科(Sergey Kuksenko)的精彩访谈


Sergey Kuksenko是一位性能工程师,他曾经看过Java 1.0版。 在此期间,他设法参与了移动,客户端,服务器应用程序和虚拟机的开发。 自2005年以来,Java一直致力于提高性能,目前正在Oracle工作,以提高JDK的性能。 Joker和JPoint最受欢迎的演讲者之一。


这个habrapost是Sergey的精彩访谈,致力于以下主题:


  • 表演崇拜;
  • 语言和库的初始设计以及何时需要优化;
  • 有希望进一步优化的领域;
  • 如何参与开发以及可以通过优化打破什么;
  • 编译技巧,寄存器放置;
  • 可以用碎肉组装猫吗?
  • 当测试连续五天和其他日常工作正常进行时;
  • 如何成为一名性能工程师;
  • 为下一个小丑准备报告。

关于生产力崇拜


奥列格(Oleg):您是我们的老发言人,这不是我们的首次采访。 告诉我一点,你现在是谁,你在做什么?


谢尔盖(Sergey):我和很多年前一样,并且正在做同样的事情。 我在Java Performance团队工作,负责Oracle Java计算机OpenJDK的性能。


奥列格(Oleg):然后我有一个有点古怪的问题:您是一位绩效工程师,您的报告涉及各种绩效。 您不认为性能问题被高估了吗? 每个人都赶着她,但这是否有必要?


谢尔盖:这是一个很好的问题。 这一切都取决于另一个。 这种观众的注意力可以被认为是过度的。 另一方面,企业生产力就是金钱。


这是人们在亚马逊的某种云上的硬件上花费的真实金钱。 如果您没有足够快地处理您的请求-就是这样,您会失去客户,失去金钱或失去其他一切。 因此,对性能的要求当然总是存在的。 问题是在每种情况下它有多重要。 我对高频交易保持沉默。


Oleg:顺便说一句,您认为Java适用于此吗?


谢尔盖(Sergey):您有机会见过像彼得·劳瑞(Peter Lawrey)这样的人吗?


奥列格(Oleg):谁是OpenHFT开发商Chronicle Software的首席执行官?


谢尔盖:这是一位来自伦敦的非常有名的朋友,他经常参加各种会议。 他们使用Java进行高频交易,生活很棒。


Oleg:他们是在Java上执行此操作还是被Java称为本机代码? 尽管如此,还是有区别的。


谢尔盖:我不知道这个水平,他没有告诉。 原则上,如果需要,所有需要的都可以在Java本身中实现。


奥列格:有趣。 例如,如果您是一个蟒蛇社区,那么他们对生产力的崇拜就少得多。 这到底是怎么回事? 也许的报告激起了对绩效的狂热? 您,希普列夫,潘金,伊凡诺夫等等。


谢尔盖:我不知道怎么回事。 俄罗斯会议上对生产力的崇拜远高于美国会议。 也许这反映了观众本身。 在我们这里,人们希望更多地参与生产力,这对他们来说很有趣。 在美国,他们想为自己付出的更多付出更多。 但这是一个假设,一个推测。 就是这样



什么时候需要优化


奥列格(Oleg):您说过仍然有演出要求。 您什么时候需要开始考虑性能? 雷声什么时候来?


谢尔盖:这是一个一般性的抽象问题。 最好再来一次以前的会议上发表的Alexey Shipilev的主题演讲 ,他在这方面的描写就足够好了。


奥列格:是的,我记得“名字Sh的曲线”。


谢尔盖(Sergey):您需要立即进行演奏,但要取决于水平。 不必立即编写基准。 例如,众所周知,在Set as a set和SortedSet之间对API体系结构级别的常规限制已经对我们施加了基本的算法限制。


如果我们将SortedSet填充到API中(尽管没有人需要排序的那个),然后将其散布到我们的系统中,那么这件事就必须被痛苦而艰辛地拉出。


问题从设计的高度开始-这是最小限度的问题。 必须使用尽可能小的限制,以便以后可以使用它们。 例如,当我扭曲各种Java片段时,想到的是非常糟糕的单词。 我想对其中一个基类做一些事情,但是我什么也做不了,因为该API是固定的,您无法再对其进行更改,因为它已经被抓取了。 但是为了进行一些技巧和超频,您需要隐藏一些细节。


案例研究:我曾经蹲过java.math.BigDecimal类。 不同方面提出了很大的要求来分散它。 当我们的BigDecimal不是“ Big”,而仅仅是Decimal时,有一个很好的特殊情况,您需要阅读它们。


当然,现在已经为此做了一个适当的包装。 但是,如果没有公共构造函数使用BigDecimal,而是使用一些静态方法和工厂,则可以将BigDecimal抽象化,并根据需要吐出两个不同的实现。 但这是不可能的,因为构造函数会突出显示。 因此,您已经必须在内部进行不必要的运行时检查,在某些情况下,您可以采用这种快速检查方法。


奥列格(Oleg):是否由此得出结论,在开发标准库时,值得抛弃设计师,而是在各地做建筑商吗?


谢尔盖:天色已晚。


奥列格:如果还不算太晚,这是个好主意吗?


谢尔盖:她会给她更大的回旋余地。 看:我们正在编写新代码,而这个新代码位于构造函数之外。 获得两个操作:首先创建一个对象,然后调用填充该对象的构造函数。 有时,隐藏对象的真实创建并创建我们在外部具有的错误对象非常有用。 这是Java早期的语言限制。


奥列格(Oleg):好吧,现在每个人都使用DI框架,使您可以随意扭曲代理并添加任何内容,从而绕过此限制。 在该语言的原始设计中,您是否可以添加类似的内容,即内置的依赖项注入容器?


谢尔盖:我对语言的初始设计有非常具体的看法。 如果您回想一下Java 1.0的历史,它带来了相当大的时间压力,所有事情都必须迅速完成。


我个人希望从第一个版本中解决数千个问题。 但是,恐怕即使从千分之二中选择一个,也就是三分之二,并且它们会在第一个Java的时候就开始制作,而Java不会问世。 这是一个标准的例子,即最好是好人的敌人。



Java还有什么可以优化的


奥列格(Oleg):普通人只能在他们的项目中修复某些问题,而作为JDK的性能工程师,您会立即影响成千上万个项目。 随之而来的问题是:在Java开发超过20年的过程中,JDK中是否有任何区域可以由核心工程师进行干预以产生显着效果? 这种“显着效果”有多明显?


Sergey:首先,现在Java根本无法在10年前的硬件上运行。 现在的Iron和10年前的Iron是两个很大的区别,建议进行各种优化。


第二,当然,当性能工程师坐下来并加速某些事情,获得​​大量数字,向上司报告,在这些超频之后掏出钱以获得奖金时,这真是太好了。 但是,有关新项目的大量工作正在进行中。 添加了一项功能,性能工程师的任务不是超频该功能,而是确保此功能一切正常。 否则,请提出一些更正。


奥列格:您如何确定? 您没有正式验证代码。 什么是“确定”?


Sergey:从性能的角度来看,确保一切正常,这是性能工程师的主观专家意见,他们会写一份报告并说“此功能中的一切正常”。 根据功能的大小,这意味着有时需要采取很多措施,有时需要进行许多不同的努力。 从您只需要笨拙地坐下来,观察那里的工作,对该区域进行基准测试,制定基准测试,查看出口处发生的情况以及做出合理的明智决定这一事实开始。


Oleg:从性能和新功能的角度来看-Java通常会向前发展吗? 那里有东西吗? 因为我们的硬件变化不大,例如,如果我们谈论英特尔。


谢尔盖:这什么时期没有变化?


奥列格(Oleg):例如最近10年。


Sergey:是的,十年前是否在硬件上安装了AVX-512?


奥列格:不。 他,大概不是总是存在于现代中吗?


谢尔盖:我绝对不会。 我们在实验室中拥有它,但是它们全都由编译器占用。 到目前为止,它们一直在拧,所以我没有看。


Oleg:是否可以将AVX-512支持视为典型功能的示例?


谢尔盖:可能。 我到底要做什么:我们有大量的工作要做,因为现代要求添加新的加密算法。 这是十年之久的加密算法根本无法依靠的事情。 我们需要新的算法和更大的密钥。 我想说,不断增加新的加密算法。


奥列格(Oleg):他们是否以某种方式加速了硬件?


谢尔盖:这一切都取决于特定的算法。 有非常好的加速算法。 顺便说一句,十年前这在Intel硬件上还行不通,但是大约有5-6个良好的指令显示效果,直到具有加速功能的AES单元为止。 所有这些都以最小的时间间隔实现。


奥列格(Oleg):关于GPU,它们还能乘矩阵吗?


Sergey:关于GPU-一个单独的对话。 为此,我们有一个巴拿马项目,所有这些工作都在其中进行,有一天它将与所有好东西一起到达Java主线。


奥列格(Oleg):我有一些熟人,有条件地从事金融数学。 从某个时候开始,他们总是切换到C ++进行计算,并声称使用托管平台中的所有这些优化和硬件非常不便。 这可以改善吗?


Sergey:我们对此也有很高的要求,并且有许多内部要求。 例如,使某些东西在机器学习领域更好地工作。 通常,这是一个普通矩阵乘法,可以在GPU上抛弃。 可以这样说,这项工作正在进行中。


我们有两个大型的伞项目:Valhalla和Panama,它们应该收集GPU之类的功能。 在Valhalla和Panama的交界处有一个直接与Java代码中的SIMD / SSE / AVX指令配合使用的矢量API,而Valhalla本身具有内联类型是朝着这个方向迈出的重要一步。



通过优化可以打破什么,如何参与开发


奥列格:您提到的雨伞彼此相似。 一个项目是否有可能影响另一个项目,包括代码和性能配置文件? 例如,您是否重构了某些东西,而不幸的罗恩·普勒斯勒(Ron Presler)却流着眼泪,正在晚上将他的测试固定在一个角落里?


谢尔盖:这总是发生。 一个具体的例子是Vector API。 为了使Vector API正常工作,我们的本机向量必须最终成为值类型,或者像现在在Java中称为内联类型。 您可以在热点中找到一种解决方法,并以某种方式实施它,但是我希望有一个通用的解决方案。 另一方面,内联类型的关键特征就是完全不必担心此数据的布局,并且此数据的布局对于Vector API极为重要。


因为实际上,它直接对应于AVX-512及其所有。 显然,您需要做一些深蹲,进行一些优化,一方面,这些将使内联类型成为普通类型,但是将具有基于硬件的布局。 自然地,会发生交叉。 如果您看一下移居巴拿马和迁徙瓦尔哈拉的人群,它们相交的一半以上。


奥列格(Oleg):纯粹是组织性的,这里您有一个项目,性能存在某种问题,但这是多个项目的交集。 接下来要做什么? 如何解决呢? 事实证明,这已经是项目和人员之间的折衷,而不是某些抽象任务之间的折衷。


Sergey:这里的一切都很简单:如果这是一个刚设计的功能的性能问题,您需要去做设计的人说:“某某某某,我们该怎么办? 让我们以不同的方式做。” 讨论开始了,问题解决了。


如果代码已经存在,则它已经可以工作了。 在理想情况下,您可以解决此问题,或者,如果无法完全解决该问题,则可以脱颖而出原型,然后再次与代码所有者联系并说:“这是原型,我们将做什么?” 此外,我们专门针对每种情况解决此问题。


奥列格(Oleg):我们这里有一些无法参与此过程的感兴趣的人,这些都是最终用户。


谢尔盖(Sergey):他们参与的程度不够高,因此他们在甲骨文公司的薪水无法获得报酬。 如果您不需要薪水,请来OpenJDK参加。


奥列格:这有多真实? OpenJDK有一些像您一样可恶的天才,普通人在哪里,您在哪里。 假设某件事对我来说放慢了速度,我该怎么办?


谢尔盖:如果您不知道问题所在,那么这是一个单独的问题,是否有人会为您寻找解决方案,这是一个问题,例如领域,示例等。 即使您不知道问题所在,也可以使用OpenJDK编写并询问。 如果有人立即点击它,人们就会抓住它。 如果对任何人都不感兴趣,它将挂起并没有答案。


奥列格(Oleg):假设我知道问题所在,甚至知道需要解决的问题。


谢尔盖:如果您知道问题所在,那就来OpenJDK,在所有必要的纸上签名,提供补丁,然后对其进行修改和浇注。


奥列格:就是这么简单吗?


谢尔盖:是的,有点官僚主义,请稍等。 昨天,Tagir( lany )得到了我放弃的一个小补丁。 他只是想被拖到尽头。 他开始自己想起它。 他说:“该死,这是什么,我已经完成了所有工作,已经计划好了,没有人在审查。” 好吧,没有人在审查。 7月,Java办公室的一半正在休假。 他们会休假,然后去做。


奥列格(Oleg):在美国度假与在俄罗斯度假的日期大致相同?


谢尔盖:不,美国的假期系统与俄罗斯的假期系统完全不同。 首先,它们明显较小。 而且,在美国,假期制度与学校挂钩。 当您有孩子度假时-然后是假期。 假期一开始,全美国就开始行动。 而且由于这里的课程在6月中旬结束并在8月中旬开始,因此假期的差额并不是很大-只有两个月。



编译技巧,寄存器放置


奥列格(Oleg):您是否曾经在家中进行过优化,然后用户不得不以不同的方式编写代码? 相对而言,如果选择子字符串的操作占用一个范围,并且现在进行完整复制,则此重构会更改您编写代码的方式。


Sergey:当然可以,但是我现在不打算给出具体的例子。 问题是,人们在编写代码时放下了什么。 如果他们需要发挥最大的性能,并且为此做了各种编译器特有的技巧,则应为编译器随时间的发展做好准备,并且他们将不得不根据编译器的当前状态不断修改其代码。 那太好了。


假设20年后,突然间,Graal将成为HotSpot的主要编译器-那么这些可怜的家伙将不得不完全重写所有内容。 仅当您承担了这样的技术职责时才会发生这种情况-跟踪编译器中的更改。 在没有直接联系的情况下编写正确的代码要简单得多,可以使用或多或少的常规通用实现方式。


顺便说一下,关于编译器-不仅关于Java编译器,而且一般而言。 有摩尔定律,这不是定律,只是根据经验观察,晶体管的数量每年半翻一番。


完全相同的法律( Proebsting法则规定 ,未经修改的代码性能每隔一年半到两年提高4%。 这4%是最终用户从编译器的发展中免费获得的。 不是硬件,即编译器。


奥列格(Oleg):我想知道这些百分比来自何处。 这是某种初始的低效率吗? 但是有一天,这种低效率的局面将结束。


Sergey:不,这只是技术开发的问题。 开始从事性能工作时,我退出了编译器。 但是一旦订婚,对我来说最大的发现是在2005年或2006年。 我在2008年完全了解了该内容,因为我没有及时阅读该文章


任何代码生成的一个非常重要的任务是寄存器分配。 众所周知,一般来说,这个问题是NP完全的。 解决它非常困难,因此所有编译器都试图驱动某种近似的算法,其质量程度各不相同。


这是一篇文章,在这里,伙计们证明了在某些情况下(涉及大量编译器和大量内部表示,并有一定限制),存在用于分配寄存器分配任务的精确多项式算法。 哇,走吧!


这发生在2005年,早期的编译器不知道这一点。


Oleg:现在您可以为Java创建新的分配器了吗?


Sergey:现在有一个理论上的解决方案,可以重写。 我没有详细介绍,但是我知道Excelsior的家伙实现了该算法。


Oleg:我们最近接受了Cliff Click的采访,他谈到了他为Java编写的疯狂复杂而疯狂的天才分配器。 不想写另一个吗?


谢尔盖:不。


奥列格:有什么正常的吗?


谢尔盖:不,他不正常。 从功利主义的角度来看,我会说我看着汇编程序,有时会看到:“好吧,是的,这里的寄存器变坏了”。 如果我要踢我们的编译器,然后重写分配器,那么我们会得到什么? 我们将获得一些好处,但是除了那些我看到寄存器分配效率低下的例子外,我不太可能看到它。 只要在这方面没有大的失败,总有事情要做并获得更多的收益。


奥列格(Oleg):在JDK中,有哪些工作领域可以解决所有引擎舱编译器或性能魔咒? 您说您需要编写正常的普通代码,一切都会好起来的,但这听起来可疑。


谢尔盖(Sergey):一切都会好起来,直到您需要超级骗子。 如果您真的需要它,请准备好始终对其进行重写。 目前,如果您编写的是一个抽象的大型应用程序,那么它通常不会在性能方面发挥作用。


一方面,一旦垃圾收集器被触发,它就会消耗掉10%到20%的内存,另一方面,应用程序架构也开始弹出。 我在应用程序堆中看到的一个巨大问题是它们正在转移数据。 我们从这里获取数据,将其传输到那里,在那里进行一些转换。 通常,任何程序都可以做到这一点。 它以某种方式将数据从一个地方传输到另一个地方。 但是,如果程序中的移位太多,则编译器将无济于事。


奥列格(Oleg):您可以尝试跟踪一些简单的事情,例如:这块内存正在改变所有者,并朝这个方向在对象之间移动。


谢尔盖:不,这是一个设计问题。 但是我不仅要转移,还要进行修改,我对它们有所作为。 如果您考虑一下,则可以在实际的大规模应用程序中获得最大的好处:是否需要进行大量的转换。 而不是十个,使七个已经很不错了。




(似乎在这里意外地复制了同一视频。实际上,一切都比较简单,Habr从YouTube缓存了错误的图片)


我们从肉末收集一只猫


Oleg:我们刚刚举行了有关分布式计算的Hydra会议。 如此之多的人非常费解诸如成本模型之类的事情,从而确定每个操作的成本-非常精细,非常准确。 人们真的很想写出所有指令,加总每条指令的成本,并查看您的代码将占用多少条。 我想知道这种方法在现代现实中如何工作。 , ?


: , . , . , . , . , , , . ?


: : « ».


: , . , . , ? . — , . , , - , .


: , ?


: , ? , . ?


: , - ?


: , — , . - . ? , , , , . , .


: .


: , 1 . , , . , - , - .




performance-


: OpenJDK . ? C++ . — -?


: , , . . OpenJDK 15 . 15 .


: , , . .


: ! , , . , , , , , . , . : , , ( , ), — . , , .


: , ?


: , , Java.


: ?


: , , Valhalla.


: - , , — , ? ? .


: , . — . , , , . , , . . 2-3 , , , , — , .


, , inline-, Java Joker. . , Java- , runtime-. red flag: runtime- 0. ? , out of order- — .


, . , . ? . . baseline, , 5-6 , — . , , - 2 — - . 3% - , . 3% ?


: , ?


: , . performance-, . , , — .


, , . performance- — , - performance- - , . , , .


, , , , performance- — class libraries hotspot, .



«» performance


: , - performance-, . , , ?


: . ? , performance- performance-.


, : , , Oracle, Twitter, Netflix , - . , — . , performance- , .


- , , performance- , ? , , .


, performance- — . : - performance review, , , , , . — performance .


: « , ...», , — . , - — , , , .


Joker


: Joker . ?


: inline-, .


: , value-?


: , , . . , . value Java- . value, value, by value, - by value, value type. , .


. , , , Rémi Forax - , inline-. , , Kotlin inline- , value- Java, .


. value-, , , mvt (minimum value types), LW 1. LW 2 — , . , , , . , , , , performance- , , , , .


: , - -?


: , - . , , , , invokedynamic .


: , , , , .


: , , , . — , , . , ?


: , , , .


: . , , inline- generic- , inline-. , .


: , - ?


: : inline- LW2 . value-, generic, .


« Java -? Valhalla» Joker , - 25-26 2019 . , .

Source: https://habr.com/ru/post/zh-CN463455/


All Articles