会议室分配时间最长_论文导论动态任务分配GPU上图计算的高效处理方式

编者按GPU作为一种硬件,相比较于CPU来说,有更多的并行度和更高的带宽,在图像处理领域取得了非常好的应用效果。越来越多的研究也正试图将GPU也应用到图计算领域中,然而GPU适合进行规则运算,但是图是一种不规则的数据表示形式,想要使用GPU高效处理图算法,需要更谨慎的策略。本文介绍一种在最近的文献中经常出现的图处理方式:动态任务分配—图上的计算任务并不是固定分配给GPU上的一个或若干个线程,而是使用动态的方式进行任务分配,最终使得不同线程得到的任务量更加均衡,从而实现更好的性能。 本文将介绍三篇论文,它们进行的是不同的图算法,但是本质上都是采用动态任务分配提高性能。

背景介绍

0d10b0c6bd5d91412ee70e5ac31cc079.png

上图是一个GPU上的图架构的简单表示。硬件层来说GPU上的全局内存与主机内存相通,可以进行数据传输;GPU上有许多流多处理器(SM),每个流多处理器上有自己若干个核和自己的片上缓存,是相对独立的单元。软件层次上,程序员启动核函数(grid),其中包括多个block,每个block上又有若干warp。Block是依赖于流多处理器的,每个block只会运行于一个流多处理器。值得一提的是,每个warp中包含32个线程,这32个线程是按照严格单指令多线程的形式运行的,是严格的同步关系,因而warp内部线程在运行代码遇到分支或者循环结构时的线程发散会导致warp内部分线程的空闲,并且warp内线程执行的任务量的不均衡会导致很严重的线程发散,因为所有线程都在等待运行时间最长的线程结束。

线程发散是我们试图寻找更好的任务分配方式的初衷,更好的任务分配方式能够保证更少的线程发散,从而提升整体性能。16f53600998802f3705e54fea83be2b2.png上图是GPU上的存储访问示意图,图(a)中,相邻的线程访问的是相邻并且对齐的地址,这样多个线程所需要的数据可以在较少的访存请求中一起取回来,而(b)图中线程访问的地址是随机的,无序的,就需要更多的访存次数。我们称(a)图中的模式是合并访存模式,是一种更加高效的访存方式。

例子:

首先我们会以三角形计数为例子,讲解什么是更好的任务分配方式。

ddef44c7764104d18e110bb20ffeba95.png

在图(graph)表示中,三个彼此相邻的节点我们称作一个三角形,三角形计数算法是求解一个图中所有三角形数目。通常三角形计数的方式如上图所示:对于一条边,对这条边的起点(src)和终点(dst)的邻接表取交集,交集的大小就是这条边所在的三角形的数目。很自然的,在三角形计数算法移植到GPU上的时候,我们可以以边作为任务分配的单位,一个线程负责处理一条边,计算这条边所在的三角形的个数。这种分配方式看起来很直观,但是会导致任务分配不均衡的情况,因为在常见的power-law图中邻接表的大小区别很大,线程的工作量也就会有很大区别,从而导致线程发散。

8cf27e791454f43469916467d9ea48e2.png

上图中介绍了一种优化了的任务分配方式,首先对于所有边的任务进行估计,然后把边按照任务量的大小分成不同的组。对于任务量很大的边所在的组,每个边分配多一些线程去处理,任务量少的边就分配较少的线程。这个方式利用事先对任务量的估计,根据任务量分配计算资源,在一定程度上缓和了线程工作量负载不均衡的问题,比前面介绍的根据边分组相比,有更好的效果。

论文1: GPU-based Graph Traversal on Compressed Graphs

SIGMOD 2019

本文设计了一个GCGT的图处理系统,针对的是大规模图中的并行算法,并且算法中包含“扩张—过滤—压缩”的过程。

2f7086820da1c5284a21800450715a81.png

上图以BFS为例,展示了在BFS的每一轮扩展的前沿(frontier)生成过程中,“扩张—过滤—压缩”的具体过程。这里“扩张”的依据是邻接关系,“过滤”是取出未访问节点,“压缩”是生成新的前沿节点。这种计算模式在BC (Betweeness Centrality), CC(Connected Component)等算法中也有很多的应用。 由于是大规模图,本文中首先采用已有的方式进行图的压缩表示,如下图所示。

