cuda线程束原语 __shfl_xor、__shfl、__shfl_up()、__shfl_down()

在CC3.0以上,支持了shuffle指令,允许thread直接读其他thread的寄存器值,只要两个thread在 同一个warp中,这种比通过shared Memory进行thread间的通讯效果更好,latency更低,同时也不消耗额外的内存资源来执行数据交换。

这里介绍warp中的一个概念lane,一个lane就是一个warp中的一个thread,每个lane在同一个warp中由lane索引唯一确定,因此其范围为[0,31]。在一个一维的block中,可以通过下面两个公式计算索引:

laneID = threadIdx.x % 32

warpID = threadIdx.x / 32

例如,在同一个block中的thread1和33拥有相同的lane索引1。

Variants of the Warp Shuffle Instruction

有两种设置shuffle的指令:一种针对整型变量,另一种针对浮点型变量。每种设置都包含四种shuffle指令变量。为了交换整型变量,使用过如下函数:

参考书籍:《cuda专家手册|GPU编程权威》

1:_shfl_xor

首先介绍__shfl_xor,因为最先用到它。

__shfl_xor(var,laneMask):Copy from a lane based on bitwise XOR of own lane ID

意思就是从当前的线程id与laneMak异或运算的值作为线程号的,把这个线程号的var值取出来。

演示图:

举例:

tid =0

laneMask =16

tid xor laneMask(0000 xor 1000)=0111=15

所有取到的值为15号线程的var

那我们看下完成测试代码:

__global__ void test_shfl_xor(int A[], int B[])
{int tid = threadIdx.x;int best = B[tid];//best = subgroup_min<32>(best, 0xffffffffu);best = __shfl_xor(best, 8);A[tid] = best;
}int main()
{int *A,*Ad, *B, *Bd;int n = 32;int size = n * sizeof(int);// CPU端分配内存A = (int*)malloc(size);B = (int*)malloc(size);for (int i = 0; i < n; i++){B[i] = rand()%101;std::cout << B[i] << std::endl;}std::cout <<"----------------------------" << std::endl;// GPU端分配内存cudaMalloc((void**)&Ad, size);cudaMalloc((void**)&Bd, size);cudaMemcpy(Bd, B, size, cudaMemcpyHostToDevice);// 定义kernel执行配置,(1024*1024/512)个block,每个block里面有512个线程dim3 dimBlock(128);dim3 dimGrid(1000);// 执行kernelconst auto t1 = std::chrono::system_clock::now();test__shfl_xor << <1, 32 >> > (Ad,Bd);cudaMemcpy(A, Ad, size, cudaMemcpyDeviceToHost);// 校验误差float max_error = 0.0;for (int i = 0; i <     32; i++){std::cout << A[i] << std::endl;}// 释放CPU端、GPU端的内存free(A);    cudaFree(Ad);free(B);cudaFree(Bd);  return 0;
}

运行结果:

41 85 72 38 80 69 65 68 96 22 49 67 51 61 63 87 66 24 80 83 71 60 64 52 90 60 49 31 23 99 94 11
----------------------------
66 24 80 83 71 60 64 52 90 60 49 31 23 99 94 11 41 85 72 38 80 69 65 68 96 22 49 67 51 61 63 87

--------------------------------

再高阶的用法,求取线程束中最大值:

