mkl_malloc 我应该对齐什么值?

What value of alignment should I with mkl_malloc?

函数 mkl_mallocmalloc 类似,但有一个额外的 alignment 参数。这是原型:

void* mkl_malloc (size_t alloc_size, int alignment);

我注意到 alignment 的不同值具有不同的性能。除了反复试验之外,是否有 规范的或有记录的 有条不紊的方法来决定 alignment 的最佳值?即正在使用的处理器、正在调用的函数、正在执行的操作等

这个问题广泛适用于任何使用 MKL 的人,所以我很惊讶它没有出现在参考手册中。

更新:我已经尝试过 mkl_sparse_spmm 并且没有注意到将对齐设置为 2 的幂到 1024 字节在性能上的显着差异,之后性能趋于下降。我使用的是 Intel Xeon E5-2683。

唯一的原因,为什么不管你的输入,你没有惩罚/指定对齐方式的好处是,无论你输入什么,你都会得到机器对齐的内存。所以在你的处理器上,它支持 AVX,无论您的输入如何,您总是获得 32 字节对齐的内存。

您还会看到,无论您选择什么对齐值,内存地址 mkl_malloc、returns 都是可整除的 32 对齐。或者,您可以测试像 _mm256_load_pd 这样的低级内部函数,这会出现段错误,当使用非 32 字节对齐的地址时,永远不会出现段错误。

一些小细节:OSX 总是给你 32 字节地址,分配内存块时独立于堆/堆栈,而 Linux 总是给你对齐的内存,当分配堆。堆栈在 Linux 上是一个运气问题,但是您已经超出了小矩阵大小的堆栈分配限制。我不了解 Windows 上的内存分配。

我注意到后者,当我为 numerics library 编写测试时,我使用 std::vector<typename T, alignment A> 进行内存分配,而较小的矩阵测试有时会在 Linux 上出现段错误。

TLDR:您的对齐输入已被有效丢弃,无论如何您都会获得机器对齐。

仅当可以使用 SSE/AVX 指令时,对齐才会影响性能 - 这在操作数组时通常是正确的,因为您希望对一系列元素应用相同的操作。

一般来说,你要选择对齐的方式是CPU,如果支持256位寄存器的AVX2,那么你想要32字节对齐,如果支持AVX512,那么64字节是最优的。

为此,mkl_malloc 将保证与您指定的值对齐,但是,显然如果数据是 32 字节对齐的,那么它们也会与 (16, 8, 4.. .)-字节边界。通话的目的是确保始终如此,从而避免任何潜在的并发症。

在我的机器上(Linux 内核 4.17.11 运行 在 i7 6700K 上),mkl_malloc 的默认对齐似乎是 128 字节(对于足够大的数组,如果它们太小了,值似乎是32KB),换句话说,任何小于该值的值都不会影响对齐,但是我可以输入256,数据将对齐到256字节边界。

相比之下,使用 malloc 为 1GB 数据提供 16 字节对齐,为 1KB 提供 32 字节对齐,无论 OS 给我绝对没有关于对齐的偏好。

因此使用 mkl_malloc 很有意义,因为它可以确保您获得所需的对齐方式。但是,这并不意味着您应该将该值设置得过大,这只会导致您浪费内存并可能使您面临更多的缓存未命中。

简而言之,您希望数据与 CPU 中向量寄存器的大小对齐,以便您可以使用相关的扩展。使用 mkl_malloc 和一些对齐参数保证对齐到 至少 该值,但是它可以更多。它应该用于确保数据按照您想要的方式对齐,但绝对没有充分的理由对齐到 1MB。

我认为对齐不能有 "best" 值。根据您的体系结构,对齐通常是由硬件强制执行的 属性,主要是出于优化原因。

关于您的具体问题,重要的是要说明您分配内存的具体目的是什么?哪一块硬件访问内存?例如,我曾使用 DMA 引擎,它要求源地址与每个事务传输大小对齐(其中 xfer 大小 = 4、8、16、32、128)。我还使用了矢量寄存器,其中有一个 128 位对齐的负载是明智的。

总结一下:视情况而定。