▶ 使用 kernels 导语并行化 for 循环

● 一重循环

 #include <stdio.h>
#include <time.h>
#include <openacc.h> const int row = * * ; int main()
{
int a[row], b[row], c[row];
for (int i = ; i < row; ++i) // 填充 a 和 b
a[i] = b[i] = i; clock_t time = clock();
#ifdef _OPENACC // 使用 OpenACC 时执行本段
#pragma acc kernels
for (int i = ; i < row; ++i) // c = a + b
c[i] = a[i] + b[i];
time = clock() - time;
printf("\nTime with acc:%d ms\n", time);
#else // 不用 OpenACC 时执行本段
for (int i = ; i < row; i++)
c[i] = a[i] + b[i];
time = clock() - time;
printf("\nTime without acc:%d ms\n", time);
#endif
getchar();
return ;
}

● 输出结果

D:\Code\OpenACC>pgcc main.c -o main-no-acc.exe -Minfo                                   // 编译,-Minfo 要求输出编译优化信息,没有额外输出

D:\Code\OpenACC>pgcc main.c -o main.exe -Minfo -acc                                     // 编译,-acc 要求使用 OpenACC
main:
, Generating implicit copyin(b[:row]) // 数据管理控制
Generating implicit copyout(c[:row])
Generating implicit copyin(a[:row])
, Loop is parallelizable // 并行优化
Generating Tesla code
, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */ // 使用默认 vector 尺寸,注释是自动生成的 D:\Code\OpenACC>main-no-acc.exe Time without acc: ms D:\Code\OpenACC>main-acc.exe
launch CUDA kernel file=D:\Code\OpenACC\main.c function=main line= device= threadid= num_gangs= num_workers= vector_length= grid= block=
// 对代码第 16 行的 for 进行了并行优化,
Time with acc: ms // 使用第 0 号设备(GPU)
// 线程编号 1,使用 gang 65536 个,worker 1 个,vector 宽度 128
// CUDA 配置为 gridDim.x = 65536,blockDim.x = 128Time
// 每单元计算负载 = row / grid / block = 2

● 二重循环

 #include <stdio.h>
#include <time.h>
#include <openacc.h> const int row = * , col = ; int main()
{
int a[row][col], b[row][col], c[row][col];
for (int i = ; i < row; i++) // 填充 a 和 b
{
for (int j = ; j < col; j++)
a[i][j] = b[i][j] = i * j;
} clock_t time = clock();
#ifdef _OPENACC
#pragma acc kernels
for (int i = ; i < row; i++) // c = a + b
{
for (int j = ; j < col; j++)
c[i][j] = a[i][j] + b[i][j];
}
time = clock() - time;
printf("\nTime with acc:%d ms\n", time);
#else
for (int i = ; i < row; i++)
{
for (int j = ; j < col; j++)
c[i][j] = a[i][j] + b[i][j];
}
time = clock() - time;
printf("\nTime without acc:%d ms\n", time);
#endif
getchar();
return ;
}

● 输出结果

D:\Code\OpenACC>pgcc main.c -o main-no-acc.exe -Minfo

D:\Code\OpenACC>pgcc main.c -o main-acc.exe -Minfo -acc
main:
, Generating implicit copyin(a[:row][:col])
Generating implicit copyout(c[:row][:col])
Generating implicit copyin(b[:row][:col])
, Loop is parallelizable
, Loop is parallelizable
Generating Tesla code
, #pragma acc loop gang, vector(4) /* blockIdx.y threadIdx.y */ // 高一层的循环使用的是 worker
, #pragma acc loop gang, vector(32) /* blockIdx.x threadIdx.x */ D:\Code\OpenACC>main-no-acc.exe Time without acc: ms D:\Code\OpenACC>main-acc.exe
launch CUDA kernel file=D:\Code\OpenACC\main.c function=main line= device= threadid= num_gangs= num_workers= vector_length= grid=16x2048 block=32x4
// 注意参数变化,仍有 num_gangs = grid,num_workers * vector_length = block
Time with acc: ms // 每单元计算负载 = row * col / grid / block = 4

