【问题标题】:openACC: Running out of device memory when copying 3D array to deviceopenACC:将 3D 数组复制到设备时设备内存不足
【发布时间】:2018-07-17 08:00:40
【问题描述】:

我是使用 openACC 的新手,我想弄清楚当我使用 copyin 数据指令(特别是在 C 中)时发生了什么。

我有一个 3D 数组,正在尝试将其复制到设备上以进行一些计算。我遇到的问题是,当我进行复制时,设备内存不足,即使根据我的估计数组应该只有 ~40 MB(20000 x 128 x 2 浮点数组)。我使用的是 GTX 950,运行时有超过 1 GB 的可用内存(使用 nvidia-smi 检查)。

这是我用来测试的代码。我用它编译了 pgcc -acc -Minfo -o copytest copytest.c

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


float ***create_test_array( int nsamples, int nchan, int npol )
{
    int s, ch; // Loop variables
    float ***array;

    array = (float ***)malloc( nsamples * sizeof(float **) );

    for (s = 0; s < nsamples; s++)
    {
        array[s] = (float **)malloc( nchan * sizeof(float *) );

        for (ch = 0; ch < nchan; ch++)
            array[s][ch] = (float *)malloc( npol * sizeof(float) );
    }

    return array;
}



void test_copy( int nsamples, int nchan, int npol, float ***arr)
{
#pragma acc data pcopyin(arr[0:nsamples][0:nchan][0:npol])
#pragma acc kernels
    for (int pol = 0; pol < npol; pol++)
    {
        for (int ch = 0; ch < nchan; ch++)
        {
            for (int s = 0; s < nsamples; s++)
            {
                arr[s][ch][pol] = 0.0;
            }
        }

    }
}


void main()
{
    int nsamples = 10000;
    int nchan = 128;
    int npol = 2;
    float ***test_array = create_test_array( 2*nsamples, nchan, npol );

    test_copy( 2*nsamples, nchan, npol, test_array );
}

非常感谢任何见解。

【问题讨论】:

    标签: c openacc


    【解决方案1】:

    这实际上是一个非常糟糕的 GPU 数据布局。问题是编译器必须匹配 GPU 上的结构,因此需要创建一个指针数组,然后为每个指针创建第二个数组或指针并将指针“附加”到它的父级。 “附加”意味着它将在父数组中的适当位置填充设备指针,但必须启动内核来执行此操作。更糟糕的是,它需要再次遍历结构以创建第三维并再次附加指针。第三个维度也被填充以对齐,这是额外内存的来源。这会导致大量额外开销,并将严重影响您的性能。

    此外,由于主机和设备之间的数据传输只能在连续的块上完成,运行时必须遍历结构并一次仅复制 2 个元素。再次,导致高开销。

    如果您可以交换“nsamples”和“npol”尺寸,您仍然会有一些开销,但 128+2x128 附件比 20000+20000x128 小很多。

    或者,您可以使用 CUDA 统一内存 (-ta=tesla:managed) 让 CUDA 运行时为您移动数据。编译器不再需要创建 GPU 数据结构或附加指针。

    第三种选择是将数组线性化(即使其成为一维数组),然后计算循环中的索引。

    【讨论】:

    • 好的,谢谢马特。我更改了代码,因此我没有调用create_test_array,而是将其创建为arr[nsamples][nchan][npol],这解决了我的问题(至少在内存问题方面)。我想这是因为现在数组都在内存中的一个位置,因此不需要进行荒谬的点创建和复制。
    • 我遇到了同样的问题并将其转换为数组修复了它。但是,我看不到这背后的数学原理。为什么 20000+20000x128 在只有大约 250 万个位置时会太多,如果每个位置占用 8 个字节,这将加起来总共 40MB,这还不到 GTX 950 内存的 0.1%。非常感谢!
    • 问题不是内存大小,而是较大数量的“附加”(设置设备指针)和小数据传输,因为传输只能在连续的块中进行。
    • 非常感谢您的回复。在将其转换为数组之前,我遇到了内存错误,所以这肯定修复了它。不管潜在的性能问题如何,为什么这种变化会使其适合设备内存? “但是 128+2x128 的附加比 20000+20000x128 少很多” 但是即使需要那么多指针,也无法填充 2GiB 的设备内存。那是我不明白的部分。再次感谢您的帮助。
    猜你喜欢
    • 2020-09-11
    • 2021-11-12
    • 1970-01-01
    • 2017-03-23
    • 2013-11-14
    • 2021-01-22
    • 2015-03-11
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多