gpt4 book ai didi

c++ - 为什么 std::equal 比两个小 std::array 的手卷循环慢得多?

转载 作者:可可西里 更新时间:2023-11-01 16:47:23 26 4
gpt4 key购买 nike

我正在分析一小段代码,它是大型模拟的一部分,令我惊讶的是,STL 函数 equal (std::equal) 比简单的 for 循环慢得多,比较两个数组元素元素。我写了一个小测试用例,我认为这是两者之间的公平比较,使用 Debian 文件库中的 g++ 6.1.1 的区别并非微不足道。我正在比较两个有符号整数的四元素数组。我测试了 std::equal、operator== 和一个小的 for 循环。我没有使用 std::chrono 来确定确切的时间,但是可以通过时间 ./a.out 明确地看出差异。

我的问题是,给出下面的示例代码,为什么 operator== 和重载函数 std::equal (我相信它调用 operator== )需要大约 40 秒才能完成,而手写循环只需要 8 秒?我正在使用最近的基于英特尔的笔记本电脑。 for 循环在所有优化级别(-O1、-O2、-O3 和 -Ofast)上都更快。我编译了代码g++ -std=c++14 -Ofast -march=native -mtune=native

Run the code

循环运行了很多次,只是为了让肉眼看清楚差异。模运算符代表对其中一个数组元素的廉价操作,并用于防止编译器在循环外进行优化。

#include<iostream>
#include<algorithm>
#include<array>

using namespace std;
using T = array<int32_t, 4>;

bool
are_equal_manual(const T& L, const T& R)
noexcept {
bool test{ true };
for(uint32_t i{0}; i < 4; ++i) { test = test && (L[i] == R[i]); }
return test;
}

bool
are_equal_alg(const T& L, const T& R)
noexcept {
bool test{ equal(cbegin(L),cend(L),cbegin(R)) };
return test;
}

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

T left{ {0,1,2,3} };
T right{ {0,1,2,3} };

cout << boolalpha << are_equal_manual(left,right) << endl;
cout << boolalpha << are_equal_alg(left,right) << endl;
cout << boolalpha << (left == right) << endl;

bool t{};
const size_t N{ 5000000000 };
for(size_t i{}; i < N; ++i) {
//t = left == right; // SLOW
//t = are_equal_manual(left,right); // FAST
t = are_equal_alg(left,right); // SLOW
left[0] = i % 10;
right[2] = i % 8;
}

cout<< boolalpha << t << endl;

return(EXIT_SUCCESS);
}

最佳答案

这是使用 are_equal_manual(left,right) 函数时 main()for 循环生成的程序集:

.L21:
xor esi, esi
test eax, eax
jne .L20
cmp edx, 2
sete sil
.L20:
mov rax, rcx
movzx esi, sil
mul r8
shr rdx, 3
lea rax, [rdx+rdx*4]
mov edx, ecx
add rax, rax
sub edx, eax
mov eax, edx
mov edx, ecx
add rcx, 1
and edx, 7
cmp rcx, rdi

下面是使用 are_equal_alg(left,right) 函数时生成的内容:

.L20:
lea rsi, [rsp+16]
mov edx, 16
mov rdi, rsp
call memcmp
mov ecx, eax
mov rax, rbx
mov rdi, rbx
mul r12
shr rdx, 3
lea rax, [rdx+rdx*4]
add rax, rax
sub rdi, rax
mov eax, ebx
add rbx, 1
and eax, 7
cmp rbx, rbp
mov DWORD PTR [rsp], edi
mov DWORD PTR [rsp+24], eax
jne .L20

我不确定第一种情况生成的代码中发生了什么,但它显然没有调用 memcmp()。它似乎根本没有比较数组的内容。虽然循环仍在迭代 5000000000 次,但它已优化为什么也不做。但是,使用 are_equal_alg(left,right) 的循环仍在执行比较。基本上,编译器仍然能够比 std::equal 模板更好地优化手动比较。

关于c++ - 为什么 std::equal 比两个小 std::array 的手卷循环慢得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39262496/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com