今年运气比较好,学了cuda之后,了解到了gpu的另两种使用语言opencl和openacc, 

opencl(Open Computing Language ,开放计算语言)是面向异构系统的并行编程语言的免费标准,支持多种设备,包含CPU(多核多线程CPU),GPU(NVIDIA,AMD),数字信号处理器(居然还支持DSP),但缺点是对源代码进行并行改进的代码量较大; 

OpenACC与cudac和opencl不同,不需要学习相对更底层的东西,不需要对代码进行很大的改进,在代码中间加上相应的指令,再用相应的编译器进行编译就能对源程序进行加速,因为是编译器自动转换为并行处理的语言所以效率比不上用cuda或着用OpenCL对源代码进行改进的效率,而且现在OpenACC只支持C/C++,Fortran(比较幸运的是之前支持OpenACC的编译器PGI只能免费试用1个月,购买要正版1w多,今年刚刚开放社区版即免费版本,这么好的东西不试一下太可惜了) 

OpenACC指令包含 导语和子语两部分如:

#pragma acc loop independent
  • 1
  • 1

中#pragma acc loop 是导语,independent是子语,导语的作用是告诉编译器接下来代码中大致要转换为怎样的并行代码(实现什么功能),子语的作用是帮助编译器更精确地改代码,具体的作用可以在用的过程中理解; 

要使用OpenACC的指令要使用相应的编译器,比如gcc不支持OpenACC 

用以下代码来验证:

