我正在测试C++标准库算法的性能,并且遇到了奇怪的事情。
这是我的代码,用于比较std::count与普通for循环的性能:
#include <algorithm>
#include <vector>
#include <iostream>
#include <chrono>
using namespace std::chrono;
int my_count(const std::vector<int>& v, int val) {
int num = 0;
for (int i: v) {
if (i == val)
num++;
}
return num;
}
int main()
{
int total_count = 0;
std::vector<int> v;
v.resize(100000000);
// Fill vector
for (int i = 0; i < v.size(); i++) {
v[i] = i % 10000;
}
int val = 1;
{
auto start = high_resolution_clock::now();
total_count += std::count(v.begin(), v.end(), val);
auto stop = high_resolution_clock::now();
std::cout << "std::count time: " << duration_cast<microseconds>(stop - start).count() << std::endl;
}
{
auto start = high_resolution_clock::now();
total_count += my_count(v, val);
auto stop = high_resolution_clock::now();
std::cout << "my_count time: " << duration_cast<microseconds>(stop - start).count() << std::endl;
}
// We need this so the compiler does not prune the code above
std::cout << "Total items: " << total_count << std::endl;
}
使用MinGW,我得到以下信息:
std::count time: 65827
my_count time: 64861
使用MSVC,我得到一个非常奇怪的结果:
std::count time: 65532
my_count time: 28584
据我所知,MinGW的结果似乎是合理的,因为据我所知,STL计数函数大致等于普通的for循环,但是MSVC的结果似乎很奇怪-为什么普通的for循环的速度比std::count快2倍以上?
这些结果在我的机器上是可重现的-一次不会发生,但是每次我运行代码时都会发生。我什至尝试更改功能顺序,运行多个
for
循环以避免缓存或分支预测偏差,但是我仍然得到相同的结果。有什么理由吗?
最佳答案
这是因为MSVC对您的手动编写的代码进行了矢量化处理,但是对std::count
却无法做到。
这是矢量化代码的外观:
movdqa xmm5, XMMWORD PTR __xmm@00000001000000010000000100000001
and rcx, -8
xorps xmm3, xmm3
xorps xmm2, xmm2
npad 3
$LL4@my_count:
movdqu xmm1, XMMWORD PTR [rax]
add r8, 8
movdqa xmm0, xmm5
paddd xmm0, xmm3
pcmpeqd xmm1, xmm4
pand xmm0, xmm1
pandn xmm1, xmm3
movdqa xmm3, xmm0
movdqa xmm0, xmm5
por xmm3, xmm1
paddd xmm0, xmm2
movdqu xmm1, XMMWORD PTR [rax+16]
add rax, 32 ; 00000020H
pcmpeqd xmm1, xmm4
pand xmm0, xmm1
pandn xmm1, xmm2
movdqa xmm2, xmm0
por xmm2, xmm1
cmp r8, rcx
jne SHORT $LL4@my_count
您可以在开始时在
xmm5
寄存器中看到它是如何加载4个的。此值将用于维护4个单独的计数器,这些计数器跟踪第1个,第2个,第3个和第4个DWORD的结果。一旦计数完成,这四个值将被加在一起形成函数的结果。MSVC矢量化器的问题似乎在于计数器,数据类型和参数类型应“兼容”:
如果不满足任何这些约束,则不会对代码进行矢量化处理。这就好像您的数据类型是32位宽,您必须在32位计数器上进行操作才能使它们一起工作是有道理的,因此,如果您的返回类型是64位宽,则需要一些其他操作(这就是GCC能够做到,但是与手动编写的循环相比,这仍然会降低
std::count
的速度)。在这种情况下,应该首选手动编写的循环,因为语义上的细微差异(返回
int
)使矢量化更容易(即使对于生成更短代码的GCC)。
关于c++ - 为什么std::count在使用MSVC编译器的循环中要慢得多,而在GCC中却如此?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62116277/