Eigen:我应该使用对齐地图进行密集计算吗?



我想对外部分配的数据执行大量计算,尤其是矩阵乘法。它可以通过Eigen::Map.不幸的是,我不是矢量化计算方面的专家,但据我所知,可以为Map指定Aligned标志。

我决定通过Eigen::MatrixXf和 'Eigen::Map' 检查矩阵乘法之间的性能差异:

void testMatProduct(
const Eigen::MatrixXf &a,
const Eigen::MatrixXf &b,
Eigen::MatrixXf &res)
{
const auto startTime = std::chrono::high_resolution_clock::now();
res.noalias() = a * b;
const auto endTime = std::chrono::high_resolution_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::microseconds>( endTime - startTime ).count();
std::cout << "Mat product elapsed " << duration / 1.0e6 << std::endl;
}
using EigenMap = Eigen::Map<Eigen::MatrixXf, Eigen::Unaligned>;
void testMapProduct(
const EigenMap &a,
const EigenMap &b,
EigenMap &res)
{
const auto startTime = std::chrono::high_resolution_clock::now();
res.noalias() = a * b;
const auto endTime = std::chrono::high_resolution_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::microseconds>( endTime - startTime ).count();
std::cout << "Map product elapsed " << duration / 1.0e6 << std::endl;
}
int main(int, char **)
{    
srand(42);
const int64_t N = 7000;
const int64_t K = 6000;
const int64_t M = 100;
Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(N, K);
Eigen::MatrixXf mat2 = Eigen::MatrixXf::Random(K, M);
Eigen::MatrixXf matRes = Eigen::MatrixXf::Zero(N, M);
// Copy data from mats to vecs
Eigen::VectorXf vec1 = Eigen::Map<Eigen::MatrixXf>(mat1.data(), mat1.rows() * mat1.cols(), 1);
Eigen::VectorXf vec2 = Eigen::Map<Eigen::MatrixXf>(mat2.data(), mat2.rows() * mat2.cols(), 1);
Eigen::VectorXf vecRes = Eigen::VectorXf::Zero(N * M);
EigenMap map1 = EigenMap(vec1.data(), mat1.rows(), mat1.cols());
EigenMap map2 = EigenMap(vec2.data(), mat2.rows(), mat2.cols());
EigenMap mapRes = EigenMap(vecRes.data(), matRes.rows(), matRes.cols());
for(int i = 0; i < 10; ++i){
testMapProduct(map1, map2, mapRes);
testMatProduct(mat1, mat2, matRes);
matRes.setZero();
vecRes.setZero();
}
return 0;
}

我很确定这不是一个有效的基准,但它应该给我一些直觉。我用-march=native编译它,它打印以下输出:

Map product elapsed 0.102751
Mat product elapsed 0.10224
Map product elapsed 0.10022
Mat product elapsed 0.100726
Map product elapsed 0.09963
Mat product elapsed 0.100697
Map product elapsed 0.099673
Mat product elapsed 0.100809
Map product elapsed 0.100195
.......

所以在我看来,地图乘积和矩阵积之间没有太大区别。

我的问题是: 1(Map<MatrixXf, Unaligned>Map<MatrixXf, Aligned>在性能方面有什么区别?我应该关心其他操作(如点积、元素加法等(的Map对齐

吗?2(我的比较是否正确?

PS对不起我的英语不好

1(数据对齐指定了应该如何访问和排列数据的方式。这意味着如果您使用的是Eigen::MatrixXf,它指的是编译时数据类型为float的未知维度矩阵,则数据指针应在 4 字节(32 位(边界上对齐(假设浮点数在您的系统上使用32 位表示(。

不同规格的数据对齐对性能有什么影响?为了回答这个问题,我们将看看下面的讨论:
Talk:在 32 位架构上,在 32 位边界上未对齐的 16 位值的访问速度会更慢吗?

  • 它影响性能的主要论点:将两个 16 位值打包到 32 位寄存器中意味着您必须花费资源将数据从一种格式转换为另一种格式

有人可能会争辩说,C/C++等语言支持子词访问,这意味着您不必转换它们,这意味着您可以节省内存空间并且不会对性能产生负面影响。

我假设 Eigen 库会自动检测到Eigen::MatrixXf的数据指针在 4 字节边界上对齐,因此如果您省略MapOption模板或将其分配给Eigen::Unaligned,则不会对性能产生影响。如果要确保使用Eigen::Aligned4(回想一下,Eigen::Aligned已被弃用,并且是Aligned16的同义词,因此为 128 位(。可以在此处查看对齐枚举器。

2(Eigen::Map享受矩阵和向量可以在不复制数据的情况下初始化的好处,这与Eigen::MatrixEigen::Vector不同。我很确定Eigen::MapEigen::Matrix使用相同的操作来乘法、加法等对象,只是引用不同。我从使用Eigen::Matrix中看到的唯一性能优势是缓存性能方面的空间局部性,如果Eigen::Map引用两个在内存中相距很远的矩阵/向量,并且在处理巨大的矩阵大小时。当然,假设您一个接一个地初始化了两个Eigen::Matrix对象,以便它们在内存中是连续的。

主要区别在于矢量化载荷是对齐载荷还是未对齐载荷(或跨越缓存线边界时(。在现代台式机CPU(例如任何带有AVX,IIRC的CPU(上,差异很小,与实际工作相比相形见绌。在其他设备上,未对齐负载的惩罚可能会有很大差异。

如果Eigen::Map保证内存对齐,则负载都可以是对齐的负载,而如果不保证,则负载必须全部是未对齐的负载。这将对应用程序产生多大影响将取决于您的目标硬件。

最新更新