C++ &引用;“坏的”;GCC优化性能

C++ &引用;“坏的”;GCC优化性能,c++,gcc,optimization,g++,mingw,C++,Gcc,Optimization,G++,Mingw,我试图理解为什么在GCC中使用-O2-march=native比不使用它们时给出的代码要慢。 请注意,我在Windows7下使用的是MinGW(GCC4.7.1) 这是我的密码: struct.hpp: #ifndef STRUCT_HPP #define STRUCT_HPP #include <iostream> class Figure { public: Figure(char *pName); virtual ~Figure(); char *

我试图理解为什么在GCC中使用-O2-march=native比不使用它们时给出的代码要慢。 请注意,我在Windows7下使用的是MinGW(GCC4.7.1)

这是我的密码:

struct.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
#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;
}
\ifndef结构水电站
#定义结构\u水电站
#包括
班级人数
{
公众:
数字(字符*pName);
虚拟~Figure();
char*GetName();
双倍面积_mm2(整数系数);
私人:
字符名[64];
虚拟双GetAreaEx_mm2()=0;
};
类别:公众人物
{
公众:
磁盘(字符*pName,双半径_mm);
~Disk();
私人:
双半径_mm;
虚拟双GetAreaEx_mm2();
};
阶级广场:公众人物
{
公众:
正方形(字符*pName,双面_mm);
~Square();
私人:
双面_mm;
虚拟双GetAreaEx_mm2();
};
#恩迪夫
struct.cpp:

#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
#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;
}
#包括
#包括“struct.hpp”
图::图(char*pName)
{
sprintf(名称,pName);
}
图::~图()
{
}
char*Figure::GetName()
{
返回名称;
}
双位数:GetArea_mm2(整数系数)
{
返回(双)系数*GetAreaEx_mm2();
}
磁盘::磁盘(字符*pName,双半径\u毫米\u):
图(pName),半径×毫米(半径×毫米)
{
}
磁盘::~Disk()
{
}
双磁盘::GetAreaEx_mm2()
{
返回3.1415926*半径×毫米*半径×毫米;
}
正方形::正方形(字符*pName,双面):
图(pName),侧壁厚度(侧壁厚度)
{
}
正方形::~Square()
{
}
双正方形::GetAreaEx_mm2()
{
返回侧_mm*侧_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
}
#包括
#包括
#包括“struct.hpp”
双Do(整数n)
{
双和_mm2=0.0;
const int figuresCount=10000;
图**P图=新图*[图计数];
对于(int i=0;iGetArea _mm2(i);
sum_mm2+=(双精度)(pFigures[i]->GetName()[0]-'-');
}
}
对于(int i=0;i考虑到我没有看到汇编代码,我将推测如下:

 for (int i=0;i <10000 ; i+=2)
 {
       pFigures[i] = new Square(...);
 }
 for (int i=1;i <10000 ; i +=2)
 {
       pFigures[i] = new Disk(...);
 }
通过删除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(...);
 }

for(int i=0;i我怀疑您在Windows上的mingw/gcc/glibc组合中遇到了一个独特的问题,因为您的代码在Linux上进行优化时执行得更快,而gcc在Linux上更像是“在家里”

在使用gcc 4.8.2的相当普通的Linux虚拟机上:

$ g++ main.cpp struct.cpp
$ time a.out

real    0m2.981s
user    0m2.876s
sys     0m0.079s

$ g++ -O2 main.cpp struct.cpp
$ time a.out

real    0m1.629s
user    0m1.523s
sys     0m0.041s
…如果您真的通过删除
struct.cpp
并将实现全部内联移动,从而使优化器不再闪烁:

$ time a.out

real    0m0.550s
user    0m0.543s
sys     0m0.000s

[OT]:在构造函数中使用
const char*
而不是将
const char*
强制转换为
char*
是危险的……谢谢,我完全意识到这一点,因此,没有理由:)谢谢你的回答,这是一个完全可能的解释。但奇怪的是Visual Studio,相反,设法戏剧性地划分了执行时间,不是吗?此外,这是一个非常简单的情况,奇怪的是VS比GCC好得多。还在这里猜测。你的建议的结果(我只分配磁盘,循环中不再有任何条件):未优化:1258毫秒优化:675毫秒(仍然比VisualStudio的条件更高…)似乎您的推测可能是正确的,但仍然没有解释为什么VS会这样做,也许VS会将for(int a…)循环移动到I循环中,而不是for(a){for(I){}你会得到一个for(i){for(a){}},这应该更快。试着自己移动循环,看看结果是否更接近。我完全没有其他猜测:)。