b733b858f1c400cbd4d46f55968c9f35.png

d2134e5ce49f5778f07e16ceb322e94b.png

上图表示了图中邻接表的压缩过程,邻接表中连续的元素成为一个interval,只记录其首个元素和大小,不连续的元素成为residual,单独列在后面。Interval和residual记录的都是和前一个元素的差,这样可以减小存储空间。同时文章又采用了VLC 编码的方式,压缩字符的存储位数,进一步减少存储空间。这里我们只讨论图遍历算法,即给出一个前沿向外扩展,并如此迭代进行的过程。

aadec0cffea8c7b27ceb66053a3c9fe1.png

上图算法一中给出了一个直观的算法,每个线程负责处理一个点的邻接表,直接扩展这个邻接表中的所有节点。跟例子中介绍的直观三角形计数算法影响,由于图的power-law的性质,线程之间会存在比较明显的工作量负载不均衡的情况。

a6e5eb755b83c41c427755bcfe084279.png算法二中给出了GCGT的实现:所有的线程会先处理intervals然后处理residual,并且一个warp中的所有线程会同时进入处理residuals的阶段。并且处理interval也是分成两步,先处理长度大于32(一个warp的大小)的interval,再处理小于32的。

5b1838f6032076d75ab20d1b33c1393d.png

上图中给出了一个图表示,图中共有8个节点。同时,图例中是线程处理residual和interval的图例。在这个算法中,每个线程起初仍然先获得一个邻接表,只不过后面warp中的32个线程协同处理获得的32个邻接表。

f0ba1ac82f1d0c3e839c2d1c8c85595d.png

上图中是直观实现中,示例图的处理流程图。每个线程面对一个邻接表,都要先解码,然后处理interval和residual。考虑到warp内线程的lock-step执行特性,decoding、处理interval、处理residual是不能同时进行的。所以图中会有大量idle的存在,并且整个warp的运行时间是由运行时间最长的线程决定的。1dddfe38ff57b9cc6e4ee8be259bd31e.png上图中表示的是GCGT框架下的处理流程图。这里主要是针对interval做了改进。所有的线程先协同处理最长的interval(图中t2获得的邻接表),剩下的Interval拼接起来,也由全部的线程协作完成。这里整体的处理周期由25缩减成11,有了非常明显的提高。 对于residual部分,也有一些改进,如下图所示。

c57cc23c19f36a3024613947e5b74413.png

对于residual的处理也包括了解码和访存两部分,这里采用的优化是所有的线程先完成自己任务中residual的解码,然后把任务拼接起来所有线程共同完成访存。可以看到整体周期进一步缩减成9。每个线程要独自完成解码的原因是由编码的方式导致的,解码需要用到前一个元素的真实值。

20ba666dbf7e63d4443ab492779aecc6.png

最后从实验结果来看,横向比较中GCGT比其他框架都有性能优势,只比GPU上的CSR表示略差,但是提供了一定的压缩比;纵向来看,每一步策略都取得了一定的优化效果。

论文2: High Performance and Scalable GPU Graph Traversal

TOPC 2015

本文中使用到任务动态分配的部分,也仅仅是从邻接表中收集邻居的部分。详细来说,对于一个BFS过程,这个算法仅仅从一系列邻接表中读进来所有的邻居,并且加载进本地存储或寄存器中。

接下来我们比较几种实现。

1.  顺序读取

每个线程获取一个邻接表的起始和终止范围,然后负责记载这个邻接表中的所有元素。很显然,这是一个非常naïve的想法,线程的负载均衡会很差。

2.  粗粒度的,warp协同的方法

下图算法5中展示了warp协同的方法,warp中的线程竞争warp的控制权,竞争的胜利者将自己的任务广播给warp中所有的线程,大家一起完成该任务,然后重复“竞争-广播-协作”的过程。

此方法中,warp内每个线程的工作都是由整个warp内所有的线程协同完成的,比较好地均衡分配了任务。

