【发布时间】:2015-08-06 20:12:49
【问题描述】:
以下代码有问题,我不明白问题出在哪里。但是,该问题仅发生在 V2 英特尔处理器而不是 V3 上。 考虑以下 C++ 代码:
struct Tuple{
size_t _a;
size_t _b;
size_t _c;
size_t _d;
size_t _e;
size_t _f;
size_t _g;
size_t _h;
};
void
deref_A(Tuple& aTuple, const size_t& aIdx) {
aTuple._a = A[aIdx];
}
void
deref_AB(Tuple& aTuple, const size_t& aIdx) {
aTuple._a = A[aIdx];
aTuple._b = B[aIdx];
}
void
deref_ABC(Tuple& aTuple, const size_t& aIdx) {
aTuple._a = A[aIdx];
aTuple._b = B[aIdx];
aTuple._c = C[aIdx];
}
....
void
deref_ABCDEFG(Tuple& aTuple, const size_t& aIdx) {
aTuple._a = A[aIdx];
aTuple._b = B[aIdx];
aTuple._c = C[aIdx];
aTuple._d = D[aIdx];
aTuple._e = E[aIdx];
aTuple._f = F[aIdx];
aTuple._g = G[aIdx];
}
请注意,A、B、C、...、G 是简单的数组(全局声明)。数组用整数填充。
方法“deref_*”,简单地将数组中的一些值(通过索引访问 - aIdx)分配给给定的结构参数“aTuple”。我首先将给定结构的单个字段作为参数分配,然后一直继续到所有字段。也就是说,每个方法都比前一个方法多分配一个字段。方法“deref_*”被调用,索引(aIdx)从 0 开始,到数组的 MAX 大小(顺便说一下,数组具有相同的大小)。索引用于访问数组元素,如代码所示——非常简单。
现在,考虑图表 (http://docdro.id/AUSil1f),它描述了从 2000 万(size_t = 8 字节)整数开始到 24 m(x 轴表示数组大小)的数组大小的性能。
对于具有 2100 万个整数 (size_t) 的数组,接触至少 5 个不同数组的方法(即 deref_ACDE...G)的性能会下降,因此您会在图中看到峰值。然后,对于具有 22 m 整数及以上的数组,性能再次提高。我想知道为什么只有 21 m 的数组大小会发生这种情况?仅当我在具有 CPU 的服务器上测试时才会发生这种情况:Intel(R) Xeon(R) CPU E5-2690 v2 @ 3.00GHz,但不使用 Haswell,即 v3。显然这是 Intel 的一个已知问题并且已经解决,但我不知道它是什么,以及如何改进 v2 的代码。
我将非常感谢您的任何提示。
【问题讨论】:
-
v3 引入了change in carche management,通过将核心所需的数据放在一起来减少读/写延迟。这也许可以解释您的观察结果
-
Christophe,但是为什么只有 21 m 的数组大小会出现性能下降?
-
您是否使用类似
perf的方式对性能计数器进行了采样? -
这可能是缓存关联性问题。你能转储数组 A...G 的起始地址吗?您是在单核上运行测试还是并行运行多个实例?
-
保罗,它不是缓存关联性,我最初也是这样。我已经向数组添加了填充,但结果相同。数组的大小不是 2 的幂,已知会导致缓存关联性问题。最后,我发现问题是 L1 中的 TLB 未命中。
标签: c++ memory optimization intel