Intel oneAPI笔记(3)--jupyter官方文档(SYCL Program Structure)学习笔记

news2024/12/29 13:34:45

前言

本文是对jupyterlab中oneAPI_Essentials/02_SYCL_Program_Structure文档的学习记录,包含对Device Selector、Data Parallel Kernel、Host Accessor、Buffer Destruction、的介绍,最后还有一个小关于向量(Vector)加法的实例

设备(Device)

设备类包含用于查询设备信息的成员函数,这对于创建多个设备的SYCL程序很有用,成员函数get_info,可以获取包括以下的信息:

名称,供应商,版本号,本地和全局工作编号,宽度内置类型,时钟频率,缓存宽度和大小,在线或离线等

设备选择器(Device Selector) 

这个类允许在运行时根据用户提供的启发式方法选择特定设备来执行内核。下面的代码示例显示了标准设备选择器的使用

运行结果

队列(Queue) 

队列类提交要由SYCL运行时执行的命令组。队列是一种将工作提交给设备的机制。一个队列映射到一个设备,多个队列可以映射到同一个设备

内核(Kernel)

内核对象不是由用户显式构造的,而是在调用parallel_for等内核调度函数时构造的,用于在设备上执行代码的方法和数据

Scope

Application scope和command group scope

执行在主机上的代码,在这个scope中可以使用c++全部代码

Kernel scope

执行在设备(Device)上的代码,这个scope中可以无法使用部分c++的功能

Parallel Kernels

并行内核允许一个操作的多个实例并行执行。这对于offload的基本for循环的并行执行非常有用,因为for循环中的每个迭代都是完全独立的,并且按任意顺序执行。并行内核是用parallel_for函数表示的。c++应用程序中的一个简单的'for'循环编写如下

用下面这种方法,可以offload到一个加速器(accelerator)中

基本并行内核的功能主要包含range、id和item类。Range类用于描述并行执行的迭代空间,id类用于在并行执行中索引内核的单个实例

上述的i可以换成item,这样的话,可以通过相关函数不仅得到原来的索引值i,还可以在这个循环内部得到range

Nd Range Kernels

基本并行内核是并行for循环的简单方法,但不允许在硬件级别进行性能优化。ND-Range内核是表达并行性的另一种方式,它通过提供对本地内存的访问和将执行映射到硬件上的计算单元来实现低级性能调优。整个迭代空间被分成称成很多工作组,工作组中的工作项被安排在硬件上的单个计算单元上

nd_range内核的功能通过nd_range和nd_item类公开。Nd_range类表示使用全局执行范围和每个工作组的本地执行范围的分组执行范围。Nd_item类表示内核函数的单个实例,并允许查询工作组范围和索引

比如上面这个例子,第一个range<1>(1024)表示全局执行范围是1024个工作单元,第二个range<1>(64)表示每个工作组的本地执行范围是64,也就是一个工作组有64个单元,也照应了图上的(4*4*4)区域

Buffer Model 

缓冲区在跨设备和主机的SYCL应用程序中封装数据。访问器是访问缓冲区数据的机器

SYCL的代码开头内容:

SYCL程序是标准的c++。该程序在主机上调用,并将计算offload到加速器上。程序员使用SYCL的队列、缓冲区、设备和内核抽象来指示应该卸载哪些部分的计算和数据

SYCL程序的第一步,我们创建一个队列。我们通过将任务提交到队列,将计算量转移到设备上。程序员可以通过选择器选择CPU、GPU、FPGA等器件。这个程序在这里使用默认的q,这意味着SYCL运行时通过使用默认选择器来选择运行时可用的最有能力的设备。但下面是一个简单的SYCL程序

设备和主机可以共享物理内存,也可以拥有不同的内存。当内存不同时,offload计算需要在主机和设备之间复制数据。SYCL不要求程序员管理数据副本。通过创建缓冲区和访问器,SYCL确保数据对主机和设备可用,而无需程序员的任何努力。SYCL还允许程序员在需要实现最佳性能时显式控制数据移动

在SYCL程序中,我们定义了一个内核(就是device 运行的那部分代码)。对于像这样的简单程序,索引空间直接映射到数组的元素。内核被封装在一个c++ lambda函数中。lambda函数在索引空间中以坐标数组的形式传递一个点。对于这个简单的程序,索引空间坐标与数组索引相同。下面程序中的parallel_for将lambda应用到索引空间。索引空间在parallel_for的第一个参数中定义为从0到N-1的一维范围

