我正在对我的代码进行一些优化。首先我使用OpenMP进行并行编程然后我使用了GNU GCC编译器提供的优化标志。我还包括一个SSE指令来计算逆平方根。但我终于意识到问题是,当每个线程将结果写入reduce变量时,最后一次操作需要大约80%的时间。这里是并行循环:
time(&t5);
# pragma omp parallel for shared(NTOT) private(dx,dy,d,H,V,E,F,G,K) reduction(+:dU)
for(j = 1; j <= NTOT; j++){
if(!(j-i)) continue;
dx = (X[2*j-2]-X[2*i-2])*a;
dy = (X[2*j-1]-X[2*i-1])*a;
d = rsqrtSSE(dx*dx+dy*dy);
H = D*d*d*d;
V = dS[0]*spin[2*j-2]+dS[1]*spin[2*j-1];
E = dS[0]*dx+dS[1]*dy;
F = spin[2*j-2]*dx+spin[2*j-1]*dy;
G = -3*d*d*E*F;
K = H*(V+G);
dU += K;
}
time(&t6);
t_loop = difftime(t6, t5);
其中rsqrtSSE()是基于xmmintrin.h中__mm_rsqrt_ps(__ m128 X)预定义函数的函数。 如果有解决方案可以解决这个问题?或者这是由于带宽限制?
我使用gcc -o prog prog.c -lm -fopenmp -O3编译 - ffast-math -march = native
这里有一些关于我的电脑的信息: 架构:x86_64 CPU操作模式:32位,64位 字节顺序:Little Endian CPU:4 在线CPU列表:0-3 每个核心的线程:2 每个插座的核心:2 套接字:1 NUMA节点:1 供应商ID:GenuineIntel CPU系列:6 型号:69 型号名称:Intel(R)Core(TM)i5-4200U CPU @ 1.60GHz 步进:1 CPU MHz:849.382 CPU max MHz:2600.0000 CPU min MHz:800.0000 BogoMIPS:4589.17 虚拟化:VT-x L1d缓存:32K L1i缓存:32K L2缓存:256K L3缓存:3072K NUMA node0 CPU(s):0-3
并使用turboboost: CPU Avg_MHz%Busy Bzy_MHz TSC_MHz - 2294 99.97 2300 2295 0 2295 100.00 2300 2295 1 2295 100.00 2300 2295 2 2292 99.87 2300 2295 3 2295 100.00 2300 2295
答案 0 :(得分:1)
您的测量存在缺陷。
第一种方法是全部删除行,允许编译器优化大部分计算,只是因为结果未被使用。
如果我理解正确的话,第二种方法是将定时指令放在循环本身内,例如在dU += K
之前/之后。不幸的是,这也没有希望产生美妙的结果。任何库定时调用都是比此操作慢的magintune命令。因此,您基本上可以衡量获得时间所需的时间。您可以通过重复多个定时调用并比较差异来尝试。
从what I have seen开始,我怀疑OpenMP实现只是将dU
保留为线程私有变量,并且只有在循环完成后才执行简化原子/锁定操作。
确定单个线路性能的更好方法是使用抽样。看一下linux的perf
工具,它会非常有用。结果仍然可能并不总是完全可靠,因为可能存在偏差。由于编译器优化(例如展开)和硬件优化(例如流水线操作),多行代码可以同时处于执行状态。说一行代码花了多少时间成为一个非常困难的问题。
查看您是否遇到问题的一种方法是尝试找出理论上的硬件性能。对__mm_rsqrt_ps
而言似乎很难。您还可以查看硬件性能计数器,看看是否有很多缓存未命中等。perf
也可以帮助您。