Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 减少C+中的GPU-CPU数据传输+;放大器_C++_Multithreading_Visual Studio_Gpgpu_C++ Amp - Fatal编程技术网

C++ 减少C+中的GPU-CPU数据传输+;放大器

C++ 减少C+中的GPU-CPU数据传输+;放大器,c++,multithreading,visual-studio,gpgpu,c++-amp,C++,Multithreading,Visual Studio,Gpgpu,C++ Amp,在尝试使用C++Amp优化应用程序时,我遇到了以下问题:数据传输。对我来说,将数据从CPU复制到GPU是没有问题的(因为我可以在应用程序的初始状态下这样做)。更糟糕的是,我需要快速访问C++Amp内核计算的结果,因此GPU和CPU之间的瓶颈是一个难题。我读到在Windows8.1下有一个性能提升,但是我正在使用Windows7,我不打算改变它。我读过关于暂存阵列的文章,但不知道它们如何帮助解决我的问题。我需要向主机返回一个浮点值,这似乎是最耗时的操作 float Subset::reductio

在尝试使用C++Amp优化应用程序时,我遇到了以下问题:数据传输。对我来说,将数据从CPU复制到GPU是没有问题的(因为我可以在应用程序的初始状态下这样做)。更糟糕的是,我需要快速访问C++Amp内核计算的结果,因此GPU和CPU之间的瓶颈是一个难题。我读到在Windows8.1下有一个性能提升,但是我正在使用Windows7,我不打算改变它。我读过关于暂存阵列的文章,但不知道它们如何帮助解决我的问题。我需要向主机返回一个浮点值,这似乎是最耗时的操作

float Subset::reduction_cascade(unsigned element_count, concurrency::array<float, 1>& a) 
{
static_assert(_tile_count > 0, "Tile count must be positive!");
//static_assert(IS_POWER_OF_2(_tile_size), "Tile size must be a positive integer power of two!");

assert(source.size() <= UINT_MAX);
//unsigned element_count = static_cast<unsigned>(source.size());
assert(element_count != 0); // Cannot reduce an empty sequence.

unsigned stride = _tile_size * _tile_count * 2;

// Reduce tail elements.
float tail_sum = 0.f;
unsigned tail_length = element_count % stride;
// Using arrays as a temporary memory.
//concurrency::array<float, 1> a(element_count, source.begin());
concurrency::array<float, 1> a_partial_result(_tile_count);

concurrency::parallel_for_each(concurrency::extent<1>(_tile_count * _tile_size).tile<_tile_size>(), [=, &a, &a_partial_result] (concurrency::tiled_index<_tile_size> tidx) restrict(amp)
{
    // Use tile_static as a scratchpad memory.
    tile_static float tile_data[_tile_size];

    unsigned local_idx = tidx.local[0];

    // Reduce data strides of twice the tile size into tile_static memory.
    unsigned input_idx = (tidx.tile[0] * 2 * _tile_size) + local_idx;
    tile_data[local_idx] = 0;
    do
    {
        tile_data[local_idx] += a[input_idx] + a[input_idx + _tile_size]; 
        input_idx += stride;
    } while (input_idx < element_count);

    tidx.barrier.wait();

    // Reduce to the tile result using multiple threads.
    for (unsigned stride = _tile_size / 2; stride > 0; stride /= 2)
    {
        if (local_idx < stride)
        {
            tile_data[local_idx] += tile_data[local_idx + stride];
        }

        tidx.barrier.wait();
    }

    // Store the tile result in the global memory.
    if (local_idx == 0)
    {
        a_partial_result[tidx.tile[0]] = tile_data[0];
    }
});

// Reduce results from all tiles on the CPU.
std::vector<float> v_partial_result(_tile_count);
copy(a_partial_result, v_partial_result.begin());
return std::accumulate(v_partial_result.begin(), v_partial_result.end(), tail_sum);  
} 
float Subset::reduction\u cascade(无符号元素计数,并发::数组&a)
{
静态断言(_tile_count>0,“tile count必须为正!”);
//static_assert(是_POWER_的_2(_tile_size),“tile size必须是2的正整数幂!”);
断言(source.size()0;步长/=2)
{
如果(本地_idx<步幅)
{
tile_数据[local_idx]+=tile_数据[local_idx+stride];
}
tidx.barrier.wait();
}
//将磁贴结果存储在全局内存中。
如果(本地_idx==0)
{
a_部分_结果[tidx.tile[0]]=tile_数据[0];
}
});
//减少CPU上所有磁贴的结果。
std::向量v_部分结果(_tile_count);
复制(a_partial_result,v_partial_result.begin());
返回std::accumulate(v_partial_result.begin()、v_partial_result.end()、tail_sum);
} 

