代码之家  ›  专栏  ›  技术社区  ›  Thomas L Holaday

静态语言的运行时优化:C++的JIT?

  •  20
  • Thomas L Holaday  · 技术社区  · 15 年前

    是否有人使用JIT技巧来提高静态编译语言(如C++)的运行时性能?基于运行时观察的热点分析和分支预测似乎可以提高任何代码的性能,但也许有一些基本的战略原因,为什么只有在虚拟机中才能进行这样的观察和实现运行时的更改。我清楚地记得无意中听到的C++编译器编写者喃喃地说:“你也可以为C++编写的程序做这件事”,而听动态语言爱好者谈论收集统计和重新排列代码,但是我的网络搜索证据支持这个内存已经枯竭。

    7 回复  |  直到 11 年前
        1
  •  32
  •   Whatever    15 年前

    配置文件引导优化不同于运行时优化。基于配置文件信息的优化仍然是离线完成的,但是一旦二进制文件被发送,就没有持续的优化,因此,如果配置文件引导优化阶段的使用模式不能准确地反映实际的使用情况,那么结果将是不完美的,并且程序也不会适应不同的使用模式。

    你可能对寻找有关 HP's Dynamo 虽然这个系统集中在本地二进制和本地二进制翻译中,但是由于C++几乎完全被编译成本地代码,所以我想这正是您所要寻找的。

    你也可以看看 LLVM 这是一个编译器框架和中间表示,它支持JIT编译和运行时优化,虽然我不确定是否有任何基于LLVM的运行时可以编译C++和执行+运行时优化它。

        2
  •  10
  •   Nils Pipenbrinck    15 年前

    在过去的几年里,我做了很多这样的优化。我实现的是一个图形渲染API。由于API定义了数千种不同的绘图模式作为通用函数,因此速度变慢了。

    最后,我为一种特定于域的语言编写了自己的小型JIT编译器(非常接近ASM,但是加入了一些高级控制结构和局部变量)。

    我得到的性能改进在10到60之间(取决于编译代码的复杂性),所以额外的工作得到了很大的回报。

    在PC上,我不会开始编写自己的JIT编译器,而是使用libjit或llvm进行JIT编译。在我的例子中,这是不可能的,因为我正在开发一个不受libjit/llvm支持的非主流嵌入式处理器,所以我必须自己发明。

        3
  •  8
  •   Quonux    11 年前

    答案更可能是:没有人比PGO更适合C++,因为好处可能不明显。

    让我详细说明一下: 准时制 从开发人员的角度来看,引擎/运行时既有好处也有缺点:它们在运行时有更多的信息,但分析的时间很少。 一些优化是非常昂贵的,如果对开始时间没有巨大的影响,您不太可能看到这样的优化:循环展开、自动矢量化(在大多数情况下也是基于循环展开)、指令选择(对使用SSE4.1的CPU使用SSE4.1)以及指令调度和重新排序(使用更好的超级SC)阿拉尔CPU)。这种优化结合了C类代码(可以从C++访问)。

    一个完整的编译器架构来进行高级编译(据我所知)是Java。 热点 使用分层编译的类似原理编译和体系结构(Java) 阿祖尔 今天最流行的系统 耶格猴 JS引擎。

    但运行时最大的优化之一是:

    多态内联缓存 (也就是说,如果使用某些类型运行第一个循环,则第二次循环的代码将是前一个循环的专用类型,并且 准时制 将使用 SSA -基于表单引擎将应用持续的折叠/传播、内联、死代码消除优化,这取决于 准时制 是的,将执行改进或改进较少的CPU寄存器分配。) 正如你可能注意到的那样, 准时制 (热点)将主要改善分支代码,并且运行时信息将比C++代码更好,但是静态编译器,在它的一边进行分析、指令重新排序,对于简单的循环,可能会得到更好的性能。此外,通常,C++代码、需要快速的区域往往不是OOP,因此 准时制 优化不会带来如此惊人的改进。

    另一个优势是 准时制交付 那是 准时制 工作于跨程序集,因此如果要执行内联,它将具有更多信息。

    让我详细说明一下:假设你有一个A级的基地,你有 只有一个 在另一个包/程序集/gem/等中实现它,即b,并动态加载。

    这个 准时制 由于B是A的唯一实现,它可以在其内部表示中的任何地方用B代码替换A调用,并且方法调用不会执行分派(查看vtable),而是直接调用。这些直接呼叫也可以是内联的。例如,这个b有一个方法: getLength() 返回2,所有调用 GETLIGHT() 可全部降为常数2。最后,C++代码将不能跳过来自另一个DLL的B的虚拟调用。

    C++的一些实现不支持对更多.CPP文件进行优化(甚至在今天的版本中也有-LTO标志)。 海湾合作委员会 这使得这成为可能)。但是如果你是一个C++开发人员,关注速度,你可能会把所有的敏感类放在同一个静态库中,或者甚至在同一个文件中,这样编译器就可以很好地内嵌它,使JIT拥有的额外信息被设计出来,由开发者自己提供,所以没有性能损失。

        4
  •  5
  •   Keith Nicholas    15 年前

    Visual Studio有一个执行运行时分析的选项,可用于优化代码。

    “按配置优化”

        5
  •  5
  •   Crashworks    15 年前

    Microsoft Visual Studio调用此“ profile guided optimization “您可以在 MSDN .基本上,使用附加的分析器运行程序很多次,以记录其热点和其他性能特征,然后可以将分析器的输出输入编译器以获得适当的优化。

        6
  •  3
  •   Zifre    15 年前

    我相信 LLVM 尝试这样做。它试图在程序的整个生命周期(编译时间、链接时间和运行时间)内进行优化。

        7
  •  2
  •   Community Egal    7 年前

    合理的问题-但前提有疑问。

    在尼尔斯的回答中,有时“优化”意味着“低级优化”,这本身就是一个很好的主题。

    然而,它是基于一个“热点”的概念,这个概念与它通常给出的关联性不太接近。

    定义:热点是一个很小的代码区域,流程的程序计数器花费大量时间。

    如果有一个热点,比如占用大量时间的紧密的内部循环,那么如果它是在您控制的代码中(即不在第三方库中),那么在低级别上尝试优化是值得的。

    现在假设内部循环包含对函数的调用,即任何函数。现在不太可能在那里找到程序计数器,因为它更可能在函数中。因此,尽管代码可能是浪费的,但它不再是一个热点。

    有许多常见的方法可以使软件变慢,其中热点就是其中之一。然而,根据我的经验,这是大多数程序员所知道的唯一一个,也是唯一一个适用于低级优化的方法。

    See this.