gpt4 book ai didi

c++ - 关于函数指针 : why the overhead time changes when the content of the function changes

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:54:45 27 4
gpt4 key购买 nike

这里是c++代码,我用的是vs2013,release模式

#include <ctime>
#include <iostream>

void Tempfunction(double& a, int N)
{
a = 0;
for (double i = 0; i < N; ++i)
{
a += i;
}
}

int main()
{
int N = 1000; // from 1000 to 8000

double Value = 0;
auto t0 = std::time(0);
for (int i = 0; i < 1000000; ++i)
{
Tempfunction(Value, N);
}
auto t1 = std::time(0);
auto Tempfunction_time = t1-t0;
std::cout << "Tempfunction_time = " << Tempfunction_time << '\n';

auto TempfunctionPtr = &Tempfunction;

Value = 0;
t0 = std::time(0);
for (int i = 0; i < 1000000; ++i)
{
(*TempfunctionPtr)(Value, N);
}
t1 = std::time(0);
auto TempfunctionPtr_time = t1-t0;
std::cout << "TempfunctionPtr_time = " << TempfunctionPtr_time << '\n';

std::system("pause");
}

我把N的值从1000改成8000,记录Tempfunction_time和TempfunctionPtr_time。结果很奇怪:

N=1000 , Tempfunction_time=1, TempfunctionPtr_time=2;
N=2000 , Tempfunction_time=2, TempfunctionPtr_time=6;
N=4000 , Tempfunction_time=4, TempfunctionPtr_time=11;
N=8000 , Tempfunction_time=8, TempfunctionPtr_time=21;

TempfunctionPtr_time - Tempfunction_time 不是常量,和 TempfunctionPtr_time = 2~3 * Tempfunction_time。差值应该是一个常量,它是函数指针的开销。

怎么了?

编辑:

假设 VS2013 内联 Tempfunction 如果它被 Tempfunction() 调用,如果它被 (*TempfunctionPtr) 调用则不内联它,那么我们可以解释差异。那么,如果这是真的,为什么编译器不能内联 (*TempfunctionPtr) ?

最佳答案

我在我的linux机器上用g++编译了现有的代码,发现时间太短,无法以秒为单位精确测量,所以重写了使用std::chrono为了更精确地测量时间——我还必须“使用”变量 Value (因此下面打印了“499500”),否则编译器将完全优化掉第一个循环。然后我得到以下结果:

Tempfunction_time = 1.47983
499500
TempfunctionPtr_time = 1.69183
499500

现在,我得到的结果是针对 GCC(版本 4.6.3 - 其他版本可用并可能给出其他结果!),它与 Microsoft 的编译器不同,因此结果可能不同 - 不同的编译器优化代码相当有时不同。我真的很惊讶编译器没有弄清楚 TempFunction 的结果只需要计算一次。但是,嘿,不用花招就可以更轻松地编写基准测试。

我的第二个观察是,对于我的编译器,如果我替换 int N=1000;用一个循环 for(int N=1000; N <= 8000; N *= 2)在主要代码周围,这两种情况之间没有或只有很小的区别 - 我不完全确定为什么,因为代码看起来相同(没有通过函数指针调用,因为编译器知道函数指针是一个常数)和TempFUnction在这两种情况下都被内联。 (当 N 是 1000 以外的其他值时,会发生相同的“平等” - 所以我不确定这里发生了什么......

要实际测量函数指针和直接函数调用之间的差异,您需要移动 TempFUnction到一个单独的文件中,并“隐藏”存储在 TempFunctionPtr 中的实际值这样编译器就无法准确地弄清楚你在做什么。

最后,我得到了这样的结果:

typedef void (*FunPtr)(double &a, int N);

void Tempfunction(double& a, int N)
{
a = 0;
for (double i = 0; i < N; ++i)
{
a += i;
}
}

FunPtr GetFunPtr()
{
return &Tempfunction;
}

“主要”代码如下:

#include <iostream>
#include <chrono>

typedef void (*FunPtr)(double &a, int N);

extern void Tempfunction(double& a, int N);
extern FunPtr GetFunPtr();

int main()
{
for(int N = 1000; N <= 8000; N *= 2)
{
std::cout << "N=" << N << std::endl;
double Value = 0;
auto t0 = std::chrono::system_clock::now();
for (int i = 0; i < 1000000; ++i)
{
Tempfunction(Value, N);
}
auto t1 = std::chrono::system_clock::now();;
std::chrono::duration<double> Tempfunction_time = t1-t0;
std::cout << "Tempfunction_time = " << Tempfunction_time.count() << '\n';
std::cout << Value << std::endl;

auto TempfunctionPtr = GetFunPtr();

Value = 0;
t0 = std::chrono::system_clock::now();
for (int i = 0; i < 1000000; ++i)
{
(*TempfunctionPtr)(Value, N);
}
t1 = std::chrono::system_clock::now();
std::chrono::duration<double> TempfunctionPtr_time = t1-t0;
std::cout << "TempfunctionPtr_time = " << TempfunctionPtr_time.count() << '\n';
std::cout << Value << std::endl;
}
}

然而,相差几千秒,变体显然是赢家,唯一的结论是显而易见的,即“调用函数比内联慢”。

N=1000
Tempfunction_time = 1.78323
499500
TempfunctionPtr_time = 1.77822
499500
N=2000
Tempfunction_time = 3.54664
1.999e+06
TempfunctionPtr_time = 3.54687
1.999e+06
N=4000
Tempfunction_time = 7.0854
7.998e+06
TempfunctionPtr_time = 7.08706
7.998e+06
N=8000
Tempfunction_time = 14.1597
3.1996e+07
TempfunctionPtr_time = 14.1577
3.1996e+07

当然,如果我们“只用了一半的隐藏技巧”,那么函数在第一种情况下是已知的并且是可内联的,而通过函数指针是未知的,我们也许可以预期会有不同。但是通过指针调用函数本身并不昂贵。当编译器决定内联函数时,真正的区别就出现了。

很明显,这些是 GCC 4.6.3 的结果,它与 MSVS2013 不是同一个编译器。您应该对上述代码中的“chrono”进行修改,看看它有什么不同。

关于c++ - 关于函数指针 : why the overhead time changes when the content of the function changes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21596937/

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