我检查了上面的示例中最耗时的操作是
copy(a_partial_result,v_partial_result.begin())。我正试图找到一个更好的方法

所以我觉得这里还有别的事情。您是否尝试过运行代码所基于的原始示例?这是

加载示例解决方案并在发布模式下构建缩减项目,然后在未连接调试器的情况下运行该项目。您应该会看到这样的输出

Running kernels with 16777216 elements, 65536 KB of data ...
Tile size:     512
Tile count:    128
Using device : NVIDIA GeForce GTX 570

                                                           Total : Calc

SUCCESS: Overhead                                           0.03 : 0.00 (ms)
SUCCESS: CPU sequential                                     9.48 : 9.45 (ms)
SUCCESS: CPU parallel                                       5.92 : 5.89 (ms)
SUCCESS: C++ AMP simple model                              25.34 : 3.19 (ms)
SUCCESS: C++ AMP simple model using array_view             62.09 : 20.61 (ms)
SUCCESS: C++ AMP simple model optimized                    25.24 : 1.81 (ms)
SUCCESS: C++ AMP tiled model                               29.70 : 7.27 (ms)
SUCCESS: C++ AMP tiled model & shared memory               30.40 : 7.56 (ms)
SUCCESS: C++ AMP tiled model & minimized divergence        25.21 : 5.77 (ms)
SUCCESS: C++ AMP tiled model & no bank conflicts           25.52 : 3.92 (ms)
SUCCESS: C++ AMP tiled model & reduced stalled threads     21.25 : 2.03 (ms)
SUCCESS: C++ AMP tiled model & unrolling                   22.94 : 1.55 (ms)
SUCCESS: C++ AMP cascading reduction                       20.17 : 0.92 (ms)
SUCCESS: C++ AMP cascading reduction & unrolling           24.01 : 1.20 (ms)
请注意,没有一个示例是在您编写代码的时间附近进行的。虽然可以公平地说CPU更快,而且数据拷贝时间是一个很大的影响因素

这是意料之中的。一个GPU的有效使用涉及到的不仅仅是像精简到GPU这样的操作。您需要移动大量计算以弥补复制开销

您应该考虑以下几点:

  • 从CodePlex运行示例会发生什么
  • 您是否正在运行启用优化的发布版本
  • 您确定运行的是实际的GPU硬件,而不是WARP(软件仿真器)加速器吗
更多有用的信息

  • 你用的是什么硬件
  • 您的数据集有多大,包括输入数据和部分结果数组的大小

与代码的计算部分相比,您如何对数据副本进行计时?请记住,C++调用AMP调用是异步的,它们将事情排队到DMA缓冲区,并且只在需要时阻止。有关计时的更多讨论,请参见下面的答案。我计时的方式与我计时非并行方法的方式相同。当我注释掉copy()方法时,我得到了从800-900毫秒到300毫秒的提升。@当我注释掉copy函数时,我得到了@up。如果您没有通过复制数据或调用synchronize()或wait()来强制AMP内核完成计算,那么您可能根本就没有计时。请参阅我上一篇评论中的链接。因此,在显式调用wait()后,我得到:~640毫秒(不含copy())和~1300毫秒(含copy()。更糟糕的是,在到处添加wait()之后,我以前的方法似乎比我预期的要慢。这真的是一个坏消息。这有帮助吗?还是你仍然在经历非常慢的拷贝?是的,这对我帮助很大。结果证明,我正在运行的测试是以美国(微秒)为单位测量的,而不是以毫秒为单位。情况就是这样。我想优化两种方法(卷积计算和另一个非常简单的数学方程)。CPU上的这个数学方程非常快(大约50微秒~=0.05毫秒)。将一个浮点从concurrency::array复制到CPU需要超过0.05毫秒的时间,我认为至少需要0.9毫秒,因此仅复制该值会使CPU的计算速度降低10倍以上。也许我错了?