为什么constexpr的性能比正常表达式差

Why is constexpr performing worse than normal expression?

本文关键字:表达式 性能比 constexpr 为什么      更新时间:2023-10-16

我知道还有一个类似的问题:constexpr在运行时表现更差
但我的案子比那个简单多了,而且答案对我来说还不够。我只是在C++11中学习constexpr,a编写了一段代码来比较它的效率,出于某种原因,使用constexpr会使我的代码运行速度慢4倍多
顺便说一句,我使用的示例与本网站中的示例完全相同:https://www.embarcados.com.br/introducao-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调用,因此速度较慢。

任何一个优秀的编译器都知道,对于给定的代码,与values相关的一切都可以在没有任何副作用的情况下进行优化。因此,所示代码永远不能给出values[i%SIZE] = (2.0 * 3.0 + 10.0) / 0.8;values[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;