我如何判断在代码中应该放置内存屏障的位置?

时间:2015-07-18 12:11:49

标签: linux-device-driver memory-barriers

当我读ldd3时,我得到了关于内存屏障的概念,据说代码执行将被重新排序,原因就像缓存和编译优化一样。我认为没有依赖关系的代码可以重新排序以获得更好的性能,并且IO端口寄存器无法优化,因为它需要包含一致的数据。但是我无法理解下面的代码,是否有任何规则要遵循我应该在哪里插入smb(),mb(),barrier()等函数?

例如,在ldd3中的示例代码 short

import pandas as pd
import datetime

def parse_date(td):
    resYear = float(td.days)/364.0                   # get the number of years including the the numbers after the dot
    resMonth = int((resYear - int(resYear))*364/30)  # get the number of months, by multiply the number after the dot by 364 and divide by 30.
    resYear = int(resYear)
    return str(resYear) + "Y" + str(resMonth) + "m"

df = pd.DataFrame([("2000-01-10", "1970-04-29")], columns=["start", "end"])
df["delta"] = [parse_date(datetime.datetime.strptime(start, '%Y-%m-%d') - datetime.datetime.strptime(end, '%Y-%m-%d')) for start, end in zip(df["start"], df["end"])]
print df

        start         end  delta
0  2000-01-10  1970-04-29  29Y9m

屏障之前的线如何以及屏障之后的线重新排序?我认为后者依赖于前者首先执行以获得 new 值。 这真让我感到困惑。

1 个答案:

答案 0 :(得分:0)

使用内存屏障代替锁定以获得更好的性能。当存储器障碍提供所需的同步时,有几种标准模式。您可以从内核源代码中读取Documentation/memory-barriers.txt

在来自ldd3的给定示例中,障碍使用比平时少。在当前内核方面(与2.20+相反,在ldd3中描述),可以使用ACCESS_ONCE()宏来表达相同的意图。

unsigned long new = *index + delta;
ACCESS_ONCE(*index) = (new >= (short_buffer + PAGE_SIZE)) ? short_buffer : new;

如果没有bariers,编译器可能会分配* index 两次

*index = *index + delta;
if(*index > (short_buffer + PAGE_BUFFER)
    *index = short_buffer;

因为*index在多个线程中用作 unprotected invariant (它显示哪个缓冲区可用),所以将中间值*index + delta写入其中会使其不变,其他人看到线程,不正确。这是由ACCESS_ONCE()宏阻止的,它强制编译器仅在被激发请求时才生成对变量的访问(写入)。

实际上,ACCESS_ONCE(以及代码中的障碍)对于volatile修饰符的变量是可还原的。