简单介绍和应用
openmp主要用来将串行程序并行化(以共享内存型的方式),还可以加入一些同步互斥操作, 编译器自动进行并行优化,如果编译器不支持,代码仍然可以正常运作,只是不能以多线程的方式加速。
- 应用
简单应用的话比较容易上手,头文件里加上#include <omp.h>
,gnu编译选项时加上-fopenmp
。 openmp里主要有四个组件(4.0版本)。
1.directives指令,每个指令以`#pragma omp`开头 2.Runtime Library Routines 运行时接口 3.Environment Variables 环境变量 4.Clauses子句 可以算是对指令的补充描述,搭配指令一起食用
- 例子 faiss L2Distance
/*********************************************************
* main
*/
#include <omp.h>
/* Compute the L2 norm of a set of nx vectors */
void fvec_norms_L2 (float * __restrict nr,
const float * __restrict x,
size_t d, size_t nx)
{
#pragma omp parallel for
for (int64_t i = 0; i < nx; i++) {
nr[i] = sqrtf (fvec_norm_L2sqr (x + i * d, d));
}
}
/*********************************************************
* SSE and AVX implementations
*/
#ifdef __SSE3__
#include <immintrin.h>
// reads 0 <= d < 4 floats as __m128
static inline __m128 masked_read (int d, const float *x)
{
assert (0 <= d && d < 4);
ALIGNED(16) float buf[4] = {0, 0, 0, 0};
switch (d) {
case 3:
buf[2] = x[2];
case 2:
buf[1] = x[1];
case 1:
buf[0] = x[0];
}
return _mm_load_ps (buf);
// cannot use AVX2 _mm_mask_set1_epi32
}
float fvec_norm_L2sqr (const float * x,
size_t d)
{
__m128 mx;
__m128 msum1 = _mm_setzero_ps();
while (d >= 4) {
mx = _mm_loadu_ps (x); x += 4;
msum1 = _mm_add_ps (msum1, _mm_mul_ps (mx, mx));
d -= 4;
}
mx = masked_read (d, x);
msum1 = _mm_add_ps (msum1, _mm_mul_ps (mx, mx));
msum1 = _mm_hadd_ps (msum1, msum1);
msum1 = _mm_hadd_ps (msum1, msum1);
return _mm_cvtss_f32 (msum1);
}
/*********************************************************
* NEON implementations
*/
#elif defined(__aarch64__)
#include <arm_neon.h>
float fvec_norm_L2sqr (const float *x, size_t d)
{
if (d & 3) return fvec_norm_L2sqr_ref (x, d);
float32x4_t accu = vdupq_n_f32 (0);
for (size_t i = 0; i < d; i += 4) {
float32x4_t xi = vld1q_f32 (x + i);
accu = vfmaq_f32 (accu, xi, xi);
}
float32x4_t a2 = vpaddq_f32 (accu, accu);
return vdups_laneq_f32 (a2, 0) + vdups_laneq_f32 (a2, 1);
}
/*********************************************************
* scalar implementations
*/
#else
float fvec_norm_L2sqr_ref (const float *x, size_t d)
{
size_t i;
double res = 0;
for (i = 0; i < d; i++)
res += x[i] * x[i];
return res;
}
float fvec_norm_L2sqr (const float *x, size_t d)
{
return fvec_norm_L2sqr_ref (x, d);
}
#endif
原理
还问原理有点离谱呀,这涉及编译器问题了呀沃土了。
- OpenMP执行模式
OpenMP的执行模型采用fork-join的形式,其中fork创建线程或者唤醒已有线程;join即多线程的会合。fork-join执行模型在刚开始执行的时候,只有一个称为“主线程”的运行线程存在。主线程在运行过程中,当遇到需要进行并行计算的时候,派生出线程来执行并行任务。在并行执行的时候,主线程和派生线程共同工作。在并行代码执行结束后,派生线程退出或者阻塞,不再工作,控制流程回到单独的主线程中。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。