Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 1
▶ 第三章,逐步优化了一个二维卷积计算的过程
● 基准代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <omp.h>
#include <assert.h>
#include <sys/mman.h> #define REAL double
#define WIDTH 1030
#define HEIGHT 2048
#define COUNT 1000
#define PAD64 0
#if PAD64 // 是否对齐到 64 Byte
#define WIDTHP ((WIDTH * sizeof(REAL) + 63) / 64 * 64 / sizeof(REAL))
#else
#define WIDTHP WIDTH
#endif void initbuf(REAL *fbuf, const int width, const int height) // 初始化矩阵
{
for (int y = ; y < height; y++)
{
REAL val = (y % ) ? : 1.0;
for (int x = ; x < width; x++)
fbuf[y * WIDTHP + x] = val;
}
return;
} // 重复计算模糊 count 次
void stencil9pt(REAL *finp, REAL *foutp, const int width, const int height,
const REAL ctr, const REAL next, const REAL diag, const int count)
{
REAL *fin = finp, *fout = foutp;
for (int i = ; i < count; i++)
{
for (int y = ; y < height - ; y++) // 不处理光环元素
{
int c = + y * WIDTHP; // ?为什么要加两次 1
int n = c - WIDTHP, s = c + WIDTHP, w = c - , e = c + ;
int nw = n - , ne = n + , sw = s - , se = s + ;
for (int x = ; x < width - ; x++)
{
fout[c] = diag * fin[nw] + diag * fin[ne] + diag * fin[sw] + diag * fin[se] +
next * fin[w] + next * fin[e] + next * fin[n] + next * fin[s] + ctr * fin[c];
c++; n++; s++; e++; w++; nw++; ne++; sw++; se++;
}
}
REAL *ftmp = fin;
fin = fout;
fout = ftmp;
}
return;
} static double dtime()
{
double tseconds = 0.0;
struct timeval mytime;
gettimeofday(&mytime, (struct timezone *) );
tseconds = (double)(mytime.tv_sec + (double)mytime.tv_usec * 1.0e-6);
return (tseconds);
} int main(int argc, char *argv[])
{
REAL *fa = (REAL *)malloc(sizeof(REAL)*WIDTHP*HEIGHT), *fb = (REAL *)malloc(sizeof(REAL)*WIDTHP*HEIGHT);
assert(fa != MAP_FAILED);
assert(fb != MAP_FAILED); printf("Initializing..%d Threads, %d x %d, PAD=%d..\n\n", omp_get_num_threads(), WIDTH, HEIGHT, WIDTHP);
initbuf(fa, WIDTHP, HEIGHT);
initbuf(fb, WIDTHP, HEIGHT); printf("Running stencil kernel %d times\n", COUNT);
const REAL stendiag = 0.00125, stennext = 0.00125, stenctr = 0.99;
double time_b, time_e;
time_b = dtime();
stencil9pt(fa, fb, WIDTHP, HEIGHT, stenctr, stennext, stendiag, COUNT);
time_e = dtime();
printf("Elapsed time : %.3f (s)\n", time_e - time_b);
printf("FLOPS: %.3f (MFlops)\n", (WIDTHP * HEIGHT) * 17.0 * COUNT / (time_e - time_b) * 1.0e-06);// 计算一个元素需要 17 次乘法或加法 free(fa);
free(fb);
return ;
}
■ 输出结果
Xeon:
Running stencil kernel times
Elapsed time: 5.754 (s)
FLOPS : 6232.567 (MFlops) XeonPhi:
Running stencil kernel times
Elapsed time: 102.042 (s)
FLOPS : 351.428 (MFlops)
● 修改计算函数,忽略指针依赖关系
void stencil9pt(REAL *finp, REAL *foutp, const int width, const int height,
const REAL ctr, const REAL next, const REAL diag, const int count)
{
REAL *fin = finp, *fout = foutp;
for (int i = ; i<count; i++)
{
for (int y = ; y < height - ; y++)
{
int c = + y * WIDTHP;
int n = c - WIDTHP, s = c + WIDTHP, w = c - , e = c + ;
int nw = n - , ne = n + , sw = s - , se = s + ;
#pragma ivdep // 忽略不明显的(指针)依赖关系
for (int x = ; x < width - ; x++)
{
fout[c] = diag * fin[nw] + diag * fin[ne] + diag * fin[sw] +diag * fin[se] +
next * fin[w] + next * fin[e] + next * fin[n] + next * fin[s] + ctr * fin[c];
c++; n++; s++; e++; w++; nw++; ne++; sw++; se++;
}
}
REAL *ftmp = fin;
fin = fout;
fout = ftmp;
}
return;
}
■ 输出结果(Xeon Phi)
Running stencil kernel times
Elapsed time: 24.052 (s)
FLOPS : 1490.925 (MFlops)
● OpenMP
void stencil9pt(REAL *finp, REAL *foutp, const int width, const int height,
const REAL ctr, const REAL next, const REAL diag, const int count)
{
REAL *fin = finp, *fout = foutp;
for (int i = ; i<count; i++)
{
int y, x;
#pragma omp parallel for private(x) // 一句 OpenMp,注意 x 线程私有
for (y = ; y < height - ; y++)
{
int c = + y * WIDTHP;
int n = c - WIDTHP, s = c + WIDTHP, w = c - , e = c + ;
int nw = n - , ne = n + , sw = s - , se = s + ;
#pragma ivdep
for (x = ; x < width - ; x++)
{
fout[c] = diag * fin[nw] + diag * fin[ne] + diag * fin[sw] + diag * fin[se] +
next * fin[w] + next * fin[e] + next * fin[n] + next * fin[s] + ctr * fin[c];
c++; n++; s++; e++; w++; nw++; ne++; sw++; se++;
}
}
REAL *ftmp = fin;
fin = fout;
fout = ftmp;
}
return;
}
■ 输出结果(Xeon Phi)
Running stencil kernel times
Elapsed time : 0.700 (s)
FLOPS : 51201.595 (MFlops)
● 数组对齐
// 打开 PAD64
#define PAD64 1 // 替换 malloc 和 free
REAL *fa = (REAL *)malloc(sizeof(REAL)*WIDTHP*HEIGHT);
REAL *fb = (REAL *)malloc(sizeof(REAL)*WIDTHP*HEIGHT);
...
free(fa);
free(fb); // 替换为
REAL *fa = (REAL *)_mm_malloc(sizeof(REAL)*WIDTHP*HEIGHT, );
REAL *fb = (REAL *)_mm_malloc(sizeof(REAL)*WIDTHP*HEIGHT, );
...
_mm_free(fa);
_mm_free(fb);
■ 输出结果(Xeon Phi)
Running stencil kernel times
Elapsed time : 0.651 (s)
FLOPS : 55155.399 (MFlops)
● 流存储
void stencil9pt(REAL *finp, REAL *foutp, const int width, const int height,
const REAL ctr, const REAL next, const REAL diag, const int count)
{
REAL *fin = finp, *fout = foutp;
for (int i = ; i<count; i++)
{
int y, x;
#pragma omp parallel for private(x)
for (y = ; y < height - ; y++)
{
int c = + y * WIDTHP;
int n = c - WIDTHP, s = c + WIDTHP, w = c - , e = c + ;
int nw = n - , ne = n + , sw = s - , se = s + ;
#pragma ivdep
#pragma vector nontemporal // 使用流存储指令(或使用编译选项 -opt-streaming-storesalways)
for (x = ; x < width - ; x++)
{
fout[c] = diag * fin[nw] + diag * fin[ne] + diag * fin[sw] + diag * fin[se] +
next * fin[w] + next * fin[e] + next * fin[n] + next * fin[s] + ctr * fin[c];
c++; n++; s++; e++; w++; nw++; ne++; sw++; se++;
}
}
REAL *ftmp = fin;
fin = fout;
fout = ftmp;
}
return;
}
■ 输出结果
Xeon:
Running stencil kernel times
Elapsed time: 1.905 (s)
FLOPS : 18824.053 (MFlops) XeonPhi:
Running stencil kernel times
Elapsed time: 0.639 (s)
FLOPS : 56145.417 (MFlops)
● 2 MB 存储页(书中代码没有 munmap 的部分)。参考(https://www.aliyun.com/jiaocheng/208004.html),但是服务器上编译时找不到 MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB 等定义,无法使用
// 替换 _mm_malloc 和 _mm_free
REAL *fa = (REAL *)_mm_malloc(sizeof(REAL)*WIDTHP*HEIGHT, );
REAL *fb = (REAL *)_mm_malloc(sizeof(REAL)*WIDTHP*HEIGHT, );
...
_mm_free(fa);
_mm_free(fb);
// 替换为
REAL *fa = (REAL *)mmap(, WIDTHP*HEIGHT * sizeof(REAL), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB, -, );
REAL *fb = (REAL *)mmap(, WIDTHP*HEIGHT * sizeof(REAL), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB, -, );
...
munmap(fa, WIDTHP*HEIGHT * sizeof(REAL));
munmap(fb, WIDTHP*HEIGHT * sizeof(REAL));
Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 1的更多相关文章
- Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 4
▶ 第五章,几个优化 ● 代码 #include <stdio.h> #include <stdlib.h> #include <math.h> #define S ...
- Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 3
▶ 第二章,几个简单的程序 ● 代码,单线程 #include <stdio.h> #include <stdlib.h> #include <string.h> ...
- Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 2
▶ 第四章,逐步优化了一个三维卷积计算的过程 ● 基准代码 #include <stdio.h> #include <stdlib.h> #include <string ...
- Xeon Phi 编程备忘
▶ 闲鱼的 Xeon Phi 3120A 配办公室的新 Xeon 服务器,记录一下环境安装过程. ● 原本尝试搭 Ubuntu 服务器,参考[https://software.intel.com/en ...
- Python猫荐书系列之五:Python高性能编程
稍微关心编程语言的使用趋势的人都知道,最近几年,国内最火的两种语言非 Python 与 Go 莫属,于是,隔三差五就会有人问:这两种语言谁更厉害/好找工作/高工资…… 对于编程语言的争论,就是猿界的生 ...
- 《高性能javascript》一书要点和延伸(上)
前些天收到了HTML5中国送来的<高性能javascript>一书,便打算将其做为假期消遣,顺便也写篇文章记录下书中一些要点. 个人觉得本书很值得中低级别的前端朋友阅读,会有很多意想不到的 ...
- 高质量C++/C编程指南(林锐)
推荐-高质量C++/C编程指南(林锐) 版本/状态 作者 参与者 起止日期 备注 V 0.9 草稿文件 林锐 2001-7-1至 2001-7-18 林锐起草 V 1.0 正式文件 林锐 20 ...
- 物联网操作系统HelloX应用编程指南
HelloX操作系统应用编程指南 HelloX应用开发概述 可以通过三种方式,在HelloX操作系统基础上开发应用: 1. 以内部命令方式实现应用,直接编译链接到HelloX的内核she ...
- JDK 高性能编程之容器
高性能编程在对不同场景下对于容器的选择有着非常苛刻的条件,这里记录下前人总结的经验,并对源码进行调试 JDK高性能编程之容器 读书笔记内容部分来源书籍深入理解JVM.互联网等 先放一个类图util,点 ...
随机推荐
- python基础——列表
Python列表脚本操作符 列表对 + 和 * 的操作符与字符串相似.+ 号用于组合列表,* 号用于重复列表. 如下所示: Python 表达式 结果 描述 len([1, 2, 3]) 3 长度 [ ...
- MySql5.7 Distinct与Order By同时使用报错的解决方案
mysql5.7版本中,如果DISTINCT和order by一起使用将会报3065错误,sql语句无法执行.这是由于5.7版本语法比之前版本语法要求更加严格导致的. 解决方案: 1.vim /etc ...
- centos7.4 可远程可视化桌面安装
先啰嗦一下VNC是什么( Virtual Network Computing)VNC允许Linux系统可以类似实现像Windows中的远程桌面访问那样访问Linux桌面.本文配置机器是兴宁市网络信息中 ...
- 关于测绘软件南方CASS(7.0)成图系统的使用心得
关于测绘软件南方CASS(7.0)成图系统的使用心得 王天池 南方CASS是一款基于CAD平台开发的一套集地形地籍空间数据建库工程工程应用土石算量等功能为一体的绘图软件. 初识这款软件是在大二校园 ...
- WEBBASE篇: 第八篇, JavaScript知识2
JavaScript 2 一,数据类型: 作用: 约束了数据在内存中所占空间大小问题的: JS数据类型分类: 基本数据类型(值类型) (1) number 类型: 数字类型,可以表示32位的整数或64 ...
- Arcmap连接数据库需管理员获取许可——创建ArcSDE连接文件
一.在装有server的服务器上创建ArcSDE连接文件 1.打开ArcMap<<ArcToolBox<<数据管理工具<<工作空间<<创建ArcSDE连 ...
- 作用域&&闭包
在了解闭包之前,先了解作用域一,作用域简单来说就是变量和函数可以访问的范围,在es5中变量作用域一般分为全局作用域和局部作用域,这个主要依据是全局变量还是局部变量 情景1: <script> ...
- Windows 下 安装 laravel(一些小笔记)
首先 安装完composer 下载地址 https://getcomposer.org/ 在 cmd 进入到 自己的项目访问目录 然后 输入命令:composer creat ...
- PythonStudy——格式化输入小练习
# 练习:用户输入姓名.年龄.工作.爱好 ,然后打印成以下格式# ------------ info of Egon -----------# Name : Egon# Age : 22# Sex : ...
- extjs_10_自己定义combotree组件
1.项目截图 2.treedata.json { text : "root", expanded : true, expandable : true, children : [{ ...