Unladen Swallow项目计划

原文链接:  http://code.google.com/p/unladen-swallow/wiki/ProjectPlan 译文链接: http://danmarner.yo2.cn/unladen-swallow-project-plan 原著: Google  译者: DaNmarner 欢迎转载,请保留原/译文链接。 =========================

Unladen Swallow项目计划

优化Python计划 注:所有引用资料的链接见相关论文

目标

我们要让Python变的更快,同时我们也希望让大型的,完好的现存应用无痛苦的转而使用Unladen Swallow项目。

  1. 创建一个比CPython速度至少快5倍的新Python版本。
  2. Python应用的表现应该非常稳定。
  3. 维持与CPython应用程序在源代码级别的兼容。
  4. 维持于CPython扩展模块在源代码级别的兼容。
  5. 我们并不是要维护一个长期的Python实现;我们把这个项目当作一个开发分支(branch),而不是一个版本分支(fork)。

项目概括

为了实现我们对于性能和兼容性的目标,我们选择对CPython进行修改,而不是从零开始开发这个实现。值得强调的是,我们选择从CPython 2.6.1着手:Python 2.6与2.4/2.5(当前为大多数有价值的应用使用)和Python 3.0(未来的终极版本)都有可以很好的共存。从一个CPython的版本着手可以是我们避免重新实现大量的内置函数,对象和标准库的模块,同时让我们重用一些现存且常用的CPython的C语言扩展API。从一个2.x CPthon可以让我们更轻松的迁移现存的应用程序;假设我们从3.x开始,并且要求大型应用程序的维护者们率先迁移他们的程序,那对我们项目的受众来说是不切实际的。 我们的主要工作是集中力量提高Python代码的执行速度,而不会在Python的运行时库上过多的努力。我们的长期计划是是使用一个创建在LLVM基础上的JIT来代替CPython传统的虚拟机,同时尽量少的影响Python的运行模式的其他部分。通过观察,我们发现Python的应用程序把大量的运行时间花费在了主eval循环。尤其是,即对例如操作码调度(opcode dispatch)这样虚拟机部件的微小调整也能对Python的运行性能产生重大影响。我们相信通过LLVM的JIT引擎把Python代码编译为机器码将会带来更多的益处。 一些显著的好处:

  • 转向JIT能让我们把Python从基于堆栈的机(stack-based machine)转为一个基于寄存器的机(register machine),实践证明这种转变提升了另一个类似语言的性能。
  • 其他的先不提,单是消除对收发操作码(opcodes)的需要本身已经是一项胜利。请参考http://bugs.python.org/issue4753上一个当前CPython对操作码发送变化的敏感性的讨论。
  • 目前的CPython虚拟机操作码接受/发送限制使进进一步的性能优化变得几乎不可能。举例来说,我们想实现数据类型回馈(type feedback)和动态的重新编译(dynamic recompilation ala SELF-93),但是我们认为用CPython编译的二进制代码来实现多态性内联高速缓存(polymorphic inline caches)将是无法接受的慢。
  • LLVM尤为值得注意。那是因为它为多个平台生成代码功能(codegen)的易用性,和它具有把C和C++编译为同种中间代码——这正是我们想要带给Python的。它能够让内联和交错解析(inlining and analysis)成为可能,消除这个当前Python和C之间的障碍。

有了产生机器码的框架,我们就可以把Python编译为更加高效的实现。以以下这段代码为例:

for i in range(3):
  foo(i)

目前它将被低效的翻译成这样

$x = range(3)
while True:
  try:
    i = $x.next()
  except StopIteration:
    break
  foo(i)

一旦我们有了知道range()代表range()内置函数的办法,我们可以把它变为类似这样

for (i = 0; i < 3; i++)
  foo(i)

在C语言里,使用unboxed数据类型进行数学 运算,可以把这个循环展开为

foo(0)
foo(1)
foo(2)

我们有意将Unladen Swallow的内部结构设计为支持多内核。服务器将来只会有越来越多的内核,我们要发掘这一点,从而可以在并行结构中完成更多的工作。例如,我们可以用一个内核作为并行优化器,它能在代码运行的时候进行日益昂贵(重要)的代码优化,用另一个内核来执行代码本身。我们也在考虑实现一个并行的GC,利用另一个内核来释放内存模块。由于大多数工业级的服务器都具有4到32个内核,我们相信这项优化的收益是一笔潜在的财富。然而,我们还是要关注高度并行的应用程序的需要,而不能盲目的消耗掉这些内核。 强调一下,这里的很多领域已经被其他的一些动态语言考虑或者实现过了,例如jRubyRubiniusParrot, 更包括像JythonPyPyIronPython这些其他的Python实现。我们正在从这些其他实现里寻找有关调试信息,正则性能以及其他提高动态语言性能的点子。这是一条已经被很多人走过的路,我们需要尽量避免重新发明轮子的困境。

