【发布时间】:2016-04-23 23:44:50
【问题描述】:
我希望 GCC 对以下代码进行矢量化处理。-fopt-info 告诉我 GCC 目前还没有。我认为问题在于W 的跨步访问或k 的向后递增。注意height 和width 是常量,index_type 当前设置为unsigned long。
我删除了一些 cmets
114 for (index_type k=height-1;k+1>0;k--) {
116 for (index_type i=0;i<width;i++) {
117 Yp[k*width + i] = 0.0;
119 for (index_type j=0;j<width;j++) {
121 Yp[k*width + i] += W[k*width*width + j*width + i]*Yp[(k+1)*width + j];
122 }
123 Yp[k*width + i] *= DF(Ap[k*width + i]);
124 }
125 }
我正在使用gcc -O3 -ffast-math -fopt-info -std=c11 ./neural.c -o neural -lm进行编译
有没有一种好方法可以使这个矢量化?您可以向我介绍更多信息吗?
我的索引方法是不是一个坏主意(即k*width*width + ...)?我需要动态分配,我认为将事物保持在内存中会更好地进行优化。
编辑:这可能有用
这些行的-fopt-info-missed 输出
./neural.c:114:3: note: not vectorized: multiple nested loops.
./neural.c:114:3: note: bad loop form.
./neural.c:116:5: note: not vectorized: control flow in loop.
./neural.c:116:5: note: bad loop form.
./neural.c:119:7: note: step unknown.
./neural.c:119:7: note: reduction used in loop.
./neural.c:119:7: note: Unknown def-use cycle pattern.
./neural.c:119:7: note: not vectorized: complicated access pattern.
./neural.c:119:7: note: bad data access.
./neural.c:110:21: note: not vectorized: not enough data-refs in basic block.
./neural.c:110:58: note: not vectorized: not enough data-refs in basic block.
./neural.c:110:62: note: not vectorized: not enough data-refs in basic block.
./neural.c:117:18: note: not vectorized: not enough data-refs in basic block.
./neural.c:114:37: note: not vectorized: not enough data-refs in basic block.
编辑:
最小的例子是HERE
我正在尝试使用 BLAS。在最小的例子中,它运行得更快,但在整个代码上它更慢......不知道为什么
编辑:
编译器正在优化代码。固定的。 BLAS 现在更快了。修复是针对整个代码,而不是最小的示例。
编辑:
与之前编辑的链接中的代码相同
#include <math.h>
#include <cblas.h>
#include <stdlib.h>
#include <stdio.h>
typedef float value_type;
typedef unsigned long index_type;
static value_type F(value_type v) {
return 1.0/(1.0 + exp(-v));
}
static value_type DF(value_type v) {
const value_type Ev = exp(-v);
return Ev/((1.0 + Ev)*(1.0 + Ev));
}
#ifndef WITH_BLAS
static void get_Yp(const value_type * __restrict__ Ap, const value_type * __restrict__ W,
value_type * __restrict__ Yp, const value_type * __restrict__ Dp,
const index_type height, const index_type width) {
for (index_type i=0;i<width;i++) {
Yp[height*width + i] = 2*DF(Ap[height*width + i])*(Dp[i] - F(Ap[height*width + i]));
}
for (index_type k=height-1;k+1>0;k--) {
for (index_type i=0;i<width;i++) {
Yp[k*width + i] = 0.0;
for (index_type j=0;j<width;j++) {
Yp[k*width + i] += W[k*width*width + j*width + i]*Yp[(k+1)*width + j];
}
Yp[k*width + i] *= DF(Ap[k*width + i]);
}
}
}
#else
static void get_Yp(const value_type * __restrict__ Ap, const value_type * __restrict__ W,
value_type * __restrict__ Yp, const value_type * __restrict__ Dp,
const index_type height, const index_type width) {
for (index_type i=0;i<width;i++) {
Yp[height*width + i] = 2*DF(Ap[height*width + i])*(Dp[i] - F(Ap[height*width + i]));
}
for (index_type k=height-1;k+1>0;k--) {
cblas_sgemv(CblasRowMajor, CblasTrans, width, width, 1,
W+k*width*width, width, Yp+(k+1)*width, 1, 0, Yp+k*width, 1);
for (index_type i=0;i<width;i++)
Yp[k*width + i] *= DF(Ap[k*width + i]);
}
}
#endif
int main() {
const index_type height=10, width=10000;
value_type *Ap=malloc((height+1)*width*sizeof(value_type)),
*W=malloc(height*width*width*sizeof(value_type)),
*Yp=malloc((height+1)*width*sizeof(value_type)),
*Dp=malloc(width*sizeof(value_type));
get_Yp(Ap, W, Yp, Dp, height, width);
printf("Done %f\n", Yp[3]);
return 0;
}
【问题讨论】:
-
尝试创建一个最小的、完整的和可验证的示例来重现问题。
-
我不确定vectorization 是不是正确的标签。
-
尝试在归约中使用
sum而不是Yp[k*width + i],然后在归约后使用Yp[k*width + i] = sum。但是你真的应该像@RossRidge 所说的那样提供一个最小的例子。另外,请记住,GCC 无论如何都不会展开减少。 ICC 展开两次,Clang 展开四次。在许多英特尔处理器上四倍应该是好的(因为 Haswell 您可能需要展开四次以上,但实现这一点更困难)因此对于减少的自动矢量化 Clang 是目前最好的。 -
你是加州大学圣地亚哥分校粒子物理学专业的学生。我认识那里的一些粒子物理学教授(至少我和他们谈过几次)。您要提供一个最小的工作示例吗?
-
昨天在帖子中编辑了最小示例。你不能得到它吗?我放了一个链接而不是放所有代码。也许我应该将代码放入问题中。你认识谁?我在实验性 CMS 小组的 Frank 手下工作。
标签: gcc vectorization auto-vectorization