我知道还有一个类似的问题:constexpr在运行时性能更差。
但是我的情况要比那个简单得多,答案对我来说还不够。 我正在学习C++11中的constexpr,并编写了一段代码来比较它的效率,由于某种原因,使用constexpr使我的代码运行速度慢了4倍以上!
顺便说一下,我使用的示例与此站点中的示例完全相同:https://www.embarcados.com.br/introductao-ao-cpp11/(它是葡萄牙语,但您可以看到关于constexpr的示例代码)。 已尝试其他表达式,结果类似。
constexpr double divideC(double num){
return (2.0 * num + 10.0) / 0.8;
}
#define SIZE 1000
int main(int argc, char const *argv[])
{
// Get number of iterations from user
unsigned long long count;
cin >> count;
double values[SIZE];
// Testing normal expression
clock_t time1 = clock();
for (int i = 0; i < count; i++)
{
values[i%SIZE] = (2.0 * 3.0 + 10.0) / 0.8;
}
time1 = clock() - time1;
cout << "Time1: " << float(time1)/float(CLOCKS_PER_SEC) << " seconds" << endl;
// Testing constexpr
clock_t time2 = clock();
for (int i = 0; i < count; i++)
{
values[i%SIZE] = divideC( 3.0 );
}
time2 = clock() - time2;
cout << "Time2: " << float(time2)/float(CLOCKS_PER_SEC) << " seconds" << endl;
return 0;
}
给定输入:9999999999
输出:
> Time1: 5.768 seconds
> Time2: 27.259 seconds
有人能告诉我这是什么原因吗? 由于constexpr计算应该在编译时运行,因此应该更快而不是更慢地运行这段代码。
我正在使用msbuild版本16.6.0.22303编译由以下CMake代码生成的Visual Studio项目:
cmake_minimum_required(VERSION 3.1.3)
project(C++11Tests)
add_executable(Cpp11Tests main.cpp)
set_property(TARGET Cpp11Tests PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET Cpp11Tests PROPERTY CXX_STANDARD 11)
如果不进行优化,编译器将保留divideC
调用,因此会更慢。
任何优秀的编译器都知道,对于给定的代码,与值
相关的所有内容都可以优化掉,而不会产生任何副作用。 因此所示代码永远无法给出值[i%size]=(2.0*3.0+10.0)/0.8;
或值[i%size]=divideC(3.0);
之间的差值之间的任何有意义的测量值
使用-o1
,任何优秀的编译器都将创建如下内容:
for (int i = 0; i < count; i++)
{
values[i%SIZE] = (2.0 * 3.0 + 10.0) / 0.8;
}
结果如下:
mov rdx, QWORD PTR [rsp+8]
test rdx, rdx
je .L2
mov eax, 0
.L3:
add eax, 1
cmp edx, eax
jne .L3
.L2:
和
for (int i = 0; i < count; i++)
{
values[i%SIZE] = divideC( 3.0 );
}
结果如下:
mov rdx, QWORD PTR [rsp+8]
test rdx, rdx
je .L4
mov eax, 0
.L5:
add eax, 1
cmp edx, eax
jne .L5
.L4:
因此这两种方法都将产生相同的机器代码,只包含循环的计数,而不包含其他任何内容。 因此,一旦打开优化,您将只测量循环,而不测量与constexpr
相关的任何内容。
使用-o2
,甚至循环也被优化掉了,您将只测量:
clock_t time1 = clock();
time1 = clock() - time1;
cout << "Time1: " << float(time1)/float(CLOCKS_PER_SEC) << " seconds" << endl;