计划蓝图

Unladen Swallow 将会每3个月发行一个新版本,发行期间进行bug修复。 2009 第一阶段(Q1) Q1主要用来对显存的CPython实现进行相对小的修改。我们的目标是在目前的基线上实现25-35%的性能提升。这个阶段的目标是相对保守的,我们想尽可能快的给客户应用程序一些看得见的性能优化,而不是要他们等到整个项目完成。 2009 第二阶段(Q2) Q2会集中力量来废除Python的虚拟机,并用一个具有相同功能的基于LLVM的实现将其代替。我们预期将会有一些性能提升,不过那不是2009Q2的主要任务。我们主要是要得到一个建立在LLVM之上的可以运行的东西。给它提速是本阶段之后的人物。 2009 第三阶段(Q3)以及将来 从Q3开始的任务将是“简单的“做好这些作业。我们不渴望做原创工作,而是尽可能的利用近30年来的研究成果。请移步相关论文来浏览我们打算实现内容的论文清单的一部分(远不及全部)。 我们计划强调对正则引擎何其他被确定为性能瓶颈的扩展模块的考虑。然而,正则表达式已经被确定为一个很好的目标并且会是我们考虑第一个进行优化的领域。 另外,我们打算去除Python的GIL和多线程的状态。我们相信通过实现一个更高级的GC,这一点是可以实现的,类似IBM的Recycler。 我们的长期目标是让Python的速度快到可以从把那些为了速度而使用C实现的类型重新用Python取代。 2009Q3准确的性能优化目标会在Q2的期间确定。

计划细节

一旦我们我们取得了一定的进展并且吸引了一部分人来采用我们的Python,我们将开始向LLVM的转换,也许会从一个开发分支开始。这将经历很多阶段:

  1. 在Python中添加llvmmodule和llvmfunction类型,它们为LLVM的模块函数类型提供了界面。教llvmmodule读取二进制文件(bitcode)并且对它们进行美丽输出。(读取bitcode对下一步并不至关重要,但它有助于测试。)
  2. llvn-py具有类似的包装类型,但是在核心解释器中使用Python定义的类型是十分困难的,所以我们需要我们自己的实现。这个实现不会是全部的包装(留给llvp-py好了)。它将仅仅是为了方便和有效的调试。

  3. 添加一个compile_llvm内置对象,它的大部分代码将和目前内置的compile对象相同,然而它会生成LLVM IR(同llvmmodule或llvmfunction数据类型)。我们可以一步一步的进行这项工作从而在整个进程中都保持一个可用的Python解释器。与此同时,我们可能会针对每一个操作码将其原本的实现转换为一个IRBuilder的实现,不过对于一些比较困难的情况我们也许只是向一个转换函数发送请求。我们也许需要/必须把这一步和下一步结合起来。有几个特别的Python结构可能带来麻烦
    • Generator:目前还没有一个针对generator的计划。我们必须要保留PC,寄存器和局部变量,问题是LLVM并没有定义一个PC,而只有标签,所以我们大概会给每一次yield一个索引然后调用当前索引来返回它。我们也可能要求所有的寄存器变量在那个时候已经被放出了。但是我们对实现细节还没有什么概念。我们预期到时候我们会想出一些主意来。
    • Closures:一个closure就是一个函数加一个预先赋值的参数,用来代表环境。
    • Exception处理
    • 函数调用问题
  4. 增加一个调用llvmfunction类型的办法。LLVM解释器也许还不能在我们需要的时候调用外部函数,使用JIT也许更加困难。我们会选择一个最简单的办法。我们只是想让一切运行起来。写上一堆测试代码。
  5. 用新的LLVM编译器取代Python用来编译二进制代码 (bitcode)的编译器,可能会附加一个标记。Talin建议使用一个代码/函数对象里的标记来解决调用和运行哪个编译器的问题。
  6. 想出一个最简单的可行的.pyc保存办法。我们希望最直接的办法——把python模块当成LLVM模块以二进制形式保存在硬盘上——就能用。我们可以在以后再添加那个高级的数据记录和预先优化代码(阶段12)
  7. 让Python知道到底应该快速JIT还是慢速JIT编译某个函数(向JIT::create传递fast==true)。Nlewcky说“代码生成模式(codegen)大概要比快速编译模式快上3倍(注:这是在debug模式下,而不是在release模式下,所以还不能确定)。”我认为我们确实应该花一些功夫来获得一个平衡。我希望Python在这个阶段能比我们最初的版本要快。
  8. 开始优化。Talin指出,实现定义的这些优化措施实现起来会很困难,因为Python的函数调用都是非直接进行的。这个关键让我们决定使用类型识别,从而让我们能直接的调用函数。
  9. (阶段8及以后可以同时开始尝试,大概会在2009Q2接近尾声的时候开始)

  10. 生成比直接翻译CPython二进制码更好的LLVM IR
  11. 想出为特定类型指定函数的办法,这样有利于内联(inline)。我们将能非常轻易的做到和psyco一样好,因为我们可以直接用他们的算法。 a. 允许用户通过注释函数来告诉解释器该用哪种编译方案。 b. 记录函数调用并且推断共同的参数类型。
  12. 如果优化措施的消耗大到了让JIT伤害到启动时间,我们可以记录那些耗时的函数从而只对它们进行优化。这里借鉴了HotSpot的工作原理。
  13. 阶段9b和阶段10要求我们同时保持不同版本的代码来满足所有的函数和已经存在的调用者。我们可能想要GC这些不同的版本,情况会变得很有趣。
  14. 把生成并优化的IR保存在硬盘上来充当.pyc文件的角色,也许还要包括进一些沿途生成的纪录。这可以让以后的运行享受到之前运行时进行的优化带来的好处。这也应了LLVM的“够程序一辈子的分析和转化的编译框架”的标榜。 :)

