]tiled_index代替index,启用平铺模式 parallel_for_each( // 把extent切分为以2*2为单位的tile(砖面) sample.extent.tile<2, 2>(), [=](tiled_index<2, 2> idx) restrict(amp) { //tile_static关键字的变量范围是整个tile(砖面) //所以每个tile(砖面)(2*2=4根线程)只实例化一个tile_static tile_static int nums[2][2]; //tile(砖面)中的所有线程分别运行下面的代码 //把值复制到tile_static实例nums,所以同一个nums会被赋值2*2=4次 nums[idx.local[1]][idx.local[0]] = sample[idx.global]; //等待tile(砖面)中的所有线程,运行完上面这段代码 idx.barrier.wait(); //现在nums中的2*2=4个元素已经有有效值了 //tile(砖面)中的所有线程再次分别运行下面的代码 //计算平均值, int sum = nums[0][0] + nums[0][1] + nums[1][0] + nums[1][1]; //把计算结果复制到array_view对象中. average[idx.global] = sum / 4; } ); //打印运算结果 for (int i = 0; i < 4; i++) { for (int j = 0; j < 6; j++) { std::cout << average(i, j) << " "; } std::cout << "\n"; } // Output: // 3 3 8 8 3 3 // 3 3 8 8 3 3 // 5 5 2 2 4 4 // 5 5 2 2 4 4 }
使用平铺的好处是,从tile_static变量存取数据要比从全局空间(array和array_view对象)要快。为了从平铺中得到性能优势,我们的算法必须把计算域拆分为tile(砖面)然后把数据放到tile_static变量中加快数据存取速度。
注意不要使用类似下面的代码来累加tile(砖面)中的数据,
tile_static float total;
total += matrix[t_idx];‘
原因[1]total的初始值是不确定的,所以第二句代码的运算没有意义。
原因[2]由于tile(砖面)中的多根线程竞争同一个title_static变量,计算结果会不确定。
内存屏障(MemoryFences)
在restrict(amp)限定中,有两种内存必须要同步:
全局内存:array或array_view实例
tile_static内存:tile(砖面)内存
内存屏障确保两种内存的线程同步,要调用内存屏障可以使用下面三种方法:
tile_barrier::wait(或tile_barrier::wait_with_all_memory_fence)方法: 建立全局内存和tile_static内存的屏障。
tile_barrier::wait_with_global_memory_fence方法 : 仅建立全局内存的屏障
tile_barrier::wait_with_tile_static_memory_fence 方法 :仅建立tile_static内存的屏障
调用特定类型的屏障(fence)可以提高你应用的性能,在下面的例子中 tile_barrier::wait_with_tile_static_memory_fence 方法的调用代替tile_barrier::wait方法的调用提高了应用的性能。
// 使用tile_static内存屏障
parallel_for_each(matrix.extent.tile
(),
[=, &averages](tiled_index
t_idx) restrict(amp) { // 把数据从全局内存中复制到title_static内存中. tile_static floattileva lues[SAMPLESIZE][SAMPLESIZE]; tileva lues[t_idx.local[0]][t_idx.local[1]] = matrix[t_idx]; // 等待title_static内存中的数据复制完毕 t_idx.barrier.wait_with_tile_static_memory_fence(); // 如果你移除if语句,代码会把被tile(砖面)中的所有线程调用,这样每个 // tile(砖面)中的元素都会被分配一个同样的平均值. if (t_idx.local[0] == 0&& t_idx.local[1] == 0) { for (int trow = 0; trow
restrict(amp)修饰的代码段是在加速器(GPU)上运行的,默认在里面的代码段,下断点不会Break(进入),在[Solution Explorer]窗口中点击项目名称,快捷键[Alt]+[Enter],打开当前项目属性页,[Configuration Properties]->[Debugging]->[Debugger Type]默认为“Auto”,改为“GPU Only”就可以Debug当前项目加速器(GPU)上运行的代码了。
据官网介绍,无符号整数的处理速度要比带符号整数快,所以尽量用无符号整数吧。
参考资料
《Using Tiles》
http://msdn.microsoft.com/en-us/library/vstudio/hh873135.aspx
《使用平铺》
http://msdn.microsoft.com/zh-cn/library/vstudio/hh873135.aspx