简介

此文简单介绍如何使用intel c++编译器实现向量化加速。

全文如下安排:

  • base : 待优化的源代码。
  • vectorization : 第一个向量化版本。
  • aligned : 内存对其对向量化的影响。

base

base版本代码:

// filename : main.cpp
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <cstdint>
#include <malloc.h>
#include <windows.h>
using namespace std;

int64_t cpu_freq;
int64_t cpu_counter(){
  int64_t clock;
    QueryPerformanceCounter((LARGE_INTEGER*)&clock);
  return clock;
}

// output time
#if 1
  int64_t gloabel_timer_begin;
  int64_t gloabel_timer_end;
  #define TB__ gloabel_timer_begin=cpu_counter()
  #define TE__ gloabel_timer_end  =cpu_counter(); \
  cout << __LINE__ << " : " << double(gloabel_timer_end-gloabel_timer_begin)/double(cpu_freq) << " seconds" << endl
#else
  #define TB__
  #define TE__
#endif

// repeat times
#define REPEATTIMES 100000

// initialize data
void init(float *data, int rows, int cols, int true_cols){
  for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
      data[i*true_cols+j] = float(rand())/float(RAND_MAX);
    }
  }
}

void multiply(float *C, float *A, float *B, int rows, int cols, int true_cols);

void print_sum(float *data, int rows, int cols, int true_cols){
  float total = 0;
  for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
      total += data[i*true_cols+j];
    }
  }
  cout << total << endl;
}

int main(){
  QueryPerformanceFrequency((LARGE_INTEGER *)&cpu_freq);

  int rows = 100;
  int cols = 101;

  int true_cols = cols;
  float *A = (float*)malloc(rows*true_cols*sizeof(float));
  float *B = (float*)malloc(rows*sizeof(float));
  float *C = (float*)malloc(rows*sizeof(float));

  init(A, rows, cols, true_cols);
  init(B, rows, 1, 1);

  // computing
  TB__;
  for (int k = 0; k < REPEATTIMES; k++){
    multiply(C, A, B, rows, cols, true_cols);
  }
  TE__;

  // print result.
  print_sum(C, rows, 1, 1);

  free(A); A = NULL;
  free(B); B = NULL;
  free(C); C = NULL;

  return 0;
}
// filename : multiply.cpp
void multiply(float *C, float *A, float *B, int rows, int cols, int true_cols){
  for (int i = 0; i < rows; i++){
    C[i] = 0;
    for (int j = 0; j < cols; j++){
      C[i] += A[i*true_cols+j]*B[j];
    }
  }
}

编译:

user@machine> icl /O1 /Qopt-report:1 /Qopt-report-phase:vec main.cpp multiply.cpp

执行:

user@machine> main.exe
73 : 0.877882 seconds
2483.53

vectorization

源代码保持不变

编译:

user@machine> icl /O2 /Qopt-report:1 /Qopt-report-phase:vec main.cpp multiply.cpp

执行:

user@machine> main.exe
73 : 0.205989 seconds
2483.53

执行速度提升了 4倍左右。


aligned

源代码修改。(注意:下面的代码有问题,结果可能有错误,原因可能是内存的问题。

// filename : main.cpp
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <cstdint>
#include <malloc.h>
#include <windows.h>
using namespace std;

int64_t cpu_freq;
int64_t cpu_counter(){
  int64_t clock;
    QueryPerformanceCounter((LARGE_INTEGER*)&clock);
  return clock;
}

// output time
#if 1
  int64_t gloabel_timer_begin;
  int64_t gloabel_timer_end;
  #define TB__ gloabel_timer_begin=cpu_counter()
  #define TE__ gloabel_timer_end  =cpu_counter(); \
  cout << __LINE__ << " : " << double(gloabel_timer_end-gloabel_timer_begin)/double(cpu_freq) << " seconds" << endl
#else
  #define TB__
  #define TE__
#endif

// repeat times
#define REPEATTIMES 100000

// initialize data
void init(float *data, int rows, int cols, int true_cols){
  for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
      data[i*true_cols+j] = float(rand())/float(RAND_MAX);
    }
  }
}

void multiply(float *C, float *A, float *B, int rows, int cols, int true_cols);

void print_sum(float *data, int rows, int cols, int true_cols){
  float total = 0;
  for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
      total += data[i*true_cols+j];
    }
  }
  cout << total << endl;
}

int main(){
  QueryPerformanceFrequency((LARGE_INTEGER *)&cpu_freq);

  int rows = 100;
  int cols = 101;

#ifdef ALIGNED
  #define ALLIGNED_LEN 32
  int true_cols = ((((cols*sizeof(float))+ALLIGNED_LEN-1)/ALLIGNED_LEN)*ALLIGNED_LEN)/sizeof(float);
  //cout << true_cols << endl;
  float *A = (float*)_aligned_malloc(rows*true_cols*sizeof(float), ALLIGNED_LEN);
  float *B = (float*)_aligned_malloc(rows*sizeof(float), ALLIGNED_LEN);
  float *C = (float*)_aligned_malloc(rows*sizeof(float), ALLIGNED_LEN);
#else
  int true_cols = cols;
  float *A = (float*)malloc(rows*true_cols*sizeof(float));
  float *B = (float*)malloc(rows*sizeof(float));
  float *C = (float*)malloc(rows*sizeof(float));
#endif

  init(A, rows, cols, true_cols);
  init(B, rows, 1, 1);

  // computing
  TB__;
  for (int k = 0; k < REPEATTIMES; k++){
    multiply(C, A, B, rows, cols, true_cols);
  }
  TE__;

  // print result.
  print_sum(C, rows, 1, 1);

#ifdef ALIGNED
  _aligned_free(A); A = NULL;
  _aligned_free(B); B = NULL;
  _aligned_free(C); C = NULL;
#else
  free(A); A = NULL;
  free(B); B = NULL;
  free(C); C = NULL;
#endif

  return 0;
}
// filename : multiply.cpp
void multiply(float *C, float *A, float *B, int rows, int cols, int true_cols){
  for (int i = 0; i < rows; i++){
    C[i] = 0;
    #ifdef ALIGNED
    #pragma vector aligned
    #endif
    for (int j = 0; j < cols; j++){
      C[i] += A[i*true_cols+j]*B[j];
    }
  }
}

