【问题标题】:Why does this "optimization" slow down my program?为什么这种“优化”会减慢我的程序?
【发布时间】:2015-03-14 22:01:20
【问题描述】:

我正在写一个图形引擎作为大学作业,最近尝试优化我的部分代码,但优化似乎反而减慢了速度。

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

在这样做时,它使用 sin 和 cos 来计算下一个点的坐标,并且因为 sin 和 cos 是浮点运算,我认为这些会很耗时,尤其是在更复杂的 lindenmayer 系统中。所以我创建了一个对象类“cossinlist”,它从 .txt 文件中将 0 到 359 度之间的每个整数角度(转换为 rad)的 cos 和 sin 的值导入到两个名为“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);
}

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(){};

“优化”被注释掉的方式与我在速度测试期间注释掉的方式相同,只有对象的实际使用被注释掉(SinCosList 仍在初始化和检查它是否可以使用的布尔值还在初始化中)

【问题讨论】:

  • 你使用了什么编译器,你给了它什么优化设置,你有没有预热你的缓存,你有没有多次运行基准测试?
  • 您做出了一个相当幼稚的假设,即浮点运算很慢,并且访问更多内存(对 CPU 缓存施加更大压力)比仅要求 CPU 计算 cos 或 sin 更快.您的代码不是更快,因为它要求 CPU 执行在现代 CPU 上效率较低的事情。
  • 我冒昧地猜测现代 CPU 已经针对 cos 和 sin 进行了很好的优化
  • @FelixNeijzen 您的编译器标志不包括任何优化标志,例如-O3?
  • 恕我直言,如果在没有优化的情况下编译所有关于优化的问题(即对于 GCC -O2 或类似的),则应立即关闭它们。如果您甚至不启用函数内联,那么谈论 C++ 代码的性能完全是在浪费每个人的时间,您只是在衡量抽象损失。

标签: c++ optimization floating-point


【解决方案1】:

(我假设coslistsinlist 是普通数组或类似的)

一些事情:

  • 你真的应该开启优化

关闭优化后,您将测量无关紧要的内容。启用优化后,未优化代码的性能与性能的相关性很差。

  • optimzedangle 应该是编译时常量。

如果优化器知道 optimizedangle 在整个程序运行过程中不会发生变化,那么它很可能能够简化代码。使用这个特定的代码 sn-p 它可能可以解决它,但如果你不需要,你不应该依赖它,而且通常非常容易不小心在你认为的地方编写代码很明显变量保持不变,但编译器比你聪明,并且意识到你打开了一个可能允许变量改变的漏洞,因此它必须编写更慢的循环来解决这个问题。

  • 分支可能不好

在内循环中的分支——尤其是不可预测的分支——会影响性能。尝试编写你的循环,这样就没有任何分支;例如确保currentangle 始终为正,或者可能使查找表720 条目变长,这样您就可以始终只索引360 + currentangle

  • 浮点 整数转换可能很慢

我倾向于避免这些,因此我从来不善于预测它何时真的是一个问题,但有可能这才是真正要你命的原因。

  • 您的表正在消耗缓存

您没有发布您的数据结构,但我想象大约 6k 字节。这是您的 L1 缓存的一个重要百分比。我不清楚这是否是这个循环中的重要影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多