● 三重循环

 #include <stdio.h>
#include <time.h>
#include <openacc.h> const int row = , col = , page = ; int main()
{
int a[row][col][page], b[row][col][page], c[row][col][page];
for (int i = ; i < row; i++) // 填充 a 和 b
{
for (int j = ; j < col; j++)
{
for (int k = ; k < page; k++)
a[i][j][k] = b[i][j][k] = i * j + k;
}
}
clock_t time = clock();
#ifdef _OPENACC
#pragma acc kernels
for (int i = ; i < row; i++) // c = a + b
{
for (int j = ; j < col; j++)
{
for (int k = ; k < page; k++)
c[i][j][k] = a[i][j][k] + b[i][j][k];
}
}
time = clock() - time;
printf("\nTime with acc:%d ms\n", time);
#else
for (int i = ; i < row; i++)
{
for (int j = ; j < col; j++)
{
for (int k = ; k < page; k++)
c[i][j][k] = a[i][j][k] + b[i][j][k];
}
}
time = clock() - time;
printf("\nTime without acc:%d ms\n", time);
#endif
getchar();
return ;
}

● 输出结果

D:\Code\OpenACC>pgcc main.c -o main-no-acc.exe -Minfo

D:\Code\OpenACC>pgcc main.c -o main-acc.exe -Minfo -acc
main:
, Generating implicit copyin(b[:row][:col][:page])
Generating implicit copyout(c[:row][:col][:page])
Generating implicit copyin(a[:row][:col][:page])
, Loop is parallelizable
, Loop is parallelizable
, Loop is parallelizable
Generating Tesla code
, #pragma acc loop gang /* blockIdx.y */ // 最高层循环尝试调整 grid
, #pragma acc loop gang, vector(4) /* blockIdx.z threadIdx.y */
, #pragma acc loop gang, vector(32) /* blockIdx.x threadIdx.x */ D:\Code\OpenACC>main-no-acc.exe Time without acc: ms D:\Code\OpenACC>main-acc.exe
launch CUDA kernel file=D:\Code\OpenACC\main.c function=main line= device= threadid= num_gangs= num_workers= vector_length= grid=16x128x16 block=32x4
// grid 变成了三维
Time with acc: ms // 每单元计算负载 = row *col * page / grid / block = 4
// row 改为 64,则 grid=16x128x16 block=32x4,计算负载 = 2
// col 改为 128,则 grid=16x128x16 block=32x4,计算负载 = 2
// page 改为 256,则 grid=8x128x32 block=32x4,计算负载 = 2
// row 改为 32,则 grid=16x32x64 block=32x4,计算负载 = 1

● 在 ubuntu 上跑一重循环的代码,注意计时器单位是 μs

cuan@CUAN:~/Temp$ pgcc -acc main.c -o main.exe
cuan@CUAN:~/Temp$ pgcc main.c -o main-no-acc.exe
cuan@CUAN:~/Temp$ ./main.exe Time with acc: us cuan@CUAN:~/Temp$ ./main-no-acc.exe Time without acc: us