对访问器(Accessor)的隐式依赖 

访问器在SYCL图中创建对内核执行排序的数据依赖关系,如果两个内核使用相同的缓冲区,第二个内核需要等待第一个内核完成,以避免竞争条件,比如下面这个图,必须在kernel1运行完之后,缓冲区A才能空闲,然后才能继续运行kernel2

样例

%%writefile lab/buffer_sample.cpp
//==============================================================
// Copyright © Intel Corporation
//
// SPDX-License-Identifier: MIT
// =============================================================
#include <sycl/sycl.hpp>

constexpr int num=16;
using namespace sycl;

  int main() {
  auto R = range<1>{ num };
  //Create Buffers A and B
  buffer<int> A{ R }, B{ R };
  //Create a device queue
  queue Q;
  //Submit Kernel 1
  Q.submit([&](handler& h) {
    //Accessor for buffer A
    accessor out(A,h,write_only);
    h.parallel_for(R, [=](auto idx) {
      out[idx] = idx[0]; }); });
  //Submit Kernel 2
  Q.submit([&](handler& h) {
    //This task will wait till the first queue is complete
    accessor out(A,h,write_only);
    h.parallel_for(R, [=](auto idx) {
      out[idx] += idx[0]; }); });
  //Submit Kernel 3
  Q.submit([&](handler& h) { 
    //Accessor for Buffer B
    accessor out(B,h,write_only);
    h.parallel_for(R, [=](auto idx) {
      out[idx] = idx[0]; }); });
  //Submit task 4
  Q.submit([&](handler& h) {
   //This task will wait till kernel 2 and 3 are complete
   accessor in (A,h,read_only);
   accessor inout(B,h);
  h.parallel_for(R, [=](auto idx) {
    inout[idx] *= in[idx]; }); }); 
      
 // And the following is back to device code
 host_accessor result(B,read_only);
  for (int i=0; i<num; ++i)
    std::cout << result[i] << "\n";      
  return 0;
}

运行结果

结果解释:并行运行kerne11和kernel3,在缓冲区A和B中分别写入0--15这16个数,然后运行kernel2,让缓冲区A中的数翻二倍,最后运行kernel4,让缓冲区A中的0--30这16个数和缓冲区B中的0--15这16个数相乘,最后输出

Host Accessor

主机访问器是使用主机缓冲区访问目标的访问器。它是在命令组的作用域之外创建的,它们用于通过构造主机访问器对象将数据同步回主机。缓冲区销毁是将数据同步回主机的另一种方法

缓冲区获取存储在vector中的数据的所有权。创建主机访问器是一个阻塞调用,只有在所有队列中修改同一缓冲区的SYCL内核完成执行并且主机可以通过该主机访问器访问数据之后才会返回

运行结果

下面介绍,主机和设备数据同步的另一种方法:缓冲区销毁

Buffer Destruction

在下面的示例中,缓冲区创建发生在单独的函数作用域中。当执行超出此函数作用域时,调用缓冲区析构函数,从而放弃数据的所有权并将数据复制回主机内存

运行结果

Custom Device Selector

自定义设备选择器使用您自己的逻辑(评分机制)自定义设备选择器

特定供应商名称的自定义设备选择器

具有GPU和特定设备名称的自定义设备选择器

基于设备的优先级的自定义设备选择器

下面是基于上种情况的案例

运行结果

Lab Exercise: Vector Add

下面是官方文档中向量相加这个练习

下面是我已经补全的代码

#include <sycl/sycl.hpp>
using namespace sycl;
int main() {
    const int N = 256;
    //# Initialize a vector and print values
    std::vector<int> vector1(N, 10);
    std::cout<<"\nInput Vector1: ";    
    for (int i = 0; i < N; i++) std::cout << vector1[i] << " ";
    //# STEP 1 : Create second vector, initialize to 20 and print values
    //# YOUR CODE GOES HERE
    std::vector<int> vector2(N, 20);
    std::cout<<"\nInput Vector2: ";
    for (int i = 0; i < N; i++) std::cout << vector2[i] << " ";
    //# Create Buffer
    buffer vector1_buffer(vector1);
    //# STEP 2 : Create buffer for second vector 
    //# YOUR CODE GOES HERE
    buffer vector2_buffer(vector2);
    //# Submit task to add vector
    queue q;
    q.submit([&](handler &h) {
      //# Create accessor for vector1_buffer
      accessor vector1_accessor (vector1_buffer,h);
      //# STEP 3 - add second accessor for second buffer
      //# YOUR CODE GOES HERE
      accessor vector2_accessor (vector2_buffer,h);
      h.parallel_for(range<1>(N), [=](id<1> index) {
        //# STEP 4 : Modify the code below to add the second vector to first one
        vector1_accessor[index] += vector2_accessor[index];
      });
   });
  //# Create a host accessor to copy data from device to host
  host_accessor h_a(vector1_buffer,read_only);
  //# Print Output values 
  std::cout<<"\nOutput Values: ";
  for (int i = 0; i < N; i++) std::cout<< vector1[i] << " ";
  std::cout<<"\n";
  return 0;
}

