【发布时间】:2013-12-25 16:24:57
【问题描述】:
我有以下功能:
void ikj(float (*a)[N], float (*b)[N], float (*c)[N], int n) {
int i, j, k;
float r;
papi_start();
for (i = 0; i < n; i++) {
for (k = 0; k < n; k++) {
r = a[i][k];
for (j = 0; j < n; j++)
c[i][j] += r * b[k][j];
}
}
papi_stop();
}
我正在使用PAPI 来计算在papi_start() 和papi_stop() 之间我有多少负载和存储,我得到的结果如下:
加载(使用PAPI_LD_INS):
32 26781
64 205053
128 1606077
256 12714815
512 101189551
1024 807406950
2048 6450848188
商店(使用PAPI_SR_INS):
32 8290
64 65698
128 524578
256 4194850
512 33555490
1024 268437701
2048 2147487778
其中第一个值是 N 的大小,第二个值是指令数。
我正在使用 O3 进行编译,我的缓存大小为 L1 = 32KB x 2(指令和数据,8 路)和 L2 = 1024KB(4 路)(2 核共享).. 我的 cpu 是Intel T3200 和 SSE3..
我知道 O3 优化了代码,因此它会在其他功能中使用预取,因为我正在加载连续地址并且我的缓存有 64 字节的行大小,所以我一次加载 16 个浮点数,但我的计算没有达不到这个值,谁能给我解释一下?
编辑:这是我的程序集文件,很抱歉将它们扔在这里,但我从未使用过程序集,我无法真正理解它:
http://dl.dropboxusercontent.com/u/878621/mmc.s http://dl.dropboxusercontent.com/u/878621/mmc_asm.s
谢谢!
【问题讨论】:
-
如果您还没有告诉我们您的
n是什么(除其他外),我们很难猜到。 -
您是否查看了编译器输出以了解编译器分配给寄存器的内容?寄存器访问不算作内存访问。此外,编译器可能已经对您的代码进行了矢量化处理,因此它通过一次加载或存储执行多个操作。
-
是的,我做到了,它是输出值的第一列,从 32 到 2048 .. @JerryCoffin
-
另外,PAPI 是否计算实际的加载和存储指令,或 L1D 获取和写回的数量?如果是加载和存储指令,那么缓存大小和行大小无关紧要。
-
@gnometorule - 硬件预取是内部的,编译器可能会添加额外的软件预取,这可能是有用的,因为编译器刚刚分析了整个代码,比 CPU 更了解程序上下文运行。但是,两者都与此性能计数器结果无关
标签: c++ c memory assembly papi