X86 忙环与障碍

X86 忙环与障碍,x86,operating-system,barrier,X86,Operating System,Barrier,我知道asm volatile(“:“memory”)阻止编译器重新排序指令。但是,在这里,我看不出什么可以重新排序,以及为什么它在并发性方面会有问题。(我考虑了可能的中断)。那么,为什么会有障碍呢 第二,相关问题。 假设我们有一段10000000行的代码(见下文)。正如我们所知,CPU可以对StoreLoad进行重新排序 mov[eax],$2; 否; 否; ...; 否; mov-ebx[ecx] CPU能够预测应用StoreLoad的可能性有多大 同样的问题也可以应用于编译器,但它涉及到各

我知道
asm volatile(“:“memory”)
阻止编译器重新排序指令。但是,在这里,我看不出什么可以重新排序,以及为什么它在并发性方面会有问题。(我考虑了可能的中断)。那么,为什么会有障碍呢

  • 第二,相关问题。 假设我们有一段10000000行的代码(见下文)。正如我们所知,CPU可以对StoreLoad进行重新排序

    mov[eax],$2; 否; 否; ...; 否; mov-ebx[ecx]

  • CPU能够预测应用StoreLoad的可能性有多大


    同样的问题也可以应用于编译器,但它涉及到各种重新排序(不仅是存储加载,也不仅仅是内存操作)

    TL:DR:这里的问题是,您只把它看作是
    std::atomic_thread_fence(std::memory_order_seq_cst)
    ,但这不是GNUC
    volatile asm
    语句所做的唯一事情


    是的,很明显,障碍是为了形成一个令人讨厌的繁忙等待-延迟循环。记住volatile
    asm
    语句不能与任何其他C语句一起重新排序,而不仅仅是内存操作

    我们仍然会得到一个循环,即使不强制所有可访问的内存都是最新的,并且被视为已关闭。因此,
    asm volatile
    语句执行此操作的原因与
    “内存”
    clobber无关

    int-loops
    是一种具有自动存储功能的本地设备。编译器可以证明任何东西(包括asm语句)都无法确定它可能在内存中的位置,因此它根本不必在内存中


    CPU能够预测应用StoreLoad的可能性有多大

    CPU不会无缘无故地寻找重新排序内存的机会!重新排序是自然发生的(除非使用MFENCE阻止),因为CPU需要缓冲存储,直到确定它们不是推测性的,并且需要缓存未命中的存储。因此,它将存储放在存储缓冲区中,它们最终提交到缓存

    CPU里没有一个小恶魔在说“啊哈,这是另一个让Gilgamesz为难的机会,也许这次我真的会用这个重新排序来欺骗他!”


    这里有一个真正的问题,那就是在一个特定的微体系结构没有足够的无序资源来缓冲该存储之前,两条指令需要相距多远(在时间上,或在INSN的数量上,或中间加载/存储的数量上)。

    我不知道,但由于StoreStore不允许重新排序,因此在数百万条其他指令运行时,对高度竞争的缓存线的缓存未命中存储不能坐在那里等待访问缓存线。除非这些说明都不是商店

    我不知道答案,但我认为Intel Haswell上的存储从理论上讲可能会延迟数百万个周期,这是合理的,可能仅受硬件仲裁机制的公平性算法的限制,该机制处理多个内核争用同一缓存线的情况


    我忘记了我读到的关于现代Intel硬件是否以这种方式工作的文章,但我认为也许一个存储可以从无序的内核中退役,但仍然没有承诺使用一级缓存。相反,它只是作为一个商店出现在商店队列中。这将使缓存未命中存储避免阻止新指令进入ROB。(加载需要探测存储缓冲区以保持单核内的正确执行,但这样做不需要ROB也跟踪存储)。

    1)可能是一个副作用,它会阻止优化器丢弃原本“不必要”的存储修改“循环”。如果将其取出并使用
    -O3
    编译函数会发生什么?我明白了,代码与设置了屏障的代码有何不同。因此,您是否建议存在障碍,因为,否则,它将被编译器删除?那2号呢。问题?也许,我没有很好地解释我的意思?我对#2没有任何想法。但是,如果没有内存缓冲,它可以完全消除“浪费时间”的循环。这是一种不好的拖延方式。如果您想替换它,可能是类似于uuu builtin\u ia32\u pause()?我没有收到您答复的通知,因为您没有使用
    @peter
    。澄清一下,你是说这是别人写的现有代码?从你看到的教学操作系统中?这并不明显,尤其是缺少分号意味着它甚至无法编译@MichaelPetch:哦,哈哈。是的,因为没有输出的
    asm()
    是隐式易失性的。“即使没有输出,编译器也必须假设asm volatile语句可以读取任何全局变量”,实际上,它不会。从gcc的扩展asm中访问(非易失性)全局变量(没有明确地将它们列为输入)是不安全的。在gcc v7.x之前,这在基本asm中也不安全。也就是说,在这个特殊的情况下,它是这样工作的,因为使用asm通常会禁用内联,函数调用会隐式刷新内存。我想这是他自己的密码。PintOS定义了一个
    barrier()
    宏,可以在许多不同的上下文中使用。它被定义为
    #define barrier()asm volatile(“::“memory”)
    它们记录为一个特殊语句,防止编译器对跨越屏障的内存状态做出假设。编译器不会对跨越屏障的变量读取或写入进行重新排序,也不会假设变量的值在屏障中未被修改,除非其地址从未被获取。@PeterCordes考虑:
    globalX=1;asm(“mov
    
    void loop(int loops) 
        {
          while (loops-- > 0)
            asm volatile ("" : : : "memory")
        }
    
    void loop_nomemclobber(int loops) {
      do {     // loop rearranged for simpler asm
        asm volatile ("" : : : /* "memory" */ );
      } while (--loops > 0);
    }
    
    loop_nomemclobber:
    .L3:
        sub     edi, 1
        test    edi, edi
        jg      .L3
        ret