运行结果

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

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

相关文章

zookeeper本地部署和集群搭建

zookeeper&#xff08;动物园管理员&#xff09;是一个广泛应用于分布式服务提供协调服务Apache的开源框架 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它 负责存储和管理大家都关心的数据 &#xff0c;然 后 接受观察…

STM32单片机在线升级,手机在线升级STM32单片机,固件远程下载方法,局域网在线程序下载

STM32单片机&#xff0c;是我们最常见的一种MCU。通常我们在使用STM32单片机都会遇到程序在线升级下载的问题。 STM32单片机的在线下载通常需要以下几种方式完成&#xff1a; 1、使用ST提供的串口下载工具&#xff0c;本地完成固件的升级下载。 2、自行完成系统BootLoader的编写…

leetcode每日一题复盘(11.6~11.12)

leetcode 37 解数独 回溯算法的最后一种问题:棋盘问题,前面的N皇后也是棋盘问题,只不过N皇后只需要一层放一个数据,数独需要多次放入数据且保证数据不冲突 方法是通过bool返回值进行多次递归,每次递归放入一个数据,将该层数据填满后换下一层

【嵌入式开发学习】__串口丢数据的几个常见原因

前言 串口是工程师最常用的串行外设之一&#xff0c;但在实际应用中&#xff0c;还是会经常遇到各种问题&#xff0c;比如丢失一字节数据。 今天&#xff0c;我们就结合STM32来讲讲UART相关内容&#xff0c;以及容易丢失一字节数据的问题。 一、UART几个标志位 这里重点说一…

支付卡行业(PCI)PIN安全要求和测试程序 7个控制目标、33个要求及规范性附录ABC 密钥注入-PCI认证-安全行业基础篇4

概述 用于在ATM和POS终端进行在线和离线支付卡交易处理期间&#xff0c;对个人身份号码&#xff08;PIN&#xff09;数据进行安全管理、处理和传输。 该标准具体包括 7 个控制目标和 33 个安全要求&#xff0c; 标准的结构分为标准主体部分&#xff0c;标准附录&#xff08;N…

聚会娱乐喝酒游戏小程序源码系统 可开流量主 带完整的搭建教程

今天罗峰来给大家分享一款聚会娱乐喝酒游戏小程序源码系统 。在聚会娱乐活动中&#xff0c;喝酒游戏是一种非常受欢迎的活动方式。但是&#xff0c;往往由于缺乏有效的组织和规则&#xff0c;导致游戏的进行不够顺畅&#xff0c;甚至出现混乱的情况。因此&#xff0c;开发一款能…

Linux提权方法总结

1、内核漏洞提权 利用内核漏洞提取一般三个环节&#xff1a;首先对目标系统进行信息收集&#xff0c;获取系统内核信息及版本信息 第二步&#xff0c;根据内核版本获取对应的漏洞以及exp 第三步&#xff0c;使用exp对目标进行攻击&#xff0c;完成提权 注&#xff1a;此处可…

Spring Security使用总结三,编写一个注册页面,不知道你有没有强迫症

不像先有鸡还是先有蛋这种话题&#xff0c;对于系统来说必须要先注册再登录&#xff0c;所以这一章主要就是讲注册&#xff0c;对于注册来说首先就是要有一个注册的页面&#xff0c;从系统的安全角度去考虑&#xff0c;这个注册页面可以是系统自带的注册页面&#xff0c;也可以…

学习笔记|构建一元线性回归模型|方差分析|方差齐性|检验残差正态性|规范表达|《小白爱上SPSS》课程:SPSS第二十讲: 一元线性回归分析怎么做?

目录 学习目的软件版本原始文档一元线性回归分析一、实战案例二、统计策略三、SPSS操作四、结果解读第一个表格为模型摘要第二表格为方差分析表第三个表格为模型系数第四张散点图&#xff08;主要检验方差齐性&#xff09; 第五张直方图和P-P图&#xff08;检验残差正态性&…

