矩阵*向量`,'矩阵'向量*和复制(矩阵)*向量之间的非直观性能差异用法性能blas

Ans*_*hvi 4 matrix julia

朱莉娅·迪斯科Julia Discourse)的问题

我正在使用Julia 1.2。这是我的测试:

a = rand(1000, 1000)
b = adjoint(a)
c = copy(b)

@btime a * x setup=(x=rand(1000)) # 114.757 ?s
@btime b * x setup=(x=rand(1000)) # 94.179 ?s
@btime c * x setup=(x=rand(1000)) # 110.325 ?s
Run Code Online (Sandbox Code Playgroud)

我期望ac至少不会变慢。

在检查了stdlib / LinearAlgebra / src / matmul.jl之后,发现朱莉娅将b.parent(即a)传递给BLAS.gemv,而不是b,而是将LAPACK的dgemv_切换到了另一个明显更快的模式。

我是否假设加速是由于以下事实而进行的,即当内存处于trans = T模式时,无论dgemv_做什么,内存都以更有利的方式对齐?如果是这样,那么我猜想这是不可行的,除了可能以某种方式在文档中提到陷阱。如果我的假设是错误的,那么对此有什么办法要做?

Ans*_*hvi 6

来自@stevengj的答复在同一Discourse线程中:

我是否假设加速是由于以下事实而进行的,即当内存处于trans = T模式时,无论dgemv_做什么,内存都以更有利的方式对齐?

关。它确实与内存有关,但这与局部性有关,而不与对齐有关。要了解的基本知识是,由于存在高速缓存行,因此从内存访问连续(或至少附近)的数据比分离的数据更有效。(连续访问在利用SIMD指令方面也具有一些优势。)

Julia会按列优先顺序存储矩阵,以便列在内存中是连续的。因此,当将转置矩阵(尚未复制)乘以向量时,它可以将其计算为连续列(=转置行)与连续向量的点积,该向量具有良好的空间局部性,因此可以利用缓存线有效。

相反,为了将非转置矩阵乘以矢量,您将矩阵的非连续的点积与矢量相乘,因此更难有效利用高速缓存行。在这种情况下,为了提高空间局部性,我相信,像OpenBLAS这样的优化BLAS实际上一次计算出矢量的多个行的点积(“块”),这就是为什么它仅慢10%而不差很多的原因。(实际上,即使转置的情况也可能会做一些阻塞,以将向量保持在缓存中。)