具有不同cpu周期的相同指令 < >我正在调试一个C++程序,两个不同的输入导致几乎相同的数字或指令,但是CPU周期之间存在格子差异。p>
下面是性能统计信息,这真的很奇怪。有人知道是什么导致了这样的时差吗具有不同cpu周期的相同指令 < >我正在调试一个C++程序,两个不同的输入导致几乎相同的数字或指令,但是CPU周期之间存在格子差异。p>,c++,performance,intel,avx,instructions,C++,Performance,Intel,Avx,Instructions,下面是性能统计信息,这真的很奇怪。有人知道是什么导致了这样的时差吗 /sai2 100000,C,98.700,60,98.695,0.2,0.0的性能计数器统计数据: 2684.371940 task-clock (msec) # 1.000 CPUs utilized 17 context-switches # 0.006 K/sec
/sai2 100000,C,98.700,60,98.695,0.2,0.0的性能计数器统计数据:
2684.371940 task-clock (msec) # 1.000 CPUs utilized
17 context-switches # 0.006 K/sec
1 cpu-migrations # 0.000 K/sec
921 page-faults # 0.343 K/sec
7,292,413,665 cycles # 2.717 GHz
11,267,827,416 instructions # 1.55 insn per cycle
940,483,779 branches # 350.355 M/sec
132,437 branch-misses # 0.01% of all branches
2.685433574 seconds time elapsed
/sai2 100000的性能计数器统计数据,p,98.700,60,98.695,0.2,0.0
25698.831411 task-clock (msec) # 1.000 CPUs utilized
72 context-switches # 0.003 K/sec
19 cpu-migrations # 0.001 K/sec
921 page-faults # 0.036 K/sec
70,402,935,601 cycles # 2.740 GHz
10,418,026,021 instructions # 0.15 insn per cycle
956,483,724 branches # 37.219 M/sec
323,444 branch-misses # 0.03% of all branches
25.702346518 seconds time elapsed
真正让我困惑的是,大多数时间成本代码几乎是相同的
// const double vector definitions
__m256d vec_1_p = _mm256_set1_pd(v_1_p_discount);
__m256d vec_p = _mm256_set1_pd(v_p_discount);
__m256d vec_tricky = _mm256_set_pd(tricky_3, tricky_2, tricky, 1);
__m256d vec_strike = _mm256_set1_pd(strike);
for (int m = m_stepNumber - 1; m > 0; m--) {
double m_s_pointer = power_d / d;
power_d = m_s_pointer;
for (int n = 0; n < m; n += 4) {
double *val = known + n;
double *dest = to_calc + n;
__m256d hold_0 = _mm256_load_pd(val);
__m256d hold_1 = _mm256_loadu_pd(val+1);
hold_0 = _mm256_mul_pd(hold_0, vec_1_p);
hold_1 = _mm256_mul_pd(hold_1, vec_p);
hold_0 = _mm256_add_pd(hold_0, hold_1);
__m256d vec_tmp = _mm256_set1_pd(m_s_pointer);
vec_tmp = _mm256_mul_pd(vec_tmp, vec_tricky);
//vec_tmp = _mm256_sub_pd(vec_tmp, vec_strike); this run in quick case
//vec_tmp = _mm256_sub_pd(vec_strike, vec_tmp); this run in slow case
hold_0 = _mm256_max_pd(hold_0, vec_tmp);
_mm256_store_pd(dest, hold_0);
m_s_pointer *= tricky_4;
}
std::swap(known, to_calc);
}
更快的案例
3.43 │398:┌─→vmovup -0x8(%rdx),%ymm3
9.18 │ │ add $0x4,%ecx
1.64 │ │ add $0x20,%rdx
5.44 │ │ vmovup -0x20(%rdx),%ymm0
12.03 │ │ add $0x20,%rsi
2.32 │ │ vmulpd %ymm1,%ymm3,%ymm3
7.28 │ │ vfmadd %ymm2,%ymm3,%ymm0
16.77 │ │ vmovup -0x20(%rsi),%ymm3
19.33 │ │ vmaxpd %ymm3,%ymm0,%ymm0
15.83 │ │ vmovup %ymm0,-0x28(%rdx)
6.70 │ │ cmp %edi,%ecx
│ └──jle 398
这些结果是可重复的吗?看起来第二次运行有很多上下文切换和cpu迁移,是否有其他东西在后台运行?结果是可复制的,我使用了一个物理&a虚拟机运行了很多次。参数100000可用于增加算法复杂度,后者总是较慢。我显示了perf record
的信息,看到的火锅是vmovup-0x20(%rsi),%ymm3
,但我无法理解原因。@AlanBirtles:考虑到第二个上下文开关运行了10倍多的时间,这些上下文开关数字看起来很正常。通常缓存未命中加载会在perf record
中显示,因为消耗加载结果的指令上花费了更多的时间,而不是加载本身,但这将是一个很明显的解释非常低的ILP在一个类似的循环。两个版本的asm版本都没有通过向量指令的循环依赖链:它们每次加载新数据并存储结果。是否有可能输出阵列与其中一个输入之间的距离是4KB的精确倍数,从而产生错误的内存依赖关系?
3.43 │398:┌─→vmovup -0x8(%rdx),%ymm3
9.18 │ │ add $0x4,%ecx
1.64 │ │ add $0x20,%rdx
5.44 │ │ vmovup -0x20(%rdx),%ymm0
12.03 │ │ add $0x20,%rsi
2.32 │ │ vmulpd %ymm1,%ymm3,%ymm3
7.28 │ │ vfmadd %ymm2,%ymm3,%ymm0
16.77 │ │ vmovup -0x20(%rsi),%ymm3
19.33 │ │ vmaxpd %ymm3,%ymm0,%ymm0
15.83 │ │ vmovup %ymm0,-0x28(%rdx)
6.70 │ │ cmp %edi,%ecx
│ └──jle 398