引言
对于这方面的姿势,也是属于意外。在使用Caffe的过程中,需要依赖一个关于矩阵计算的库,可是
使用atlas或者openblas, 当然有资金支持的话可以使用更快地MKL, 而一个穷小白就只能从开源免费的计算库中选了,就选了OpenBlas。 后来因为缘分,认识了OpenBlas的创始人,从他们公司的工作中了解到还有机器学习算法优化加速的这么个工作。其中涉及到如OpenMP, SIMD, 当然编译器优化也是不容忽视的。在此,总结一下工作中用到的一些函数,免得下次见到不认识了。
Intrinsic function[^1]
我对这个的理解就是在汇编的基础上进行向量化的封装的一些宏或者函数, 同时可以操作很多个数据,如使用SSE可以操作128位的数据,可以使4个int类型,也可以使用8个short类型也可以是16个char类型的数据。
从intrinsic guide[^2]中就可以看出Intel关于SIMD方面的发展历程。MMX(主要是16位指令)到后面的SSE2 SSE4.2(32位指令)等等。 查阅文档的时候后可以按照计算的类别:
计算类型
计算类型根据操作数据的类型分别封装了加减乘除,文档中对接口函数说明得很是清楚,还包括生成目标指令是什么。如:
Synopsis
__m128i _mm_add_epi16 (__m128i a, __m128i b)
#include "emmintrin.h"
Instruction: paddw xmm, xmm
CPUID Flags: SSE2
Description
Add packed 16-bit integers in a and b, and store the results in dst.
Operation
FOR j := 0 to 7
i := j*16
dst[i+15:i] := a[i+15:i] + b[i+15:i]
ENDFOR
从外,函数命名很有规律 _mm_操作_操作的数据类型
, 数据类型__m128i
表示integer类型的向量数组,__m128
表示单精度类型的向量数组,__128d
表示双精度类型的向量数组。
__m128i _mm_add_epi16 (__m128i a, __m128i b); //Add packed 16-bit integers in a and b
__m128d _mm_div_pd (__m128d a, __m128d b); // Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b
__m128d _mm_mul_sd (__m128d a, __m128d b); // Multiply the lower double-precision (64-bit) floating-point element in a and b, store the result in the lower element of dst, and copy the upper element from a to the upper element of dst.
__m128i _mm_subs_epi16 (__m128i a, __m128i b)
__m128i _mm_subs_epu16 (__m128i a, __m128i b)
设置\初始化向量数组
__m128i _mm_set_epi16 (short e7, short e6, short e5, short e4, short e3, short e2, short e1, short e0);
__m128i _mm_set_epi32 (int e3, int e2, int e1, int e0);
__m128i _mm_set_epi8 (char e15, char e14, char e13, char e12, char e11, char e10, char e9, char e8, char e7, char e6, char e5, char e4, char e3, char e2, char e1, char e0);
__m128d _mm_set_pd (double e1, double e0);
__m128d _mm_set_pd1 (double a); // Broadcast double-precision (64-bit) floating-point value a to all elements of dst.
__m128 _mm_set_ps (float e3, float e2, float e1, float e0);
__m128 _mm_set_ps1 (float a);
__m128d _mm_set_sd (double a);
__m128 _mm_set_ss (float a);
__m128i _mm_set1_epi16 (short a);
__m128i _mm_set1_epi32 (int a);
__m128i _mm_set1_epi64 (__m64 a);
__m128i _mm_set1_epi64x (__int64 a);
__m128i _mm_set1_epi8 (char a);
__m128d _mm_set1_pd (double a);
__m128 _mm_set1_ps (float a);
__m128i _mm_setr_epi16 (short e7, short e6, short e5, short e4, short e3, short e2