gpt4 book ai didi

c++ - "Bad"GCC优化性能

转载 作者:搜寻专家 更新时间:2023-10-31 01:38:47 27 4
gpt4 key购买 nike

我试图理解为什么将 -O2 -march=native 与 GCC 一起使用会比不使用它们时产生更慢的代码。请注意,我在 Windows 7 下使用 MinGW (GCC 4.7.1)。

这是我的代码:

结构.hpp :

#ifndef STRUCT_HPP
#define STRUCT_HPP

#include <iostream>

class Figure
{
public:
Figure(char *pName);
virtual ~Figure();

char *GetName();
double GetArea_mm2(int factor);

private:
char name[64];
virtual double GetAreaEx_mm2() = 0;
};

class Disk : public Figure
{
public:
Disk(char *pName, double radius_mm);
~Disk();

private:
double radius_mm;
virtual double GetAreaEx_mm2();
};

class Square : public Figure
{
public:
Square(char *pName, double side_mm);
~Square();

private:
double side_mm;
virtual double GetAreaEx_mm2();
};

#endif

结构.cpp :

#include <cstdio>
#include "struct.hpp"

Figure::Figure(char *pName)
{
sprintf(name, pName);
}

Figure::~Figure()
{
}

char *Figure::GetName()
{
return name;
}

double Figure::GetArea_mm2(int factor)
{
return (double)factor*GetAreaEx_mm2();
}

Disk::Disk(char *pName, double radius_mm_) :
Figure(pName), radius_mm(radius_mm_)
{
}

Disk::~Disk()
{
}

double Disk::GetAreaEx_mm2()
{
return 3.1415926*radius_mm*radius_mm;
}

Square::Square(char *pName, double side_mm_) :
Figure(pName), side_mm(side_mm_)
{
}

Square::~Square()
{
}

double Square::GetAreaEx_mm2()
{
return side_mm*side_mm;
}

main.cpp

#include <iostream>
#include <cstdio>
#include "struct.hpp"

double Do(int n)
{
double sum_mm2 = 0.0;
const int figuresCount = 10000;
Figure **pFigures = new Figure*[figuresCount];

for (int i = 0; i < figuresCount; ++i)
{
if (i % 2)
pFigures[i] = new Disk((char *)"-Disque", i);
else
pFigures[i] = new Square((char *)"-Carré", i);
}

for (int a = 0; a < n; ++a)
{
for (int i = 0; i < figuresCount; ++i)
{
sum_mm2 += pFigures[i]->GetArea_mm2(i);
sum_mm2 += (double)(pFigures[i]->GetName()[0] - '-');
}
}

for (int i = 0; i < figuresCount; ++i)
delete pFigures[i];

delete[] pFigures;

return sum_mm2;
}

int main()
{
double a = 0;

StartChrono(); // home made lib, working fine
a = Do(10000);
double elapsedTime_ms = StopChrono();

std::cout << "Elapsed time : " << elapsedTime_ms << " ms" << std::endl;

return (int)a % 2; // To force the optimizer to keep the Do() call
}

我编译这段代码两次:

1 : 没有优化

mingw32-g++.exe -Wall -fexceptions -std=c++11 -c main.cpp -o main.o

mingw32-g++.exe -Wall -fexceptions -std=c++11 -c struct.cpp -o struct.o

mingw32-g++.exe -o program.exe main.o struct.o -s

2 : 使用-O2优化

mingw32-g++.exe -Wall -fexceptions -O2 -march=native -std=c++11 -c main.cpp -o main.o

mingw32-g++.exe -Wall -fexceptions -O2 -march=native -std=c++11 -c struct.cpp -o struct.o

mingw32-g++.exe -o program.exe main.o struct.o -s

1:执行时间:

1196 毫秒(使用 Visual Studio 2013 时为 1269 毫秒)

2:执行时间:

1569 毫秒(Visual Studio 2013 为 403 毫秒)!!!!!!!!!!!!!!

使用 -O3 代替 -O2 不会改善结果。我过去是,现在仍然是,非常相信 GCC 和 Visual Studio 是等效的,所以我不明白这种巨大的差异。另外,我不明白为什么优化版本比 GCC 的非优化版本慢。

我在这里错过了什么吗?(请注意,我在 Ubuntu 上使用正版 GCC 4.8.2 时遇到了同样的问题)

谢谢你的帮助

最佳答案

考虑到我没有看到汇编代码,我将推测如下:

通过删除 if 子句并导致以下情况,可以(由编译器)优化分配循环:

 for (int i=0;i <10000 ; i+=2)
{
pFigures[i] = new Square(...);
}
for (int i=1;i <10000 ; i +=2)
{
pFigures[i] = new Disk(...);
}

考虑到结束条件是4的倍数,可以更“高效”

 for (int i=0;i < 10000 ;i+=2*4)
{
pFigures[i] = ...
pFigures[i+2] = ...
pFigures[i+4] = ...
pFigures[i+6] = ...
}

在内存方面,这将使 Disks 分配 4 x 4 和 Square 4 x 4。

现在,这意味着它们将在彼此相邻的内存中找到。

接下来,您将按正常顺序将 vector 迭代 10000 次(正常情况下,我指的是一个接一个的索引)。

想想这些形状在内存中分配的地方。你最终会有4倍的缓存未命中(想想边界的例子,当在不同的页面中找到4个圆盘和4个正方形时,你会在页面之间切换8 次...在正常情况下,您只会在页面之间切换一次)。

这种优化(如果由编译器完成,并且在您的特定代码中)优化了 Allocation 的时间,而不是访问时间(在您的示例中这是最大的负载)。

通过删除 i%2 来测试它,看看你得到什么结果。

同样,这纯属推测,它假设性能较低的原因是循环优化。

关于c++ - "Bad"GCC优化性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32271272/

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