【问题标题】:How to optimize a simple numeric type wrapper class in C++?如何在 C++ 中优化一个简单的数字类型包装类?
【发布时间】:2011-07-19 08:52:33
【问题描述】:

我正在尝试在 C++ 中实现一个定点类,但我遇到了性能问题。我已将问题简化为浮点类型的简单包装器,但它仍然很慢。我的问题是 - 为什么编译器无法完全优化它?

“浮动”版本比“浮动”版本快 50%。为什么?!

(我使用 Visual C++ 2008,测试了所有可能的编译器选项,当然是发布配置)。

请看下面的代码:

#include <cstdio>
#include <cstdlib>
#include "Clock.h"      // just for measuring time

#define real Float      // Option 1
//#define real float        // Option 2

struct Float
{
private:
    float value;

public:
    Float(float value) : value(value) {}
    operator float() { return value; }

    Float& operator=(const Float& rhs)
    {
        value = rhs.value;
        return *this;
    }

    Float operator+ (const Float& rhs) const
    {
        return Float( value + rhs.value );
    }

    Float operator- (const Float& rhs) const
    {
        return Float( value - rhs.value );
    }

    Float operator* (const Float& rhs) const
    {
        return Float( value * rhs.value );
    }

    bool operator< (const Float& rhs) const
    {
        return value < rhs.value;
    }
};

struct Point
{
    Point() : x(0), y(0) {}
    Point(real x, real y) : x(x), y(y) {}

    real x;
    real y;
};

int main()
{
    // Generate data
    const int N = 30000;
    Point points[N];
    for (int i = 0; i < N; ++i)
    {
        points[i].x = (real)(640.0f * rand() / RAND_MAX);
        points[i].y = (real)(640.0f * rand() / RAND_MAX);
    }

    real limit( 20 * 20 );

    // Check how many pairs of points are closer than 20
    Clock clk;

    int count = 0;
    for (int i = 0; i < N; ++i)
    {
        for (int j = i + 1; j < N; ++j)
        {
            real dx = points[i].x - points[j].x;
            real dy = points[i].y - points[j].y;
            real d2 = dx * dx + dy * dy;
            if ( d2 < limit )
            {
                count++;
            }
        }
    }

    double time = clk.time();

    printf("%d\n", count);
    printf("TIME: %lf\n", time);

    return 0;
}

【问题讨论】:

  • 您是否开启了最大优化标志。当你打开它们时,我已经看到魔法发生了。
  • 生成程序集并检查差异所在...
  • 您可以尝试将所有方法显式标记为“内联”
  • 顺便说一下,如果你的类实现了定点算法而不是浮点数,你能不能把它命名为“Fixed”而不是“Float”?你的同事会感谢你的。
  • 我玩过许多不同的优化选项,但没有效果。我查看了程序集 - 没有“调用”,因此内联有效。只有更多的说明。请参阅:future-processing.com/~mczardybon/FloatVSfloat.png

标签: c++ performance optimization fixed-point


【解决方案1】:

IMO,它与优化标志有关。我在 g++ linux-64 机器上检查了你的程序。没有任何优化,它给出的结果与您告诉 which 50% less 的结果相同。

保持最大优化开启(即-O4)。两个版本都是一样的。开启优化并检查。

【讨论】:

  • 我已经安装了 GCC,实际上它运行良好!使用 GCC,时间是 1.13 秒,而使用 VC++ 是 1.70 秒(浮点数)或 2.58 秒(浮点数)。我还发现将 'dx * dx + dy * dy' 直接移动到条件可以将 VC++ 的性能提高 21%! VC++怎么可能优化得这么差?!我打开了所有可能的优化选项并测试了许多不同的组合。
  • 哇...当我从“Win32”切换到“x64”平台时,执行时间从 2.58 秒下降到 0.77 秒! 'float' 和 'Float' 也是一样的。
【解决方案2】:

尝试通过引用传递。您的类足够小,以至于通过引用传递它的开销(是的,如果编译器不对其进行优化,则会产生开销),可能比仅仅复制类要高。所以这...

Float operator+ (const Float& rhs) const
{
   return Float( value + rhs.value );
}

变成这样……

Float operator+ (Float rhs) const
{
   rhs.value+=value;
   return rhs;
}

它避免了一个临时对象,并且可以避免指针取消引用的一些间接性。

【讨论】:

  • 我试过了 - 不起作用。它甚至将时间进一步增加了 59%。
【解决方案3】:

经过进一步调查,我完全确信这是编译器优化管道的问题。与使用非封装 float 相比,此实例中生成的代码明显糟糕。我的建议是将这个潜在问题报告给 Microsoft,看看他们对此有何看法。我还建议您继续实现您计划的此类的定点版本,因为为整数生成的代码看起来是最佳的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    • 2014-04-26
    • 2016-12-29
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    相关资源
    最近更新 更多