我最近花了几天时间学习gcc 4.7的自动向量化。我按照网上看到的一些例子设置好环境,但是当我实际运行代码并在开启或关闭向量化后进行比较时,发现运行时间没有明显的差异。
以下是我使用的代码:
基本上,这相当于只使用 -O3。我自己添加了标志,这样我只需要删除“ftree-vectorize”,就能够测试不带向量化的结果。
以下是 ftree-vectorize-verbose 标志的输出,以显示代码确实正在进行向量化:
请注意,向量化在3次迭代后是有益的,我正在运行2^29~=500,000,000次迭代。因此,如果关闭向量化,我应该期望运行时间大不相同,对吧?
好的,这里是代码的运行时间(我连续运行了20次):
再次排除异常值,这给出了平均运行时间为57.9秒,标准偏差为3.6秒。
因此,这两个版本的运行时间在统计上无法区分。
有人能告诉我我做错了什么吗?编译器输出的“盈利门槛”不是我想象的意思吗?我非常感谢大家能给我任何帮助,我过去一周一直在试图弄清楚这个问题。
编辑:我实现了@nilspipenbrinck建议的更改,似乎已经奏效。我将向量化循环放入函数中,并多次调用该函数。没有向量化的相对运行时间现在为24.0秒(小于0.1秒的sigma),向量化的相对运行时间为20.8秒(小于0.2秒的sigma),或者速度提高了13%。虽然不如我所希望的那样快,但至少现在我知道它正在工作!感谢您抽出时间查看我的问题并写出答案,我非常感激。
以下是我使用的代码:
#include <string.h>
#include <stdlib.h>
#include <emmintrin.h>
#include <stdio.h>
#include <math.h>
int main(int argc, char** argv) {
long b = strtol(argv[2], NULL, 0);
unsigned long long int i;
unsigned long long int n = (int)pow(2,29);
float total = 0;
float *__restrict__ x1;
float *__restrict__ y1;
posix_memalign((void *)&x1, 16, sizeof(float)*n);
posix_memalign((void *)&y1, 16, sizeof(float)*n);
float *__restrict__ x = __builtin_assume_aligned(x1,16);
float *__restrict__ y = __builtin_assume_aligned(y1,16);
for (i=0;i<n;i++) {
x[i] = i;
y[i] = i;
}
for (i=0; i<n; i++) {
y[i] += x[i];
}
printf("y[%li]: \t\t\t\t%f\n", b,y[b]);
printf("correct answer: \t\t\t%f\n", (b)*2);
return 0;
}
对我来说,这些东西有些多余,但是为了让编译器理解发生了什么(特别是数据对齐的事实),这些都是必要的。从命令行读取的“b”变量只是因为我担心编译器会完全优化掉循环。
当启用向量化时,以下是编译器命令:
gcc47 -ftree-vectorizer-verbose=3 -msse2 -lm -O2 -finline-functions -funswitch-loops -fpredictive-commoning -fgcse-after-reload -fipa-cp-clone test.c -ftree-vectorize -o v
基本上,这相当于只使用 -O3。我自己添加了标志,这样我只需要删除“ftree-vectorize”,就能够测试不带向量化的结果。
以下是 ftree-vectorize-verbose 标志的输出,以显示代码确实正在进行向量化:
Analyzing loop at test.c:29
29: vect_model_load_cost: aligned.
29: vect_model_load_cost: inside_cost = 1, outside_cost = 0 .
29: vect_model_load_cost: aligned.
29: vect_model_load_cost: inside_cost = 1, outside_cost = 0 .
29: vect_model_simple_cost: inside_cost = 1, outside_cost = 0 .
29: vect_model_store_cost: aligned.
29: vect_model_store_cost: inside_cost = 1, outside_cost = 0 .
29: cost model: Adding cost of checks for loop versioning aliasing.
29: Cost model analysis:
Vector inside of loop cost: 4
Vector outside of loop cost: 4
Scalar iteration cost: 4
Scalar outside cost: 1
prologue iterations: 0
epilogue iterations: 0
Calculated minimum iters for profitability: 2
29: Profitability threshold = 3
Vectorizing loop at test.c:29
29: Profitability threshold is 3 loop iterations.
29: created 1 versioning for alias checks.
29: LOOP VECTORIZED.
Analyzing loop at test.c:24
24: vect_model_induction_cost: inside_cost = 2, outside_cost = 2 .
24: vect_model_simple_cost: inside_cost = 2, outside_cost = 0 .
24: not vectorized: relevant stmt not supported: D.5806_18 = (float) D.5823_58;
test.c:7: note: vectorized 1 loops in function.
请注意,向量化在3次迭代后是有益的,我正在运行2^29~=500,000,000次迭代。因此,如果关闭向量化,我应该期望运行时间大不相同,对吧?
好的,这里是代码的运行时间(我连续运行了20次):
59.082s
79.385s
57.557s
57.264s
53.588s
54.300s
53.645s
69.044s
57.238s
59.366s
56.314s
55.224s
57.308s
57.682s
56.083s
369.590s
59.963s
55.683s
54.979s
62.309s
除去那个奇怪的 370 秒的异常值,平均运行时间为 58.7 秒,标准差为 6.0 秒。
接下来,我将使用与之前相同的命令进行编译,但不使用 -ftree-vectorize 标志:
gcc47 -ftree-vectorizer-verbose=3 -msse2 -lm -O2 -finline-functions -funswitch-loops -fpredictive-commoning -fgcse-after-reload -fipa-cp-clone test.c -o nov
再次连续运行程序20次,得到以下时间:
69.471s
57.134s
56.240s
57.040s
55.787s
56.530s
60.010s
60.187s
324.227s
56.377s
55.337s
54.110s
56.164s
59.919s
493.468s
63.876s
57.389s
55.553s
54.908s
56.828s
再次排除异常值,这给出了平均运行时间为57.9秒,标准偏差为3.6秒。
因此,这两个版本的运行时间在统计上无法区分。
有人能告诉我我做错了什么吗?编译器输出的“盈利门槛”不是我想象的意思吗?我非常感谢大家能给我任何帮助,我过去一周一直在试图弄清楚这个问题。
编辑:我实现了@nilspipenbrinck建议的更改,似乎已经奏效。我将向量化循环放入函数中,并多次调用该函数。没有向量化的相对运行时间现在为24.0秒(小于0.1秒的sigma),向量化的相对运行时间为20.8秒(小于0.2秒的sigma),或者速度提高了13%。虽然不如我所希望的那样快,但至少现在我知道它正在工作!感谢您抽出时间查看我的问题并写出答案,我非常感激。