为什么这种"优化"会减慢我的程序?

Fel*_*zen 0 c++ floating-point optimization

我正在编写一个图形引擎作为大学的任务,并且最近尝试优化我的部分代码,但是优化似乎会减慢它的速度.

代码的这一特定部分处理2D Lindenmayer系统并将它们转换为"line2D"对象列表,这些对象可以由程序的另一部分处理成图像.

在这样做时,它使用sin和cos来计算下一个点的坐标,并且因为sin和cos是浮点运算,我认为这些将是时间密集的,尤其是在更复杂的lindenmayer系统中.所以我创建了一个对象类"cossinlist",它从.txt文件中导入cos和sin的值,用于0到359度之间的每个整数角度(转换为rad)到两个名为"coslist"和"sinlist"的地图作为关键.这样我在处理包含小数部分的角度时只需要执行实际的触发器.

然后我决定用一个相对密集的系统来测量执行时间和优化(没有它)(通过评论它):使用它,引擎在33.4016秒内生成图像,没有它只需要25.3686秒.这是一个实质性的差异,但不是预期的方式.我做了更多的测试,他们都给出了相似的差异比例,所以现在我想知道......是什么导致了这种差异?

功能:

img::EasyImage LSystem2D(const unsigned int size, const ini::DoubleTuple & backgroundcolor, LParser::LSystem2D & System, const ini::DoubleTuple & color)
{
    CosSinList cossinlist;
    std::string string;
    Lines2D Lines;
    double origin = 0;
    Point2D currentpos(origin, origin);
    Point2D newpos(origin, origin);
    std::stack<Point2D> savedpositions;
    double currentangle = System.get_starting_angle();
    std::stack<double> savedangles;
    const img::Color linecolor(color.at(0)*255,color.at(1)*255,color.at(2)*255);
    const img::Color BGcolor(backgroundcolor.at(0)*255,backgroundcolor.at(1)*255,backgroundcolor.at(2)*255);
    string = ReplaceLsystem(System, (System.get_initiator()), (System.get_nr_iterations()));
    bool optimizedangle = false;
    if(System.get_angle() == rint(System.get_angle()) && (System.get_starting_angle() == rint(System.get_starting_angle()))
    {
        optimizedangle = true;
    }
    for(char& c : string)
    {
        if(currentangle > 359){currentangle -= 360;}
        if(currentangle < -359){currentangle += 360;}
        if(System.get_alphabet().count(c) != 0)
        {
            /*if(optimizedangle == true)
            {
                if(currentangle >= 0)
                {
                    newpos.X = currentpos.X+(cossinlist.coslist[currentangle]);
                    newpos.Y = currentpos.Y+(cossinlist.sinlist[currentangle]);
                }
                else
                {
                    newpos.X = currentpos.X+(cossinlist.coslist[360+currentangle]);
                    newpos.Y = currentpos.Y+(cossinlist.sinlist[360+currentangle]);
                }
            }
            else
            {*/
                newpos.X = currentpos.X+cos(currentangle*PI/180);
                newpos.Y = currentpos.Y+sin(currentangle*PI/180);
            //}
            if(System.draw(c))
            {
                Lines.push_back(Line2D(currentpos,newpos,linecolor));
                currentpos = newpos;
            }
            else
            {
                currentpos = newpos;
            }

        }
        else if(c=='-')
        {
            currentangle -= System.get_angle();
        }
        else if(c=='+')
        {
            currentangle += System.get_angle();
        }
        else if(c=='[')
        {
            savedpositions.push(currentpos);
            savedangles.push(currentangle);
        }
        else if(c==']')
        {
            currentpos = savedpositions.top();
            savedpositions.pop();
            currentangle = savedangles.top();
            savedangles.pop();

        }
    }
    return Drawlines2D(Lines, size, BGcolor);
}
Run Code Online (Sandbox Code Playgroud)

SinCosList类:

#include <fstream>
#include <iostream>
#include <map>
#include "CosSinList.h"
using namespace std;

CosSinList::CosSinList()
{
    string line;
    std::fstream cosstream("coslist.txt", std::ios_base::in);
    double a;
    double i = 0;
    while (cosstream >> a)
    {
        coslist[i] = a;
        i += 1;
    }
    std::fstream sinstream("sinlist.txt", std::ios_base::in);
    i = 0;
    while (sinstream >> a)
    {
        sinlist[i] = a;
        i += 1;
    }
};

CosSinList::~CosSinList(){};
Run Code Online (Sandbox Code Playgroud)

"优化"以与在速度测试期间评论它相同的方式被注释掉,只有对象的实际使用被注释掉(SinCosList仍然被初始化,并且检查它是否可以使用的布尔值仍然是被初始化)

小智 5

(我假设coslistsinlist有普通阵列或类似的)

有些事情:

  • 你真的应该改变优化

通过优化,您可以测量无关紧要的东西.一旦优化开启,未优化代码的性能与性能相关性差.

  • optimzedangle 应该是一个编译时常量.

优化器很可能是能够简化代码,如果它知道optimizedangle不整个程序的运行而改变.使用这个特定的代码片段,它可能会解决它,但是你不应该依赖它,如果你不需要,并且通常很容易意外编写代码,你认为变量显然是一个变量保持不变,但是编译器比你聪明,并意识到你已经打开了一个可能允许变量改变的漏洞,所以它必须编写较慢的循环来解决这个问题.

  • 分支可能很糟糕

在内循环中分支 - 特别是不可预测的分支 - 可能会破坏性能.尝试编写循环,这样就没有任何分支; 例如,确保currentangle始终为正,或者可以使查找表720条目长,这样您就可以始终只进行索引360 + currentangle.

  • 浮点< - >整数转换可能很慢

我倾向于避免这些,因此我从来没有擅长预测何时它真的是一个问题,但这可能是真正杀死你的东西.

  • 你的表正在消耗缓存

你没有发布你的数据结构,但我想象大约6k字节.这是你的L1缓存的一个重要百分比.这对我来说是不明显的,这是否是这个循环中的重要影响.