将数据从 GPU 复制到 CPU

And*_*hyn 4 c++-amp

我正在尝试使用 C++ AMP 计算矩阵。我使用宽度和高度为 3000 x 3000 的数组,并重复计算过程 20000 次:

    //_height=_width=3000
    extent<2> ext(_height,_width);
    array<int, 2> GPU_main(ext,gpuDevice.default_view);
    array<int, 2> GPU_res(ext,gpuDevice.default_view);
    copy(_main, GPU_main);
    array_view<int,2> main(GPU_main);
    array_view<int,2> res(GPU_res);
    res.discard_data();
    number=20000;
    for(int i=0;i<number;i++)
    {
        parallel_for_each(e,[=](index<2> idx)restrict(amp)
        {
           res(idx)=main(idx)+idx[0];//not depend from calculation type
        }
    array_view<TYPE, 2>  temp=res;
    res=main;
    main=temp;
    }
    copy(main, _main);
Run Code Online (Sandbox Code Playgroud)

在计算之前,我将矩阵从主机内存复制到 GPU 内存,并创建一个array_view从 0 到 7 的代码行。

之后,我启动一个循环来计算某些操作并重复 20000 次。每次迭代我都会启动一个parallel_for_each使用 C++ AMP 进行计算的循环。

GPU计算速度非常快,但是当我将结果复制到主机时,array _main我发现这个操作需要很多时间,而且我发现如果我number从20000减少到2000,复制的时间也会减少。

为什么会出现这种情况,是同步问题吗?

Ade*_*ler 5

您的代码(按原样)无法编译,下面是一个固定版本,我认为它具有相同的意图如果您想从计算时间中分离出复制时间,那么最简单的方法就是使用array<>和明确的副本。

        int _height, _width;
        _height = _width = 3000;
        std::vector<int> _main(_height * _width); // host data.
        concurrency::extent<2> ext(_height, _width);
        // Start timing data copy
        concurrency::array<int, 2> GPU_main(ext /* default accelerator */);
        concurrency::array<int, 2> GPU_res(ext);
        concurrency::array<int, 2> GPU_temp(ext);
        concurrency::copy(begin(_main), end(_main), GPU_main);
        // Finish timing data copy
        int number = 20000;
        // Start timing compute
        for(int i=0; i < number; ++i)
        {
            concurrency::parallel_for_each(ext,
                [=, &GPU_res, &GPU_main](index<2> idx)restrict(amp)
            {
               GPU_res(idx) = GPU_main(idx) + idx[0];
            });
            concurrency::copy(GPU_res, GPU_temp);       // Swap arrays on GPU
            concurrency::copy(GPU_main, GPU_res);
            concurrency::copy(GPU_temp, GPU_main);
        }
        GPU_main.accelerator_view.wait(); // Wait for compute
        // Finish timing compute
        // Start timing data copy
        concurrency::copy(GPU_main, begin(_main));
        // Finish timing data copy
Run Code Online (Sandbox Code Playgroud)

请注意wait()调用强制计算完成。请记住,C++ AMP 命令通常在 GPU 上对工作进行排队,并且仅当您使用wait()显式等待时才保证执行,或者通过在array_view<上调用(例如)synchronize()来隐式等待。 > . 为了更好地了解计时,您应该分别对计算和数据副本进行计时(如上所示)。您可以在这里找到一些基本的计时代码:http://ampbook.codeplex.com/SourceControl/changeset/view/100791#1983676 in Timer.h 在同一文件夹中有一些使用示例。

然而。我不确定我是否真的会以这种方式编写代码,除非我想打破复制和计算时间。对于纯粹存在于 GPU 上的数据使用array<>,对于从 GPU 复制到或从 GPU 复制的数据使用array_view<>要简单得多。

这看起来像下面的代码。

        int _height, _width;
        _height = _width = 3000;
        std::vector<int> _main(_height * _width); // host data.
        concurrency::extent<2> ext(_height, _width);
        concurrency::array_view<int, 2> _main_av(_main.size(), _main); 
        concurrency::array<int, 2> GPU_res(ext);
        concurrency::array<int, 2> GPU_temp(ext);
        concurrency::copy(begin(_main), end(_main), _main_av);
        int number = 20000;
        // Start timing compute and possibly copy
        for(int i=0; i < number; ++i)
        {
            concurrency::parallel_for_each(ext,
                [=, &GPU_res, &_main_av](index<2> idx)restrict(amp)
            {
               GPU_res(idx) = _main_av(idx) + idx[0];
            });
            concurrency::copy(GPU_res, GPU_temp);  // Swap arrays on GPU
            concurrency::copy(_main_av, GPU_res);
            concurrency::copy(GPU_temp, _main_av);
        }
        _main_av.synchronize();  // Will wait for all work to finish
        // Finish timing compute & copy
Run Code Online (Sandbox Code Playgroud)

现在只需要在GPU上的数据就声明在GPU上,需要同步的数据也声明在GPU上。更清晰、更少的代码。

您可以通过阅读我关于 C++ AMP 的书来了解更多信息:)