今年运气比较好,学了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. post Cache

    http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5 POST The POST method is used to request ...

  2. Oracle逻辑导入数据(IMP/IMPDP)

    使用IMPDP导入数据的前提是数据是使用EMPDP导出的,同样也是在DOS窗口下直接输入IMPDP和登录数据库的用户名,即可导人数据. impdp导到指定用户下: impdp student/1234 ...

  3. 通过100张图一步步理解CNN

    https://blog.csdn.net/v_july_v/article/details/79434745 Youtube上迄今为止最好的卷积神经网络快速入门教程 https://www.bili ...

  4. [Algorithm] 242. Valid Anagram

    Given two strings s and t , write a function to determine if t is an anagram of s. Example 1: Input: ...

  5. 爬虫高性能asyncio+ahttpio

    async实现协程,异步编程 我们都知道,现在的服务器开发对于IO调度的优先级控制权已经不再依靠系统,都希望采用协程的方式实现高效的并发任务,如js.lua等在异步协程方面都做的很强大. python ...

  6. 浅谈LCA

    目录 什么是LCA 倍增求LCA dfs bfs 树剖求LCA 什么是LCA LCA就是最近公共祖先 对于有根树\(Tree\)的两个结点\(u.v\),最近公共祖先\(LCA(T,u,v)\)表示一 ...

  7. 【UVA1057】Routing

    [UVA1057]Routing 题面 洛谷 题解 有一个比较好想的dp就是\(f_{i,j}\)表示第一个点在\(i\),第二个点在\(j\)的最小点数,但是直接搞不好转移. 考虑建出反图,那么\( ...

  8. 洛谷P2949题解

    若想要深入学习反悔贪心,传送门. Description: 有 \(n\) 项工作,每 \(i\) 项工作有一个截止时间 \(D_i\) ,完成每项工作可以得到利润 \(P_i\) ,求最大可以得到多 ...

  9. Flume 实战,将多台机器日志直接收集到 Kafka

    目前我们使用的一个 b 端软件的报错日志分散在集群各处,现在想把它收集到一个地方然后统一丢进 Kafka 提供给下游业务进行消费. 我想到了 flume,之前让同事搭建的这次自己想多了解一些细节于是就 ...

  10. 在vb.net中使用委托:经理 和 员工

    现在开发的一个 vb.net系统,其中有两个窗体:alert窗体和 case窗体. 在alert窗体中列出了当前可以操作的若干个alert(可以理解为数据记录),用户可以选择将其中一个或几个alert ...