确定X86程序集中的内存访问时间

时间:2015-06-03 13:28:55

标签: assembly x86

我正在尝试确定访问两个内存地址的时间,这两个内存地址由某个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。

1 个答案:

答案 0 :(得分:0)

不管你的代码是否真正衡量你想要的是什么,你的代码是正确的。 Intel x86指令集不遵循ARM指令集设计时使用的相同RISC原则。 RISC中有专门用于加载和存储到内存的单独指令。这与早期的CPU设计风格(追溯名为CISC)不同,大多数指令都可以直接访问内存。不只是移动指令,还有添加和跳转等内容。所以,是的,你的MOVL指令按照你的意愿在内存中加载EAX的32位值。

请注意,因为您在MOVL asm语句中使用了"D"约束,所以编译器必须在每个asm语句之前重新加载EDI。由于没有明显的理由将其约束到EDI,我建议使用"r"约束,以便编译器可以选择两个不同的寄存器。启用优化后,编译器只能在循环外加载这两个寄存器,而不是在循环期间每次加载。 (如果您不使用优化,则编译器将在每次循环迭代期间从堆栈中存储addrdaddr的任何一种方式加载寄存器。)

例如:

    asm volatile (
        "movl (%0), %%eax\n\t"
        :
        : "r" (addr)
        : "eax"
    );

    asm volatile (
        "movl (%0), %%eax\n\t"
        :
        : "r" (daddr)
        : "eax"
    );