如何解决为什么特征密集动态矩阵的 setZero 比静态矩阵更快?
我编译了以下代码进行测试
#include <iostream>
#include <Eigen/Dense>
#include <chrono>
int main()
{
constexpr size_t t = 10000;
constexpr size_t size = 100;
auto t1 = std::chrono::steady_clock::now();
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> m1;
for (size_t i = 0; i < t; ++i)
{
m1.setZero(size,size);
}
auto t2 = std::chrono::steady_clock::now();
Eigen::Matrix<double,size,size> m2;
for (size_t i = 0; i < t; ++i)
{
m2.setZero();
}
auto t3 = std::chrono::steady_clock::now();
double t12 = static_cast<std::chrono::duration<double>>(t2 - t1).count();
double t23 = static_cast<std::chrono::duration<double>>(t3 - t2).count();
std::cout << "dynamic: " << t12 << " static: " << t23 << std::endl;
return 0;
}
我发现动态矩阵总是比静态矩阵快
使用 -O0
编译
dynamic: 2.34759 static: 4.29692
使用 -O3
编译
dynamic: 0.0170274 static: 0.0363988
直观地说,动态矩阵的 setZero
不会分配导致内存分配开销的新内存吗?
解决方法
TL;DR:性能结果强烈依赖于目标平台和编译器。
首先,这个断言并不总是正确的。实际上,动态版本在我的机器上速度更快,因为我得到了结果 dynamic: 0.128093 static: 0.142624
(使用 -std=c++20 -O3 -DNDEBUG
和 GCC 10.2.1)。原因是 GCC/Clang 在动态版本中生成调用 memset
的代码,而它们在静态情况下(更具体地说是 128 位 SSE 指令)生成许多直接归零SIMD 指令。在某些情况下,memset
实现可能比主流编译器(例如 GCC 和 Clang)生成的代码更快。
确实,如果 libc 是为目标机器优化的,而 GCC 可能不使用它,memset
可以使用更广泛的 SIMD 指令。这可能是 x86-64 平台的情况,其中 AVX-256 和 AVX-512 可用,但主流编译器不会自动启用,因为所有 x86 上生成的二进制文件都需要复古兼容性 -64 平台。当启用平台上可用的最先进的 SIMD 指令集时,静态版本的结果往往要好得多,但仍然不应该总是如此。在我的机器上,我得到了 dynamic: 0.105638 static: 0.0929698
,并添加了 -march=native
。
更深入的分析表明,我的 libc(GNU libc 2.31)没有直接使用 SIMD 指令,而是使用 rep stos
指令。现代处理器可以优化此指令并执行比 1 字节宽得多的存储。然而,它也有显着的启动开销。有关此说明及其性能的详细信息,请参阅 this great detailed post。
比较两个实现的其他参数很重要:CPU 缓存的大小/种类和 RAM 的速度以及矩阵大小。事实上,如果矩阵不适合 CPU 缓存,那么 memset
实现通常会更快,因为 非时间存储 (NTS)。在使用写分配缓存的处理器(如英特尔处理器)上尤其如此,因为这样的处理器会在没有 NTS 指令的情况下从 RAM 中读取矩阵,然后将零写入其中(此过程最多比只是用 NTS 指令直接写入内存)。
事情是 GCC/Clang 假设静态矩阵足够小,因此它可能适合 CPU 缓存(并且可能在缓存中,因为矩阵在实践中应该存储在堆栈中),因此使用经典存储大量展开循环中的指令可能比仅使用 memset
更快,后者使用多个版本并根据数据大小和目标平台选择一个好的版本。希望这通常是正确的,因此您会获得性能结果。请注意,当大小是动态的,因为它在编译时是未知的,因此很难做出这种假设(没有配置文件引导的优化)。
请注意,其他参数可能很重要,例如执行顺序(因为频率缩放)和内存对齐(尽管它们在我的机器上似乎并不重要)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。