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

● 基准代码

 #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. 初始C#(二)

    一 数组 定义:能存放任意多个同类型数据 声明与赋值:声明:数据类型[ ]变量名                                        赋值:变量名=new 数据类型[长度] ...

  2. 二、JAVA基本数据类型:内置数据类型,引用类型

    变量的值存储在内存中,内存管理系统通过变量的类型分配存储空间,且该空间只能存储该类型数据,通过定义不同的变量,在内存中储存不同类型的数据. JAVA的两大数据类型 1. 内置数据类型 2.引用数据类型 ...

  3. ubuntu 16.04 编译安装 trl8291cu系列 无线网卡驱动

    1 先 下载git包 和相关编译工具 sudo apt-get update sudo apt-get install git linux-headers-generic build-essentia ...

  4. 基于TCP的安卓客户端开发

    一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户 ...

  5. 导入maven项目导入依赖不会报错,但使用的jar会标红

    方法1: 1.通过编译找到报错的jar; 2.在 repository找到此jar,一般未下载完大小为1k我的是这样(); 3.删除未下载完全的jar,在项目上执行maven reimport会重新下 ...

  6. Python之小练习

    1.1 2 3 4 5 6 7 8能组成多少个不同的两位数? count = 0for i in range(1,9): for V in range(1,9): if i != V: count+= ...

  7. python2.7安装beautifulsoup包

    python2.7安装beautifulsoup包 准备条件: 1.已经安装好python2.7 2.下载beautifulsoup包,选择合适的包,网址:https://www.crummy.com ...

  8. Centos6.5搭建Elasticsearch

    ElasticSearch是基于Lucene的搜索服务.支持分布式多用户能力的全文搜索引擎,提供RESTful web接口.Elasticsearch是用Java开发的,Apache旗下开源项目,支持 ...

  9. [Java] Thread -- 避免Race Condition (Synchronized)

    public class TestRaceCondition implements Runnable{ public static int counter = 0; public static voi ...

  10. python 文件读写模式r,r+,w,w+,a,a+的区别(附代码示例)

    如下表   模式 可做操作 若文件不存在 是否覆盖 r 只能读 报错 - r+ 可读可写 报错 是 w 只能写 创建 是 w+ 可读可写 创建 是 a 只能写 创建 否,追加写 a+ 可读可写 创建 ...