G.O.S.S.I.P 阅读推荐 2022-08-03

admin 2022年8月4日10:58:42评论58 views字数 2360阅读7分52秒阅读模式

如何给论文起标题?有时候简单粗暴的命名风格也不失为一种选择,例如今天为大家介绍的这篇USENIX ATC 2022论文 Investigating Managed Language Runtime Performance: Why JavaScript and Python are 8x and 29x slower than C++, yet Java and Go can be Faster? 就单刀直入,迅速吸引了小编这样的小白读者的注意!

G.O.S.S.I.P 阅读推荐 2022-08-03

这篇看上去很像饭圈粉丝互相攻击的论文,看似支持Java和Go而嘲笑JavaScript和Python,但是论文毕竟是科学严谨的学术写作成果,就算是diss也要逻辑严密,作者以C++为baseline,横向比较了Java、Go、JavaScript和Python四种语言的解释器(runtime,或者说interpreter)的性能。作者通过对runtime进行插桩分析,并开发了一个名为LangBench的benchmark套件,包括6个不同的应用,帮助开发者精确定量地分析追踪各种语言的runtime的overhead究竟是怎么产生的。

下载LangBench: https://github.com/topics/langbench

作者的研究表明,开发相同功能的程序,用JavaScript和Python(V8/Node.js,CPython)分别会产生 8.01x/29.50x 的运行开销(得罪人的说法就是杀了所有Python程序员祭天,摩尔定律还可以再延续5代……),而Java和Go表现就好很多——OpenJDK和Go开发的程序仅仅只有 1.43x/1.30x 的运行开销。更重要的是,JavaScript和Python只考虑了单核运行,OpenJDK和Go则更好地考虑了并行优化~

进入正题,大家都知道,解释器运行模型天然就很适合做instrumentation,但是作为一个性能测试的研究工作,作者是如何保证插桩分析尽可能对测试产生较小的干扰呢?下图是作者对不同的语言的解释器中每条bytecode指令进行插桩、统计运行时间消耗的基本代码:

G.O.S.S.I.P 阅读推荐 2022-08-03

对JavaScript这样包含Just-in-time compilation的执行模型,插桩分析也会更复杂一些,需要对解释器和JIT编译器都进行处理(前些年在Android平台上做taint analysis的研究工作也遇到过类似的问题:当原来的Dalvik VM从单纯的解释执行转为解释/编译混合模型直到最后的基本全编译模型,也出现了从TaintDroid到TaintART这样的转变。)

为了全面衡量各种类型的应用场景,作者设计的LangBench benchmark套件包含了如下6个程序,能够比较均衡地评估CPU、内存、I/O的开销,同时也考虑了并行化的需求(作者只是想表达,我会用5种语言开发数独、排序、文件服务器,猎头快来找我):

G.O.S.S.I.P 阅读推荐 2022-08-03

外行看评测结果,内行看根本原因,所以我们首先看看性能评测的情况:

G.O.S.S.I.P 阅读推荐 2022-08-03

作为“人生苦短、我用Python”的信徒,小编看到上图也不得不接受事实——Python解释器(CPython)在性能开销方面遥遥领先,在生产环境中并不适合用来对数独进行求解~ 但是我们不禁要问,为什么不同语言的性能开销差别如此大,这背后究竟是人性的扭曲还是道德的沦丧?于是作者深入剖析了一番,指出:

  • 类型检查和内存访问边界检查产生开销:解释型语言虽然慢,但是不会产生内存破坏漏洞,这个是一个安全上巨大的加分项,这背后当然是对类型转换和内存区域访问的严格检查在默默发挥作用。如果把这些检查关闭,会换来很多性能的提升(例如下图中对V8 JIT编译器进行修改,关闭了所有检查后,可以避免41.8%的性能开销),但是你会愿意吗?

G.O.S.S.I.P 阅读推荐 2022-08-03

  • 解释执行本身产生开销:这一项看上去很像废话,实际上是在比较不同的解释执行语言的JIT编译能力的强弱——OpenJDK在JIT编译上能够吊锤JS和Python(比V8快2.59x,比CPython快5.34x,因为避免了大量的弱类型检查,同时字节码设计上更适合底层优化)。而单纯比较JS和Python的解释器,作者发现CPython解释器的各类代码优化实现都不如V8解释器,虽然这些优化手段可能大部分都已经在2005年出版的Virtual Machines: Versatile Platforms for Systems and Processes这本书里面提及了。

G.O.S.S.I.P 阅读推荐 2022-08-03

  • 内存管理(Garbage Collectin)产生开销:解释性语言大量使用了自动化动态内存管理,虽然省去了程序员的各种烦心事,但是内存的垃圾回收必然要涉及非常多的复杂判断。涉及这方面的研究非常多,其中有一个叫做“写屏障”(write barrier)的概念,大家可以去网上搜索一下相关知识。作者指出,对write barrier使用不同的算法,性能上影响也比较大,Go在这方面做过不少优化,因此获得了很多性能上的收益。

  • 没有充分利用并行化:在测试中,作者发现,Node.js 和 CPython 解释器对并行的支持很不好,没有天然利用好现代硬件多核的优势,往往需要程序员自己去开辟多任务处理。不过,如果并行任务只涉及到I/O而不涉及到CPU和内存的共享资源分配,Node.js 和 CPython 解释器的多任务表现就会变好一些。

最后,作者在论文第8章中介绍了OpenJDK和Go在GC和并发上的一些优化技巧(所以它们能表现更好),同时也介绍了一个C++在实现文件读写并发时需要向解释器学习的小贴士,大家可以学习学习~


论文PDF: https://www.usenix.org/system/files/atc22-lion.pdf


原文始发于微信公众号(安全研究GoSSIP):G.O.S.S.I.P 阅读推荐 2022-08-03

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年8月4日10:58:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   G.O.S.S.I.P 阅读推荐 2022-08-03https://cn-sec.com/archives/1220687.html

发表评论

匿名网友 填写信息