- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我试图理解 OpenMP 破坏循环矢量化的概念原因。此外,解决此问题的任何建议都会有所帮助。我正在考虑手动并行化它来解决这个问题,但这肯定不会很优雅并且会导致大量代码膨胀,因为我的代码包含几个这样的部分,这些部分适合矢量化和并行化。
我正在使用
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60315.1 for x64
使用 OpenMP:
info C5002: loop not vectorized due to reason '502'
没有 OpenMP:
info C5001: loop vectorized
VS vectorization page说这个错误发生在:
Induction variable is stepped in some manner other than a simple +1
我可以强制它步进 1 吗?
循环
#pragma omp parallel for
for (int j = 0; j < H*W; j++)//A,B,C,D,IN are __restricted
{
float Gs = D[j]-B[j];
float Gc = A[j]-C[j];
in[j]=atan2f(Gs,Gc);
}
尽力而为(?)
#pragma omp parallel
{// This seems to vectorize, but it still requires quite a lot of boiler code
int middle = H*W/2;
#pragma omp sections nowait
{
#pragma omp section
for (int j = 0; j < middle; j++)
{
float Gs = D[j]-B[j];
float Gc = A[j]-C[j];
in[j]=atan2f(Gs,Gc);
}
#pragma omp section
for (int j = middle; j < H*W; j++)
{
float Gs = D[j]-B[j];
float Gc = A[j]-C[j];
in[j]=atan2f(Gs,Gc);
}
}
}
最佳答案
我建议您手动进行矢量化。原因之一是自动矢量化似乎不能很好地处理携带的循环依赖性(循环展开)。
为了避免代码膨胀和神秘的内在函数,我使用了 Agner Fog 的 vector 类。根据我的经验,它与使用内部函数一样快,并且它会根据您的编译方式自动利用 SSE2-AVX2(AVX2 在 Intel 模拟器上进行测试)。我已经使用适用于 SSE2 到 AVX2 的 vector 类编写了 GEMM 代码,当我在具有 AVX 的系统上运行时,我的代码已经比仅使用 SSE 的 Eigen 更快。这是带有 vector 类的函数(我没有尝试展开循环)。
#include "omp.h"
#include "math.h"
#include "vectorclass.h"
#include "vectormath.h"
void loop(const int H, const int W, const int outer_stride, float *A, float *B, float *C, float *D, float* in) {
#pragma omp parallel for
for (int j = 0; j < H*W; j+=8)//A,B,C,D,IN are __restricted, W*H must be a multiple of 8
{
Vec8f Gs = Vec8f().load(&D[j]) - Vec8f().load(&B[j]);
Vec8f Gc = Vec8f().load(&A[j]) - Vec8f().load(&C[j]);
Vec8f invec = atan(Gs, Gc);
invec.store(&in[j]);
}
}
当你自己进行矢量化时,你必须小心数组边界。在上面的函数中,HW 需要是 8 的倍数。有几种解决方案,但最简单和最有效的解决方案是使数组 (A,B,C,D,in) 大一点(最大 7 个更大的 float )如果需要是 8 的倍数。然而,另一个解决方案是使用下面的代码,它不需要 WH 是 8 的倍数,但它不是那么漂亮。
#define ROUND_DOWN(x, s) ((x) & ~((s)-1))
void loop_fix(const int H, const int W, const int outer_stride, float *A, float *B, float *C, float *D, float* in) {
#pragma omp parallel for
for (int j = 0; j < ROUND_DOWN(H*W,8); j+=8)//A,B,C,D,IN are __restricted
{
Vec8f Gs = Vec8f().load(&D[j]) - Vec8f().load(&B[j]);
Vec8f Gc = Vec8f().load(&A[j]) - Vec8f().load(&C[j]);
Vec8f invec = atan(Gs, Gc);
invec.store(&in[j]);
}
for(int j=ROUND_DOWN(H*W,8); j<H*W; j++) {
float Gs = D[j]-B[j];
float Gc = A[j]-C[j];
in[j]=atan2f(Gs,Gc);
}
}
自己进行矢量化的一个挑战是找到一个 SIMD 数学库(例如,atan2f)。 vector 类支持 3 个选项。非 SIMD、AMD 的 LIBM 和英特尔的 SVML(我在上面的代码中使用了非 SIMD 选项)。 SIMD math libraries for SSE and AVX
您可能想要考虑的最后一些评论。 Visual Studio 具有自动并行化(默认情况下关闭)以及自动矢量化(默认情况下,至少在 Release模式下)。您可以试试这个而不是 OpenMP 来减少代码膨胀。 http://msdn.microsoft.com/en-us/library/hh872235.aspx
此外,Microsoft 还拥有并行模式库。值得研究,因为 Microsoft 的 OpenMP 支持有限。它几乎与 OpenMP 一样易于使用。这些选项之一可能更适合自动矢量化(尽管我对此表示怀疑)。正如我所说,我会使用 vector 类手动进行向量化。
关于c++ - 如何提示 OpenMP Stride?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16513709/
我发现可以从 (X, Y) 步幅为 1,图像要求我们将步幅参数指定为 img.strides * 2 或 img.strides + img.strides。 我不知道他们如何在知道编号的情况下快速计
我试图通过参数将一个 Int 常量传递给我的 for 循环的 stride。它采用类型 T.stride。 let notchStep:Int = 5 for degrees:Double i
此代码会引发编译器错误:“参数类型‘StrideTo’应为类或类约束类型的实例” extension Array { func chunks(_ chunkSize: Int) -> [[El
我试图创建一个 Hstack'd 卡片列表,也就是说,我想创建一系列行的 ScrollView 。每行将包含两个并排显示的 View 的 HStack,并由一些列表数据结构初始化。 struct My
我正在尝试将字节数组读入 YuvImage ,但我无法理解 strides 参数的含义。谁能帮忙(最好举个例子?)谢谢。 最佳答案 这里是对 yuv 视频的 stride 的描述: http://ms
我有一个非常大的 numpy 数组(145000 行 * 550 列)。我想在子数组中创建滚动切片。我试图用一个函数来实现它。函数 lagged_vals 的行为符合预期,但 np.lib.strid
该图是未加权且无向的。 给定两个顶点 s 和 t,步幅为 k,我想找到它们之间的最短路径: 长度能被k整除 路径中的每 k 个“步骤”,从第一个开始算起,都是一条简单路径。 意思是,每一步只能“跳转”
我试图理解 OpenMP 破坏循环矢量化的概念原因。此外,解决此问题的任何建议都会有所帮助。我正在考虑手动并行化它来解决这个问题,但这肯定不会很优雅并且会导致大量代码膨胀,因为我的代码包含几个这样的部
我目前正在研究 numpy,在 numpy 中有一个主题叫做“strides”。我明白那是什么。但是它是如何工作的呢?我没有在网上找到任何有用的信息。谁能让我通俗易懂地理解一下? 最佳答案 numpy
我最近了解到 strides在 answer to this post ,并且想知道如何使用它们比我在 this post 中提出的更有效地计算移动平均滤波器(使用卷积过滤器)。 这是我目前所拥有的。
我正在使用 ffmpeg for android 编写简单的视频播放器。以下是我遵循的步骤 从文件 中读取 AVFrame 使用 sws_scale 将 AVFrame 转换为 RGB565 格式 使
我正在尝试从 WPF BitmapSource 获取像素数据目的。据我所知,这可以通过调用它的 CopyPixels 来完成。方法。这个方法需要一个stride参数,不知道怎么获取。据我所知,stri
__global__ void substract(float *A, float *B, float *res, int *n) { int size = *n; int tid =
最近在对经过训练的 pylearn2 模型进行预测时遇到了问题。下面提供了回溯的相关位。我已确保 model.get_input_shape() 与我传递给生成的 theano 预测函数的 numpy
//Defining geometry var vertices = [ +0.0,+0.0,+0.0, +0.0,+0.0,+1.0, -0.5,+0.0,+0.0,
在浏览 pytorch 文档时,我在许多函数中遇到了术语 layout = torch.strided。任何人都可以帮助我了解它在哪里使用以及如何使用。描述说这是返回张量的所需布局。布局是什么意思,有
通常要反转列表应该执行以下操作: >>>>l = [1, 2, 3, 4, 5] >>>>l[::-1] [5, 4, 3, 2, 1] 但不是这样的确切语法: list[::] 如果我不提供可选参
我正在尝试根据教程运行cifar10_train.py,但我得到了 "cifar10_input.py", line 87, in read_cifar10 tf.strided_slice(reco
我理解给定一个可迭代对象,例如 >>> it = [1, 2, 3, 4, 5, 6, 7, 8, 9] 我可以把它变成一个列表,然后在任意点切掉末端,例如 >>> it[1:-2] [2, 3, 4
请有人解释一下(ASCII 真的很受欢迎)stride 参数在 Canvas.drawBitmap() 中代表什么?在 Bitmap.setPixels()/getPixels() ?我知道这是一种跳
我是一名优秀的程序员,十分优秀!