测量TLB对Cortex-A9的影响

阅读以下文章后,我想尝试一个作者的testing,即测量效果TLB在最后的执行时间。

我正在研究embeddedCortex-A9的三星Galaxy S3。

根据文件:

  • 我们在L1中有两个用于指令和数据caching的微型TLB( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0388e/Chddiifa.html )

  • 主TLB位于L2( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0388e/Chddiifa.html )

  • 数据微型TLB有32个入口(指令微型TLB有32或64个入口)

  • L1'大小= 32千字节
  • L1caching行== 32字节
  • L2'大小== 1MB

我写了一个小程序,用N个条目分配一个结构数组。 每个条目的大小是== 32字节,所以它适合在caching线。 我执行几个读取访问,并测量执行时间。

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时,我得到一个“内存不足”(为什么?微型TLB超出了?主TLB超出了?超过了页表?超过了虚拟内存?)

有人可以解释我真正从4到256个条目,然后从257到404条目?

TLB对执行时间的影响

编辑1

正如已经build议的那样,我运行了membench( src代码 )并且在结果之下:

membench的结果

编辑2

在下面的文章 (第3页)中,他们跑了(我想)是相同的基准。 但是从他们的情节中清楚地看到不同的步骤,这不是我的情况。

在这里输入图像说明

现在,根据他们的结果和解释,我只能辨别出几件事情。

  • 因为正如他们所说的那样,图确认L1caching行大小是32字节

“一旦数组大小超过数据高速caching(32KB)的大小,读取开始产生失误[…],每当读取产生错误时,都会出现拐点”。

在我的情况下,当stride == 32 Bytes时出现第一个拐点。 – 该图显示我们有一个二级(L2)caching。 我认为这是由黄线(1MB == L2大小)描绘的 – 因此,最后两个图表可能反映了访问主内存(+ TLB?)时的延迟。

但是从这个基准,我无法确定:

  • caching关联性。 通常,D-Cache和I-Cache是​​4路关联的( Cortex-A9 TRM )。
  • TLB的影响。 正如他们所说,

在大多数系统中,延迟的次要增加表明了TLB,它caching了有限数量的虚拟到物理翻译。[…]由于TLB引起的延迟没有增加,这表明“

大页面大小可能已被使用/实现。

编辑3

这个链接解释了另一个成员图的TLB效应。 实际上,我可以在我的图上检索相同的效果。

在4KB的页面系统中,当你增长的时候,当它们仍然是<4K时,你将享受到每个页面的利用越来越less,你将不得不在每次访问时访问第二级TLB [ …]

cortex-A9支持4KB页面模式 。 事实上,正如人们在图表中可以看到步长== 4K,则延迟时间正在增加,然后在达到4K时

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

tl; dr – >提供适当的MVCE 。

这个答案应该是一个评论,但是太大,不能发表评论,所以发帖回答:

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

  2. 解决了所有这些问题后,代码没有任何问题(甚至在执行第一个mmap之前,程序就退出了)。我一直在给大括号使用大括号,下面是第一个和第二个错误:

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

无论条件如何,两条线都会终止您的程序。

  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; } 

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

结论

如果您需要帮助,请发布一个最小化,完整和可validation的示例,而不是别的。