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

● 一重循环

  1. #include <stdio.h>
  2. #include <time.h>
  3. #include <openacc.h>
  4.  
  5. const int row = * * ;
  6.  
  7. int main()
  8. {
  9. int a[row], b[row], c[row];
  10. for (int i = ; i < row; ++i) // 填充 a 和 b
  11. a[i] = b[i] = i;
  12.  
  13. clock_t time = clock();
  14. #ifdef _OPENACC // 使用 OpenACC 时执行本段
  15. #pragma acc kernels
  16. for (int i = ; i < row; ++i) // c = a + b
  17. c[i] = a[i] + b[i];
  18. time = clock() - time;
  19. printf("\nTime with acc:%d ms\n", time);
  20. #else // 不用 OpenACC 时执行本段
  21. for (int i = ; i < row; i++)
  22. c[i] = a[i] + b[i];
  23. time = clock() - time;
  24. printf("\nTime without acc:%d ms\n", time);
  25. #endif
  26. getchar();
  27. return ;
  28. }

● 输出结果

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

● 二重循环

  1. #include <stdio.h>
  2. #include <time.h>
  3. #include <openacc.h>
  4.  
  5. const int row = * , col = ;
  6.  
  7. int main()
  8. {
  9. int a[row][col], b[row][col], c[row][col];
  10. for (int i = ; i < row; i++) // 填充 a 和 b
  11. {
  12. for (int j = ; j < col; j++)
  13. a[i][j] = b[i][j] = i * j;
  14. }
  15.  
  16. clock_t time = clock();
  17. #ifdef _OPENACC
  18. #pragma acc kernels
  19. for (int i = ; i < row; i++) // c = a + b
  20. {
  21. for (int j = ; j < col; j++)
  22. c[i][j] = a[i][j] + b[i][j];
  23. }
  24. time = clock() - time;
  25. printf("\nTime with acc:%d ms\n", time);
  26. #else
  27. for (int i = ; i < row; i++)
  28. {
  29. for (int j = ; j < col; j++)
  30. c[i][j] = a[i][j] + b[i][j];
  31. }
  32. time = clock() - time;
  33. printf("\nTime without acc:%d ms\n", time);
  34. #endif
  35. getchar();
  36. return ;
  37. }

● 输出结果

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

● 三重循环

  1. #include <stdio.h>
  2. #include <time.h>
  3. #include <openacc.h>
  4.  
  5. const int row = , col = , page = ;
  6.  
  7. int main()
  8. {
  9. int a[row][col][page], b[row][col][page], c[row][col][page];
  10. for (int i = ; i < row; i++) // 填充 a 和 b
  11. {
  12. for (int j = ; j < col; j++)
  13. {
  14. for (int k = ; k < page; k++)
  15. a[i][j][k] = b[i][j][k] = i * j + k;
  16. }
  17. }
  18. clock_t time = clock();
  19. #ifdef _OPENACC
  20. #pragma acc kernels
  21. for (int i = ; i < row; i++) // c = a + b
  22. {
  23. for (int j = ; j < col; j++)
  24. {
  25. for (int k = ; k < page; k++)
  26. c[i][j][k] = a[i][j][k] + b[i][j][k];
  27. }
  28. }
  29. time = clock() - time;
  30. printf("\nTime with acc:%d ms\n", time);
  31. #else
  32. for (int i = ; i < row; i++)
  33. {
  34. for (int j = ; j < col; j++)
  35. {
  36. for (int k = ; k < page; k++)
  37. c[i][j][k] = a[i][j][k] + b[i][j][k];
  38. }
  39. }
  40. time = clock() - time;
  41. printf("\nTime without acc:%d ms\n", time);
  42. #endif
  43. getchar();
  44. return ;
  45. }

● 输出结果

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

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

  1. cuan@CUAN:~/Temp$ pgcc -acc main.c -o main.exe
  2. cuan@CUAN:~/Temp$ pgcc main.c -o main-no-acc.exe
  3. cuan@CUAN:~/Temp$ ./main.exe
  4.  
  5. Time with acc: us
  6.  
  7. cuan@CUAN:~/Temp$ ./main-no-acc.exe
  8.  
  9. 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. (6)time&datetime(时间模块)

    什么是时间模块 就是处理时间相关的功能 如用户注册的时间.统计程序运行的时间等 time 模块  计算机中有三种时间 1.时间戳 从1970年到今天,这个时间段中间经历的秒数 获取时间戳:time.t ...

  2. 【java规则引擎】《Drools7.0.0.Final规则引擎教程》第4章 4.2 ruleflow-group&salience

    转载至:https://blog.csdn.net/wo541075754/article/details/75299888 ruleflow-group 在使用规则流的时候要用到ruleflow-g ...

  3. PostgREST docker-compose 试用

    PostgREST 是一款很不错的直接将pg 数据库暴露为restapi ,使用了基于行级别安全访问控制, 比较全的restapi 查询以及集成了swagger openapi docker-comp ...

  4. 系列文章--jQuery教程

    从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery (四) 使用jQu ...

  5. oracle之 11.2.0.4 bbed安装

    一. bbed安装: 1.ORACLE 11G下安装BBED,需要从ORACLE 10G中复制三个包 sbbdpt.o .ssbbded.o 并将两个文件移到$ORACLE_HOME/rdbms/li ...

  6. c#中如何保存焦点控件?

    对所有文本框添加焦点获得事件,头部再定义一个全局的object或者control的类型对象,在焦点获得事件中把当前控件对象赋值给之前定义的object或者control对象,操作的话就对这个全局量操作 ...

  7. Microsoft Dynamics CRM4.0 创建单据的时候,自动生成单据编号的通用方法

    一.新建两个实体,具体如下: 单据流水号(new_maxbillcode) 显示名称 名称 类型 格式 最大长度 需求级别 IME模式 备注 名称 new_name nvarchar 文本 100 业 ...

  8. ExtJS中,将Grid表头中的全选复选框取消复选

    今天发现公司产品用的EXTJS中使用Grid时,Grid表头中的全选复选框的选中状态不是很准确,就写了这个小扩展 在js中加入下面方法,在需要取消全选的地方调用即可,例:Ext.getCmp('gri ...

  9. "二阶“条件概率

    公式: P(E|F)=P(E|GF)P(G|F)+P(E|GcF)P(Gc|F) 解释: 已知F发生,E发生的条件概率为P(E|F). 现在多考虑一个条件G,G可能发生也可能不发生. 若F已发生条件下 ...

  10. 【ActiveMQ入门-5】ActiveMQ学习-消息持久性

    ActiveMQ中的消息持久性     ActiveMQ很好的支持了消息的持久性(Persistence).消息持久性对于可靠消息传递来说应该是一种比较好的方法,有了消息持久化,即使发送者和接受者不是 ...