编译:

user@machine> icl /DALIGNED /O2 /Qopt-report:1 /Qopt-report-phase:vec main.cpp multiply.cpp

执行:

82 : 0.17747 seconds
2483.53

相对第一个优化的版本又提升了一点速度。


结论

vectorization版本:不需要改变源代码,通过修改编译器选项直接实现向量化。

aligned版本:需要修改代码,使得内存对其。可以进一步获得性能。

ICL Auto Vectorization的更多相关文章

  1. 使用Auto TensorCore CodeGen优化Matmul

    使用Auto TensorCore CodeGen优化Matmul 本文将演示如何使用TVM Auto TensorCore CodeGen在Volta / Turing GPU上编写高性能matmu ...

  2. C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)

    #include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...

  3. overflow:hidden与margin:0 auto之间的冲突

    相对于父容器水平居中的代码margin:0 auto与overflow:hidden之间存在冲突.当这两个属性同时应用在一个DIV上时,在chrome浏览器中将无法居中.至于为啥我也不明白.

  4. Android Auto开发之一《开始学习Auto 》

    共同学习,共同进步, 转载请注明出处.欢迎微信交流:sfssqs,申请注明"Android Car"字样 ================= =================== ...

  5. width:100%;与width:auto;的区别

    <div> <p>1111</p> </div> div{ width:980px; background-color: #ccc; height:30 ...

  6. SQl 2005 For XMl 简单查询(Raw,Auto,Path模式)(1)

    很多人对Xpath可能比较熟悉,但不知道有没有直接操作过数据库,我们都知道 在Sql2005里公支持的几种查询有Raw,Auto模式,页并没有Path和Elements用法等,如果在2000里使用过 ...

  7. margin:0 auto;不居中

    margin:0 auto:不居中可能有以下两个的原因; 1.没有设置宽度<div style="margin:0 auto;"></div>看看上面的代码 ...

  8. 初学C++ 之 auto关键字(IDE:VS2013)

    /*使用auto关键字,需要先赋初值,auto关键字是会根据初值来判断类型*/ auto i = ; auto j = ; cout << "auto i = 5" & ...

  9. C++11 - 类型推导auto关键字

    在C++11中,auto关键字被作为类型自动类型推导关键字 (1)基本用法 C++98:类型 变量名 = 初值;   int i = 10; C++11:auto 变量名 = 初值;  auto i ...

随机推荐

  1. Linux正则表达式总结【网络资源整理】

    正则表达式的分类 1.基本的正则表达式(Basic Regular Expression 又叫Basic RegEx 简称BREs) 2.扩展的正则表达式(Extended Regular Expre ...

  2. [LeetCode] Bulb Switcher II 灯泡开关之二

    There is a room with n lights which are turned on initially and 4 buttons on the wall. After perform ...

  3. 机器学习技法:05 Kernel Logistic Regression

    Roadmap Soft-Margin SVM as Regularized Model SVM versus Logistic Regression SVM for Soft Binary Clas ...

  4. Basic command and advice for memcached

    Storage Commands set Most common command. Store this data, possibly overwriting any existing data. N ...

  5. ●BZOJ 1076 [SCOI2008]奖励关

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1076题解: 期望dp. (模糊的题意,2333) 题中的:"现在决定不吃的宝物以后 ...

  6. bzoj 3261最大异或和

    Description 给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类型: 1.Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1. 2.Qlrx:询问操作,你需要 ...

  7. Luogu1613 跑路

    题目描述 小A的工作不仅繁琐,更有苛刻的规定,要求小A每天早上在6:00之前到达公司,否则这个月工资清零.可是小A偏偏又有赖床的坏毛病.于是为了保住自己的工资,小A买了一个十分牛B的空间跑路器,每秒钟 ...

  8. poj 2417 && poj3243(Baby-Step Giant-Step)

    Discrete Logging Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4624   Accepted: 2113 ...

  9. 微信小程序-参数传递与事件处理

    前言 开发过程中经常会遇到从一个页面携带数据到另一个页面的情况,所以需要知道以下信息,什么是事件?有哪些传递方式?如果传递数组呢?如果传递对象呢? 一.事件 什么是事件 事件是视图层到逻辑层的通讯方式 ...

  10. C++是跨平台的语言

    最开始学习Java时,老师就说Java是跨平台的,而c++不是,这里要纠正一下观点,c++也是跨平台的,只不过是实现跨平台的方式不同而已. 1.平台 一般我们把CPU处理器与操作系统的整体叫平台.不同 ...