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.…

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

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

CDH- Hive HWI 配置

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

Hive - HWI 简单使用

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

html之插入图片

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

html之figure元素和figcaption元素为图片声明标题

figure和figcaption元素结合来为图片、视频、表格或者嵌入元素声明标题。以前使用如下方式为图片添加标题&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&g…

常用数学符号大全、关系代数符号

http://www.dataguru.cn/thread-247437-1-1.html 常用数学符号大全、关系代数符号 1、几何符号   ⊥ ∥ ∠ ⌒ ⊙ ≡ ≌ △   2、代数符号   ∝ ∧ ∨ &#xff5e; ∫ ≠ ≤ ≥ ≈ ∞ ∶   3、运算符号   如加号&#xff08;&a…

Segment-based Disparity Refinement with Occlusion Handling for Stereo Matching翻译和理解

摘要 摘要:本文提出了一种视差细化方法&#xff0c;通过对视差统计意义的探讨&#xff0c;直接细化赢者通吃视差图。根据基于分割的立体匹配的主要步骤&#xff0c;将参考图像过度分割为超像素&#xff0c;并通过改进的随机样本对每个超像素进行视差面拟合共识(RANSAC)。我们设…

Hadoop文章收集汇总 - 如禁止转载,请及时联系本人 收集学习互联网各位前辈分享的文章

工具自动自动集成文章列表与URL 公众号名称标题作者发布时间Hadoop实操如何使用Sentry管理Hive仓库目录外的其他目录的acl同步Fayson2018/9/30 8:27Hadoop实操如何使用Impala合并小文件Fayson2018/9/29 1:14Hadoop实操如何规划设置Kafka Broker的heap sizeFayson2018/9/28 0:27…

html之文档的头部和元数据定义(上)

什么叫元数据&#xff1f; 要理解这个问题&#xff0c;首先要知道“元”是什么。元(meta)&#xff0c;一般被我们翻译成“关于……的……”。 元数据(meta data)——“data about data” 关于数据的数据&#xff0c;一般是结构化数据&#xff08;如存储在数据库里的数据&#x…

win10(UEFI)和Ubuntu双系统安装,无法进入ubuntu。

因为win10采用UEFI引导&#xff0c;所以在安装Ubuntu系统的时候着重注意 其中一个分区为efi作为引导分区 要将安装的启动引导器(grub2)设备选择在efi分区上 如下图&#xff1a;

双目标定与矫正 matlab

matlab版本有2015a 或更新的本 1.预先拍摄好多幅标定板图像 像这样&#xff1a; 分别将左右图像放在left和right文件夹中。 2.相机标定 选择APPS,下拉菜单选择"stereo camera calibration" 进入一下界面&#xff0c;点击“add image”,分别设置camera1 &#xff0…

堆排序原理及算法实现(最大堆)

堆排序 堆排序是利用堆的性质进行的一种选择排序。下面先讨论一下堆。 1.堆 堆实际上是一棵完全二叉树&#xff0c;其任何一非叶节点满足性质&#xff1a; Key[i]<key[2i1]&&Key[i]<key[2i2]或者Key[i]>Key[2i1]&&key>key[2i2] 即任何一非叶节点的…

Hbase Region in transition (RIT) 异常解决

查看Hbase状态&#xff0c;突然发现出现了RIT&#xff0c;并且很长时间了~ 查看了一些相关RIT介绍 &#xff08;部分介绍和Hbase2.0不同&#xff0c;如&#xff1a;RIT状态信息2.0已不在zookeeper保存&#xff09; https://mp.weixin.qq.com/s?__bizMzU5OTQ1MDEzMA&mid224…

邻接表的构建、DFS、BFS搜索

接着上次的文章“图的构建&#xff08;邻接链表法&#xff09;”&#xff0c;邻接链表法构建图相对来说比较简单&#xff0c;并且遍历起来也相对简单&#xff0c;但是要是动态添加图的节点和图的边&#xff0c;则是实在不方便&#xff0c;不过现在不管那么多&#xff0c;今天的…

Storm性能简单测试

看了很多关于Storm性能的文章&#xff0c;说法不一&#xff0c;自己根据实际业务测一下是否能满足自身要求&#xff08;只做了简单集群和代码调优&#xff09; 场景&#xff1a;kafka消费数据标准化后存储到Hbase中 服务器资源&#xff1a;两台32G内存做Supervisor 使用资源平…

Hbase Shell 介绍

目录 Scan 创建表 Count 清空表数据 删除数据 删除表 删除列簇 判断表是否为‘enable’ 插入 Region管理 Scan 查询某个表某个列的数据&#xff1a; scan tableName,{COLUMN>列族&#xff1a;列,LIMIT>需要查看条数} 指定开始Rowkey查询 scan tableName,{STARTRO…

拓扑排序 详解 + 并查集 详解 + 最小生成树详解

若您发现本文有什么错误&#xff0c;请联系我&#xff0c;我会及时改正的&#xff0c;谢谢您的合作&#xff01; 本文为原创文章&#xff0c;转载请注明出处 本文链接 &#xff1a; http://www.cnblogs.com/Yan-C/p/3943940.html 。 哎呀&#xff0c;好久了啊&#xff0c;想…

Impala Shell 简单命令

目录 1.更新元数据 2.对查询结果去格式化 3.查询结果存储到文件 4.去格式化后指定分隔符 5.-p或者--show-profiles:显示查询的执行计划(与EXPLAIN语句输出相同)和每个查询语句底层的执行步骤的详细信息. 6.指定主机名连接 (-i) 7.执行查询语句 8.指定脚本文件执行SQL …

CDH邮件预警

转载自&#xff1a;http://blog.51cto.com/feature09/2055835 在CDH的7180页面找到Cloudera Managerment Service 如图所示&#xff1a; 在Configuration中&#xff0c;搜索alert 设置接收信息的邮箱。 设置内容都在图片上&#xff1a; 添加邮件页眉说明&#xff0c;第一行显…