JIT 编译可以 运行 比编译时模板实例化更快吗?

Can JIT compilation run faster than compile time template instantiation?

我最近听到很多人说 JIT 编译生成的代码非常快,甚至比任何静态编译器生成的代码都快。当涉及到 C++ STL 样式的模板化代码时,我发现这很难相信,但这些人(通常来自 C#/Java 背景)坚持认为情况确实如此。

因此我的问题是:您可以在运行时而不是在编译时进行哪些类型的优化?

编辑:澄清:我更感兴趣的是那种不可能静态地做的事情,而不是任何行业中的典型案例。

与上面声称的答案相反:

  1. 特定于体系结构的扩展可以很容易地被静态编译器使用。 Visual Studio,例如,有一个可以打开和关闭的 SIMD 扩展选项。

  2. 高速缓存大小对于给定体系结构的处理器通常是相同的。以Intel为例,通常L1缓存大小为4kB,L2缓存大小为32kB,L3缓存大小为4MB。

  3. 只有当您出于某种原因编写一个可以使用超过 4GB 内存的大型程序时,才需要优化内存大小。

  4. 这实际上可能是一种优化,其中使用 JIT 编译器实际上很有用。但是,您可以创建比核心更多的线程,这意味着这些线程将使用 CPU 中具有更多核心的单独核心,并且只是 CPU 中具有更少核心的线程。我还认为假设 CPU 有 4 个核心是很安全的。

尽管如此,即使使用多核优化也不会使使用 JIT 编译器变得有用,因为程序的安装程序可以检查可用的内核数量,并安装针对该计算机的内核数量进行了最优化的程序的适当版本核心。

我认为 JIT 编译不会比静态编译产生更好的性能。您始终可以创建代码的多个版本,每个版本都针对特定设备进行了优化。我能想到的唯一可以使 JIT 代码更快的优化类型是当您接收输入时,无论您用来处理它的代码都可以优化,以使代码在最常见的情况下更快(JIT 编译器可能能够发现),但在极少数情况下速度较慢。即使那样,您也可以执行该优化(但是,静态编译器将无法执行此优化)。

例如,假设您可以对数学算法执行优化,该算法会导致值 1-100 出现错误,但所有更高的数字都适用于此优化。您注意到值 1-100 可以很容易地预先计算,所以您这样做:

switch(num) {
    case 0: {
        //code
    }
    //...until case 100
}

//main calculation code

然而,这是低效的(假设 switch 语句未编译为跳转 table),因为情况 0-100 很少被输入,因为它们是在没有计算机帮助的情况下通过心理发现的。 JIT 可能会发现这样更有效(在看到很少输入 0-100 范围内的值后):

if(num < 101) {
    switch(num) {
        /...same as other code above
    }
}

//main calculation code

在这个版本的代码中,在最常见的情况下只执行 1 个 if 而不是在极少数情况下平均执行 50 个 if(如果 switch 语句被实现为一系列 if)。

你可以在运行时做的事情

  • 查看存在哪些特殊指令(AMD 与英特尔,....)
  • 检测缓存拓扑
  • 检测内存大小
  • 核心数

以及我从列表中遗漏的其他内容

这是否总是让事情快 10 倍,不是。但它确实提供了编译时不可用的优化机会(对于广泛分布的代码;显然,如果您知道它只会在 3 种不同的硬件配置上使用,那么您可以进行自定义构建等)

JIT 编译器可以测量发生条件跳转的可能性,并相应地调整发出的代码。静态编译器也可以做到这一点,但不是自动的;它需要程序员的提示。

显然这只是众多因素中的一个,但它确实表明 可能 JIT 在适当的条件下变得更快。