我正在尝试确定访问两个内存地址的时间,这两个内存地址由某个delta隔开。我的代码必须混合x86和C,并且将运行“裸机”(没有任何操作系统;编辑:我实际上正在修改memtest)以获得最精确的结果。
我比x86更习惯ARM程序集,因此我可能会犯一些错误(我想知道为什么mov在x86中做了很多不同的事情)。到目前为止我的代码如下。
inline unsigned timeread (ulong addr, ulong delta, int iter)
{
ulong daddr;
int i;
ulong st_low, st_high;
ulong end_low, end_high;
daddr = addr + delta;
asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
for (i = 0; i < iter; ++i)
{
asm __volatile__ (
"movl (%0), %%eax\n\t"
:
: "D" (addr)
: "eax"
);
asm __volatile__ (
"movl (%0), %%eax\n\t"
:
: "D" (daddr)
: "eax"
);
}
asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high));
asm __volatile__ (
"subl %2,%0\n\t"
"sbbl %3,%1"
: "=a" (end_low), "=d" (end_high)
: "g" (st_low), "g" (st_high),
"0" (end_low), "1" (end_high)
);
return end_low;
}
我正在使用gcc并使用标志-march = i486 -m32进行编译。
编辑:在调用函数之前,我调用memtest,set_cache(0)提供的函数,以便停用缓存(至少,就是它所说的)。调用set_cache(1)会极大地减少执行时间(我从~2000个周期下降到<10个周期)。 如果还有一些缓存,我想memtest也找不到解决这个问题的方法。
编辑:提出问题通常有助于得到答案...
汇编代码是否正确?我很惊讶mov能够访问x86中的RAM,因为在ARM中你会使用专用的LDR。
答案 0 :(得分:0)
不管你的代码是否真正衡量你想要的是什么,你的代码是正确的。 Intel x86指令集不遵循ARM指令集设计时使用的相同RISC原则。 RISC中有专门用于加载和存储到内存的单独指令。这与早期的CPU设计风格(追溯名为CISC)不同,大多数指令都可以直接访问内存。不只是移动指令,还有添加和跳转等内容。所以,是的,你的MOVL指令按照你的意愿在内存中加载EAX的32位值。
请注意,因为您在MOVL asm语句中使用了"D"
约束,所以编译器必须在每个asm语句之前重新加载EDI。由于没有明显的理由将其约束到EDI,我建议使用"r"
约束,以便编译器可以选择两个不同的寄存器。启用优化后,编译器只能在循环外加载这两个寄存器,而不是在循环期间每次加载。 (如果您不使用优化,则编译器将在每次循环迭代期间从堆栈中存储addr
和daddr
的任何一种方式加载寄存器。)
例如:
asm volatile (
"movl (%0), %%eax\n\t"
:
: "r" (addr)
: "eax"
);
asm volatile (
"movl (%0), %%eax\n\t"
:
: "r" (daddr)
: "eax"
);