测量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条目?
编辑1
正如已经build议的那样,我运行了membench( src代码 )并且在结果之下:
编辑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 。
这个答案应该是一个评论,但是太大,不能发表评论,所以发帖回答:
-
我不得不修复一堆语法错误(缺less分号)并声明未定义的variables。
-
解决了所有这些问题后,代码没有任何问题(甚至在执行第一个
mmap
之前,程序就退出了)。我一直在给大括号使用大括号,下面是第一个和第二个错误:
。
// after calloc: if(entries == NULL) perror("calloc failed"); exit(1); // after mmap if(entries[i] == MAP_FAILED) perror("mmap failed"); exit(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的示例,而不是别的。