【问题标题】:Why does TEST with register operands run slower than CMP with memory and immediate operands? [duplicate]为什么带有寄存器操作数的 TEST 比带有内存和立即操作数的 CMP 运行得慢? [复制]
【发布时间】:2021-02-14 14:22:32
【问题描述】:

假设我正在迭代一个大型数据集,并根据用户提供的变量进行区分大小写或不区分大小写的排序。我认为因为这个用户提供的值永远不会改变,所以将它放入寄存器是一个好主意,例如:

int main(int argc, char * argv[])
{

    clock_t t0, t1;
    int sort = 1;

    t0 = clock();
    register int case_insensitive_sort = sort;
    int z = 0;
    for (int i=0; i < 1e8; i++) {
        if (case_insensitive_sort) {
            z += 3; // for debugging to see where it's going
        } else {
            z -= 5;
        }
    };
    t1 = clock();
    printf("The function took %fs to complete.\n", ((double)(t1-t0))/CLOCKS_PER_SEC);

    t0 = clock();
    int case_insensitive_sort2 = sort;
    z = 0;
    for (int i=0; i < 1e8; i++) {
        if (case_insensitive_sort2) {
            z += 3; // for debugging to see where it's going
        } else {
            z -= 5;
        }
    };
    t1 = clock();
    printf("The function took %fs to complete.\n", ((double)(t1-t0))/CLOCKS_PER_SEC);
    return 0;

}

这是编译器输出的示例 -- https://godbolt.org/z/7KrGzr。似乎带有 register 前缀的寄存器中有一个比较,看它是否为 0:

testl   %ebx, %ebx

如果没有它,它会与内存地址进行比较:

cmpl    $0, -12(%rbp)

然而,当我在本地运行时,没有 register 的版本要快得多:

函数完成耗时 0.255494 秒。

函数完成耗时 0.188364 秒。

为什么会这样?我认为使用寄存器而不是进行内存比较会快得多。


更新:感谢您提供的所有帮助。从彼得的建议和链接的答案来看,最大的改进不是来自register-ing case_insensitive_sort,而是通过在循环变量上进行:

register int case_insensitive_sort = sort;
register int z = 0;
for (register int i=0; i < 1e8; i++) { ...

由此我得到以下两者之间的改进:

函数用了 0.255494 秒完成了寄存器(之前)。
该函数需要 0.038112 秒才能完成寄存器(之后)。
该函数在没有寄存器的情况下需要 0.252963 秒才能完成。

【问题讨论】:

标签: c performance assembly gcc x86


【解决方案1】:
  1. 在不启用编译器优化的情况下进行任何微优化毫无意义。
  2. 对编译器进行优化会忽略 register 关键字
  3. 您的测试没有测试任何东西。

启用编译器优化后,生成的代码完全相同。 https://godbolt.org/z/Tfjn9x

【讨论】:

  • 是的,是的,但是这并不能回答为什么test ebx, ebx 比其他内存引用慢的问题
猜你喜欢
  • 1970-01-01
  • 2016-11-06
  • 2018-03-24
  • 1970-01-01
  • 2014-07-25
  • 2016-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多