如何使用 SSE 优化矩阵 3 乘 3 的点?

How to optimize a matrix 3 by 3 multiplication with a point with SSE?

我必须在我的图像的每个点上应用一个变换矩阵来获得新的点坐标。

为此,我创建了一个自定义 Matrix3by3 class,其中包含一个大小为 9 的浮点数组。

为了将矩阵应用于每个点,我首先创建了这个函数:

constexpr auto apply_matrix(const Matrix3by3 & m, const Vec2i & p) -> Vec2f
{
  const auto x = m.at(0, 0) * p.x + m.at(0, 1) * p.y + m.at(0, 2);
  const auto y = m.at(1, 0) * p.x + m.at(1, 1) * p.y + m.at(1, 2);
  const auto z = m.at(2, 0) * p.x + m.at(2, 1) * p.y + m.at(2, 2);

  return { x / z, y / z };
}

如您所见,由于我的 2D 图像中没有 z 值,此函数将执行简单的矩阵乘法而不进行最后一次乘法。

这很好用,但由于这部分代码是热代码,我正在尝试优化它,所以我创建了它的 SSE 版本:

constexpr auto apply_matrix(const Matrix3by3 & m, const Vec2i & p) -> Vec2f
{
  using SSEVec3 = union {
    struct
    {
      float z, y, x;

    };
    __m128 values_ = _mm_setzero_ps();
  };

  const auto mvec1 = _mm_set_ps(0, m.at(0, 0), m.at(0, 1), m.at(0, 2));
  const auto mvec2 = _mm_set_ps(0, m.at(1, 0), m.at(1, 1), m.at(1, 2));
  const auto mvec3 = _mm_set_ps(0, m.at(2, 0), m.at(2, 1), m.at(2, 2));

  const auto pvec1 = _mm_set1_ps(static_cast<float>(p.x));
  const auto pvec2 = _mm_set1_ps(static_cast<float>(p.y));

  auto result = SSEVec3{};
  result.values_ = _mm_add_ps(_mm_add_ps(_mm_mul_ps(mvec1, pvec1), _mm_mul_ps(mvec2, pvec2)), mvec3);

  return { result.x / result.z, result.y / result.z };
}

这个也可以,但是比第一个版本慢,而且由于我正在学习 SSE,所以我不明白为什么会这样。

我对第二个版本的想法是并行计算 x、y 和 z 值。

所以,这就是我的问题,为什么 SSE 版本比较慢,我如何优化它以使其尽可能快?

谢谢!

一般来说,只优化需要优化的部分,而不是你认为需要优化的部分。

可能是(原始)代码中最糟糕的一点,而您的 'optimizations' 根本没有帮助,就是重复的 部分 。除浮点数或双精度数远比此代码中的其他所有内容都差,因此您最好的优化是通过计算 1/z(将 一次)计算为辅助变量,然后乘以来减少它两次结果。

但是 - 如开头所说 - 您可能不需要任何优化,或者您可能需要其他优化。测试、剖析并寻找最慢的一段代码。猜测通常会导致浪费精力和不必要的代码复杂性。