sycl异构编程

标签: c++  开发语言  

学习了一天的sycl编程,感觉是挺好的一种技术标准,有intell的dpc++,codeplay的computecpp编译器做的不错,可以用amd和intel的gpu,但是都不支持英伟达的gpu,太可惜。

 

SYCL是一种用于编程异构系统的开放式行业标准。SYCL的设计允许编写标准的C++源代码,使其可以在异构设备或主机上运行。

用于SYCL的术语历史上继承自OpenCL,并添加了一些特定于SYCL的内容。然而,SYCL是一种通用的C++编程模型,可以在OpenCL之外的其他异构API之上进行布局。

SYCL(发音为“sickle”)是一种用于异构计算的免版税、跨平台抽象C++编程模型。SYCL基于并行API或OpenCL等标准的基本概念、可移植性和效率,同时增加了单源C++的易用性和灵活性。

使用SYCL的开发人员能够使用他们习惯的许多技术(如继承和模板)编写标准的现代C++代码。同时,开发人员可以通过SYCL库的功能访问底层实现(如OpenCL)的全部功能,必要时还可以通过API与直接使用底层实现编写的代码进行互操作。

为了减少编程工作量并提高开发人员编写代码的灵活性,SYCL以几种方式扩展了OpenCL模型等标准中的概念,超越了C++特性的一般用途:

?在异构设备上执行并行内核既方便又灵活。常见的并行模式使用简单语法进行优先排序,通过一系列C++类型,程序员可以在需要时表达额外的需求,如同步;

?当使用缓冲区和访问器时,SYCL中的数据访问与数据存储分离。通过依赖C++风格的资源获取即初始化(RAII)习惯用法来捕获设备代码块之间的数据依赖关系,运行时库可以跟踪数据移动并提供正确的行为,而无需手动管理内核实例之间的事件依赖关系,也无需程序员显式移动数据。这种方法使数据并行任务图(可能已经是执行模型的一部分)能够由SYCL程序员轻松安全地构建;

?统一共享内存(USM)为显式数据分配和移动提供了一种机制。这种方法允许在异构设备上使用基于指针的算法和数据结构,并允许跨主机和设备增加代码的重用;

?分层并行语法提供了一种以易于理解的现代C++形式表达数据并行性的方法,类似于OpenCL设备或OpenMP目标设备执行模型。它更清晰地分层并行循环和同步点,以避免代码碎片,并更有效地映射到CPU风格的架构。

SYCL保留了受OpenCL标准启发的执行模型、运行时功能集和设备功能。该标准对SYCL能够支持的所有C++功能施加了一些限制。这确保了设备代码在尽可能广泛的设备上的可移植性。因此,虽然代码可以用标准C++语法编写,并与标准C++程序互操作,但整个C++功能集在SYCL设备代码中不可用。特别是,本规范定义的SYCL设备代码不支持虚拟函数调用、一般的函数指针、异常、运行时类型信息或可能依赖于这些特性或特定主机编译器特性的全套C++库。然而,这些基本限制可以通过一些特定的Khronos或供应商扩展来缓解。

下面是三个实例

void test0()
{
	const int N = 1024;
	int data[N];  //allocate data to be worked on
	queue myQueue;  //create default queue to enqueue work

	// By wrapping all the sycl work in a {} block, we ensure
	// all sycl tasks must complete before existing the block,
	// because the destructor of resultBuf will wait
	{
		//wrap our data varibale in a buffer
		buffer<int, 1> resultBuf{ data, range<1>{N} };

		//create a command group to issue commands to the queue
		myQueue.submit([&](handler& cgh) {
			//request access to the buffer without initialization
			accessor writeResult{ resultBuf, cgh, write_only, no_init };
			
			// enqueue a parallel for task with N work items
			cgh.parallel_for(N, [=](auto idx) {
				// Initialize each buffer element with its own rank  number starting at 0
				writeResult[idx] = idx;
			});  // end of the kernel function
		});  // end of our commands for this queue
	}  // end of scope, so we wait for work producing resultBuf to complete

	// Print result
	for (int i = 0; i < N; i++) {
		std::cout << "data[" << i << "] = " << data[i] << std::endl;
	}

}

