免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: ruslin
打印 上一主题 下一主题

内核同步,优化内存屏障问题。 [复制链接]

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
11 [报告]
发表于 2011-10-13 18:15 |只看该作者
回复 9# ruslin


    硬件处于物理地址的时候,乱序导致硬件工作不正常。硬件自身有状态机。

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
12 [报告]
发表于 2011-10-13 18:32 |只看该作者
本帖最后由 zylthinking 于 2011-10-13 18:47 编辑
回复  eexplorer


我还是有点疑惑。
现在就假设是在up上。加了barrier宏使编译器没有重新排序指令,但 ...
ruslin 发表于 2011-10-13 13:01



应该是 barrier 前的即便再乱序, 也不能在 barrier 后的指令执行后它再执行, 同理, barrier 后的指令再怎么乱, 也要等barrier 前的指令全部执行完毕它们才能执行---即便这些barrier前后的指令是乱序的;
但我不明白为什么需要这样; 程序员怎么能预测到跨越 barrier 的乱序会出现问题, 为什么会出现
如果我能弄判断出来肯定会出问题, 自然会使用 barrier 避免, 所以根本问题就是程序员是怎么知道的

求解

论坛徽章:
0
13 [报告]
发表于 2011-10-14 08:23 |只看该作者
回复 12# zylthinking


优化屏障barrier不能保证cpu不把barrier前后的指令乱序执行,只有内存屏障才有这个作用。

例如:
a = 1;
barrier()
b = 2;

可能cpu先把b的内存设为2,再把a的内存设为1的

论坛徽章:
0
14 [报告]
发表于 2011-10-14 08:25 |只看该作者
回复 11# smalloc

按照你说的,我想解释在我的例子上,我还是想不通。

论坛徽章:
0
15 [报告]
发表于 2011-10-14 09:42 |只看该作者
关于LZ举的例子,我在2.6.35的代码里面没有看到readl有volatile变量呀~
  1. #define readl inl
  2. ......
  3. static inline u32 inl(u32 port)
  4. {
  5.         u32 v;
  6.         asm volatile("inl %1,%0" : "=a" (v) : "dN" (port));
  7.         return v;
  8. }
复制代码
asm里面的volatile修饰应该是说asm里面的代码不要重排吧~
如果是这样的话,barrier()不就是为了避免编译器用一个寄存器来缓存readl的返回值么?


另外,LZ提到一个问题。既然barrier()只能阻止编译器乱序,而不能阻止CPU乱序,那么barrier还有什么用呢?
我是这样理解的,barrier()是内存屏障的弱化版本,能用barrier()解决问题的地方,用barrier()自然更高效。
那么什么样的地方用barrier()就能解决问题了呢?
之前有篇帖子讨论了“preempt_disable()中怎么只有barrier而没有CPU内存屏障呢?”,http://bbs.chinaunix.net/thread-2054255-1-1.html。这就是个例子。

论坛徽章:
0
16 [报告]
发表于 2011-10-14 10:17 |只看该作者
本帖最后由 ruslin 于 2011-10-14 10:41 编辑

回复 15# kouu

>>>>关于LZ举的例子,我在2.6.35的代码里面没有看到readl有volatile变量呀~

比如我说的例子。
    while ((--i > 0) &&
            (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
                barrier();
        }

看readl的实现(31,35代码都一样):
#define readl(addr) __le32_to_cpu(__raw_readl(addr))
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
        return *(const volatile u32 __force *) addr;
}
明显readl访问的是volatile型变量。

---------------------------------------------------------------------------------

对于preempt_disable为什么用barrier,其实跟我发的主题意思一样,起得优化屏障的第二个作用,防止编译器寄存器优化它后面的代码。原因,其他cpu不会访问到这个count(每核心进程相关的thread_info,多线程它们的thread_info也不一样),没有必要处理顺序一致行问题所以没有用内存屏障。
#define preempt_disable() \
do { \
        inc_preempt_count(); \
        barrier(); \
} while (0)


---------------------------------------------------------------------------------

如果对于一段普通代码,编译器优化后,重新排列指令就会导致问题?我目前还么有想出这样的例子来。


总之,仍然没有解决我的疑惑。

论坛徽章:
0
17 [报告]
发表于 2011-10-14 11:06 |只看该作者
回复 13# ruslin


write a;
barrier();
read b;

我觉得是这样理解(纯属猜测,不对的地方请高手指出):barrier()只是防止compile reorder指令,但cpu可以乱序执行write a和read b两条指令
假设cpu先执行read b, 但是在执行完write a后,来了一个中断改变了b的值,那么我觉得cpu应该丢弃前面read b执行的结果,重新执行一遍read b,这样cpu在硬件上保证一旦在write a后发生了一些事件,需要顺序执行write a和read b,会discard以前的结果,保证program order。

但是如果没有barrier()的话,compiler就把read b移到write a前面的话,就没有办法保证上面我说的情况了。

论坛徽章:
0
18 [报告]
发表于 2011-10-14 11:08 |只看该作者
回复 16# ruslin


    volatile 是用来修饰变量addr,而不是修饰readl的返回值的吧~ 编译器不可以缓存readl的返回值么?

    关于指令重排会出问题,就比如preempt_disable的例子:

    inc_preempt_count();
    barrier();
    do_something...

    do_something的代码是需要禁止抢占的,如果没有barrier(),do_something如果被重排到inc_preempt_count()之前,那么就有可能在不该被抢占的地方被抢占。

    那么,就算用了barrier(),CPU执行的时候不也一样可能乱序么,怎么就不会出问题? 这就是我刚才转的那篇帖子要讨论的东西,不知道LZ是否已经理解。


    LZ又说,没有找到“普通”的代码在指令重排后会出问题的例子。如果说“普通”的代码指的是有明显上下文因果关系的代码,那么指令重排和乱序执行都不会有问题,因为保证上下文因果关系是根本原则。
    比如:a=XXX; b=func(a);,b的值依赖于a的结果,就不能重排。

    而对于“非普通”的代码,依赖关系可能是存在的,但是又不能从代码的上下文中看出来。这个时候就需要用到屏障了。
    比如:addr=XXX; val=data; 字面上看addr和data毫无关系,但是它们可能正好是某个设备的地址端口和数据端口,addr的值决定了读data时的输出。

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
19 [报告]
发表于 2011-10-14 11:33 |只看该作者
回复 1# ruslin
多谢分享。
barrier()应该是用来防止编译器优化的。
防止CPU乱序执行的应该是汇编指令lock吧?这个不太确定

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
20 [报告]
发表于 2011-10-14 12:13 |只看该作者
回复  ruslin
多谢分享。
barrier()应该是用来防止编译器优化的。
防止CPU乱序执行的应该是汇编指令loc ...
瀚海书香 发表于 2011-10-14 11:33


lock 指令是怎么防止的呢, 我的意思是说, 二进制文件中, lock 前有若干条指令, lock 后有若干条指令, 那么 lock 防乱序的手段是不是就是在之前的和之后的划一道沟, 让沟前沟后的各自乱去, 不能跨沟乱???
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP