gpt4 book ai didi

c - GCC 自动矢量化对运行时没有影响,即使假定为 "profitable"

转载 作者:太空狗 更新时间:2023-10-29 17:11:05 25 4
gpt4 key购买 nike

过去几天我一直在阅读有关 gcc 4.7 的自动向量化。我按照我在网上看到的一些示例进行操作,设置似乎是正确的。但是当我实际运行代码并比较打开或关闭矢量化时,运行时间没有明显差异。

这是我一直在使用的代码:

#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.0s(<0.1s 的 sigma),而矢量化的相对运行时间为 20.8s(<0.2s 的 sigma),或者速度提高了 13%。没有我希望的那么多,但至少现在我知道它的工作原理!感谢您花时间查看我的问题并写下答案,我真的很感激。

最佳答案

你不会做太多算术运算。因此,测试代码的运行时间受内存限制。例如。您花费大部分时间在 CPU 和内存之间移动数据。

此外,您的 n 非常大,有 2^29 个元素。因此,您不会以任何方式从一级和二级缓存中获益。

如果您想看到 SSE 的改进,请使用较小的 n,这样您只需要接触 8 或 16 KB 的数据。还要确保数据是“热的”,例如它最近被 CPU 访问过。这样,数据就不必从主内存中移出,而是从缓存中移出,速度要快几个数量级。

作为替代方案,您还可以做更多的很多算术运算。这将使内存预取系统有机会在您利用 CPU 进行数学运算时在后台从主内存中获取数据。

总结:如果算法速度快于系统移动内存的速度,您将看不到任何好处。内存访问时间将成为瓶颈,您使用 SSE 指令集节省的几个周期将在内存访问时序的噪音中丢失。

关于c - GCC 自动矢量化对运行时没有影响,即使假定为 "profitable",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26945981/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com