今年运气比较好,学了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. java 如何用pattern 和 Matcher 来使用正则表达式(一)

    近期用到了java或者scala的正则表达式的用法,抽点时间总结一下: 转自:https://www.cnblogs.com/haodawang/p/5967219.html java的regex库 ...

  2. router.beforeEach、路由元信息、导航守卫与函数式编程

    一.函数的识别: 1.router.beforeEach:主函数.高阶函数.入口函数: 2.匿名参量函数:处理跳转过程中的附加逻辑 (to, from, next) => { if (to.ma ...

  3. flutter中的异步机制Future

    饿补一下Flutter中Http请求的异步操作. Dart是一个单线程语言,可以理解成物理线路中的串联,当其遇到有延迟的运算(比如IO操作.延时执行)时,线程中按顺序执行的运算就会阻塞,用户就会感觉到 ...

  4. CVE-2017-7494复现 Samba远程代码执行

    Samba是在Linux和Unix系统上实现Smb协议的一个免费软件,由服务器及客户端程序构成,Samba服务对应的TCP端口有139.445等.Smb一般作为文件共享服务器,专门提供Linux与Wi ...

  5. redisql 试用

    redisql 是一个redis 模块,可以让redis 支持sql 查询,基于rust编写 具有以下特性 快速,每秒130k的插入 使用标准sql 容易操作,基于redis,使用标准的redis 二 ...

  6. 记录一次JVM配置优化的案例

    上周公司有一个应用,一到晚上高峰期的时候RT(响应时间)就很长.后来上服务器看了下JVM的配置,发现运维在启动参数那里把-Xss给设成了10M.导致每个线程占用的内存过大,导致内存消耗过快,其它线程排 ...

  7. data.table

    data.table: Extension of 'data.frame' 安装 data.table install.packages("data.table") 官网:http ...

  8. Oracle之clob字段不能union的问题

    原因:由于clob类型字段不能使用group by函数,而union中需要使用group by过滤掉重复纪录: 解决方法:union可以改为union all.

  9. 高通平台sensor框架图【学习笔记】

  10. JPA的懒加载

    JPA数据懒加载LAZY和实时加载EAGER(二)   懒加载LAZY和实时加载EAGER的概念,在各种开发语言中都有广泛应用.其目的是实现关联数据的选择性加载,懒加载是在属性被引用时,才生成查询语句 ...