说,我给了一台假想的机器:Hypothetical Von-Neumann。
图片说:
现在,鉴于这台机器。我想知道计算代码片段的CPU周期成本的细节/规则。例如,请使用此代码,其中A
是1024x1024 int
矩阵,并且已使用整数进行初始化:
#define N 1024
sum=0;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
sum+=A[i][j];
}
A
。我不是在寻找一个确切的答案,只是想知道如何搞清楚它的程序。我不完全确定代码如何使用各种内存。例如,当i = 0
和j = 0
(第一次迭代)时,A将从主内存中调用吗?那么这意味着1 kB的数据是从主内存传输到缓存还是只有4 Byte,因为该元素只是一个整数?那些指令或操作的内存呢?只是对此感到困惑。
A[i][j]
替换为A[j][i]
以上该怎么办?编辑:我只想知道如何计算CPU周期来仅获取矩阵A的数据。
答案 0 :(得分:0)
假设32位int并且没有其他优化,那么实际使用缓存
A是一个2-dim数组,看起来像here提到的1-dim数组:
int array1[2][2] = {{0, 1}, {2, 3}};
在内存中看起来像这样:
0 1 2 3
因此,当CPU尝试执行sum += A[i][j]
时,它需要1 KB来自内存,代价为150个CPU周期并将其写入缓存。这个动作第一次发生的时间是i=j=0
,所以来自那个地方的1 KB的整数(假设32位整数)是2 ^ 8整数(基本上它是A [0] [0-] 255]第一个要素)。
现在,每次添加sum += A[i][j]
都是通过转到缓存并使用那里写的内存完成的(还有时间检查数据是否在缓存中,但是因为你没有&#39在问题中提到它,我现在也会这样做)
所以,总而言之,您只需要以150个周期的成本将1 KB放入缓存中,并且您可以从中读取另外255个(再次假设为32位int)ints in 1每个int循环(第一个已经从内存中读取)
糟糕,糟糕的事情会发生。此操作将使缓存生产力无效,因为每次您将获取新的int,您将发现它不在缓存中,您将不得不从内存中获取它(再次150个循环。再次:( )
答案 1 :(得分:0)
要计算循环时间,您需要知道每个缓存行的字节数,整数的大小,并准确计算执行此循环所需的时间还取决于编译器为其生成的内容。循环迭代,至少两个循环的内部将执行100万次,因此对于一个增量和一个比较操作的典型情况,至少需要几百万个循环。
考虑到缓存行的大小,所花费的时间是:
显然,索引的顺序很重要:C中数组中元素的地址,比如T arr[A][B];
,访问arr[a][b]
是arr + (sizeof(T) * (A * a + b)
,所以如果“下一个”访问距离很远,然后缓存行不会占用被访问的下一个元素。
[我相信问题的Fortran部分是指在Fortran中,给定元素的地址计算与C的地址计算相反 - 换句话说,第一个索引是移动一个的索引如果我们具有与上面相同的数组定义,则一次sizeof(T)
,最右边的索引正在移动sizeof(T) * B
。]