#include<stdio.h>
#ifdef _OPENACC
#include<openacc.h>
#endif
int main()
{
#ifdef OPENACC
printf("Number of device :%d\n",acc_get_num_devices(acc_device_not_host));
#else
printf("OpenACC is not support.\n");
#endif
return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果用gcc进行编译 

gcc test.c -o test.c 

./test.exe 

会出现 OpenACC is not support 

用支持OpenACC的PGI编译器进行编译: 

pgcc -acc test.c -o test.exe 

./test.exe 

会出现Number of device :1 

支持OpenACC的设备为一个 

像cuda一样先学习循环数组进行

#include<stdio.h>
#define N 256
int main()
{
int i,a[N],b[N],c[N];
for(i=0;i<N;i++)
{
a[i]=0;
b[i]=c[i]=i;
}
#pragma acc kernels
for(i=0;i<N;i++)
{
a[i]=b[i]+c[i];
}
printf("a[N-1]=%d \n",a[N-1]);
return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

这里通过在循环前面加上#pragma acc kernels指令来将下面的循环改为并行处理。 

通过pgcc进行编译后执行可以得到结果; 

pgcc -acc -Minfo klc.c -o klc.exe 

通过在 选项-Minfo可以返回一些编译信息: 

设置PGI编译器环境的变量:export PGI_ACC_NOTITY=1 

将环境变量告诉编译器可以得到运行程序时输出的一些CUDA内核配置 

./klc.exe 

launch CUDA kernel file=… 

function =main line=12 device=0,threadid=1 num_gangs=2 num_workers=1 vector_length=128 grid=2 block=128 

OpenACC中gangs,workers,vectors类似于CUDA中的grids,blocks,threads来表示线程数,线程块数,不同的是在CUDA中这些量可以表示为三维的结构,而在OpenACC中表示为一维,其中gangs对应blocks,workers、vectors对应threads; 

读《OpenACC并行编程实战》后记

OpenACC中常用的一些导语与子语 : 

#pragma acc kernels 

如同上一篇代码所显示,在代码前之间加上,编译器发现这一指令时会自动将接下来代码中可以改动的改成并行

#include<stdio.h>
#define N 256
int main()
{
int i,a[N],b[N],c[N];
for(i=0;i<N;i++)
{
a[i]=0;
b[i]=c[i]=i;
}
#pragma acc kernels
for(i=0;i<N;i++)
{
a[i]=b[i]+c[i];
}
printf("a[N-1]=%d \n",a[N-1]);
return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

一重循环嵌套启用一个或多个gangs和相应的vectors来实现多线程, 

二重循环嵌套和三重循环嵌套时增加gangs和works来实现多线程; 

如果想看经过编译后的代码,可以在编译的时候选用选项nollvm和keepgpu 

pgcc -acc -Minfo -ta=tesla:nollvm,keepgpu test.c 

可能得到中间代码文件 test.n001.gpu ,其中tesla为显卡的架构 

#pragma acc loop 

用loop相对于前面的kernel,可以更加准确地指导编译器的并行化工作 

loop导语直接跟着循环语句 

loop在使用时会自动检测数据的依赖性,当数据相互依赖时会将数据串行运行如下面例子:

#include<stdio.h>
#define N 1024
int main()
{
int i,a[N],b[N],c[N];
for(i=0;i<N;i++)
{
a[i]=0;
b[i]=c[i]=i;
}
#pragma acc kernels
{
#pragma acc loop
for(i=0;i<N;i++)
a[i]=b[i]+c[i];
#pragma acc loop
for(i=0;i<N;i++)
b[i]=b[i-1];
}
printf("b[2]=%d\n",b[2]);
return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

显然第一个loop下面的循环中的数据不是相互依赖的可以转化为并行, 

第二个loop下面的循环中数据是相互依赖的,所以只能以串行的方式进行 

最后返回值为:

b[2]=0;
  • 1
  • 1

independent子语告诉编译器该循环的迭代步是相互独立的,强制允许生成并行代码

#include<stdio.h>
#define N 1024
int main()
{
int i,a[N],b[N],c[N];
for(i=0;i<N;i++)
{
a[i]=0;
b[i]=c[i]=i;
}
#pragma acc kernels
{
#pragma acc loop
for(i=0;i<N;i++)
a[i]=b[i]+c[i];
#pragma acc loop independent
for(i=0;i<N;i++)
b[i]=b[i-1];
}
printf("b[2]=%d\n",b[2]);
return 0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

编译器将不检测循环内数据的依赖性而选择并行处理,最终结果为:

b[2]=1
  • 1
  • 1

用independent子语时编译器可能会误解原程序想表达的意思,所以要注意; 

reduction子语: 

reduction子语常用语一些计算的求和,乘积等,以求和为例: 
s=∑ni=1ai=s1+s2=∑n1i=1ai+∑ni=n1+1ai 

将数据分成两部分相加,最后再赋给s,相乘也一样 

在c/c++中reduction子语试用于int,float,doubl,complex,char,wchar_t,适用于:+,*,max,min,&,|,%,&&,|| 

用法如下面例子:

#include<stdio.h>
#define N 101
int main()
{
int a[N],i,ired;
for(i=0;i<N;i++)
a[i]=i;
ired=0;
#pragma acc parallel
{
#pragma acc loop reduction(+;ired)
for(i=0;i<N;i++)
ired+=a[i];
}
printf("ired=%d\n",ired);
return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在reduction(;)第一个参数为数学符号,第二个参数为最后赋予值的变量

【ARM-Linux开发】OpenACC并行编程实战笔记的更多相关文章

  1. Linux下的C编程实战

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来, Linu ...

  2. 《OpenCL异构并行编程实战》补充笔记散点,第一至四章

    ▶ 总体印象:适合 OpenCL 入门的书,有丰富的代码和说明,例子较为简单.先把 OpenCL 代码的基本结构(平台 → 设备 → 上下文 → 命令队列 → 创建缓冲区 → 读写缓冲区 → 编译代码 ...

  3. 《Visual C++并行编程实战》译者序

    说来凑巧,当开始着手这本书的翻译时,我刚刚入手了自己第一台四核计算机,而翻译工作临近完成之时,我又为自己添置了一台iPad 2(这是一台双核计算机).由此可见,多核计算机已经完全进入了我的日常生活.鉴 ...

  4. 在Ubuntu上建立Arm Linux 开发环境

    我使用的是友善2410的板子,以前都是用Fedora,现在家里的电脑被我转为Linux专用的了,装的是Ubuntu.但是嵌入式还是要玩的,在装载过程中也遇到一些小麻烦.在此记录一下,一来自己比较健忘, ...

  5. Java并发编程实战.笔记十一(非阻塞同步机制)

    关于非阻塞算法CAS. 比较并交换CAS:CAS包含了3个操作数---需要读写的内存位置V,进行比较的值A和拟写入的新值B.当且仅当V的值等于A时,CAS才会通过原子的方式用新值B来更新V的值,否则不 ...

  6. 《Linux多线程服务端编程》笔记——多线程服务器的适用场合

    如果要在一台多核机器上提供一种服务或执行一个任务,可用的模式有 运行一个单线程的进程 运行一个多线程的进程 运行多个单线程的进程 运行多个多线程的进程 这些模式之间的比较已经是老生常谈,简单地总结 模 ...

  7. 《Linux多线程服务端编程》笔记——线程同步精要

    并发编程基本模型 message passing和shared memory. 线程同步的四项原则 尽量最低限度地共享对象,减少需要同步的场合.如果确实需要,优先考虑共享 immutable 对象. ...

  8. 《OpenCL异构并行编程实战》补充笔记散点,第五至十二章

    ▶ 第五章,OpenCL 的并发与执行模型 ● 内存对象与上下文相关而不是与设备相关.设备在不同设备之间的移动如下,如果 kernel 在第二个设备上运行,那么在第一个设备上产生的任何数据结果在第二个 ...

  9. 成功移植SQLite3到ARM Linux开发板

    SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了 ...

随机推荐

  1. python列表各种切片姿势

    顺着切,反着切,想怎么切就怎么切,但是别被坑. mylist = [1,2,3,4,5,6,7,8,9] print(mylist[2:7:2]) # [3, 5, 7] print(mylist[: ...

  2. hive中时间操作(二)

    转:https://blog.csdn.net/qq646748739/article/details/77997276 --Hive中日期函数总结:--1.时间戳函数--日期转时间戳:从1970-0 ...

  3. live-pusher属性值的改变

    例如:组件推流过程中,切换前后摄像头时,要改变mirror的值并使其生效: LivePusherContext = wx.createLivePusherContext() 1. LivePusher ...

  4. MySQL - binlog日志简介及设置

    基本概念 binlog是Mysql sever层维护的一种二进制日志,与innodb引擎中的redo/undo log是完全不同的日志:其主要是用来记录对mysql数据更新或潜在发生更新的SQL语句, ...

  5. Ajax无法访问回调函数seccess问题

    1,后台返回的数据是标准json格式,前端dataType也是josn, 2,没有跨域访问, 但是一直只执行error方法, 原因出在: 应设置为button按钮,指明类型为button

  6. 使用viper 进行golang 应用的配置管理

    viper 是一个强大的golang 配置管理包,支持多种配置格式内容的读取,同时支持读取key/value 存储的数据 而且不只是读取内容 ,同时也包含了,配置的写入操作. 以下是一个简单的demo ...

  7. apache-maven安装

    1.下载maven 网址:http://maven.apache.org 2.下载maven和安装 由于最新版的可能会有问题,我选择下载旧版本 一般都下载二进制的zip文件 解压后文件夹apache- ...

  8. request和response文件下载案例

    一.需求分析 * 文件下载需求: 1. 页面显示超链接 2. 点击超链接后弹出下载提示框 3. 完成图片文件下载 * 分析: 1. 超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析 ...

  9. 在Eclipse打开css文件时,会自动调用文本编辑器打开,而不是在Eclipse中打开

    问题描述 在Eclipse中打开css文件时候,如下图,使用系统自带的文本编辑器打开 解决方案 点击Window下的Preference,找到File Associations,然后点击Add,将cs ...

  10. kubernetes --- weave

    #wget 'https://cloud.weave.works/launch/k8s/weavescope.yaml?k8s-service-type=NodePort&k8s-versio ...