OpenACC kernels的更多相关文章

  1. 7.OpenACC

    OpenACC: openacc 可以用于fortran, c 和 c++程序,可以运行在CPU或者GPU设备. openacc的代码就是在原有的C语言基础上进行修改,通过添加:compiler di ...

  2. OpenACC 梯度下降法求解线性方程的优化

    ▶ 书上第二章,用一系列步骤优化梯度下降法解线性方程组.才发现 PGI community 编译器不支持 Windows 下的 C++ 编译(有 pgCC 命令但是不支持 .cpp 文件,要专业版才支 ...

  3. OpenACC 优化矩阵乘法

    ▶ 按书上的步骤使用不同的导语优化矩阵乘法 ● 所有的代码 #include <iostream> #include <cstdlib> #include <chrono ...

  4. OpenACC 与 CUDA 的相互调用

    ▶ 按照书上的代码完成了 OpenACC 与CUDA 的相互调用,以及 OpenACC 调用 cuBLAS.便于过程遇到了很多问题,注入 CUDA 版本,代码版本,计算能力指定等,先放在这里,以后填坑 ...

  5. OpenACC Julia 图形

    ▶ 书上的代码,逐步优化绘制 Julia 图形的代码 ● 无并行优化(手动优化了变量等) #include <stdio.h> #include <stdlib.h> #inc ...

  6. OpenACC 异步计算

    ▶ 按照书上的例子,使用 async 导语实现主机与设备端的异步计算 ● 代码,非异步的代码只要将其中的 async 以及第 29 行删除即可 #include <stdio.h> #in ...

  7. OpenACC 书上的范例代码(Jacobi 迭代),part 3

    ▶ 使用Jacobi 迭代求泊松方程的数值解 ● 使用 data 构件,强行要求 u0 仅拷入和拷出 GPU 各一次,u1 仅拷入GPU 一次 #include <stdio.h> #in ...

  8. OpenACC数据管理语句

    ▶ 书中第4章,数据管理部分的代码和说明 ● 代码,关于 copy,copyin,copyout,create #include <stdio.h> #include <openac ...

  9. OpenACC 书上的范例代码(Jacobi 迭代),part 2

    ▶ 使用Jacobi 迭代求泊松方程的数值解 ● 首次使用 OpenACC 进行加速,使用动态数组,去掉了误差控制 #include <stdio.h> #include <stdl ...

随机推荐

  1. 51Nod:1003 阶乘后面0的数量

    1003 阶乘后面0的数量  基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题  收藏  关注 n的阶乘后面有多少个0? 6的阶乘 = 1*2*3*4*5*6 = 72 ...

  2. 1010. Radix (25) pat

    Given a pair of positive integers, for example, 6 and 110, can this equation 6 = 110 be true? The an ...

  3. android 学习过程中登陆失效的个人理解

    今天在学习的过程中,要做登陆失效的功能,所以就找了些资料.好好看了一下.研究了一番,慢慢的做出来了! 比方:你在一个手机端登陆了账号,在另外的一个手机端也登陆了账号,此时.前一个手机端的账号会提示登陆 ...

  4. MySQLi基于面向对象的编程

    http://blog.csdn.net/koastal/article/details/50650500

  5. 如何开启GZIP

    服务器设置 gzip 压缩是 web 开发里很普遍的做法.假设你要请求一个 100k 的文件,网络传输速度为 50k/s,需要 2s 才能得到数据,但是如果在服务器设置了 gzip 压缩,将服务端的文 ...

  6. sprintf拼接字符串的问题

    ] = {}; char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', ...

  7. 【转】每天一个linux命令(8):cp 命令

    原文网址:http://www.cnblogs.com/peida/archive/2012/10/29/2744185.html cp命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一 ...

  8. vue 项目中,定时器(setInterval)的写法

    vue 项目中,定时器(setInterval)的写法: fetchJobList是一个方法,里面有dispatch一个action进行请求接口的代码. data () { return { inte ...

  9. Spring MVC 向页面传值-Map、Model、ModelMap、ModelAndView

    Spring MVC 向页面传值,有4种方式: ModelAndView Map Model ModelMap 使用后面3种方式,都是在方法参数中,指定一个该类型的参数. Model Model 是一 ...

  10. net core 2.0学习笔记(一):开发运行环境搭建 (转)

    期待已久的.net core 2.0终于发布了!大家等的花儿都谢了. 不过比预期提前了一个多月,这在微软历史上还真的不多见.按照历史经验看,2.0版本应该比较靠谱,我猜这也是社区非常火爆的原因吧.下面 ...