[英]Measurement of TLB effects on a Cortex-A9
在阅读了以下论文后, https://people.freebsd.org/~lstewart/articles/cpumemory.pdf (“每个程序员应该了解内存的内容”)我想尝试一下作者的测试,即测量效果TLB的最终执行时间。
我正在研究嵌入Cortex-A9的三星Galaxy S3。
根据文件:
我们在L1中有两个用于指令和数据缓存的微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 )
Data micro TLB有32个条目(指令微TLB有32或64个条目)
我写了一个小程序,用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时,我得到“内存不足”(为什么?超出了TLB?主TLB超出了?页面表超出了?超出了进程的虚拟内存?)
有人可以解释一下,从4到256个条目,然后从257到404条目真正发生了什么?
编辑1
正如有人建议的那样,我运行了membench( src代码 )并在结果下面:
编辑2
在下面的论文 (第3页)中,他们运行(我想)相同的基准。 但是从他们的情节中可以清楚地看到不同的步骤,这不是我的情况。
现在,根据他们的结果和解释,我只能识别一些事情。
“一旦数组大小超过数据高速缓存的大小(32KB),读取开始产生未命中[...]当每次读取产生错误时会发生拐点”。
在我的情况下,当stride == 32 Bytes时出现第一个拐点。 - 图表显示我们有一个二级(L2)缓存。 我认为它用黄线表示(1MB == L2大小) - 因此后者上面的最后两个图可能反映了访问主存储器时的延迟(+ TLB?)。
但是从这个基准测试来看,我无法确定:
在大多数系统中,延迟的次要增加表示TLB,TLB缓存有限数量的虚拟到物理翻译。[..] TLB引起的延迟没有增加表明[...]“
可能已经使用/实现了大页面大小。
编辑3
该链接解释了另一个元素图的TLB效应。 实际上可以在我的图表上检索相同的效果。
在一个4KB的页面系统上,随着你的步伐越来越大,当它们仍然<4K时,你将享受越来越少的每页使用率[...]你必须在每次访问时访问二级TLB [ ...]
cortex-A9支持4KB页面模式 。 事实上,正如人们可以在我的图表中看到步幅== 4K,等待时间增加,然后,当它达到4K时
你突然开始受益,因为你实际上是在跳过整个页面。
tl; dr - >提供适当的MVCE 。
这个答案应该是一个评论,但是太大而不能发布为评论,所以发布为答案:
我不得不修复一堆语法错误(缺少分号)并声明未定义的变量。
解决了所有这些问题之后,代码没有任何问题(程序甚至在执行第一个mmap
之前就退出了。我给出的提示始终使用大括号,这是你的第一个错误,第二个错误是由NOT执行的:
。
// 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.
结论
如果您需要帮助,请发布一个Minimal,Complete和Verifiable示例,而不是其他内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.