测试与考量

性能

Unladen Swallow包含了一个具有很多有趣的性能测试的tests目录。pref.py是我们所关心的基准的主要界面,它将负责调配运行,清理*.py[co]文件和利用测试结果来获取我们感兴趣的数据。 Unladen Swallow的基准套件被设计为致力于主流热门的Python程序,尤其是web应用。我们调查过的主流Web应用显示出他们主要的性能瓶颈在template系统上,所以我们初期的套件将集中精力在这方面:

  • Django和Spitfire的template。 两种大相径庭的实现Template语言的方式。
  • 2to3。 把Python 2的源码翻译为Python 3。具有一个很有意思的,大量依赖对象和方法的纯Python内核。
  • Pickle及逆Pickle。 大块头的Web应用依靠memcache,而后者用Python的pickle格式进行序列化。

除此之外,我们的基准套件里还包含了几个很一般的库,例如Richards,PyStone还有PyBench;我们包含这些仅仅是为了保持完整性和与其他 Python版本的兼容性,其他版本确实使用他们。Unladen Swallow认为这些基准库并不能衡量真实世界的Python应用或Python实现的性能,并且我们不会以默认状态运行它们或者把他们纳入决策因素。 有关项目长期表现的统计,Unladen Swallow利用了Google内部的标准性能考量框架。项目组成员将在邮件列表定期发布性能上的进展。对于一些小修改的测试,按照基准页面的描述使用perf.py就足够了。

准确性

为了保证实现的准确性,Unladen Swallow同时使用标准的Python测试组建和一些知名的Python 2.6第三方库。 值得一提的是,我们会测试第三方的C扩展库,因为这些库是最容易因为C语言中无法探明的变化而垮掉的。 随着我们在JIT实现上的进展,我们将在常规测试中引入一个参数测试器(fuzzer)。我们计划尽可能的重用Victor Stinner的Python的Fusil,因为 a)它是即成的, b)曾经被用来发现真实的Python缺陷。 Unladen Swallow还维护了一个BuildBot实例用来针对每一次对主版本的代码提交运行以上的测试。

风险

可能会不能和主线版本融合。 可能有一些有意见的,保守的高级Python核心开发成员会反对我们项目的融合,因为它会带来过于重大的变化。这是件好事!对变化的反抗在这种情况下是一 件非常好的事情,因为它会带来对我们的版本及其对CPython长远冲击的一次完全,公开的检验——这是开源社区,永远欢迎不同的声音。我们相信我们能证 明我们所提倡的改变,并且通过和Guido以及其他维护Python的高级成员保持密切的沟通,我们希望能把我们的工作局限在那些有希望能被接受的改变 上。然而,一些补丁还是可能被拒绝。如果是这样,我们将陷入支持一个与事实标准的不同Python的实现的境地, 或者不能变得像我们计划的那么快。C'est la vie。 LLVM有很多未知的方面: 对扩展库的影响?JIT在多线程应用的行为?对Python启动时间的影响? Windows支持: CPython目前具有很好的Windows支持,我们为了能和主线版本融合不得不维护这一状态。由于Unladen Swallow的工程师基本上对Windows开发甚至Windows的系统都没有多少经验,保持Windows支持在一个可接受的水平可能会减慢我们的 工作进程或者迫使我们在Windows上去除一部分有利于提高性能的代码。社区的贡献也许能帮的上忙。

信息交流

所有有关Unladen Swallow的信息交流都将在Unladen Swallow列表上进行。在这里会进行设计上的讨论,发布开发的最新进展,性能数据,代码评价以及所有其他一切该开源项目的细节。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值