template <typename T, unsigned int GROUP_SIZE, unsigned int STEP>
struct subgroup_min_impl {static __device__ T call(T x, uint32_t mask) {
#if CUDA_VERSION >= 9000x = min(x, __shfl_xor_sync(mask, x, STEP / 2, GROUP_SIZE));
#elsex = min(x, __shfl_xor(x, STEP / 2, GROUP_SIZE));
#endifreturn subgroup_min_impl<T, GROUP_SIZE, STEP / 2>::call(x, mask);}
};
template <typename T, unsigned int GROUP_SIZE>
struct subgroup_min_impl<T, GROUP_SIZE, 1u> {static __device__ T call(T x, uint32_t) {return x;}
};template <unsigned int GROUP_SIZE, typename T>
__device__ inline T subgroup_min(T x, uint32_t mask) {return subgroup_min_impl<T, GROUP_SIZE, GROUP_SIZE>::call(x, mask);
}__global__ void test__shfl_xor(int A[], int B[])
{int tid = threadIdx.x;int best = B[tid];best = subgroup_min<32>(best, 0xffffffffu);//best = __shfl_xor(best, 16);A[tid] = best;
}int main()
{int *A,*Ad, *B, *Bd;int n = 32;int size = n * sizeof(int);// CPU端分配内存A = (int*)malloc(size);B = (int*)malloc(size);for (int i = 0; i < n; i++){   B[i] = rand()%101;std::cout << B[i] << std::endl;}std::cout <<"----------------------------" << std::endl;// GPU端分配内存cudaMalloc((void**)&Ad, size);cudaMalloc((void**)&Bd, size);cudaMemcpy(Bd, B, size, cudaMemcpyHostToDevice); // 定义kernel执行配置,(1024*1024/512)个block,每个block里面有512个线程dim3 dimBlock(128);dim3 dimGrid(1000);// 执行kernelconst auto t1 = std::chrono::system_clock::now();test_shfl_xor << <1, 32 >> > (Ad,Bd);cudaMemcpy(A, Ad, size, cudaMemcpyDeviceToHost);// 校验误差float max_error = 0.0;for (int i = 0; i <     32; i++){std::cout << A[i] << std::endl;}cout << "max error is " << max_error << endl;// 释放CPU端、GPU端的内存free(A);free(B);   cudaFree(Ad);cudaFree(Bd);return 0;
}

运行结果

41 85 72 38 80 69 65 68 96 22 49 67 51 61 63 87 66 24 80 83 71 60 64 52 90 60 49 31 23 99 94 11
----------------------------
11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11

_shfl_xor介绍完毕

--------------------------------------

2.__shfl()

 

Direct copy from indexed lane:复制lane id数据

__shfl(int var,int srclane,int width =32)

 

这个就是比较简单,咱们直接上代码:

__global__ void test_shfl(int A[], int B[])
{int tid = threadIdx.x;int best = B[tid];best = __shfl(best, 3);A[tid] = best;
}int main()
{int *A,*Ad, *B, *Bd;int n = 32;int size = n * sizeof(int);// CPU端分配内存A = (int*)malloc(size);B = (int*)malloc(size);for (int i = 0; i < n; i++){   B[i] = rand()%101;std::cout << B[i] << std::endl;}std::cout <<"----------------------------" << std::endl;// GPU端分配内存cudaMalloc((void**)&Ad, size);cudaMalloc((void**)&Bd, size);cudaMemcpy(Bd, B, size, cudaMemcpyHostToDevice); // 定义kernel执行配置,(1024*1024/512)个block,每个block里面有512个线程dim3 dimBlock(128);dim3 dimGrid(1000);// 执行kernelconst auto t1 = std::chrono::system_clock::now();test_shfl << <1, 32 >> > (Ad,Bd);cudaMemcpy(A, Ad, size, cudaMemcpyDeviceToHost);// 校验误差float max_error = 0.0;for (int i = 0; i <     32; i++){std::cout << A[i] << std::endl;}cout << "max error is " << max_error << endl;// 释放CPU端、GPU端的内存free(A);free(B);   cudaFree(Ad);cudaFree(Bd);return 0;
}

按以上代码逻辑,取得数据全是第3号线程的数:

运行结果:

41 85 72 38 80 69 65 68 96 22 49 67 51 61 63 87 66 24 80 83 71 60 64 52 90 60 49 31 23 99 94 11
----------------------------
38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38

 

--------------------------------------------------------------------------------------------------------------------------------

3.__shfl_up()

__shfl_up(int var,unsigned int delta,int width =32):Copy from a lane with lower ID relative to caller

 

把tid-delta的线程好的var复制给tid的 var,如果tid-delta<0,var保持原来的值

见代码:

__global__ void test_shfl_up(int A[], int B[])
{int tid = threadIdx.x;int best = B[tid];best = __shfl_up(best, 3);A[tid] = best;
}

运行结果:

41 85 72 38 80 69 65 68 96 22 49 67 51 61 63 87 66 24 80 83 71 60 64 52 90 60 49 31 23 99 94 11
----------------------------
41 85 72 41 85 72 38 80 69 65 68 96 22 49 67 51 61 63 87 66 24 80 83 71 60 64 52 90 60 49 31 23

--------------------------------------------------------------------------------------

4.__shfl_down

__shfl_down(int var,unsigned int delta,int width =32)

把tid+delta的线程好的var复制给tid的 var,如果tid+delta>32,var保持原来的值

测试代码:

__global__ void test_shfl_down(int A[], int B[])
{int tid = threadIdx.x;int best = B[tid];best = __shfl_down(best, 3);A[tid] = best;
}

运行结果:

41 85 72 38 80 69 65 68 96 22 49 67 51 61 63 87 66 24 80 83 71 60 64 52 90 60 49 31 23 99 94 11
----------------------------
38 80 69 65 68 96 22 49 67 51 61 63 87 66 24 80 83 71 60 64 52 90 60 49 31 23 99 94 11 99 94 11

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/510221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hue添加RDBMS(关系型数据库)

Hue添加RDBMS方式 Hue界面没有Mysql添加方式&#xff0c;需要修改配置切换至Hue3界面&#xff0c;找一下 3.发现有添加方式 4.点进去发现&#xff0c;说要再配置文件中添加 5.经查阅资料发现&#xff0c;需要在hue的配置中hue_safety_valve.ini 修改/添加 相关数据库配置 6.…

html之属性的定义

<元素 属性"值"(或者值)>内容</元素>2.3.4属性的定义1.不定义属性2.属性值中的空白eg:<img src"c:/hello world">因为属性值是连续字符序列&#xff0c;因此hello与world之间的空白处应该用%20&#xff0c;<img srcc:/hello%20world&…

#error This file requires compiler and library support for the ISO C++ 2011 standard

解决方式&#xff1a; set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdc11")

HBase BlockCache系列 - 探求BlockCache实现机制

转载自&#xff1a;http://hbasefly.com/2016/04/26/hbase-blockcache-2/ HBase BlockCache系列第一篇文章《走进BlockCache》从全局视角对HBase中缓存、Memstore等作了简要概述&#xff0c;并重点介绍了几种BlockCache方案及其演进过程&#xff0c;对此还不了解的可以点这里。…

html之属性的应用

在html文档中&#xff0c;某些地方不允许存在某些字符。因此使用其他字符代替eg&#xff1a;小于号(<)和and符号(&)&#xff0c;如果错误的使用这些符号&#xff0c;会造成html解析器将显示错误。eg&#xff1a;<p><html></p>可以显示html如果不用其他…

ubuntu安装tensorflow-gpu 和pytorch

本文参考了&#xff1a; https://blog.csdn.net/qq_27825451/article/details/89082978 谢谢这位博主 这里我们选择清华源 sudo python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tensorflow-gpu1.2.0 pip install -i https://pypi.tuna.tsinghua.edu.c…

Hbase Memstore刷新方式与Region的数目上限

目录 Region数目上限 Region大小上限 MemStore的刷新方式&#xff08;触发条件&#xff09; HLog (WAL) Size & Memstore Flush 频繁的Memstore Flushes Region数目上限 RegionServer的region数目取决于memstore的内存使用&#xff0c;每个region拥有一组memstore&am…

CDH- Hive HWI 配置

目录 一、HWI安装 二、其中遇到一些问题&#xff1a; 1.遇到如下问题&#xff0c;将jre环境中的toos.jar 服务到lib目录下 2.CDH中没有hwi相关配置参数&#xff0c;手动加入并修改端口为9998&#xff0c;发现并未生效&#xff0c;暂时未找到原因所在。 一、HWI安装 通过查看…

ubuntu 安装PCL

如果你对PCL版本没有要求可以根据下面的方式安装&#xff1a; sudo apt-get install libpcl-dev 编译工程的时候可能会出现两个错误&#xff1a; 1. *** No rule to make target /usr/lib/x86_64-linux-gnu/libproj.so, needed by pcl_test. Stop 解决方式&#xff1a; s…

html之添加注释

为文档添加注释 <!--这里是注释--> 或者 <!--这里也是注释 并且可以分为多行-->

Hive - HWI 简单使用

进入HWI web页面 查看数据库中的表&#xff1a; 单击Create Session&#xff0c;并输入任务名称&#xff08;自定义&#xff09; 输入相关信息 Result File:结果输出文件 Error File:错误输出文件(可不填) Query&#xff1a;需要执行的语句,一些需要设置的参数也在这里面进…

ubuntu16.04安装ROS

参考博客: https://blog.csdn.net/weixin_43159148/article/details/83375218

HDFS balancer 异常处理

Hbase批量导入数据时&#xff0c;服务器负载较高&#xff0c;导致HDFS数据没有及时均衡&#xff0c;导致有一个DataNode数据暴增&#xff0c;手动进行balancer。 增加HDFS DataNode节点&#xff0c;想要均衡数据存储&#xff0c;执行 hdfs balancer -threshold 10 突然有一些…

html之关于空白和空白字符

分为&#xff1a;有意义空白和无意义空白2.71关于断行符<p> </p>2.72空白字符四种。。。记住&#xff1a;应该将空白置于开始标签之前&#xff0c;而不是紧跟着开始标签之后&#xff08;eg&#xff1a;<p>hello <a hre...>world</a> 避免<p&g…

“__popcnt64 is undefined

添加头文件&#xff1a; #include <intrin.h>

html之特殊字符表

特殊符号命名实体十进制编码特殊符号命名实体十进制编码Α&Alpha;Β&Beta;Γ&Gamma;Δ&Delta;Ε&Epsilon;Ζ&Zeta;Η&Eta;Θ&Theta;Ι&Iota;Κ&Kappa;Λ&Lambda;Μ&Mu;Ν&Nu;Ξ&Xi;Ο&Omicron;Π&Pi;Ρ&R…

cmake 学习笔记

1.路径 _mkdir(ROOT_DIR "/data/"); if (NOT ROOT_DIR_DEFINED) add_definitions(-DROOT_DIR"${PROJECT_SOURCE_DIR}") set(ROOT_DIR_DEFINED ON) endif() if (NOT ROOT_DIR_DEFINED) set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) if (AR…

HDFS查看异常:Operation category READ is not supported in state standby. Visit

跨集群访问hdfs失败 $ hdfs dfs -ls hdfs://test:8020/hbase ls: Operation category READ is not supported in state standby. Visit https://s.apache.org/sbnn-error 意思是namenode不可用&#xff0c;查看namenode状态 hdfs-site.xml<property><name>dfs.h…

html之插入图片

GIF、JPEG、PNG是最符合在网页设计中使用的格式&#xff0c;但是要想将它们呈现在网页中&#xff0c;必须将它们链接在网页&#xff0c;这是通过HTML中添加到图片的路径链接来实现的。 使用html中的img可以实现该功能 图片的源地址(src属性) <img src"文件路径"…