当前位置: 首页 > 面试题库 >

矩阵乘法:矩阵大小差异小,时序差异大

越勇
2023-03-14
问题内容

我有一个矩阵乘法代码,如下所示:

for(i = 0; i < dimension; i++)
    for(j = 0; j < dimension; j++)
        for(k = 0; k < dimension; k++)
            C[dimension*i+j] += A[dimension*i+k] * B[dimension*k+j];

在此,矩阵的大小由表示dimension。现在,如果矩阵的大小为2000,则运行此代码需要147秒,而如果矩阵的大小为2048,则需要447秒。所以虽然没有区别。的乘积为(2048 * 2048 * 2048)/(2000 * 2000 * 2000)= 1.073,时间差为447/147
=3。有人可以解释为什么会这样吗?我希望它可以线性扩展,但不会发生。我不是在尝试制作最快的矩阵乘法代码,而只是在试图理解为什么会这样。

规格:AMD Opteron双核心节点(2.2GHz),2G RAM,gcc v 4.5.0

程序编译为 gcc -O3 simple.c

我也在英特尔的icc编译器上运行了此命令,并看到了类似的结果。

编辑:

正如评论/答案中所建议的那样,我运行的维度为2060的代码需要145秒。

这是完整的程序

#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>

/* change dimension size as needed */
const int dimension = 2048;
struct timeval tv;

double timestamp()
{
        double t;
        gettimeofday(&tv, NULL);
        t = tv.tv_sec + (tv.tv_usec/1000000.0);
        return t;
}

int main(int argc, char *argv[])
{
        int i, j, k;
        double *A, *B, *C, start, end;

        A = (double*)malloc(dimension*dimension*sizeof(double));
        B = (double*)malloc(dimension*dimension*sizeof(double));
        C = (double*)malloc(dimension*dimension*sizeof(double));

        srand(292);

        for(i = 0; i < dimension; i++)
                for(j = 0; j < dimension; j++)
                {   
                        A[dimension*i+j] = (rand()/(RAND_MAX + 1.0));
                        B[dimension*i+j] = (rand()/(RAND_MAX + 1.0));
                        C[dimension*i+j] = 0.0;
                }

        start = timestamp();
        for(i = 0; i < dimension; i++)
                for(j = 0; j < dimension; j++)
                        for(k = 0; k < dimension; k++)
                                C[dimension*i+j] += A[dimension*i+k] *
                                        B[dimension*k+j];

        end = timestamp();
        printf("\nsecs:%f\n", end-start);

        free(A);
        free(B);
        free(C);

        return 0;
}

问题答案:

这是我的疯狂猜测: 缓存

可能是您可以将2行2000 doubles放入缓存中。略小于32kb L1缓存。(同时留出其他必要的空间)

但是,当您将其增加到2048时,它将使用 整个 缓存(并且由于需要其他空间而浪费了一些缓存)

假设高速缓存策略是LRU,则将高速缓存仅溢出一小部分将导致整个行被重复刷新并重新加载到L1高速缓存中。

另一种可能是由于2的幂导致的缓存关联性。尽管我认为处理器是2路L1关联的,所以在这种情况下我认为这并不重要。(但我还是会把这个想法丢掉)

可能的解释2: 由于L2缓存上的超对齐,冲突缓存未命中。

您的B数组正在列上进行迭代。这样访问就大步向前。2k x 2k每个矩阵的总数据大小约为32 MB。这比您的L2缓存大得多。

当数据不完全对齐时,您将在B上具有适当的空间局部性。尽管您要跳行并且每个高速缓存行仅使用一个元素,但是高速缓存行仍保留在L2高速缓存中,以供中间循环的下一次迭代重用。

但是,当数据完全对齐(2048)时,这些跃点将全部落在相同的“缓存方式”上,并且将远远超过您的L2缓存关联性。因此,所访问的缓存行B不会在下一次迭代中保留在缓存中。
相反,它们将需要从ram一直拉出。



 类似资料:
  • 我在查看一些代码时发现了以下内容: 有什么区别呢?顺便说一句:我对矩阵很陌生

  • 问题内容: 我正在尝试创建一个矩阵以显示Pandas数据框中的行之间的差异。 我要这样: 要变成这样(差异垂直): 这是可以通过内置函数实现的,还是需要构建一个循环以获得所需的输出?谢谢你的帮助! 问题答案: 这是numpy广播的标准用例: 我们使用values属性访问基础的numpy数组,并引入了一个新轴,因此结果是二维的。 您可以将其与原始系列结合使用: 由于@Divakar,也可以使用以下命

  • 有一个矩阵a,比如: 我只想得到每行没有3个或更多数字的行,它们之间都有最大差异 此函数应仅返回第1行。

  • 主要内容:逐元素矩阵乘法,矩阵乘积运算,矩阵点积矩阵乘法是将两个矩阵作为输入值,并将 A 矩阵的行与 B 矩阵的列对应位置相乘再相加,从而生成一个新矩阵,如下图所示: 注意:必须确保第一个矩阵中的行数等于第二个矩阵中的列数,否则不能进行矩阵乘法运算。 图1:矩阵乘法 矩阵乘法运算被称为向量化操作,向量化的主要目的是减少使用的 for 循环次数或者根本不使用。这样做的目的是为了加速程序的计算。 下面介绍 NumPy 提供的三种矩阵乘法,从而进一步

  • 问题内容: 在numpy中,我有N个3x3矩阵的数组。这将是我如何存储它们的示例(我正在提取内容): 我也有一个由3个向量组成的数组,这将是一个示例: 我似乎无法弄清楚如何通过numpy将它们相乘,从而实现如下效果: 与的形状(在投射到阵列)是。但是,由于速度的原因,列表实现是不可能的。 我尝试了各种换位的np.dot,但最终结果没有得到正确的形状。 问题答案: 使用 脚步 : 1)保持第一根轴对

  • 我想使用寄存器(逐行信息)通过向量算法创建矩阵乘法。打开外循环4次我有空洞matvec_XMM(双* a,双* x,双* y,整数n,整数磅)函数的问题,它返回了不好的结果,这是算法wchich我必须使用: 它是ma代码:

  • 考虑两个矩阵A和B.如果A是mxn矩阵而B是nxp矩阵,它们可以相乘以产生mxn矩阵C.只有当A中的列数n等于数量时才可以进行矩阵乘法在B.中的行n 在矩阵乘法中,第一矩阵中的行的元素与第二矩阵中的对应列相乘。 在得到的矩阵C中的第 (i,j)位置中的每个元素是第i行的第i行中的元素与第二矩阵的第 j列中的对应元素的乘积的总和。 MATLAB中的矩阵乘法是使用*运算符执行的。 例子 (Exampl

  • 我正在尝试将一种基于马氏距离的方法转换为我的代码,该方法适用于图像,必须处理时间序列。这是Matlab代码,用户将图像作为输入传递,然后首先重塑它,然后计算平均值、协方差矩阵及其逆矩阵(他使用图像大小): 这是我的代码,在这里我用Python实现了第一部分。我没有图像,但有一个时间序列,其形状是(24230,30),这就是为什么我避免了重塑部分: 如果我尝试运行它,我会得到错误: 线性误差:奇异矩