void test1()
{
	const int N = 1024;
	//Create default queue to enqueue work
	queue myQueue;

	//Allocate shared memory bound to the device and context associated to the queue
	//Replacing malloc_shared with malloc_host would yield a correct program that
	//allocated device-visible memory on the host.
	int *data = malloc_shared<int>(N,myQueue);
	myQueue.parallel_for(N, [=](id<1>idx) {
		//Initialize each buffer element with its own rank number starting at 0
		data[idx] = idx;
	}); // End of the kernel function
	myQueue.wait();//Print result
	for (int i=0;i<N;i++)
		std::cout <<"data["<<i<<"] = "<<data[i]<<std::endl;
	
}
void test2()
{
	//size of the matrices
	constexpr size_t N = 2000;
	constexpr size_t M = 3000;
	// Create a queue to work on
	queue myQueue;
	// Create some 2D buffers of float for our matrices
	buffer<float, 2>a{ range<2>{N, M} };
	buffer<float, 2>b{ range<2>{N, M} };
	buffer<float, 2>c{ range<2>{N, M} };
	// Launch an asynchronous kernel to initialize a 
	myQueue.submit([&](handler& cgh) {
		// The kernel writes a, so get a write accessor on it
		accessor A{ a, cgh,write_only };
		// Enqueue a parallel kernel iterating on a N * M 2D iteration space
		cgh.parallel_for(range<2>{N, M}, [=](id<2>index) {
			A[index] = index[0] * 2+ index[1];
			});
		});
	// Launch an asynchronous kernel to initialize b
	myQueue.submit([&](handler& cgh) {
		// The kernel writes b, so get a write accessor on it
		accessor B{ b, cgh, write_only };
		// From the access pattern above, the SYCL runtime detects that this 
		// command_group is independent from the first one and can be 
		// scheduled independently 

		// Enqueue a parallel kernel iterating on a N * M 2D iteration space
		cgh.parallel_for(range<2>{N, M}, [=](id<2>index) {
			B[index] = index[0] * 2014 + index[1] * 42;
		});
	});
	
	// Launch an asynchronous kernel to compute matrix addition c a b
	myQueue.submit([&](handler& cgh) {
		// In the kernel a and b are read, but c is written
		accessor A{ a, cgh, read_only };
		accessor B{ b, cgh, read_only };
		accessor C{ c, cgh, write_only };
		// From these accessors, the SYCL runtime will ensure that when 
		// this kernel is run, the kernels computing aand b have completed 

		// Enqueue a parallel kernel iterating on a N * M 2D iteration space
		cgh.parallel_for(range<2>{N, M}, [=](id<2>index) {
			C[index] = A[index] + B[index];
		});
	});
	// Ask for an accessor to read c from application scope.The SYCL runtime
	// waits for c to be ready before returning from the constructor
	host_accessor C{ c, read_only };

	std::cout << std::endl << "Result:" << std::endl;
	for (size_t i = 0; i < N; i++) {
		for (size_t j = 0; j < M; j++) {
			// Compare the result to the analytic value
			if (C[i][j] != i * (2 + 2014) + j * (1 + 42)) {
				std::cout << "Wrong value " << C[i][j] << "on element " << i << " "
					<< j << std::endl;
				exit(-1);
			}
		}
	}
	std::cout <<"Good computation!"<<std::endl;

}

SYCL旨在提高数据的局部性和移动效率

? SYCL将数据存储与数据访问分开

? SYCL具有用于访问不同地址空间中的数据的独立结构

? SYCL允许您创建数据依赖关系图

 

 

数据相关性图的好处

?允许您根据关系描述问题

?不需要排队显式复制

?可以使用RAII执行同步

?必要时自动将数据复制回主机

?消除复杂事件处理的需要

?自动构建内核之间的相关性

?允许运行时生成数据移动优化

