今年运气比较好,学了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. Objective-C Classes Are also Objects

    https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC ...

  2. Codeforces Round #603 (Div. 2) D. Secret Passwords(并查集)

    链接: https://codeforces.com/contest/1263/problem/D 题意: One unknown hacker wants to get the admin's pa ...

  3. 简单双向链表的实现&新约瑟夫问题

    题目描述: 给定m个人,从s开始报数,数字顺加,报到n的人出列,然后数字顺减报到k的人出列,求出列顺序 样例输入: 8 1 3 2 样例输出: 3 6 1 5 2 8 4 7 分析: 约瑟夫问题主要就 ...

  4. MongoDB shell 3 集合方法

    方法名 描述 db.collection.aggregate() 聚合,主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果 db.collection.bulkWrite() 批量写入 ...

  5. Numpy | 11 迭代数组

    NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式. 迭代器最基本的任务的可以完成对数组元素的访问. 实例1:使用 arange() 函数创建一个 2x3 ...

  6. vuex传递数据的流程

    当组件修改数据的时候必须通过store.dispatch来调用actions中的方法,当actions中的方法被触发的时候通过调用commit的方法来触发mutations里面的方法,mutation ...

  7. kafka消费端提交offset的方式

    Kafka 提供了 3 种提交 offset 的方式 自动提交 复制 1234 consumer.commitSync(); 手动异步提交 offset 复制 1 consumer.commitAsy ...

  8. vs2017使用OpenGL的方法

    第一步:将相应的.lib和.h文件放到相应的文件夹中,具体如下: 将GLAUX.LIB,GLU32.LIB,OPENGL32.LIB 放到....\VC\Tools\MSVC\14.10.25017\ ...

  9. 洛谷P2607题解

    想要深入学习树形DP,请点击我的博客. 本题的DP模型同 P1352 没有上司的舞会.本题的难点在于如何把基环树DP转化为普通的树上DP. 考虑断边和换根.先找到其中的一个环,在上面随意取两个点, 断 ...

  10. 【CSP模拟赛】Freda的旗帜

    题目描述  要开运动会了,Freda承担起了制作全校旗帜的工作.旗帜的制作方法是这样的:Freda一共有C种颜色的布条,每种布条都有无数个,你可以认为这些布条的长.宽.厚都相等,只有颜色可能不同.每个 ...