▶ 第三章,逐步优化了一个二维卷积计算的过程

● 基准代码

 #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的更多相关文章

  1. Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 4

    ▶ 第五章,几个优化 ● 代码 #include <stdio.h> #include <stdlib.h> #include <math.h> #define S ...

  2. Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 3

    ▶ 第二章,几个简单的程序 ● 代码,单线程 #include <stdio.h> #include <stdlib.h> #include <string.h> ...

  3. Xeon Phi 《协处理器高性能编程指南》随书代码整理 part 2

    ▶ 第四章,逐步优化了一个三维卷积计算的过程 ● 基准代码 #include <stdio.h> #include <stdlib.h> #include <string ...

  4. Xeon Phi 编程备忘

    ▶ 闲鱼的 Xeon Phi 3120A 配办公室的新 Xeon 服务器,记录一下环境安装过程. ● 原本尝试搭 Ubuntu 服务器,参考[https://software.intel.com/en ...

  5. Python猫荐书系列之五:Python高性能编程

    稍微关心编程语言的使用趋势的人都知道,最近几年,国内最火的两种语言非 Python 与 Go 莫属,于是,隔三差五就会有人问:这两种语言谁更厉害/好找工作/高工资…… 对于编程语言的争论,就是猿界的生 ...

  6. 《高性能javascript》一书要点和延伸(上)

    前些天收到了HTML5中国送来的<高性能javascript>一书,便打算将其做为假期消遣,顺便也写篇文章记录下书中一些要点. 个人觉得本书很值得中低级别的前端朋友阅读,会有很多意想不到的 ...

  7. 高质量C++/C编程指南(林锐)

    推荐-高质量C++/C编程指南(林锐) 版本/状态 作者 参与者 起止日期 备注 V 0.9 草稿文件 林锐   2001-7-1至 2001-7-18 林锐起草 V 1.0 正式文件 林锐   20 ...

  8. 物联网操作系统HelloX应用编程指南

    HelloX操作系统应用编程指南 HelloX应用开发概述 可以通过三种方式,在HelloX操作系统基础上开发应用: 1.        以内部命令方式实现应用,直接编译链接到HelloX的内核she ...

  9. JDK 高性能编程之容器

    高性能编程在对不同场景下对于容器的选择有着非常苛刻的条件,这里记录下前人总结的经验,并对源码进行调试 JDK高性能编程之容器 读书笔记内容部分来源书籍深入理解JVM.互联网等 先放一个类图util,点 ...

随机推荐

  1. 关于SUID SGID

    pattern 模式 permission 权限 The problem 问题 .-exec 找到的所有文件 variable 变量 一.1.grep sed awk 正则表达式 三大平台 #ifco ...

  2. intelij idea设置成eclipse快捷键

    1.导入jar包文件: https://pan.baidu.com/s/1QSd_CY5X_dUUw74evbckXg  密码: 23rq 2.idea -->settting ---> ...

  3. maven win 安装 与 IntelliJ IDEA 配置Maven【2018-11-14最新最有姿势攻略】

    [博客园cnblogs笔者m-yb原创,转载请加本文博客链接,笔者github: https://github.com/mayangbo666,公众号aandb7,QQ群927113708] http ...

  4. centos7下zabbix4.0配置磁盘IO监控

    一:准备 1.1:安装sysstat yum -y install sysstat 1.2:安装zabbix-get yum install -y zabbix-get.x86_64 1.3:iost ...

  5. spring boot 常见的配置问题

    最近在自学spring boot ,新手教程网上很多,这里主要记录下配置过程中的一些疑难杂症.这些记录都是针对以下配置生成的项目 1.该项目一定要用jdk1.8 2.application.prope ...

  6. noj二分查找

    二分查找: 要么左边,要么右边,哈哈哈哈 描述 给定一个单调递增的整数序列,问某个整数是否在序列中.   输入 第一行为一个整数n,表示序列中整数的个数:第二行为n(n不超过10000)个整数:第三行 ...

  7. Linuxs升级系统自带的openssh

      最近有空复习了一下Linux,在虚拟机上安装了个CentOS6.5,顺便升级一下系统自带的openssh,任何系统操作都有风险,正式环境请做好备份工作.废话少说,直接贴代码.     1.准备工作 ...

  8. C# 流水号生成器开发

    前言 本文将使用一个Nuget公开的组件技术来实现一个流水号生成器,提供了一些简单的API,来方便的实现一个通用的流水号. 在visual studio 中的NuGet管理器中可以下载安装,也可以直接 ...

  9. Linux_x86下NX与ASLR绕过技术

    本文介绍Linux_x86下NX与ASLR绕过技术,并对GCC的Stack Canaries保护技术进行原理分析. 本文使用存在漏洞代码如下: /* filename : sof.c */ #incl ...

  10. Angular4.0引入第三方框架,eg: bootstrap、jquery

    最近学习angular4.0,在练习是需要使用jquery和bootstrap.但是查阅了,大多数都是angular2的方法,或者是angular4.0的方法但是不准确.花了一些时间终于捣腾出来了,把 ...