如何计算C ++代码段的CPU周期成本?

时间:2016-01-23 18:15:05

标签: c++ memory

说,我给了一台假想的机器:Hypothetical Von-Neumann

图片说:

  • 缓存为1 kB,获取1个浮点(8个字节)的成本为1个CPU周期。
  • 如果代码所需的数据不在缓存中,则以150个CPU周期为代价从RAM(10MB)中获取1 kB数据。

现在,鉴于这台机器。我想知道计算代码片段的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];
}
  1. 我如何计算no。获取矩阵A数据所需的CPU周期?我&#39;米 混淆了如何从主存储器中取出矩阵A。我不是在寻找一个确切的答案,只是想知道如何搞清楚它的程序。我不完全确定代码如何使用各种内存。
  2. 例如,当i = 0j = 0(第一次迭代)时,A将从主内存中调用吗?那么这意味着1 kB的数据是从主内存传输到缓存还是只有4 Byte,因为该元素只是一个整数?那些指令或操作的内存呢?只是对此感到困惑。

    1. 如果我将A[i][j]替换为A[j][i]以上该怎么办?
    2. 另外,如果在FORTRAN中写入完全相同的代码,它会有什么不同?
    3. 编辑:我只想知道如何计算CPU周期来仅获取矩阵A的数据。

2 个答案:

答案 0 :(得分:0)

假设32位int并且没有其他优化,那么实际使用缓存

  1. 我如何计算no。需要CPU周期? 我对如何从主存储器中提取数组A感到困惑。
  2. 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循环(第一个已经从内存中读取)

    1. 如果我用上面的A [j] [i]替换A [i] [j]怎么办?
    2. 糟糕,糟糕的事情会发生。此操作将使缓存生产力无效,因为每次您将获取新的int,您将发现它不在缓存中,您将不得不从内存中获取它(再次150个循环。再次:( )

答案 1 :(得分:0)

要计算循环时间,您需要知道每个缓存行的字节数,整数的大小,并准确计算执行此循环所需的时间还取决于编译器为其生成的内容。循环迭代,至少两个循环的内部将执行100万次,因此对于一个增量和一个比较操作的典型情况,至少需要几百万个循环。

考虑到缓存行的大小,所花费的时间是:

  • totalsize = 1024 * 1024 * sizeof(int);
  • 150 * totalsize / cachelinesize
  • 1 *(totalsize - (totalsize / cachelinesize))

显然,索引的顺序很重要:C中数组中元素的地址,比如T arr[A][B];,访问arr[a][b]arr + (sizeof(T) * (A * a + b),所以如果“下一个”访问距离很远,然后缓存行不会占用被访问的下一个元素。

[我相信问题的Fortran部分是指在Fortran中,给定元素的地址计算与C的地址计算相反 - 换句话说,第一个索引是移动一个的索引如果我们具有与上面相同的数组定义,则一次sizeof(T),最右边的索引正在移动sizeof(T) * B。]