621afdff5334b6af7ccf657981efd9f6.png

3.  细粒度的,基于scan的方法

下图展示了基于scan的方法的算法流程。这个方法中,将一个block中所有的线程获得的邻接表都拼接到一起,然后所有block中的线程协作处理这个拼接完成后的表。这个算法比上一个算法更好的地方在于协调了整个block内线程的工作负载,但是也有额外的拼接代价。

23ea20f9d0280f3401d1f1e0de4df95a.png

4.  Scan+warp 协调+block协调的方式。

1) 邻接表长度非常大的线程首先竞争整个block的控制权,整个block的运算资源都一起处理这个邻接表。

2) 剩下的线程中,邻接表长度适中的,线程竞争warp控制权,整个warp协作处理。

3) 最后剩下工作量比较小的线程,所有的任务拼接到一起,由整个block协作完成。

这个算法很好地协调了整个block内的工作负载的均衡性,又减少了大量拼接的代价,是最优的解决方案。从下面的三个性能指标中也能看出来,上面几种算法的性能,以及跟最优性能之间的差异。

0765a28b5a53a2ed86dd8d032a63300f.png

论文3:Update on Triangle Counting on GPU

HPEC 2019

这篇文章研究的是GPU上的三角形计数算法,其中naïve的三角形计数的任务分配在前面已经介绍过了,使用一个线程处理一条边。下面的算法1就是这种实现的伪代码。d706a13991fe19b86e85510be5171df2.png上文中我们还介绍了优化的三角形计数的任务分配,即根据任务量的预先估计,给每个边分配合适的线程,使得线程的任务大致相当。但是这种算法也有它的局限性:预先估计需要消耗额外的时间;并且同一组中的边获得相同数目的线程,但是实际上它们的任务量也有区别。本文中提出了动态分配的三角形计数算法,算法伪码如下算法2所示

6133ed5f5b66b89fd7d36c6d314406e0.png

这里采用的方法跟前面的两种论文中的思想有些类似,一个线程获得整个warp的控制权,向所有线程广播自己的任务,然后大家协同完成这组任务,这样warp内线程的工作是非常均衡的。实验效果如下图所示

5e69b6390cff99ee046bb95e9c2b95f3.png

总结

动态任务分配是GPU上进行图计算任务中一种比较好的任务分配方式,可以使线程之间的工作量更加均衡,很好解决图的不规则形带来的问题,并且能够减少线程的发散,实际上也有更好的合并访存效果。这种方法也不是完美的,动态计算需要额外的计算开销,以便得到线程各自的任务。当然这种负面影响完全可以被所带来的性能提升抵消。综合而言,这种方法还是非常值得我们学习和借鉴。

参考文献

[1] J. Fox, O. Green, K. Gabert, X. An, and D. A. Bader. Fast and adaptive list intersections on the gpu. In 2018 IEEE High Performance extreme Computing Conference (HPEC), pages 1–7. IEEE, 2018. [2] O. Green, J. Fox, A. Watkins, A. Tripathy, K. Gabert, E. Kim, X. An, K. Aatish, and D. A. Bader. Logarithmic radix binning and vectorized triangle counting. In 2018 IEEE High Performance extreme Computing Conference (HPEC), pages 1–7. IEEE, 2018.[3] Sha M, Li Y, Tan K, et al. GPU-based Graph Traversal on Compressed Graphs[C]. international conference on management of data, 2019: 775-792.[4] Duane Merrill, Michael Garland, and Andrew Grimshaw. 2015. High-Performance and Scalable GPU Graph Traversal. ACM Trans. Parallel Comput. 1, 2, Article 14 (January 2015), 30 pages.[5] C. Pearson et al., "Update on Triangle Counting on GPU," 2019 IEEE High Performance Extreme Computing Conference (HPEC), Waltham, MA, USA, 2019, pp. 1-7, doi: 10.1109/HPEC.2019.8916547.9bb1d8c1cec6c09ece305a37b52a7a47.png

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

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

相关文章

JS(Javascript)校验表单项的内容是否合规