PHP语言、B/S手术麻醉临床信息管理系统源码

手术麻醉临床信息管理系统有着完善的临床业务功能&#xff0c;能够涵盖整个围术期的工作&#xff0c;能够采集、汇总、存储、处理、展现所有的临床诊疗资料。通过该系统的实施&#xff0c;能够规范麻醉科的工作流程&#xff0c;实现麻醉手术过程的信息数字化&#xff0c;自动生…

虚析构函数

1)类指针指向本身的对象 Son *xiaoming new Son; delete xiaoming; 构造及析构顺序&#xff1a; 父类构造 子类构造&#xff1b; 子类析构&#xff1b; 父类析构。 2)父类指针指向子类对象,&#xff0c;父类析构函数不是虚函数 Father *father new Son; delete f…

Redis-持久化

RDB快照&#xff08;snapshot&#xff09; &#xff08;1&#xff09;Redis将内存数据库快照保存dump.rdb的二进制文件中 &#xff08;2&#xff09;Redis将内存flush到磁盘文件的默认策略&#xff1a; N秒内数据集至少有M个改动 &#xff08;3&#xff09;Redis允许手动flush&…

Android Studio(RecyclerView)

前言 ListView的缺点&#xff0c;在RecyclerView得到了补充改善&#xff08;横纵向排列子元素、多列布局等等&#xff09; 代码 前面在适配器章节已经介绍了其对应的适配器&#xff0c;这里就简单展示一下多列布局的页面效果和相关代码 <androidx.recyclerview.widget.Recyc…

干货|AI辅助完成论文的正确打开方式!

论文写作中可能遇到问题 1. 选题问题&#xff1a;是否无法确定研究方向和选择合适的题目&#xff1f; 2. 文献综述问题&#xff1a;是否困惑如何进行文献调研和综述&#xff1f; 3. 方法论问题&#xff1a;是否不知道该选择何种研究方法&#xff1f; 4. 数据处理问题&#…

【Kubernetes部署】通过Kubeadm部署Kubernetes高可用集群

Kubeadm 一、kubeadm部署思路二、基本架构2.1 资源分配2.2 系统初始化操作&#xff08;所有节点&#xff09;2.2.1关闭防火墙、selinux和swap分区2.2.2 修改主机名&#xff0c;添加域名映射2.2.3 内核相关2.2.4 加载ip_vs模块2.2.5 时间同步 三、部署docker3.1 通过yum安装dock…

10个免费3D模型网站

作为一名独立游戏开发者,自己创建图形、配乐、动画和更多东西是相当具有挑战性的。 创建资产所需的成本和时间有时是许多游戏开发商无法承受的。 这就是他们选择在互联网上搜索免费内容的原因。现在,在浩瀚的内容海洋中获得如此免费的东西有点困难。 本文列出了 10 个免费 3D…

C语言34种运算符的用法解析

C 算术运算符 操作员运算符的含义加法或一元加法-减法或一元减法*乘法/分配%除法后的余数&#xff08;模除&#xff09; // 算数运算符的使用 #include <stdio.h> int main() {int a 9,b 4, c;c ab;printf("ab %d \n",c);c a-b;printf("a-b %d \n…

R语言环境下使用curl库做的爬虫代码示例

curl库是一个用于传输数据的工具和库&#xff0c;它支持多种协议&#xff0c;包括HTTP、FTP、SMTP等。在爬虫中&#xff0c;curl库可以用来获取网页内容&#xff0c;从而实现爬取网页的功能。通过设置curl的选项&#xff0c;可以实现对网页的请求、响应、重定向等操作。在使用c…

【前段基础入门之】=>CSS3新特性 @keyframes 动画

导语 在 CSS3 新特性中&#xff0c;新增了动画效果 的定义方式&#xff0c;这使得我们可以通过使用 CSS&#xff0c;从而开发出精美的动画效果&#xff0c;所以本章节&#xff0c;就来详细聊一聊如何通过 CSS 去创建一个动画效果案例 帧 **学习动画之前&#xff0c;我们得先了…

windows11 画图软件调整图片大小

win11自带的画图功能可以调整图片的大小和尺寸 搜索 画图&#xff0c;点击画图应用&#xff0c;打开图片 要把图片调整成800*1200。先打开文件菜单 选择图像属性 此处可以调整图片的尺寸和大小&#xff08;非等比例调整&#xff09; 选择图像下调整大小&#xff08;等比例调整…