?在内核之前预先将数据复制到设备

?避免在内核之后将不必要的数据复制回主机

版权声明:本文为yanfeng1022原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yanfeng1022/article/details/126360158

智能推荐

vue移动端中手写一个树形结构业务,页面见里面

我这个业务需求是根据后台传给我的树形结构数据写的一个选择仓库的功能 由于一开始选框架选错了用cube ui 导致现在好多功能都必须自己写,所以才有了现在。 上图是我的第一级别 上图是我的最后一级 我这里实现是用的递归 首先当然是在页面写上获取仓库的接口啦 先上html js代码 可能注释不是很详细, 第一次发表这么长一段 有什么问题可以在下面说一下,我看到就回复...

WebRTC 系列文章 一对一视频通话和文字聊天

WebRTC 系列文章 一对一视频通话和文字聊天 环境准备 码代码 首先是信令服务器 引入依赖 信令服务器 网页 javascrpit 测试结果 这是WebRTC系列文章的第三篇。这次我们来实现一个可以一对一视频通话和有文字聊天功能的项目。 如果你对WebSocket、ICE、SDP、这些知识还不是很了解的话,推荐你先看下文章末尾的几篇推荐文章。 在此特别感谢 前端李老师的帮助 环境准备 桌面游览...

LeetCode -844. 比较含退格的字符串(栈、双指针)

比较含退格的字符串 方法一(栈): 方法二:双指针 一个字符是否会被删掉,只取决于该字符后面的退格符,而与该字符前面的退格符无关。因此当我们逆序地遍历字符串,就可以立即确定当前字符是否会被删掉。...

Java递归与迭代求斐波那契数列

Fibonacci 数列: 指的是这样一个数列:1、1、2、3、5、8、13、21、34……即从第三项开始,每一项等于它的前两项之和。 递归 程序调用自身的编程技巧称为递归。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的...

Android 如何实现时间年月日三级联动呢 直接上代码 看效果图

2 , 是不是很简单呢? 觉的不错的小伙伴可以点个赞。        ...

猜你喜欢

Redis(三):Redis的内存淘汰机制与持久化机制

一:Redis的内存淘汰机制   redis 设置过期时间 Redis中有个设置时间过期的功能,即对存储在 redis 数据库中的值可以设置一个过期时间。作为一个缓存数据库,这是非常实用的。如我们一般项目中的 token 或者一些登录信息,尤其是短信验证码都是有时间限制的,按照传统的数据库处理方式,一般都是自己判断过期,这样无疑会严重影响项目性能。 我们 set key 的时候,都可以给...

druid连接池配置监控页面

jdbc.properties相关配置 spring-content.xml相关配置 web.xml 相关配置 以上三种配置完成后输入localhost:8080/druid/index.jsp,监控页面显示如下图:  ...

用基数排序实现单词按字典序排序(包含大写)

输入字符串的处理: 所以字符串中最长单词的长度为mxp 基数排序时将每一个长度小于mxp的字符串后位填补‘A’ 即Cards Cap中mxp=4,Cap–>CapAA 这样所有的字符串就统一长度。 代码:...

OsgEarth加载DEM高程切片

DEM数据下载 登录地理空间数据云,导航到高级检索,选择数据集(SRTMDEM 90M 分辨率原始高程数据),并设置好行政区进行检索。   DEM数据拼接 下载的SRTM数据为分块的*.img栅格数据,使用QGIS加载数据,并使用Raster -> Miscellaneous -> Merge... 工具拼接,并保存成*.tif格式。   DEM数据切片 osgea...

hive系列之窗口函数

hive系列之窗口函数 文章目录 hive系列之窗口函数 一、窗口函数 二、常用窗口函数 2.1 排序 2.1.1 NTILE 2.1.2 rank() 2.1.3 dense_rank() 2.1.4 row_number() 2.2 聚合 2.3 分析 2.3.1 LAG和LEAD函数 2.3.2 first_value和last_value函数 2.4 window子句 2.5 补充rows...


http://www.vxiaotou.com