<script !src"">/*** 分析&#xff1a;* 1.给表单绑定onsubmit事件* 监听器中判断每个方法检验的结果&#xff0c;如果都是true&#xff0c;则监听器方法返回true&#xff1b;如果有一个为false,* 则监听器方法返回false* 2.定义一些方法分别校验各个表单项* 3…

java \t怎么从头开始_如何从头开始以正确的面向对象方式创建Java Web Framework

java \t怎么从头开始您如何用Java设计Web应用程序&#xff1f; 您安装了Spring&#xff0c;阅读了手册&#xff0c;创建了控制器 &#xff0c;创建了一些视图&#xff0c;添加了一些注释 &#xff0c;它就可以工作了。 如果没有Spring &#xff08;Ruby中没有Ruby on Rails&…

kl散度的理解_以曲率的视角理解自然梯度优化

一个故事我要讲一个故事:一个你几乎肯定听过的故事&#xff0c;但它的侧重点与你习以为常关注的不同。所有现代深度学习模型都使用梯度下降进行训练。 在梯度下降的每个步骤中&#xff0c;您的参数值从某个起始点开始&#xff0c;然后将它们移动到最大损失减少的方向。 你可以通…

JSP的学习笔记

文章目录概念原理JSP 脚本JSP 内置对象概念 Java Server Pages &#xff1a;Java 服务器端页面 可以理解为&#xff1a;一个特殊的页面&#xff0c;其中既可以指定定义 html 标签&#xff0c;又可以定义 Java 代码 用于简化 Servlet 中的输出页面数据的代码的书写!!! 原理 J…

程序员面试算法_程序员的前20个搜索和排序算法面试问题

程序员面试算法大家好&#xff0c;如果您正在准备编程工作面试或正在寻找新工作&#xff0c;那么您知道这不是一个容易的过程。 在您职业的任何阶段&#xff0c;您都必须幸运地接到电话并进行第一轮面试&#xff0c;但是在初学者方面&#xff0c;当您寻找第一份工作时就更加困难…

御用导航提示页面_UI网站导航设计知识与五个知识案例

导航设计是网站的基石。它确定了至关重要的指标&#xff0c;例如转化率和跳出率&#xff0c;页面停留时间&#xff0c;点击量&#xff0c;并且通常是决定您的访问者拥有良好体验并以比您所说的“用户流量”更快退出网站的决定性因素。但是&#xff0c;好的设计是什么样的呢?一…

Servlet规范中定义的过滤器

文章目录什么是过滤器写过滤器的步骤配置初始化参数过滤器的优先级过滤器的优点过滤器执行过程图解过滤敏感词的示例代码使用 Servlet 来过滤敏感词使用过滤器来过滤敏感词通过配置初始化参数来设置敏感词关于 web.xml 的配置什么是过滤器 Servlet 规范当中定义的一种特殊的类…

Spring Boot错误–创建在类路径资源DataSourceAutoConfiguration中定义的名称为“ dataSource”的bean时出错...

大家好&#xff0c;如果您使用的是Spring Boot&#xff0c;并且遇到诸如“无法为数据库类型NONE确定嵌入式数据库驱动程序类”或“在类路径资源ataSourceAutoConfiguration中定义的名称为dataSource的bean创建错误”之类的错误&#xff0c;那么您来对地方了地点。 在本文中&…

simulink怎么生成vxworks的执行程序_从EPB模型谈谈Simulink代码生成

前段时间有读者朋友问代码生成的例子&#xff0c;说他正在做EPB的仿真模型&#xff0c;但总是和应用串不到一块去&#xff0c;我这里就从一个简单EPB控制模型来谈谈simulink代码生成&#xff0c;总结代码生成方法的同时也顺便回答他的问题。1.EPB模型准备用来举例说明的模型很简…

通过Socket实现文件上传/上传文件

文章目录整个功能的实现步骤客户端的实现步骤服务端的实现步骤示例代码整个功能的实现步骤 1.客户端使用本地的字节输入流读取被上传的文件数据 2.客户端使用网络字节输出流&#xff0c;将读取到的文件数据发送给服务端 3.服务端使用网络字节输入流读取客户端发送过来的文件数…

构造函数调用默认构造函数_显式无参数构造函数与默认构造函数

构造函数调用默认构造函数大多数不熟悉Java的开发人员都会Swift了解到&#xff0c;如果他们没有指定至少一个显式构造函数&#xff0c;则会为Java类隐式创建一个“ 默认构造函数 ”&#xff08; 由javac进行创建&#xff09;。 Java语言规范的 8.8.9节简要指出&#xff1a;“如…

Artifact到底是什么

将项目构建成一个可以在服务器部署的文件包&#xff08;如&#xff1a;war 包或者 exploded 的文件包&#xff09;&#xff0c;或者构建成的 jar 包&#xff08;这些 jar 包通常是某些模块程序文件&#xff0c;也可以是某些插件程序文件&#xff09;&#xff0c;这些都叫 Artif…

python win10 桌面_Python3如何实现Win10桌面自动切换

得空写了个自动切换桌面背景图片的小程序。再不写python就要扔键盘了&#xff0c;对vue还有那么一点好感&#xff0c;天天php真是有够烦。准备工作准备个文件夹放在桌面上&#xff0c;平时看到什么高清好图就拽进去。运行脚本脚本如下&#xff1a;#!/usr/bin/pythonimport ctyp…

java中抽象类继承抽象类_用Java中的抽象类扩展抽象类

java中抽象类继承抽象类示例问题 当我创建Java :: Geci抽象类AbstractFieldsGenerator和AbstractFilteredFieldsGenerator我遇到了一个不太复杂的设计问题。 我想强调一下&#xff0c;这个问题和设计对于某些人来说似乎很明显&#xff0c;但是在我最近与一位初级开发人员&#…

pb90代码如何连接sql2008r2_如何使用 HTTP Headers 来保护你的 Web 应用

众所周知&#xff0c;无论是简单的小网页还是复杂的单页应用&#xff0c;Web 应用都是网络攻击的目标。2016 年&#xff0c;这种最主要的攻击模式 —— 攻击 web 应用&#xff0c;造成了大约 40% 的数据泄露。事实上&#xff0c;现在来说&#xff0c;了解网络安全并不是锦上添花…

Servlet配置初始化参数/配置参数

文章目录给某个Servlet配置初始化参数配置全局的参数ServletConfig给某个Servlet配置初始化参数 也可以通过注解的方式来配置初始化参数&#xff1a; 在 Servlet 中获取针对 Servlet 的参数值&#xff1a; String version getInitParameter("version");配置全局的…

poi动态创建文档_POI创建的文档具有不同条件的灵活样式

poi动态创建文档介绍 这篇文章解释了基于各种标准将样式应用于文档的困难并提供了解决方案。 Java编程中的常见任务之一是根据存储在数据库中的数据创建Excel报告。 在这些情况下&#xff0c;Java程序员使用POI :-)。 这些报告通常对样式和数据格式有严格的规定。 数据通常是SQ…

python编码程序_python 编码

网页的编码方式是简体中文gb2312 (查看网页源码&#xff0c;可以看到)&#xff0c;而python内部的编码方式为unicode&#xff0c;之前的代码是这样的&#xff1a;contentAll urllib.urlopen(urlLink).read()soup BeautifulSoup.BeautifulSoup(contentAll) #生成BeautifulSou…

比特(bit)_二进制数

二进制数位&#xff0c;也叫比特位&#xff0c;其实就是指位置&#xff0c;是指二进制数的位置。例如&#xff0c;0101 这是二进制数&#xff0c;而且是 4 位的二进制数&#xff0c;因为有 4 个位置&#xff0c;每个位置放一个二进制数&#xff0c;确切的说是每个位置放一个二进…

javax线程池超时结束_没有Javax的Jakarta EE:这次世界也不会结束

javax线程池超时结束如果您错过了新闻&#xff0c; Oracle将向Eclipse基金会捐赠Java EE规范 。 这个决定是在规范过程中进行了相当长时间的Hibernate之后&#xff0c;人们理所当然地怀疑Oracle丧失了对Java EE的战略兴趣。 首先&#xff0c;Java EE和更广泛的Java社区很好地满…