c - 使用连续的内存分配,乘以大矩阵要慢得多

标签 c memory-management multidimensional-array malloc matrix-multiplication

在实现神经网络时,我注意到如果我将内存分配为数据集数组的单个连续 block ,执行时间会增加数倍。

比较这两种内存分配方式:

float** alloc_2d_float(int rows, int cols, int contiguous)
{
    int i;
    float** array = malloc(rows * sizeof(float*));

    if(contiguous)
    {
        float* data = malloc(rows*cols*sizeof(float));
        assert(data && "Can't allocate contiguous memory");

        for(i=0; i<rows; i++)
            array[i] = &(data[cols * i]);
    }
    else
        for(i=0; i<rows; i++)
        {
            array[i] = malloc(cols * sizeof(float));
            assert(array[i] && "Can't allocate memory");
        }

    return array;
}

以下是使用 -march=native -Ofast 编译时的结果(尝试了 gcc 和 clang):

michael@Pascal:~/NN$ time ./test 300 1 0

Multiplying (100000, 1000) and (300, 1000) arrays 1 times, noncontiguous memory allocation.

Allocating memory:    0.2 seconds
Initializing arrays: 0.8 seconds
Dot product:         3.3 seconds

real    0m4.296s
user    0m4.108s
sys     0m0.188s

michael@Pascal:~/NN$ time ./test 300 1 1

Multiplying (100000, 1000) and (300, 1000) arrays 1 times, contiguous memory allocation.

Allocating memory:    0.0 seconds
Initializing arrays: 40.3 seconds
Dot product:         13.5 seconds    

real    0m53.817s
user    0m4.204s
sys     0m49.664s

代码如下: https://github.com/michaelklachko/NN/blob/master/test.c

请注意,对于连续内存,初始化和点积都慢得多。

我的预期恰恰相反——一个连续的内存块应该比大量单独的小块对缓存更友好。或者至少它们在性能上应该是相似的(这台机器有 64GB 内存,其中 90% 未使用)。

编辑:这是压缩的独立代码(我仍然建议改用 github 版本,它有测量和格式化语句):

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

float** alloc_2d_float(int rows, int cols, int contiguous){
    int i;
    float** array = malloc(rows * sizeof(float*));
    if(contiguous){
        float* data = malloc(rows*cols*sizeof(float));
        for(i=0; i<rows; i++)
            array[i] = &(data[cols * i]);
    }
    else
    for(i=0; i<rows; i++)
        array[i] = malloc(cols * sizeof(float));
    return array;
}

void initialize(float** array, int dim1, int dim2){
    srand(time(NULL));
    int i, j;
    for(i=0; i<dim1; i++)
        for(j=0; j<dim2; j++)
            array[i][j] = rand()/RAND_MAX;
}

int main(){
    int i,j,k, dim1=100000, dim2=1000, dim3=300;
    int contiguous=0;
    float temp;

    float** array1 = alloc_2d_float(dim1, dim2, contiguous);
    float** array2 = alloc_2d_float(dim3, dim2, contiguous);
    float** result = alloc_2d_float(dim1, dim3, contiguous);

    initialize(array1, dim1, dim2);
    initialize(array2, dim3, dim2);

    for(i=0; i<dim1; i++)
        for(k=0; k<dim3; k++){
            temp = 0;
            for(j=0; j<dim2; j++)
                temp += array1[i][j] * array2[k][j];
            result[i][k] = temp;
    }
}

最佳答案

看起来您遇到了编译器运行代码矢量化的能力或障碍。 我试图重复你的实验但没有成功 -

mick@mick-laptop:~/Загрузки$ ./a.out 100 1 0

将 (100000, 1000) 和 (100, 1000) 数组相乘 1 次,不连续 内存分配。

初始化数组...

乘法数组...

执行时间: 分配内存:0.1秒 初始化数组:0.9 秒 点积:44.8秒

mick@mick-laptop:~/Загрузки$ ./a.out 100 1 1

将(100000, 1000)和(100, 1000)数组相乘1次,连续 内存分配。

初始化数组...

乘法数组...

执行时间: 分配内存:0.0 秒 初始化数组:1.0 秒 点积:46.3秒

关于c - 使用连续的内存分配,乘以大矩阵要慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41293349/

相关文章:

c - 3D数组的动态内存分配

c - 作为指针的参数未正确递增

c - 将 2 个值插入链表节点

c - 了解头文件中的函数定义

c - 使用 gcc -O2 优化如何解决问题 : pointer pointing nothing and having integer value as -23 in it, 消失了?

python - 如何在Python中将一维径向轮廓转换为二维数组

C++ 从 .txt 中读取浮点值并将它们放入一个未知大小的二维数组中

Java 2d Array 还是 2d ArrayList?

c - gtk3 滚动窗口大小,调整大小后里面有 gtkbox 和按钮

c++ - 即使我解压了 4.8.1,GCC -v 也会返回 GCC 4.7.3?