Matrix “矩阵*向量”与“矩阵和#x2019;”之间的非直观性能差异vector`和`copy(矩阵’;)*vector`使用性能blas

Matrix “矩阵*向量”与“矩阵和#x2019;”之间的非直观性能差异vector`和`copy(矩阵’;)*vector`使用性能blas,matrix,julia,Matrix,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 我希望a和c至少不会慢下来 检查stdlib/LinearAlgebra

问题来自

我用的是茱莉亚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
我希望ac至少不会慢下来

检查stdlib/LinearAlgebra/src/matmul.jl后,发现Julia将b.parent(即a)传递到BLAS.gemv,而不是b,并将LAPACK的dgemv切换到不同且明显更快的模式


我假设加速来自这样一个事实,即当处于trans=T模式时,内存以一种更有利的方式对齐dgemv所做的任何事情,对吗?如果是这样的话,那么我猜这是不可行的,除了可能在文档中提到gotcha之外。如果我的假设是错误的,那么对此有什么办法吗?

来自@stevengj的同一条对话线索的回答:

我假设加速来自这样一个事实,即当处于trans=T模式时,内存以一种更有利的方式对齐dgemv所做的任何事情,对吗

接近。它确实与内存有关,但与对齐无关。需要了解的基本情况是,由于内存的存在,从内存中访问连续(或至少是附近)数据比访问分离的数据更有效。(连续访问在利用指令方面也有一些优势。)

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

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