测量TLB对Cortex-A9的影响

时间:2015-05-29 12:59:56

标签: c arm benchmarking embedded-linux cortex-a

阅读下面的论文https://people.freebsd.org/~lstewart/articles/cpumemory.pdf("每个程序员应该了解内存和#34;)我想尝试一下作者的测试,即测量效果TLB在最后的执行时间。

我正在开发一款嵌入了Cortex-A9的三星Galaxy S3。

根据文件:

我写了一个小程序,用N个条目分配一个结构数组。每个条目的大小为== 32个字节,因此它适合缓存行。 我执行几次读取访问,并测量执行时间。

typedef struct {
     int elmt; // sizeof(int) == 4 bytes
     char padding[28]; // 4 + 28 = 32B == cache line size
}entry;


volatile entry ** entries = NULL;

//Allocate memory and init to 0
entries = calloc(NB_ENTRIES, sizeof(entry *));
if(entries == NULL) perror("calloc failed"); exit(1);

for(i = 0; i < NB_ENTRIES; i++)
{
      entries[i] = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
      if(entries[i] == MAP_FAILED) perror("mmap failed"); exit(1);
}

entries[LAST_ELEMENT]->elmt = -1

//Randomly access and init with random values
n = -1;
i = 0;
while(++n < NB_ENTRIES -1)
{
      //init with random value
      entries[i]->elmt = rand() % NB_ENTRIES;

      //loop till we reach the last element
      while(entries[entries[i]->elmt]->elmt != -1)
      {
            entries[i]->elmt++;
            if(entries[i]->elmt == NB_ENTRIES)
                     entries[i]->elmt = 0;
      }

       i = entries[i]->elmt;
}


gettimeofday(&tStart, NULL);
for(i = 0; i < NB_LOOPS; i++)
{
     j = 0;
     while(j != -1)
     {
          j = entries[j]->elmt
     }
}
gettimeofday(&tEnd, NULL);

time = (tEnd.tv_sec - tStart.tv_sec);
time *= 1000000;
time += tEnd.tv_usec - tStart.tv_usec;
time *= 100000
time /= (NB_ENTRIES * NBLOOPS);

fprintf(stdout, "%d %3lld.%02lld\n", NB_ENTRIES, time / 100, time % 100);

我有一个外部循环,使NB_ENTRIES从4变化到1024.

如下图所示,当NB_ENTRIES == 256个条目时,执行时间更长。

当NB_ENTRIES == 404时,我得到一个&#34;内存不足&#34; (为什么?微TLB超出?主TLB超出?页面表超出了?超过了虚拟内存?)

有人可以解释一下,从4到256个条目,然后从257到404条目真正发生了什么?

Effects of TLB on execution time

编辑1

正如有人建议的那样,我运行了membench(src code)并低于结果:

membench results

编辑2

在下面的paper(第3页)中,他们运行(我猜)相同的基准。但是从他们的情节中可以清楚地看到不同的步骤,这不是我的情况。

enter image description here

现在,根据他们的结果和解释,我只能识别一些事情。

  • 图表确认L1缓存行大小为32字节,因为他们说
  

&#34;一旦数组大小超过数据高速缓存的大小(32KB),读取开始产生未命中[...]当每次读取产生错误时会出现拐点&#34;。

在我的情况下,当stride == 32 Bytes时出现第一个拐点。   - 图表显示我们有一个二级(L2)缓存。我认为它是用黄线描绘的(1MB == L2尺寸)   - 因此,后者上面的最后两个图可能反映了访问主内存时的延迟(+ TLB?)。

然而,从这个基准测试来看,我无法确定:

  • 缓存关联性。通常,D-Cache和I-Cache是​​4向关联的(Cortex-A9 TRM)。
  • TLB效应。正如他们所说,
  在大多数系统中,延迟的次要增加表示TLB,TLB缓存有限数量的虚拟到物理翻译。[..]由TLB引起的延迟没有增加表明[...] &#34;

可能已经使用/实施了大页面大小。

编辑3

这个link解释了另一个元素图的TLB效应。实际上可以在我的图表上检索相同的效果。

  

在一个4KB的页面系统上,随着你的步伐越来越大,他们仍然会在4K,你会越来越少地利用每一页[...]你必须在每次访问时访问第二级TLB [...]

皮质-A9支持4KB pages mode。 事实上,正如人们可以在我的图表中看到步幅== 4K,延迟时间正在增加,然后,当它达到4K时

  

你突然开始受益,因为你实际上正在跳过整个页面。

1 个答案:

答案 0 :(得分:2)

tl; dr - &gt;提供适当的MVCE

这个答案应该是一个评论,但是太大而无法发布为评论,所以发布为答案:

  1. 我不得不修复一堆语法错误(缺少分号)并声明未定义的变量。

  2. 解决了所有这些问题之后,代码没有任何问题(程序甚至在执行第一个mmap之前就退出了。我给出的提示始终使用大括号,这是你的第一个以及因为不这样做导致的第二个错误:

  3. // after calloc:
    if(entries == NULL) perror("calloc failed"); exit(1);
    // after mmap
    if(entries[i] == MAP_FAILED) perror("mmap failed"); exit(1);
    

    无论条件如何,这两行都会终止你的程序。

    1. 这里有一个无限循环(重新格式化,添加了大括号,但没有其他变化):
    2. //Randomly access and init with random values
      n = -1;
      i = 0;
      while (++n < NB_ENTRIES -1) {
          //init with random value
          entries[i]->elmt = rand() % NB_ENTRIES;
      
          //loop till we reach the last element
          while (entries[entries[i]->elmt]->elmt != -1) {
              entries[i]->elmt++;
              if (entries[i]->elmt == NB_ENTRIES) {
                  entries[i]->elmt = 0;
              }
          }
      
          i = entries[i]->elmt;
      }
      

      首先通过将entries[0]->elmt设置为某个随机值开始迭代,然后内循环递增直到达到LAST_ELEMENT。然后i设置为该值(即LAST_ELEMENT),第二个循环将结束标记-1覆盖为某个其他随机值。然后它会在内部循环中不断增加mod NB_ENTRIES,直到你按下CTRL + C.

        

      结论

      如果您需要帮助,请发布Minimal, Complete, and Verifiable example而不是其他内容。